remove unneeded code

This commit is contained in:
p_caiwfeng
2021-10-02 16:33:48 +08:00
parent 454cd7a4a9
commit b00c33de5c
10 changed files with 42 additions and 835 deletions

View File

@@ -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
}
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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,

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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...),
)

View File

@@ -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()
}()