diff --git a/engine/engine.go b/engine/engine.go index 1c890e16..08253233 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -132,6 +132,10 @@ func general(k *Key) error { } tunnel.T().SetUDPTimeout(k.UDPTimeout) } + + if k.UDPDisabled { + tunnel.T().SetUDPDisabled(true) + } return nil } diff --git a/engine/key.go b/engine/key.go index 5a86d53a..d852519e 100644 --- a/engine/key.go +++ b/engine/key.go @@ -17,4 +17,5 @@ type Key struct { TUNPreUp string `yaml:"tun-pre-up"` TUNPostUp string `yaml:"tun-post-up"` UDPTimeout time.Duration `yaml:"udp-timeout"` + UDPDisabled bool `yaml:"udp-disabled"` } diff --git a/main.go b/main.go index 201c396d..d0ff4e5f 100644 --- a/main.go +++ b/main.go @@ -27,6 +27,7 @@ func init() { flag.IntVar(&key.Mark, "fwmark", 0, "Set firewall MARK (Linux only)") flag.IntVar(&key.MTU, "mtu", 0, "Set device maximum transmission unit (MTU)") flag.DurationVar(&key.UDPTimeout, "udp-timeout", 0, "Set timeout for each UDP session") + flag.BoolVar(&key.UDPDisabled, "udp-disabled", false, "Disable UDP") flag.StringVar(&configFile, "config", "", "YAML format configuration file") flag.StringVar(&key.Device, "device", "", "Use this device [driver://]name") flag.StringVar(&key.Interface, "interface", "", "Use network INTERFACE (Linux/MacOS only)") diff --git a/proxy/socks5.go b/proxy/socks5.go index bdc9b04c..19dd4ea7 100644 --- a/proxy/socks5.go +++ b/proxy/socks5.go @@ -26,6 +26,13 @@ type Socks5 struct { } func NewSocks5(addr, user, pass string) (*Socks5, error) { + unix := len(addr) > 0 && addr[0] == '/' + + // For support Linux abstract namespace + if len(addr) > 2 && addr[1] == '@' || addr[1] == 0x00 { + addr = addr[1:] + } + return &Socks5{ Base: &Base{ addr: addr, @@ -33,7 +40,7 @@ func NewSocks5(addr, user, pass string) (*Socks5, error) { }, user: user, pass: pass, - unix: len(addr) > 0 && addr[0] == '/', + unix: unix, }, nil } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 9f69d5dd..6a04399b 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -31,6 +31,9 @@ type Tunnel struct { // UDP session timeout. udpTimeout *atomic.Duration + // UDP disabled flag. + udpDisabled *atomic.Bool + // Internal proxy.Dialer for Tunnel. dialerMu sync.RWMutex dialer proxy.Dialer @@ -44,12 +47,13 @@ type Tunnel struct { func New(dialer proxy.Dialer, manager *statistic.Manager) *Tunnel { return &Tunnel{ - tcpQueue: make(chan adapter.TCPConn), - udpQueue: make(chan adapter.UDPConn), - udpTimeout: atomic.NewDuration(udpSessionTimeout), - dialer: dialer, - manager: manager, - procCancel: func() { /* nop */ }, + tcpQueue: make(chan adapter.TCPConn), + udpQueue: make(chan adapter.UDPConn), + udpTimeout: atomic.NewDuration(udpSessionTimeout), + udpDisabled: atomic.NewBool(false), + dialer: dialer, + manager: manager, + procCancel: func() { /* nop */ }, } } @@ -114,3 +118,7 @@ func (t *Tunnel) SetDialer(dialer proxy.Dialer) { func (t *Tunnel) SetUDPTimeout(timeout time.Duration) { t.udpTimeout.Store(timeout) } + +func (t *Tunnel) SetUDPDisabled(disabled bool) { + t.udpDisabled.Store(disabled) +} diff --git a/tunnel/udp.go b/tunnel/udp.go index 87973862..c976d63f 100644 --- a/tunnel/udp.go +++ b/tunnel/udp.go @@ -17,6 +17,11 @@ import ( func (t *Tunnel) handleUDPConn(uc adapter.UDPConn) { defer uc.Close() + if t.udpDisabled.Load() { + log.Warnf("[UDP] dial %s: blocked", uc.ID().RemoteAddress) + return + } + id := uc.ID() metadata := &M.Metadata{ Network: M.UDP,