diff --git a/core/chain.go b/core/chain.go index d002a6ac..2bea1a6d 100644 --- a/core/chain.go +++ b/core/chain.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "net" - "time" ) var ( @@ -100,29 +99,15 @@ func (c *Chain) IsEmpty() bool { return c == nil || len(c.nodeGroups) == 0 } -// Dial connects to the target TCP address addr through the chain. -// Deprecated: use DialContext instead. -func (c *Chain) Dial(address string, opts ...ChainOption) (conn net.Conn, err error) { - return c.DialContext(context.Background(), "tcp", address, opts...) -} - // DialContext connects to the address on the named network using the provided context. -func (c *Chain) DialContext(ctx context.Context, network, address string, opts ...ChainOption) (conn net.Conn, err error) { - options := &ChainOptions{} - for _, opt := range opts { - opt(options) - } - +func (c *Chain) DialContext(ctx context.Context, network, address string) (conn net.Conn, err error) { retries := 1 if c != nil && c.Retries > 0 { retries = c.Retries } - if options.Retries > 0 { - retries = options.Retries - } for i := 0; i < retries; i++ { - conn, err = c.dialWithOptions(ctx, network, address, options) + conn, err = c.dial(ctx, network, address) if err == nil { break } @@ -130,10 +115,7 @@ func (c *Chain) DialContext(ctx context.Context, network, address string, opts . return } -func (c *Chain) dialWithOptions(ctx context.Context, network, address string, options *ChainOptions) (net.Conn, error) { - if options == nil { - options = &ChainOptions{} - } +func (c *Chain) dial(ctx context.Context, network, address string) (net.Conn, error) { route, err := c.selectRouteFor(address) if err != nil { return nil, err @@ -144,11 +126,6 @@ func (c *Chain) dialWithOptions(ctx context.Context, network, address string, op ipAddr = c.resolve(address) } - timeout := options.Timeout - if timeout <= 0 { - timeout = DialTimeout - } - if route.IsEmpty() { switch network { case "udp", "udp4", "udp6": @@ -158,7 +135,7 @@ func (c *Chain) dialWithOptions(ctx context.Context, network, address string, op default: } d := &net.Dialer{ - Timeout: timeout, + Timeout: DialTimeout, // LocalAddr: laddr, // TODO: optional local address } return d.DialContext(ctx, network, ipAddr) @@ -169,8 +146,7 @@ func (c *Chain) dialWithOptions(ctx context.Context, network, address string, op return nil, err } - cOpts := append([]ConnectOption{AddrConnectOption(address)}, route.LastNode().ConnectOptions...) - cc, err := route.LastNode().Client.ConnectContext(ctx, conn, network, ipAddr, cOpts...) + cc, err := route.LastNode().Client.ConnectContext(ctx, conn, network, ipAddr) if err != nil { conn.Close() return nil, err @@ -188,21 +164,13 @@ func (*Chain) resolve(addr string) string { } // Conn obtains a handshaked connection to the last node of the chain. -func (c *Chain) Conn(opts ...ChainOption) (conn net.Conn, err error) { - options := &ChainOptions{} - for _, opt := range opts { - opt(options) - } - +func (c *Chain) Conn() (conn net.Conn, err error) { ctx := context.Background() retries := 1 if c != nil && c.Retries > 0 { retries = c.Retries } - if options.Retries > 0 { - retries = options.Retries - } for i := 0; i < retries; i++ { var route *Chain @@ -227,17 +195,12 @@ func (c *Chain) getConn(_ context.Context) (conn net.Conn, err error) { nodes := c.Nodes() node := nodes[0] - cc, err := node.Client.Dial(node.Addr, node.DialOptions...) + cc, err := node.Client.Dial(node.Addr) if err != nil { return } - cn, err := node.Client.Handshake(cc, node.HandshakeOptions...) - if err != nil { - cc.Close() - return - } - conn = cn + conn = cc return } @@ -255,7 +218,7 @@ func (c *Chain) selectRouteFor(addr string) (route *Chain, err error) { } route = newRoute() - var nl []Node + var nodes []Node for _, group := range c.nodeGroups { var node Node @@ -264,41 +227,10 @@ func (c *Chain) selectRouteFor(addr string) (route *Chain, err error) { return } - if node.Client.Transporter.Multiplex() { - node.DialOptions = append(node.DialOptions, - ChainDialOption(route), - ) - route = newRoute() // cutoff the chain for multiplex node. - } - route.AddNode(node) - nl = append(nl, node) + nodes = append(nodes, node) } - route.route = nl - + route.route = nodes return } - -// ChainOptions holds options for Chain. -type ChainOptions struct { - Retries int - Timeout time.Duration -} - -// ChainOption allows a common way to set chain options. -type ChainOption func(opts *ChainOptions) - -// RetryChainOption specifies the times of retry used by Chain.Dial. -func RetryChainOption(retries int) ChainOption { - return func(opts *ChainOptions) { - opts.Retries = retries - } -} - -// TimeoutChainOption specifies the timeout used by Chain.Dial. -func TimeoutChainOption(timeout time.Duration) ChainOption { - return func(opts *ChainOptions) { - opts.Timeout = timeout - } -} diff --git a/core/client.go b/core/client.go index de930175..bc218493 100644 --- a/core/client.go +++ b/core/client.go @@ -2,13 +2,7 @@ package core import ( "context" - "crypto/tls" - "fmt" "net" - "net/url" - "time" - - "github.com/ginuerzh/gosocks5" ) // Client is a proxy client. @@ -22,200 +16,10 @@ type Client struct { // Connector is responsible for connecting to the destination address. type Connector interface { - // Deprecated: use ConnectContext instead. - Connect(conn net.Conn, address string, options ...ConnectOption) (net.Conn, error) - ConnectContext(ctx context.Context, conn net.Conn, network, address string, options ...ConnectOption) (net.Conn, error) -} - -type autoConnector struct { - User *url.Userinfo -} - -// AutoConnector is a Connector. -func AutoConnector(user *url.Userinfo) Connector { - return &autoConnector{ - User: user, - } -} - -func (c *autoConnector) Connect(conn net.Conn, address string, options ...ConnectOption) (net.Conn, error) { - return c.ConnectContext(context.Background(), conn, "tcp", address, options...) -} - -func (c *autoConnector) ConnectContext(ctx context.Context, conn net.Conn, network, address string, options ...ConnectOption) (net.Conn, error) { - var cnr Connector - switch network { - case "tcp", "tcp4", "tcp6": - fmt.Println("xxxxxxxxxxxxxxxxxxxxxxx------------------------------------------") - //cnr = &httpConnector{User: c.User} - default: - cnr = SOCKS5UDPTunConnector(c.User) - } - - return cnr.ConnectContext(ctx, conn, network, address, options...) + ConnectContext(ctx context.Context, conn net.Conn, network, address string) (net.Conn, error) } // Transporter is responsible for handshaking with the proxy server. type Transporter interface { - Dial(addr string, options ...DialOption) (net.Conn, error) - Handshake(conn net.Conn, options ...HandshakeOption) (net.Conn, error) - // Indicate that the Transporter supports multiplex - Multiplex() bool -} - -// DialOptions describes the options for Transporter.Dial. -type DialOptions struct { - Timeout time.Duration - Chain *Chain - Host string -} - -// DialOption allows a common way to set DialOptions. -type DialOption func(opts *DialOptions) - -// TimeoutDialOption specifies the timeout used by Transporter.Dial -func TimeoutDialOption(timeout time.Duration) DialOption { - return func(opts *DialOptions) { - opts.Timeout = timeout - } -} - -// ChainDialOption specifies a chain used by Transporter.Dial -func ChainDialOption(chain *Chain) DialOption { - return func(opts *DialOptions) { - opts.Chain = chain - } -} - -// HostDialOption specifies the host used by Transporter.Dial -func HostDialOption(host string) DialOption { - return func(opts *DialOptions) { - opts.Host = host - } -} - -// HandshakeOptions describes the options for handshake. -type HandshakeOptions struct { - Addr string - Host string - User *url.Userinfo - Timeout time.Duration - Interval time.Duration - Retry int - TLSConfig *tls.Config -} - -// HandshakeOption allows a common way to set HandshakeOptions. -type HandshakeOption func(opts *HandshakeOptions) - -// AddrHandshakeOption specifies the server address -func AddrHandshakeOption(addr string) HandshakeOption { - return func(opts *HandshakeOptions) { - opts.Addr = addr - } -} - -// HostHandshakeOption specifies the hostname -func HostHandshakeOption(host string) HandshakeOption { - return func(opts *HandshakeOptions) { - opts.Host = host - } -} - -// UserHandshakeOption specifies the user used by Transporter.Handshake -func UserHandshakeOption(user *url.Userinfo) HandshakeOption { - return func(opts *HandshakeOptions) { - opts.User = user - } -} - -// TimeoutHandshakeOption specifies the timeout used by Transporter.Handshake -func TimeoutHandshakeOption(timeout time.Duration) HandshakeOption { - return func(opts *HandshakeOptions) { - opts.Timeout = timeout - } -} - -// IntervalHandshakeOption specifies the interval time used by Transporter.Handshake -func IntervalHandshakeOption(interval time.Duration) HandshakeOption { - return func(opts *HandshakeOptions) { - opts.Interval = interval - } -} - -// RetryHandshakeOption specifies the times of retry used by Transporter.Handshake -func RetryHandshakeOption(retry int) HandshakeOption { - return func(opts *HandshakeOptions) { - opts.Retry = retry - } -} - -// TLSConfigHandshakeOption specifies the TLS config used by Transporter.Handshake -func TLSConfigHandshakeOption(config *tls.Config) HandshakeOption { - return func(opts *HandshakeOptions) { - opts.TLSConfig = config - } -} - -// ConnectOptions describes the options for Connector.Connect. -type ConnectOptions struct { - Addr string - Timeout time.Duration - User *url.Userinfo - Selector gosocks5.Selector - UserAgent string - NoTLS bool - NoDelay bool -} - -// ConnectOption allows a common way to set ConnectOptions. -type ConnectOption func(opts *ConnectOptions) - -// AddrConnectOption specifies the corresponding address of the target. -func AddrConnectOption(addr string) ConnectOption { - return func(opts *ConnectOptions) { - opts.Addr = addr - } -} - -// TimeoutConnectOption specifies the timeout for connecting to target. -func TimeoutConnectOption(timeout time.Duration) ConnectOption { - return func(opts *ConnectOptions) { - opts.Timeout = timeout - } -} - -// UserConnectOption specifies the user info for authentication. -func UserConnectOption(user *url.Userinfo) ConnectOption { - return func(opts *ConnectOptions) { - opts.User = user - } -} - -// SelectorConnectOption specifies the SOCKS5 client selector. -func SelectorConnectOption(s gosocks5.Selector) ConnectOption { - return func(opts *ConnectOptions) { - opts.Selector = s - } -} - -// UserAgentConnectOption specifies the HTTP user-agent header. -func UserAgentConnectOption(ua string) ConnectOption { - return func(opts *ConnectOptions) { - opts.UserAgent = ua - } -} - -// NoTLSConnectOption specifies the SOCKS5 method without TLS. -func NoTLSConnectOption(b bool) ConnectOption { - return func(opts *ConnectOptions) { - opts.NoTLS = b - } -} - -// NoDelayConnectOption specifies the NoDelay option for ss.Connect. -func NoDelayConnectOption(b bool) ConnectOption { - return func(opts *ConnectOptions) { - opts.NoDelay = b - } + Dial(addr string) (net.Conn, error) } diff --git a/core/handler.go b/core/handler.go index 63aec296..e42083b4 100644 --- a/core/handler.go +++ b/core/handler.go @@ -1,14 +1,8 @@ package core import ( - "bufio" - "crypto/tls" "net" "net/url" - "time" - - "github.com/ginuerzh/gosocks5" - "github.com/go-log/log" ) // Handler is a proxy server handler @@ -19,30 +13,16 @@ type Handler interface { // HandlerOptions describes the options for Handler. type HandlerOptions struct { - Addr string Chain *Chain Users []*url.Userinfo Authenticator Authenticator - TLSConfig *tls.Config - MaxFails int - FailTimeout time.Duration - Retries int - Timeout time.Duration Node Node - TCPMode bool IPRoutes []IPRoute } // HandlerOption allows a common way to set handler options. type HandlerOption func(opts *HandlerOptions) -// AddrHandlerOption sets the Addr option of HandlerOptions. -func AddrHandlerOption(addr string) HandlerOption { - return func(opts *HandlerOptions) { - opts.Addr = addr - } -} - // ChainHandlerOption sets the Chain option of HandlerOptions. func ChainHandlerOption(chain *Chain) HandlerOption { return func(opts *HandlerOptions) { @@ -57,34 +37,6 @@ func AuthenticatorHandlerOption(authenticator Authenticator) HandlerOption { } } -// MaxFailsHandlerOption sets the max_fails option of HandlerOptions. -func MaxFailsHandlerOption(n int) HandlerOption { - return func(opts *HandlerOptions) { - opts.MaxFails = n - } -} - -// FailTimeoutHandlerOption sets the fail_timeout option of HandlerOptions. -func FailTimeoutHandlerOption(d time.Duration) HandlerOption { - return func(opts *HandlerOptions) { - opts.FailTimeout = d - } -} - -// RetryHandlerOption sets the retry option of HandlerOptions. -func RetryHandlerOption(retries int) HandlerOption { - return func(opts *HandlerOptions) { - opts.Retries = retries - } -} - -// TimeoutHandlerOption sets the timeout option of HandlerOptions. -func TimeoutHandlerOption(timeout time.Duration) HandlerOption { - return func(opts *HandlerOptions) { - opts.Timeout = timeout - } -} - // NodeHandlerOption set the server node for server handler. func NodeHandlerOption(node Node) HandlerOption { return func(opts *HandlerOptions) { @@ -92,64 +44,9 @@ func NodeHandlerOption(node Node) HandlerOption { } } -// TCPModeHandlerOption sets the tcp mode for tun/tap device. -func TCPModeHandlerOption(b bool) HandlerOption { - return func(opts *HandlerOptions) { - opts.TCPMode = b - } -} - // IPRoutesHandlerOption sets the IP routes for tun tunnel. func IPRoutesHandlerOption(routes ...IPRoute) HandlerOption { return func(opts *HandlerOptions) { opts.IPRoutes = routes } } - -type autoHandler struct { - options *HandlerOptions -} - -// AutoHandler creates a server Handler for auto proxy server. -func AutoHandler(opts ...HandlerOption) Handler { - h := &autoHandler{} - h.Init(opts...) - return h -} - -func (h *autoHandler) Init(options ...HandlerOption) { - if h.options == nil { - h.options = &HandlerOptions{} - } - for _, opt := range options { - opt(h.options) - } -} - -func (h *autoHandler) Handle(conn net.Conn) { - br := bufio.NewReader(conn) - b, err := br.Peek(1) - if err != nil { - log.Logf("[auto] %s - %s: %s", conn.RemoteAddr(), conn.LocalAddr(), err) - conn.Close() - return - } - - cc := &bufferdConn{Conn: conn, br: br} - var handler Handler - switch b[0] { - case gosocks5.Ver5: // socks5 - handler = &socks5Handler{options: h.options} - } - handler.Init() - handler.Handle(cc) -} - -type bufferdConn struct { - net.Conn - br *bufio.Reader -} - -func (c *bufferdConn) Read(b []byte) (int, error) { - return c.br.Read(b) -} diff --git a/core/node.go b/core/node.go index 99060dd8..6e0ec682 100644 --- a/core/node.go +++ b/core/node.go @@ -17,18 +17,14 @@ var ( // Node is a proxy node, mainly used to construct a proxy chain. type Node struct { - Addr string - Host string - Protocol string - Transport string - Remote string // remote address, used by tcp/udp port forwarding - url *url.URL // raw url - User *url.Userinfo - Values url.Values - DialOptions []DialOption - HandshakeOptions []HandshakeOption - ConnectOptions []ConnectOption - Client *Client + Addr string + Protocol string + Transport string + Remote string // remote address, used by tcp/udp port forwarding + url *url.URL // raw url + User *url.Userinfo + Values url.Values + Client *Client } // ParseNode parses the node info. @@ -50,7 +46,6 @@ func ParseNode(s string) (node Node, err error) { node = Node{ Addr: u.Host, - Host: u.Host, Remote: strings.Trim(u.EscapedPath(), "/"), Values: u.Query(), User: u.User, diff --git a/core/socks.go b/core/socks.go index f1a4da17..d0b6817b 100644 --- a/core/socks.go +++ b/core/socks.go @@ -154,37 +154,22 @@ func SOCKS5Connector(user *url.Userinfo) Connector { return &socks5Connector{User: user} } -func (c *socks5Connector) Connect(conn net.Conn, address string, options ...ConnectOption) (net.Conn, error) { - return c.ConnectContext(context.Background(), conn, "tcp", address, options...) +func (c *socks5Connector) Connect(conn net.Conn, address string) (net.Conn, error) { + return c.ConnectContext(context.Background(), conn, "tcp", address) } -func (c *socks5Connector) ConnectContext(ctx context.Context, conn net.Conn, network, address string, options ...ConnectOption) (net.Conn, error) { +func (c *socks5Connector) ConnectContext(ctx context.Context, conn net.Conn, network, address string) (net.Conn, error) { switch network { case "udp", "udp4", "udp6": cnr := &socks5UDPTunConnector{User: c.User} - return cnr.ConnectContext(ctx, conn, network, address, options...) + return cnr.ConnectContext(ctx, conn, network, address) } - opts := &ConnectOptions{} - for _, option := range options { - option(opts) - } - - timeout := opts.Timeout - if timeout <= 0 { - timeout = ConnectTimeout - } - - conn.SetDeadline(time.Now().Add(timeout)) + conn.SetDeadline(time.Now().Add(ConnectTimeout)) defer conn.SetDeadline(time.Time{}) - user := opts.User - if user == nil { - user = c.User - } cc, err := socks5Handshake(conn, - selectorSocks5HandshakeOption(opts.Selector), - userSocks5HandshakeOption(user), + userSocks5HandshakeOption(c.User), ) if err != nil { return nil, err @@ -219,7 +204,7 @@ func (c *socks5Connector) ConnectContext(ctx context.Context, conn net.Conn, net } if reply.Rep != gosocks5.Succeeded { - return nil, errors.New("Service unavailable") + return nil, errors.New("service unavailable") } return conn, nil @@ -235,39 +220,16 @@ func SOCKS5UDPTunConnector(user *url.Userinfo) Connector { return &socks5UDPTunConnector{User: user} } -func (c *socks5UDPTunConnector) Connect(conn net.Conn, address string, options ...ConnectOption) (net.Conn, error) { - return c.ConnectContext(context.Background(), conn, "udp", address, options...) -} - -func (c *socks5UDPTunConnector) ConnectContext(ctx context.Context, conn net.Conn, network, address string, options ...ConnectOption) (net.Conn, error) { +func (c *socks5UDPTunConnector) ConnectContext(ctx context.Context, conn net.Conn, network, address string) (net.Conn, error) { switch network { case "tcp", "tcp4", "tcp6": return nil, fmt.Errorf("%s unsupported", network) } - - opts := &ConnectOptions{} - for _, option := range options { - option(opts) - } - - user := opts.User - if user == nil { - user = c.User - } - - timeout := opts.Timeout - if timeout <= 0 { - timeout = ConnectTimeout - } - conn.SetDeadline(time.Now().Add(timeout)) + conn.SetDeadline(time.Now().Add(ConnectTimeout)) defer conn.SetDeadline(time.Time{}) taddr, _ := net.ResolveUDPAddr("udp", address) - return newSocks5UDPTunnelConn(conn, - nil, taddr, - selectorSocks5HandshakeOption(opts.Selector), - userSocks5HandshakeOption(user), - ) + return newSocks5UDPTunnelConn(conn, nil, taddr, userSocks5HandshakeOption(c.User)) } type socks5Handler struct { @@ -344,9 +306,6 @@ func (h *socks5Handler) handleConnect(conn net.Conn, req *gosocks5.Request) { 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 err error var cc net.Conn @@ -368,9 +327,7 @@ func (h *socks5Handler) handleConnect(conn net.Conn, req *gosocks5.Request) { fmt.Fprintf(&buf, "%s", host) log.Log("[route]", buf.String()) - cc, err = route.Dial(host, - TimeoutChainOption(h.options.Timeout), - ) + cc, err = route.DialContext(context.Background(), "tcp", host) if err == nil { break } diff --git a/core/tcp.go b/core/tcp.go index 7f38bf79..24636788 100644 --- a/core/tcp.go +++ b/core/tcp.go @@ -1,6 +1,8 @@ package core -import "net" +import ( + "net" +) // tcpTransporter is a raw TCP transporter. type tcpTransporter struct{} @@ -10,28 +12,8 @@ func TCPTransporter() Transporter { return &tcpTransporter{} } -func (tr *tcpTransporter) Dial(addr string, options ...DialOption) (net.Conn, error) { - opts := &DialOptions{} - for _, option := range options { - option(opts) - } - - timeout := opts.Timeout - if timeout <= 0 { - timeout = DialTimeout - } - if opts.Chain == nil { - return net.DialTimeout("tcp", addr, timeout) - } - return opts.Chain.Dial(addr) -} - -func (tr *tcpTransporter) Handshake(conn net.Conn, options ...HandshakeOption) (net.Conn, error) { - return conn, nil -} - -func (tr *tcpTransporter) Multiplex() bool { - return false +func (tr *tcpTransporter) Dial(addr string) (net.Conn, error) { + return net.DialTimeout("tcp", addr, DialTimeout) } type tcpListener struct { diff --git a/core/tun.go b/core/tun.go index 77f2dc15..5a22117f 100644 --- a/core/tun.go +++ b/core/tun.go @@ -15,7 +15,6 @@ import ( "github.com/shadowsocks/go-shadowsocks2/shadowaead" "github.com/songgao/water" "github.com/songgao/water/waterutil" - "github.com/xtaci/tcpraw" "golang.org/x/net/ipv4" "golang.org/x/net/ipv6" ) @@ -181,16 +180,8 @@ func (h *tunHandler) Handle(conn net.Conn) { return err } } else { - if h.options.TCPMode { - if raddr != nil { - pc, err = tcpraw.Dial("tcp", raddr.String()) - } else { - pc, err = tcpraw.Listen("tcp", h.options.Node.Addr) - } - } else { - laddr, _ := net.ResolveUDPAddr("udp", h.options.Node.Addr) - pc, err = net.ListenUDP("udp", laddr) - } + laddr, _ := net.ResolveUDPAddr("udp", h.options.Node.Addr) + pc, err = net.ListenUDP("udp", laddr) } if err != nil { return err diff --git a/core/udp.go b/core/udp.go deleted file mode 100644 index 51a37d94..00000000 --- a/core/udp.go +++ /dev/null @@ -1,311 +0,0 @@ -package core - -import ( - "errors" - "net" - "sync" - "sync/atomic" - "time" - - "github.com/go-log/log" -) - -// UDPListenConfig is the config for UDP Listener. -type UDPListenConfig struct { - TTL time.Duration // timeout per connection - Backlog int // connection backlog - QueueSize int // recv queue size per connection -} - -type udpListener struct { - ln net.PacketConn - connChan chan net.Conn - errChan chan error - connMap *udpConnMap - config *UDPListenConfig -} - -// UDPListener creates a Listener for UDP server. -func UDPListener(addr string, cfg *UDPListenConfig) (Listener, error) { - laddr, err := net.ResolveUDPAddr("udp", addr) - if err != nil { - return nil, err - } - ln, err := net.ListenUDP("udp", laddr) - if err != nil { - return nil, err - } - - if cfg == nil { - cfg = &UDPListenConfig{} - } - - backlog := cfg.Backlog - if backlog <= 0 { - backlog = defaultBacklog - } - - l := &udpListener{ - ln: ln, - connChan: make(chan net.Conn, backlog), - errChan: make(chan error, 1), - connMap: new(udpConnMap), - config: cfg, - } - go l.listenLoop() - return l, nil -} - -func (l *udpListener) listenLoop() { - for { - // NOTE: this buffer will be released in the udpServerConn after read. - b := MPool.Get().([]byte) - - n, raddr, err := l.ln.ReadFrom(b) - if err != nil { - log.Logf("[udp] peer -> %s : %s", l.Addr(), err) - l.Close() - l.errChan <- err - close(l.errChan) - return - } - - conn, ok := l.connMap.Get(raddr.String()) - if !ok { - conn = newUDPServerConn(l.ln, raddr, &udpServerConnConfig{ - ttl: l.config.TTL, - qsize: l.config.QueueSize, - onClose: func() { - l.connMap.Delete(raddr.String()) - log.Logf("[udp] %s closed (%d)", raddr, l.connMap.Size()) - }, - }) - - select { - case l.connChan <- conn: - l.connMap.Set(raddr.String(), conn) - log.Logf("[udp] %s -> %s (%d)", raddr, l.Addr(), l.connMap.Size()) - default: - conn.Close() - log.Logf("[udp] %s - %s: connection queue is full (%d)", raddr, l.Addr(), cap(l.connChan)) - } - } - - select { - case conn.rChan <- b[:n]: - if Debug { - log.Logf("[udp] %s >>> %s : length %d", raddr, l.Addr(), n) - } - default: - log.Logf("[udp] %s -> %s : recv queue is full (%d)", raddr, l.Addr(), cap(conn.rChan)) - } - } -} - -func (l *udpListener) Accept() (conn net.Conn, err error) { - var ok bool - select { - case conn = <-l.connChan: - case err, ok = <-l.errChan: - if !ok { - err = errors.New("accpet on closed listener") - } - } - return -} - -func (l *udpListener) Addr() net.Addr { - return l.ln.LocalAddr() -} - -func (l *udpListener) Close() error { - err := l.ln.Close() - l.connMap.Range(func(k interface{}, v *udpServerConn) bool { - v.Close() - return true - }) - - return err -} - -type udpConnMap struct { - size int64 - m sync.Map -} - -func (m *udpConnMap) Get(key interface{}) (conn *udpServerConn, ok bool) { - v, ok := m.m.Load(key) - if ok { - conn, ok = v.(*udpServerConn) - } - return -} - -func (m *udpConnMap) Set(key interface{}, conn *udpServerConn) { - m.m.Store(key, conn) - atomic.AddInt64(&m.size, 1) -} - -func (m *udpConnMap) Delete(key interface{}) { - m.m.Delete(key) - atomic.AddInt64(&m.size, -1) -} - -func (m *udpConnMap) Range(f func(key interface{}, value *udpServerConn) bool) { - m.m.Range(func(k, v interface{}) bool { - return f(k, v.(*udpServerConn)) - }) -} - -func (m *udpConnMap) Size() int64 { - return atomic.LoadInt64(&m.size) -} - -// udpServerConn is a server side connection for UDP client peer, it implements net.Conn and net.PacketConn. -type udpServerConn struct { - conn net.PacketConn - raddr net.Addr - rChan chan []byte - closed chan struct{} - closeMutex sync.Mutex - nopChan chan int - config *udpServerConnConfig -} - -type udpServerConnConfig struct { - ttl time.Duration - qsize int - onClose func() -} - -func newUDPServerConn(conn net.PacketConn, raddr net.Addr, cfg *udpServerConnConfig) *udpServerConn { - if conn == nil || raddr == nil { - return nil - } - - if cfg == nil { - cfg = &udpServerConnConfig{} - } - qsize := cfg.qsize - if qsize <= 0 { - qsize = defaultQueueSize - } - c := &udpServerConn{ - conn: conn, - raddr: raddr, - rChan: make(chan []byte, qsize), - closed: make(chan struct{}), - nopChan: make(chan int), - config: cfg, - } - go c.ttlWait() - return c -} - -func (c *udpServerConn) Read(b []byte) (n int, err error) { - n, _, err = c.ReadFrom(b) - return -} - -func (c *udpServerConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { - select { - case bb := <-c.rChan: - n = copy(b, bb) - if cap(bb) == mediumBufferSize { - MPool.Put(bb[:cap(bb)]) - } - case <-c.closed: - err = errors.New("read from closed connection") - return - } - - select { - case c.nopChan <- n: - default: - } - - addr = c.raddr - - return -} - -func (c *udpServerConn) Write(b []byte) (n int, err error) { - return c.WriteTo(b, c.raddr) -} - -func (c *udpServerConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { - n, err = c.conn.WriteTo(b, addr) - - if n > 0 { - if Debug { - log.Logf("[udp] %s <<< %s : length %d", addr, c.LocalAddr(), n) - } - - select { - case c.nopChan <- n: - default: - } - } - - return -} - -func (c *udpServerConn) Close() error { - c.closeMutex.Lock() - defer c.closeMutex.Unlock() - - select { - case <-c.closed: - return errors.New("connection is closed") - default: - if c.config.onClose != nil { - c.config.onClose() - } - close(c.closed) - } - return nil -} - -func (c *udpServerConn) ttlWait() { - ttl := c.config.ttl - if ttl == 0 { - ttl = defaultTTL - } - timer := time.NewTimer(ttl) - defer timer.Stop() - - for { - select { - case <-c.nopChan: - if !timer.Stop() { - <-timer.C - } - timer.Reset(ttl) - case <-timer.C: - c.Close() - return - case <-c.closed: - return - } - } -} - -func (c *udpServerConn) LocalAddr() net.Addr { - return c.conn.LocalAddr() -} - -func (c *udpServerConn) RemoteAddr() net.Addr { - return c.raddr -} - -func (c *udpServerConn) SetDeadline(t time.Time) error { - return c.conn.SetDeadline(t) -} - -func (c *udpServerConn) SetReadDeadline(t time.Time) error { - return c.conn.SetReadDeadline(t) -} - -func (c *udpServerConn) SetWriteDeadline(t time.Time) error { - return c.conn.SetWriteDeadline(t) -} diff --git a/pkg/route.go b/pkg/route.go index 667131f2..f427cd8a 100644 --- a/pkg/route.go +++ b/pkg/route.go @@ -45,34 +45,9 @@ func parseChainNode(ns string) (nodes []core.Node, err error) { if serverName == "" { serverName = "localhost" // default server name } - timeout := node.GetDuration("timeout") - - host := node.Get("host") - if host == "" { - host = node.Host - } - - node.DialOptions = append(node.DialOptions, - core.TimeoutDialOption(timeout), - core.HostDialOption(host), - ) - - node.ConnectOptions = []core.ConnectOption{ - core.UserAgentConnectOption(node.Get("agent")), - core.NoTLSConnectOption(node.GetBool("notls")), - core.NoDelayConnectOption(node.GetBool("nodelay")), - } - - handshakeOptions := []core.HandshakeOption{ - core.AddrHandshakeOption(node.Addr), - core.HostHandshakeOption(host), - core.IntervalHandshakeOption(node.GetDuration("ping")), - core.TimeoutHandshakeOption(timeout), - core.RetryHandshakeOption(node.GetInt("retry")), - } node.Client = &core.Client{ - Connector: core.AutoConnector(node.User), + Connector: core.SOCKS5UDPTunConnector(node.User), Transporter: core.TCPTransporter(), } @@ -80,13 +55,10 @@ func parseChainNode(ns string) (nodes []core.Node, err error) { for _, ip := range ips { nd := node.Clone() nd.Addr = ip - // override the default node address - nd.HandshakeOptions = append(handshakeOptions, core.AddrHandshakeOption(ip)) // One node per IP nodes = append(nodes, nd) } if len(ips) == 0 { - node.HandshakeOptions = handshakeOptions nodes = []core.Node{node} } @@ -107,8 +79,6 @@ func (r *route) GenRouters() ([]router, error) { if err != nil { return nil, err } - ttl := node.GetDuration("ttl") - timeout := node.GetDuration("timeout") tunRoutes := parseIPRoutes(node.Get("route")) gw := net.ParseIP(node.Get("gw")) // default gateway @@ -122,12 +92,6 @@ func (r *route) GenRouters() ([]router, error) { switch node.Transport { case "tcp": ln, err = core.TCPListener(node.Addr) - case "udp": - ln, err = core.UDPListener(node.Addr, &core.UDPListenConfig{ - TTL: ttl, - Backlog: node.GetInt("backlog"), - QueueSize: node.GetInt("queue"), - }) case "tun": cfg := core.TunConfig{ Name: node.Get("name"), @@ -150,17 +114,13 @@ func (r *route) GenRouters() ([]router, error) { case "tun": handler = core.TunHandler() default: - handler = core.AutoHandler() + handler = core.SOCKS5Handler() } handler.Init( - core.AddrHandlerOption(ln.Addr().String()), core.ChainHandlerOption(chain), core.AuthenticatorHandlerOption(core.DefaultAuthenticator), - core.RetryHandlerOption(node.GetInt("retry")), - core.TimeoutHandlerOption(timeout), core.NodeHandlerOption(node), - core.TCPModeHandlerOption(node.GetBool("tcp")), core.IPRoutesHandlerOption(tunRoutes...), ) diff --git a/remote/remote_test.go b/remote/remote_test.go index 7adb86d0..eb1c8bf8 100644 --- a/remote/remote_test.go +++ b/remote/remote_test.go @@ -219,7 +219,7 @@ func TestGetTopController(t *testing.T) { fmt.Println(controller.Scale) } -func TestDdp(t *testing.T) { +func TestUdp(t *testing.T) { go func() { server() }()