From 2750c7ead04f441f1760e7c005076bf437e2a984 Mon Sep 17 00:00:00 2001 From: duama <30264485+duament@users.noreply.github.com> Date: Sat, 11 Apr 2020 21:45:56 +0800 Subject: [PATCH] Fix: set SO_REUSEADDR for UDP listeners on linux (#630) --- common/sockopt/reuseaddr_linux.go | 19 +++++++++++++++++++ common/sockopt/reuseaddr_other.go | 11 +++++++++++ dns/server.go | 7 +++++++ proxy/redir/udp_linux.go | 6 +++++- proxy/socks/udp.go | 6 ++++++ 5 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 common/sockopt/reuseaddr_linux.go create mode 100644 common/sockopt/reuseaddr_other.go diff --git a/common/sockopt/reuseaddr_linux.go b/common/sockopt/reuseaddr_linux.go new file mode 100644 index 00000000..a1d19bfd --- /dev/null +++ b/common/sockopt/reuseaddr_linux.go @@ -0,0 +1,19 @@ +package sockopt + +import ( + "net" + "syscall" +) + +func UDPReuseaddr(c *net.UDPConn) (err error) { + rc, err := c.SyscallConn() + if err != nil { + return + } + + rc.Control(func(fd uintptr) { + err = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) + }) + + return +} diff --git a/common/sockopt/reuseaddr_other.go b/common/sockopt/reuseaddr_other.go new file mode 100644 index 00000000..2b136950 --- /dev/null +++ b/common/sockopt/reuseaddr_other.go @@ -0,0 +1,11 @@ +// +build !linux + +package sockopt + +import ( + "net" +) + +func UDPReuseaddr(c *net.UDPConn) (err error) { + return +} diff --git a/dns/server.go b/dns/server.go index 2f8585c0..c2bd08c8 100644 --- a/dns/server.go +++ b/dns/server.go @@ -3,6 +3,8 @@ package dns import ( "net" + "github.com/Dreamacro/clash/common/sockopt" + D "github.com/miekg/dns" ) @@ -58,6 +60,11 @@ func ReCreateServer(addr string, resolver *Resolver) error { return err } + err = sockopt.UDPReuseaddr(p) + if err != nil { + return err + } + address = addr handler := newHandler(resolver) server = &Server{handler: handler} diff --git a/proxy/redir/udp_linux.go b/proxy/redir/udp_linux.go index 83a82a72..228daca4 100644 --- a/proxy/redir/udp_linux.go +++ b/proxy/redir/udp_linux.go @@ -31,7 +31,11 @@ func setsockopt(c *net.UDPConn, addr string) error { } rc.Control(func(fd uintptr) { - err = syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1) + err = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) + + if err == nil { + err = syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1) + } if err == nil && isIPv6 { err = syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, IPV6_TRANSPARENT, 1) } diff --git a/proxy/socks/udp.go b/proxy/socks/udp.go index 46e681ff..1e623fb5 100644 --- a/proxy/socks/udp.go +++ b/proxy/socks/udp.go @@ -5,6 +5,7 @@ import ( adapters "github.com/Dreamacro/clash/adapters/inbound" "github.com/Dreamacro/clash/common/pool" + "github.com/Dreamacro/clash/common/sockopt" "github.com/Dreamacro/clash/component/socks5" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/tunnel" @@ -22,6 +23,11 @@ func NewSocksUDPProxy(addr string) (*SockUDPListener, error) { return nil, err } + err = sockopt.UDPReuseaddr(l.(*net.UDPConn)) + if err != nil { + return nil, err + } + sl := &SockUDPListener{l, addr, false} go func() { for {