1 Star 0 Fork 0

Ragus/gost

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
forward.go 16.90 KB
一键复制 编辑 原始数据 按行查看 历史
ginuerzh 提交于 2020-02-27 14:56 . add relay proxy protocol
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
package gost
import (
"context"
"errors"
"net"
"strings"
"sync"
"time"
"fmt"
"github.com/ginuerzh/gosocks5"
"github.com/go-log/log"
smux "gopkg.in/xtaci/smux.v1"
)
type forwardConnector struct {
}
// ForwardConnector creates a Connector for data forward client.
func ForwardConnector() Connector {
return &forwardConnector{}
}
func (c *forwardConnector) Connect(conn net.Conn, address string, options ...ConnectOption) (net.Conn, error) {
return c.ConnectContext(context.Background(), conn, "tcp", address, options...)
}
func (c *forwardConnector) ConnectContext(ctx context.Context, conn net.Conn, network, address string, options ...ConnectOption) (net.Conn, error) {
return conn, nil
}
type baseForwardHandler struct {
raddr string
group *NodeGroup
options *HandlerOptions
}
func (h *baseForwardHandler) Init(options ...HandlerOption) {
if h.options == nil {
h.options = &HandlerOptions{}
}
for _, opt := range options {
opt(h.options)
}
h.group = NewNodeGroup() // reset node group
h.group.SetSelector(&defaultSelector{},
WithStrategy(h.options.Strategy),
WithFilter(&FailFilter{
MaxFails: h.options.MaxFails,
FailTimeout: h.options.FailTimeout,
}),
)
n := 1
addrs := append(strings.Split(h.raddr, ","), h.options.IPs...)
for _, addr := range addrs {
if addr == "" {
continue
}
// We treat the remote target server as a node, so we can put them in a group,
// and perform the node selection for load balancing.
h.group.AddNode(Node{
ID: n,
Addr: addr,
Host: addr,
marker: &failMarker{},
})
n++
}
}
type tcpDirectForwardHandler struct {
*baseForwardHandler
}
// TCPDirectForwardHandler creates a server Handler for TCP port forwarding server.
// The raddr is the remote address that the server will forward to.
// NOTE: as of 2.6, remote address can be a comma-separated address list.
func TCPDirectForwardHandler(raddr string, opts ...HandlerOption) Handler {
h := &tcpDirectForwardHandler{
baseForwardHandler: &baseForwardHandler{
raddr: raddr,
group: NewNodeGroup(),
options: &HandlerOptions{},
},
}
for _, opt := range opts {
opt(h.options)
}
return h
}
func (h *tcpDirectForwardHandler) Init(options ...HandlerOption) {
h.baseForwardHandler.Init(options...)
}
func (h *tcpDirectForwardHandler) Handle(conn net.Conn) {
defer conn.Close()
log.Logf("[tcp] %s - %s", conn.RemoteAddr(), conn.LocalAddr())
retries := 1
if h.options.Chain != nil && h.options.Chain.Retries > 0 {
retries = h.options.Chain.Retries
}
if h.options.Retries > 0 {
retries = h.options.Retries
}
var cc net.Conn
var node Node
var err error
for i := 0; i < retries; i++ {
if len(h.group.Nodes()) > 0 {
node, err = h.group.Next()
if err != nil {
log.Logf("[tcp] %s - %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
return
}
}
cc, err = h.options.Chain.Dial(node.Addr,
RetryChainOption(h.options.Retries),
TimeoutChainOption(h.options.Timeout),
)
if err != nil {
log.Logf("[tcp] %s -> %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
node.MarkDead()
} else {
break
}
}
if err != nil {
return
}
node.ResetDead()
defer cc.Close()
addr := node.Addr
if addr == "" {
addr = conn.LocalAddr().String()
}
log.Logf("[tcp] %s <-> %s", conn.RemoteAddr(), addr)
transport(conn, cc)
log.Logf("[tcp] %s >-< %s", conn.RemoteAddr(), addr)
}
type udpDirectForwardHandler struct {
*baseForwardHandler
}
// UDPDirectForwardHandler creates a server Handler for UDP port forwarding server.
// The raddr is the remote address that the server will forward to.
// NOTE: as of 2.6, remote address can be a comma-separated address list.
func UDPDirectForwardHandler(raddr string, opts ...HandlerOption) Handler {
h := &udpDirectForwardHandler{
baseForwardHandler: &baseForwardHandler{
raddr: raddr,
group: NewNodeGroup(),
options: &HandlerOptions{},
},
}
for _, opt := range opts {
opt(h.options)
}
return h
}
func (h *udpDirectForwardHandler) Init(options ...HandlerOption) {
h.baseForwardHandler.Init(options...)
}
func (h *udpDirectForwardHandler) Handle(conn net.Conn) {
defer conn.Close()
log.Logf("[udp] %s - %s", conn.RemoteAddr(), conn.LocalAddr())
var node Node
var err error
if len(h.group.Nodes()) > 0 {
node, err = h.group.Next()
if err != nil {
log.Logf("[udp] %s - %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
return
}
}
cc, err := h.options.Chain.DialContext(context.Background(), "udp", node.Addr)
if err != nil {
node.MarkDead()
log.Logf("[udp] %s - %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
return
}
defer cc.Close()
node.ResetDead()
addr := node.Addr
if addr == "" {
addr = conn.LocalAddr().String()
}
log.Logf("[udp] %s <-> %s", conn.RemoteAddr(), addr)
transport(conn, cc)
log.Logf("[udp] %s >-< %s", conn.RemoteAddr(), addr)
}
type tcpRemoteForwardHandler struct {
*baseForwardHandler
}
// TCPRemoteForwardHandler creates a server Handler for TCP remote port forwarding server.
// The raddr is the remote address that the server will forward to.
// NOTE: as of 2.6, remote address can be a comma-separated address list.
func TCPRemoteForwardHandler(raddr string, opts ...HandlerOption) Handler {
h := &tcpRemoteForwardHandler{
baseForwardHandler: &baseForwardHandler{
raddr: raddr,
group: NewNodeGroup(),
options: &HandlerOptions{},
},
}
for _, opt := range opts {
opt(h.options)
}
return h
}
func (h *tcpRemoteForwardHandler) Init(options ...HandlerOption) {
h.baseForwardHandler.Init(options...)
}
func (h *tcpRemoteForwardHandler) Handle(conn net.Conn) {
defer conn.Close()
retries := 1
if h.options.Retries > 0 {
retries = h.options.Retries
}
var cc net.Conn
var node Node
var err error
for i := 0; i < retries; i++ {
if len(h.group.Nodes()) > 0 {
node, err = h.group.Next()
if err != nil {
log.Logf("[rtcp] %s - %s : %s", conn.LocalAddr(), h.raddr, err)
return
}
}
cc, err = net.DialTimeout("tcp", node.Addr, h.options.Timeout)
if err != nil {
log.Logf("[rtcp] %s -> %s : %s", conn.LocalAddr(), node.Addr, err)
node.MarkDead()
} else {
break
}
}
if err != nil {
return
}
defer cc.Close()
node.ResetDead()
log.Logf("[rtcp] %s <-> %s", conn.LocalAddr(), node.Addr)
transport(cc, conn)
log.Logf("[rtcp] %s >-< %s", conn.LocalAddr(), node.Addr)
}
type udpRemoteForwardHandler struct {
*baseForwardHandler
}
// UDPRemoteForwardHandler creates a server Handler for UDP remote port forwarding server.
// The raddr is the remote address that the server will forward to.
// NOTE: as of 2.6, remote address can be a comma-separated address list.
func UDPRemoteForwardHandler(raddr string, opts ...HandlerOption) Handler {
h := &udpRemoteForwardHandler{
baseForwardHandler: &baseForwardHandler{
raddr: raddr,
group: NewNodeGroup(),
options: &HandlerOptions{},
},
}
for _, opt := range opts {
opt(h.options)
}
return h
}
func (h *udpRemoteForwardHandler) Init(options ...HandlerOption) {
h.baseForwardHandler.Init(options...)
}
func (h *udpRemoteForwardHandler) Handle(conn net.Conn) {
defer conn.Close()
var node Node
var err error
if len(h.group.Nodes()) > 0 {
node, err = h.group.Next()
if err != nil {
log.Logf("[rudp] %s - %s : %s", conn.RemoteAddr(), h.raddr, err)
return
}
}
raddr, err := net.ResolveUDPAddr("udp", node.Addr)
if err != nil {
node.MarkDead()
log.Logf("[rudp] %s - %s : %s", conn.RemoteAddr(), node.Addr, err)
return
}
cc, err := net.DialUDP("udp", nil, raddr)
if err != nil {
node.MarkDead()
log.Logf("[rudp] %s - %s : %s", conn.RemoteAddr(), node.Addr, err)
return
}
defer cc.Close()
node.ResetDead()
log.Logf("[rudp] %s <-> %s", conn.RemoteAddr(), node.Addr)
transport(conn, cc)
log.Logf("[rudp] %s >-< %s", conn.RemoteAddr(), node.Addr)
}
type tcpRemoteForwardListener struct {
addr net.Addr
chain *Chain
connChan chan net.Conn
ln net.Listener
session *muxSession
sessionMux sync.Mutex
closed chan struct{}
closeMux sync.Mutex
}
// TCPRemoteForwardListener creates a Listener for TCP remote port forwarding server.
func TCPRemoteForwardListener(addr string, chain *Chain) (Listener, error) {
laddr, err := net.ResolveTCPAddr("tcp", addr)
if err != nil {
return nil, err
}
ln := &tcpRemoteForwardListener{
addr: laddr,
chain: chain,
connChan: make(chan net.Conn, 1024),
closed: make(chan struct{}),
}
if !ln.isChainValid() {
ln.ln, err = net.Listen("tcp", ln.addr.String())
return ln, err
}
go ln.listenLoop()
return ln, err
}
func (l *tcpRemoteForwardListener) isChainValid() bool {
if l.chain.IsEmpty() {
return false
}
lastNode := l.chain.LastNode()
if (lastNode.Protocol == "forward" && lastNode.Transport == "ssh") ||
lastNode.Protocol == "socks5" || lastNode.Protocol == "" {
return true
}
return false
}
func (l *tcpRemoteForwardListener) listenLoop() {
var tempDelay time.Duration
for {
conn, err := l.accept()
select {
case <-l.closed:
if conn != nil {
conn.Close()
}
return
default:
}
if err != nil {
if tempDelay == 0 {
tempDelay = 1000 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 6 * time.Second; tempDelay > max {
tempDelay = max
}
log.Logf("[rtcp] accept error: %v; retrying in %v", err, tempDelay)
time.Sleep(tempDelay)
continue
}
tempDelay = 0
select {
case l.connChan <- conn:
default:
conn.Close()
log.Logf("[rtcp] %s - %s: connection queue is full", conn.RemoteAddr(), conn.LocalAddr())
}
}
}
func (l *tcpRemoteForwardListener) Accept() (conn net.Conn, err error) {
if l.ln != nil {
return l.ln.Accept()
}
select {
case conn = <-l.connChan:
case <-l.closed:
err = errors.New("closed")
}
return
}
func (l *tcpRemoteForwardListener) accept() (conn net.Conn, err error) {
lastNode := l.chain.LastNode()
if lastNode.Protocol == "forward" && lastNode.Transport == "ssh" {
return l.chain.Dial(l.addr.String())
}
if l.isChainValid() {
if lastNode.GetBool("mbind") {
return l.muxAccept() // multiplexing support for binding.
}
cc, er := l.chain.Conn()
if er != nil {
return nil, er
}
conn, err = l.waitConnectSOCKS5(cc)
if err != nil {
cc.Close()
}
}
return
}
func (l *tcpRemoteForwardListener) muxAccept() (conn net.Conn, err error) {
session, err := l.getSession()
if err != nil {
return nil, err
}
cc, err := session.Accept()
if err != nil {
session.Close()
return nil, err
}
return cc, nil
}
func (l *tcpRemoteForwardListener) getSession() (s *muxSession, err error) {
l.sessionMux.Lock()
defer l.sessionMux.Unlock()
if l.session != nil && !l.session.IsClosed() {
return l.session, nil
}
conn, err := l.chain.Conn()
if err != nil {
return nil, err
}
defer func(c net.Conn) {
if err != nil {
c.Close()
}
}(conn)
conn.SetDeadline(time.Now().Add(HandshakeTimeout))
defer conn.SetDeadline(time.Time{})
conn, err = socks5Handshake(conn, userSocks5HandshakeOption(l.chain.LastNode().User))
if err != nil {
return nil, err
}
req := gosocks5.NewRequest(CmdMuxBind, toSocksAddr(l.addr))
if err := req.Write(conn); err != nil {
log.Log("[rtcp] SOCKS5 BIND request: ", err)
return nil, err
}
rep, err := gosocks5.ReadReply(conn)
if err != nil {
log.Log("[rtcp] SOCKS5 BIND reply: ", err)
return nil, err
}
if rep.Rep != gosocks5.Succeeded {
log.Logf("[rtcp] bind on %s failure", l.addr)
return nil, fmt.Errorf("Bind on %s failure", l.addr.String())
}
log.Logf("[rtcp] BIND ON %s OK", rep.Addr)
// Upgrade connection to multiplex stream.
session, err := smux.Server(conn, smux.DefaultConfig())
if err != nil {
return nil, err
}
l.session = &muxSession{
conn: conn,
session: session,
}
return l.session, nil
}
func (l *tcpRemoteForwardListener) waitConnectSOCKS5(conn net.Conn) (net.Conn, error) {
conn, err := socks5Handshake(conn, userSocks5HandshakeOption(l.chain.LastNode().User))
if err != nil {
return nil, err
}
req := gosocks5.NewRequest(gosocks5.CmdBind, toSocksAddr(l.addr))
if err := req.Write(conn); err != nil {
log.Log("[rtcp] SOCKS5 BIND request: ", err)
return nil, err
}
// first reply, bind status
conn.SetReadDeadline(time.Now().Add(ReadTimeout))
rep, err := gosocks5.ReadReply(conn)
if err != nil {
log.Log("[rtcp] SOCKS5 BIND reply: ", err)
return nil, err
}
conn.SetReadDeadline(time.Time{})
if rep.Rep != gosocks5.Succeeded {
log.Logf("[rtcp] bind on %s failure", l.addr)
return nil, fmt.Errorf("Bind on %s failure", l.addr.String())
}
log.Logf("[rtcp] BIND ON %s OK", rep.Addr)
// second reply, peer connected
rep, err = gosocks5.ReadReply(conn)
if err != nil {
log.Log("[rtcp]", err)
return nil, err
}
if rep.Rep != gosocks5.Succeeded {
log.Logf("[rtcp] peer connect failure: %d", rep.Rep)
return nil, errors.New("peer connect failure")
}
log.Logf("[rtcp] PEER %s CONNECTED", rep.Addr)
return conn, nil
}
func (l *tcpRemoteForwardListener) Addr() net.Addr {
if l.ln != nil {
return l.ln.Addr()
}
return l.addr
}
func (l *tcpRemoteForwardListener) Close() error {
if l.ln != nil {
return l.ln.Close()
}
l.closeMux.Lock()
defer l.closeMux.Unlock()
select {
case <-l.closed:
return nil
default:
close(l.closed)
}
return nil
}
type udpRemoteForwardListener struct {
addr net.Addr
chain *Chain
connMap *udpConnMap
connChan chan net.Conn
ln *net.UDPConn
ttl time.Duration
closed chan struct{}
ready chan struct{}
once sync.Once
closeMux sync.Mutex
config *UDPListenConfig
}
// UDPRemoteForwardListener creates a Listener for UDP remote port forwarding server.
func UDPRemoteForwardListener(addr string, chain *Chain, cfg *UDPListenConfig) (Listener, error) {
laddr, err := net.ResolveUDPAddr("udp", addr)
if err != nil {
return nil, err
}
if cfg == nil {
cfg = &UDPListenConfig{}
}
backlog := cfg.Backlog
if backlog <= 0 {
backlog = defaultBacklog
}
ln := &udpRemoteForwardListener{
addr: laddr,
chain: chain,
connMap: new(udpConnMap),
connChan: make(chan net.Conn, backlog),
ready: make(chan struct{}),
closed: make(chan struct{}),
config: cfg,
}
go ln.listenLoop()
<-ln.ready
return ln, err
}
func (l *udpRemoteForwardListener) isChainValid() bool {
if l.chain.IsEmpty() {
return false
}
lastNode := l.chain.LastNode()
return lastNode.Protocol == "socks5" || lastNode.Protocol == ""
}
func (l *udpRemoteForwardListener) listenLoop() {
for {
conn, err := l.connect()
if err != nil {
log.Logf("[rudp] %s : %s", l.Addr(), err)
return
}
l.once.Do(func() {
close(l.ready)
})
func() {
defer conn.Close()
for {
b := make([]byte, mediumBufferSize)
n, raddr, err := conn.ReadFrom(b)
if err != nil {
log.Logf("[rudp] %s : %s", l.Addr(), err)
break
}
uc, ok := l.connMap.Get(raddr.String())
if !ok {
uc = newUDPServerConn(conn, raddr, &udpServerConnConfig{
ttl: l.config.TTL,
qsize: l.config.QueueSize,
onClose: func() {
l.connMap.Delete(raddr.String())
log.Logf("[rudp] %s closed (%d)", raddr, l.connMap.Size())
},
})
select {
case l.connChan <- uc:
l.connMap.Set(raddr.String(), uc)
log.Logf("[rudp] %s -> %s (%d)", raddr, l.Addr(), l.connMap.Size())
default:
uc.Close()
log.Logf("[rudp] %s - %s: connection queue is full (%d)",
raddr, l.Addr(), cap(l.connChan))
}
}
select {
case uc.rChan <- b[:n]:
if Debug {
log.Logf("[rudp] %s >>> %s : length %d", raddr, l.Addr(), n)
}
default:
log.Logf("[rudp] %s -> %s : recv queue is full", raddr, l.Addr(), cap(uc.rChan))
}
}
}()
}
}
func (l *udpRemoteForwardListener) connect() (conn net.PacketConn, err error) {
var tempDelay time.Duration
for {
select {
case <-l.closed:
return nil, errors.New("closed")
default:
}
if l.isChainValid() {
var cc net.Conn
cc, err = getSocks5UDPTunnel(l.chain, l.addr)
if err != nil {
log.Logf("[rudp] %s : %s", l.Addr(), err)
} else {
conn = cc.(net.PacketConn)
}
} else {
var uc *net.UDPConn
uc, err = net.ListenUDP("udp", l.addr.(*net.UDPAddr))
if err == nil {
l.addr = uc.LocalAddr()
conn = uc
}
}
if err != nil {
if tempDelay == 0 {
tempDelay = 1000 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 6 * time.Second; tempDelay > max {
tempDelay = max
}
log.Logf("[rudp] Accept error: %v; retrying in %v", err, tempDelay)
time.Sleep(tempDelay)
continue
}
return
}
}
func (l *udpRemoteForwardListener) Accept() (conn net.Conn, err error) {
select {
case conn = <-l.connChan:
case <-l.closed:
err = errors.New("accpet on closed listener")
}
return
}
func (l *udpRemoteForwardListener) Addr() net.Addr {
return l.addr
}
func (l *udpRemoteForwardListener) Close() error {
l.closeMux.Lock()
defer l.closeMux.Unlock()
select {
case <-l.closed:
return nil
default:
l.connMap.Range(func(k interface{}, v *udpServerConn) bool {
v.Close()
return true
})
close(l.closed)
}
return nil
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/ragus/gost.git
git@gitee.com:ragus/gost.git
ragus
gost
gost
master

搜索帮助