From 127a000058a0b572f059df650b7d9beba95c615e Mon Sep 17 00:00:00 2001 From: mzz2017 <2017@duck.com> Date: Fri, 7 Apr 2023 20:38:06 +0800 Subject: [PATCH] fix/optimize: reroute if necessary and add opendns as bootstrap dns --- common/netutils/dns.go | 14 +++++++++++++- component/dns/upstream.go | 2 +- control/control_plane.go | 11 +++++++---- control/tcp.go | 8 +++++++- control/udp.go | 8 +++++++- 5 files changed, 35 insertions(+), 8 deletions(-) diff --git a/common/netutils/dns.go b/common/netutils/dns.go index e902f7d..3103b37 100644 --- a/common/netutils/dns.go +++ b/common/netutils/dns.go @@ -28,6 +28,8 @@ var ( systemDnsNextUpdateAfter time.Time BadDnsAnsError = fmt.Errorf("bad dns answer") + + BootstrapDns = netip.MustParseAddrPort("208.67.222.222:5353") ) func TryUpdateSystemDns() (err error) { @@ -61,7 +63,17 @@ func tryUpdateSystemDns() (err error) { err = fmt.Errorf("no valid dns server in /etc/resolv.conf") return err } - systemDns = netip.MustParseAddrPort(dnsConf.servers[0]) + systemDns = netip.AddrPort{} + for _, s := range dnsConf.servers { + ipPort := netip.MustParseAddrPort(s) + if !ipPort.Addr().IsLoopback() { + systemDns = ipPort + break + } + } + if !systemDns.IsValid() { + systemDns = BootstrapDns + } return nil } diff --git a/component/dns/upstream.go b/component/dns/upstream.go index ea41f58..cfb7744 100644 --- a/component/dns/upstream.go +++ b/component/dns/upstream.go @@ -92,7 +92,7 @@ func NewUpstream(ctx context.Context, upstream *url.URL) (up *Upstream, err erro return nil, fmt.Errorf("failed to resolve dns_upstream: %w", err) } if !ip46.Ip4.IsValid() && !ip46.Ip6.IsValid() { - return nil, fmt.Errorf("dns_upstream has no record") + return nil, fmt.Errorf("dns_upstream %v has no record", upstream.String()) } return &Upstream{ diff --git a/control/control_plane.go b/control/control_plane.go index 15a8a5b..4e45986 100644 --- a/control/control_plane.go +++ b/control/control_plane.go @@ -491,8 +491,8 @@ func (c *ControlPlane) dnsUpstreamReadyCallback(dnsUpstream *dns.Upstream) (err return nil } -func (c *ControlPlane) ChooseDialTarget(outbound consts.OutboundIndex, dst netip.AddrPort, domain string) (dialTarget string, dialMode consts.DialMode) { - dialMode = consts.DialMode_Ip +func (c *ControlPlane) ChooseDialTarget(outbound consts.OutboundIndex, dst netip.AddrPort, domain string) (dialTarget string, shouldReroute bool) { + dialMode := consts.DialMode_Ip if !outbound.IsReserved() && domain != "" { switch c.dialMode { @@ -521,6 +521,9 @@ func (c *ControlPlane) ChooseDialTarget(outbound consts.OutboundIndex, dst netip c.muRealDomainSet.Lock() c.realDomainSet.AddString(domain) c.muRealDomainSet.Unlock() + + // Should use this domain to reroute + shouldReroute = true } } } @@ -553,7 +556,7 @@ func (c *ControlPlane) ChooseDialTarget(outbound consts.OutboundIndex, dst netip "to": dialTarget, }).Debugln("Rewrite dial target to domain") } - return dialTarget, dialMode + return dialTarget, shouldReroute } type Listener struct { @@ -758,7 +761,7 @@ func (c *ControlPlane) chooseBestDnsDialer( default: return nil, fmt.Errorf("unexpected ipversion: %v", ver) } - outboundIndex, mark, _, err := c.Route(req.realSrc, netip.AddrPortFrom(dAddr, dnsUpstream.Port), "", proto.ToL4ProtoType(), req.routingResult) + outboundIndex, mark, _, err := c.Route(req.realSrc, netip.AddrPortFrom(dAddr, dnsUpstream.Port), dnsUpstream.Hostname, proto.ToL4ProtoType(), req.routingResult) if err != nil { return nil, err } diff --git a/control/tcp.go b/control/tcp.go index 0d6f09c..4a10b0e 100644 --- a/control/tcp.go +++ b/control/tcp.go @@ -68,6 +68,11 @@ func (c *ControlPlane) handleConn(lConn net.Conn) (err error) { outboundIndex = consts.OutboundControlPlaneRouting } + dialTarget, shouldReroute := c.ChooseDialTarget(outboundIndex, dst, domain) + if shouldReroute { + outboundIndex = consts.OutboundControlPlaneRouting + } + switch outboundIndex { case consts.OutboundDirect: case consts.OutboundControlPlaneRouting: @@ -82,6 +87,8 @@ func (c *ControlPlane) handleConn(lConn net.Conn) (err error) { outboundIndex.String(), ) } + // Reset dialTarget. + dialTarget, _ = c.ChooseDialTarget(outboundIndex, dst, domain) default: } // TODO: Set-up ip to domain mapping and show domain if possible. @@ -99,7 +106,6 @@ func (c *ControlPlane) handleConn(lConn net.Conn) (err error) { return fmt.Errorf("failed to select dialer from group %v (%v): %w", outbound.Name, networkType.String(), err) } - dialTarget, _ := c.ChooseDialTarget(outboundIndex, dst, domain) if c.log.IsLevelEnabled(logrus.InfoLevel) { c.log.WithFields(logrus.Fields{ "network": networkType.String(), diff --git a/control/udp.go b/control/udp.go index 27841a4..6434804 100644 --- a/control/udp.go +++ b/control/udp.go @@ -143,6 +143,11 @@ func (c *ControlPlane) handlePkt(lConn *net.UDPConn, data []byte, src, pktDst, r outboundIndex = consts.OutboundControlPlaneRouting } + dialTarget, shouldReroute := c.ChooseDialTarget(outboundIndex, realDst, domain) + if shouldReroute { + outboundIndex = consts.OutboundControlPlaneRouting + } + if routingResult.Must > 0 { isDns = false // Regard as plain traffic. } @@ -164,6 +169,8 @@ func (c *ControlPlane) handlePkt(lConn *net.UDPConn, data []byte, src, pktDst, r outboundIndex.String(), ) } + // Reset dialTarget. + dialTarget, _ = c.ChooseDialTarget(outboundIndex, realDst, domain) default: } if isDns { @@ -197,7 +204,6 @@ func (c *ControlPlane) handlePkt(lConn *net.UDPConn, data []byte, src, pktDst, r // TODO: Rewritten domain should not use full-cone (such as VMess Packet Addr). // Maybe we should set up a mapping for UDP: Dialer + Target Domain => Remote Resolved IP. // However, games may not use QUIC for communication, thus we cannot use domain to dial, which is fine. - dialTarget, _ := c.ChooseDialTarget(outboundIndex, realDst, domain) // Get udp endpoint. var ue *UdpEndpoint