diff --git a/coremain/config.go b/coremain/config.go index f54dbaed7..6377acd6c 100644 --- a/coremain/config.go +++ b/coremain/config.go @@ -77,6 +77,15 @@ type ServerListenerConfig struct { ProxyProtocol bool `yaml:"proxy_protocol"` // accepting the PROXYProtocol IdleTimeout uint `yaml:"idle_timeout"` // (sec) used by tcp, dot, doh as connection idle timeout. + + // Issue: https://github.com/IrineSistiana/mosdns/pull/657 + // When a TPROXY is processing a UDP connection, + // for example: if the Dest Addr is 8.8.8.8:53, + // the TPROXY program must bind to 8.8.8.8:53 on TPROXY host os + // and send the UDP packet back to the Client to make sure the Src Addr and Port is 8.8.8.8:53 , + // IF, when mosdns has bind :53 on this host os without SO_REUSEADDR, + // the behavior of the TPROXY program will fail with EADDRINUSE (Address already in use) + ReuseAddr bool `yaml:"reuse_addr"` // used by udp on unix alike systems. } type APIConfig struct { diff --git a/coremain/server.go b/coremain/server.go index 4588335ed..e27906ad2 100644 --- a/coremain/server.go +++ b/coremain/server.go @@ -20,6 +20,7 @@ package coremain import ( + "context" "errors" "fmt" "github.com/IrineSistiana/mosdns/v4/pkg/server" @@ -28,6 +29,7 @@ import ( "github.com/pires/go-proxyproto" "go.uber.org/zap" "net" + "syscall" "time" ) @@ -115,7 +117,13 @@ func (m *Mosdns) startServerListener(cfg *ServerListenerConfig, dnsHandler dns_h var run func() error switch cfg.Protocol { case "", "udp": - conn, err := net.ListenPacket("udp", cfg.Addr) + // see also: https://github.com/IrineSistiana/mosdns/pull/657 + var lc net.ListenConfig + lc.Control = func(network, address string, c syscall.RawConn) error { + return serverSocketOption(c, cfg, network, address) + } + + conn, err := lc.ListenPacket(context.Background(), "udp", cfg.Addr) if err != nil { return err } diff --git a/coremain/utilities_other.go b/coremain/utilities_other.go new file mode 100644 index 000000000..3e4918f44 --- /dev/null +++ b/coremain/utilities_other.go @@ -0,0 +1,15 @@ +//go:build !(linux || darwin || freebsd || netbsd || openbsd) + +package coremain + +import ( + "errors" + "syscall" +) + +func serverSocketOption(c syscall.RawConn, cfg *ServerListenerConfig, network, address string) error { + if cfg.ReuseAddr { + return errors.New("reuseaddr not supported on this platform") + } + return nil +} diff --git a/coremain/utilities_unix.go b/coremain/utilities_unix.go new file mode 100644 index 000000000..39e418b7d --- /dev/null +++ b/coremain/utilities_unix.go @@ -0,0 +1,20 @@ +//go:build linux || darwin || freebsd || netbsd || openbsd + +package coremain + +import ( + "syscall" +) + +func serverSocketOption(c syscall.RawConn, cfg *ServerListenerConfig, network, address string) error { + var errSysCall error + errControl := c.Control(func(fd uintptr) { + if cfg.ReuseAddr { + errSysCall = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) + } + }) + if errSysCall != nil { + return errSysCall + } + return errControl +}