mirror of
https://github.com/MetaCubeX/Clash.Meta.git
synced 2025-04-04 13:43:33 +03:00
chore: listening tcp together for dns server (#1792)
This commit is contained in:
parent
c7661d7765
commit
c99c71a969
15 changed files with 140 additions and 102 deletions
|
@ -43,7 +43,7 @@ func MPTCP() bool {
|
|||
return getMultiPathTCP(&lc.ListenConfig)
|
||||
}
|
||||
|
||||
func ListenContext(ctx context.Context, network, address string) (net.Listener, error) {
|
||||
func preResolve(network, address string) (string, error) {
|
||||
switch network { // like net.Resolver.internetAddrList but filter domain to avoid call net.Resolver.lookupIPAddr
|
||||
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "ip", "ip4", "ip6":
|
||||
if host, port, err := net.SplitHostPort(address); err == nil {
|
||||
|
@ -59,11 +59,19 @@ func ListenContext(ctx context.Context, network, address string) (net.Listener,
|
|||
break
|
||||
default:
|
||||
if _, err := netip.ParseAddr(host); err != nil { // not ip
|
||||
return nil, fmt.Errorf("invalid network address: %s", address)
|
||||
return "", fmt.Errorf("invalid network address: %s", address)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return address, nil
|
||||
}
|
||||
|
||||
func ListenContext(ctx context.Context, network, address string) (net.Listener, error) {
|
||||
address, err := preResolve(network, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mutex.RLock()
|
||||
defer mutex.RUnlock()
|
||||
|
@ -74,6 +82,21 @@ func Listen(network, address string) (net.Listener, error) {
|
|||
return ListenContext(context.Background(), network, address)
|
||||
}
|
||||
|
||||
func ListenPacketContext(ctx context.Context, network, address string) (net.PacketConn, error) {
|
||||
address, err := preResolve(network, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mutex.RLock()
|
||||
defer mutex.RUnlock()
|
||||
return lc.ListenPacket(ctx, network, address)
|
||||
}
|
||||
|
||||
func ListenPacket(network, address string) (net.PacketConn, error) {
|
||||
return ListenPacketContext(context.Background(), network, address)
|
||||
}
|
||||
|
||||
func init() {
|
||||
keepalive.SetDisableKeepAliveCallback.Register(func(b bool) {
|
||||
mutex.Lock()
|
||||
|
|
30
common/sockopt/reuse_common.go
Normal file
30
common/sockopt/reuse_common.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package sockopt
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func RawConnReuseaddr(rc syscall.RawConn) (err error) {
|
||||
var innerErr error
|
||||
err = rc.Control(func(fd uintptr) {
|
||||
innerErr = reuseControl(fd)
|
||||
})
|
||||
|
||||
if innerErr != nil {
|
||||
err = innerErr
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func UDPReuseaddr(c net.PacketConn) error {
|
||||
if c, ok := c.(syscall.Conn); ok {
|
||||
rc, err := c.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return RawConnReuseaddr(rc)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,9 +1,5 @@
|
|||
//go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows
|
||||
|
||||
package dialer
|
||||
package sockopt
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func addrReuseToListenConfig(*net.ListenConfig) {}
|
||||
func reuseControl(fd uintptr) error { return nil }
|
22
common/sockopt/reuse_unix.go
Normal file
22
common/sockopt/reuse_unix.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||
|
||||
package sockopt
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func reuseControl(fd uintptr) error {
|
||||
e1 := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
|
||||
e2 := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
|
||||
|
||||
if e1 != nil {
|
||||
return e1
|
||||
}
|
||||
|
||||
if e2 != nil {
|
||||
return e2
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
9
common/sockopt/reuse_windows.go
Normal file
9
common/sockopt/reuse_windows.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package sockopt
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func reuseControl(fd uintptr) error {
|
||||
return windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_REUSEADDR, 1)
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
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
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
//go:build !linux
|
||||
|
||||
package sockopt
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func UDPReuseaddr(c *net.UDPConn) (err error) {
|
||||
return
|
||||
}
|
|
@ -5,13 +5,11 @@ import (
|
|||
"net"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"github.com/metacubex/mihomo/common/sockopt"
|
||||
)
|
||||
|
||||
func addrReuseToListenConfig(lc *net.ListenConfig) {
|
||||
addControlToListenConfig(lc, func(ctx context.Context, network, address string, c syscall.RawConn) error {
|
||||
return c.Control(func(fd uintptr) {
|
||||
windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_REUSEADDR, 1)
|
||||
})
|
||||
return sockopt.RawConnReuseaddr(c)
|
||||
})
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||
|
||||
package dialer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func addrReuseToListenConfig(lc *net.ListenConfig) {
|
||||
addControlToListenConfig(lc, func(ctx context.Context, network, address string, c syscall.RawConn) error {
|
||||
return c.Control(func(fd uintptr) {
|
||||
unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
|
||||
unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
|
||||
})
|
||||
})
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
"errors"
|
||||
"net"
|
||||
|
||||
"github.com/metacubex/mihomo/adapter/inbound"
|
||||
"github.com/metacubex/mihomo/common/sockopt"
|
||||
"github.com/metacubex/mihomo/context"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
|
@ -20,8 +21,9 @@ var (
|
|||
)
|
||||
|
||||
type Server struct {
|
||||
*D.Server
|
||||
handler handler
|
||||
handler handler
|
||||
tcpServer *D.Server
|
||||
udpServer *D.Server
|
||||
}
|
||||
|
||||
// ServeDNS implement D.Handler ServeDNS
|
||||
|
@ -55,12 +57,19 @@ func ReCreateServer(addr string, resolver *Resolver, mapper *ResolverEnhancer) {
|
|||
return
|
||||
}
|
||||
|
||||
if server.Server != nil {
|
||||
server.Shutdown()
|
||||
server = &Server{}
|
||||
address = ""
|
||||
if server.tcpServer != nil {
|
||||
_ = server.tcpServer.Shutdown()
|
||||
server.tcpServer = nil
|
||||
}
|
||||
|
||||
if server.udpServer != nil {
|
||||
_ = server.udpServer.Shutdown()
|
||||
server.udpServer = nil
|
||||
}
|
||||
|
||||
server.handler = nil
|
||||
address = ""
|
||||
|
||||
if addr == "" {
|
||||
return
|
||||
}
|
||||
|
@ -77,31 +86,36 @@ func ReCreateServer(addr string, resolver *Resolver, mapper *ResolverEnhancer) {
|
|||
return
|
||||
}
|
||||
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
p, err := net.ListenUDP("udp", udpAddr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = sockopt.UDPReuseaddr(p)
|
||||
if err != nil {
|
||||
log.Warnln("Failed to Reuse UDP Address: %s", err)
|
||||
|
||||
err = nil
|
||||
}
|
||||
|
||||
address = addr
|
||||
handler := NewHandler(resolver, mapper)
|
||||
server = &Server{handler: handler}
|
||||
server.Server = &D.Server{Addr: addr, PacketConn: p, Handler: server}
|
||||
|
||||
go func() {
|
||||
server.ActivateAndServe()
|
||||
p, err := inbound.ListenPacket("udp", addr)
|
||||
if err != nil {
|
||||
log.Errorln("Start DNS server(UDP) error: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := sockopt.UDPReuseaddr(p); err != nil {
|
||||
log.Warnln("Failed to Reuse UDP Address: %s", err)
|
||||
}
|
||||
|
||||
log.Infoln("DNS server(UDP) listening at: %s", p.LocalAddr().String())
|
||||
server.udpServer = &D.Server{Addr: addr, PacketConn: p, Handler: server}
|
||||
_ = server.udpServer.ActivateAndServe()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
l, err := inbound.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
log.Errorln("Start DNS server(TCP) error: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
log.Infoln("DNS server(TCP) listening at: %s", l.Addr().String())
|
||||
server.tcpServer = &D.Server{Addr: addr, Listener: l, Handler: server}
|
||||
_ = server.tcpServer.ActivateAndServe()
|
||||
}()
|
||||
|
||||
log.Infoln("DNS server listening at: %s", p.LocalAddr().String())
|
||||
}
|
||||
|
|
|
@ -18,13 +18,12 @@ type UDPListener struct {
|
|||
}
|
||||
|
||||
func NewUDP(addr string, pickCipher core.Cipher, tunnel C.Tunnel, additions ...inbound.Addition) (*UDPListener, error) {
|
||||
l, err := net.ListenPacket("udp", addr)
|
||||
l, err := inbound.ListenPacket("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = sockopt.UDPReuseaddr(l.(*net.UDPConn))
|
||||
if err != nil {
|
||||
if err := sockopt.UDPReuseaddr(l); err != nil {
|
||||
log.Warnln("Failed to Reuse UDP Address: %s", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -140,13 +140,12 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi
|
|||
_service := *service
|
||||
service := &_service // make a copy
|
||||
|
||||
ul, err := net.ListenPacket("udp", addr)
|
||||
ul, err := inbound.ListenPacket("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = sockopt.UDPReuseaddr(ul.(*net.UDPConn))
|
||||
if err != nil {
|
||||
if err := sockopt.UDPReuseaddr(ul); err != nil {
|
||||
log.Warnln("Failed to Reuse UDP Address: %s", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -82,13 +82,12 @@ func New(config LC.ShadowsocksServer, tunnel C.Tunnel, additions ...inbound.Addi
|
|||
|
||||
if config.Udp {
|
||||
//UDP
|
||||
ul, err := net.ListenPacket("udp", addr)
|
||||
ul, err := inbound.ListenPacket("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = sockopt.UDPReuseaddr(ul.(*net.UDPConn))
|
||||
if err != nil {
|
||||
if err := sockopt.UDPReuseaddr(ul); err != nil {
|
||||
log.Warnln("Failed to Reuse UDP Address: %s", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -40,12 +40,12 @@ func NewUDP(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*UDPLi
|
|||
inbound.WithSpecialRules(""),
|
||||
}
|
||||
}
|
||||
l, err := net.ListenPacket("udp", addr)
|
||||
l, err := inbound.ListenPacket("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := sockopt.UDPReuseaddr(l.(*net.UDPConn)); err != nil {
|
||||
if err := sockopt.UDPReuseaddr(l); err != nil {
|
||||
log.Warnln("Failed to Reuse UDP Address: %s", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -152,13 +152,12 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) (
|
|||
for _, addr := range strings.Split(config.Listen, ",") {
|
||||
addr := addr
|
||||
|
||||
ul, err := net.ListenPacket("udp", addr)
|
||||
ul, err := inbound.ListenPacket("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = sockopt.UDPReuseaddr(ul.(*net.UDPConn))
|
||||
if err != nil {
|
||||
if err := sockopt.UDPReuseaddr(ul); err != nil {
|
||||
log.Warnln("Failed to Reuse UDP Address: %s", err)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue