fix/optimize: reroute if necessary and add opendns as bootstrap dns

This commit is contained in:
mzz2017
2023-04-07 20:38:06 +08:00
parent efacd08910
commit 127a000058
5 changed files with 35 additions and 8 deletions

View File

@ -28,6 +28,8 @@ var (
systemDnsNextUpdateAfter time.Time systemDnsNextUpdateAfter time.Time
BadDnsAnsError = fmt.Errorf("bad dns answer") BadDnsAnsError = fmt.Errorf("bad dns answer")
BootstrapDns = netip.MustParseAddrPort("208.67.222.222:5353")
) )
func TryUpdateSystemDns() (err error) { func TryUpdateSystemDns() (err error) {
@ -61,7 +63,17 @@ func tryUpdateSystemDns() (err error) {
err = fmt.Errorf("no valid dns server in /etc/resolv.conf") err = fmt.Errorf("no valid dns server in /etc/resolv.conf")
return err 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 return nil
} }

View File

@ -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) return nil, fmt.Errorf("failed to resolve dns_upstream: %w", err)
} }
if !ip46.Ip4.IsValid() && !ip46.Ip6.IsValid() { 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{ return &Upstream{

View File

@ -491,8 +491,8 @@ func (c *ControlPlane) dnsUpstreamReadyCallback(dnsUpstream *dns.Upstream) (err
return nil return nil
} }
func (c *ControlPlane) ChooseDialTarget(outbound consts.OutboundIndex, dst netip.AddrPort, domain string) (dialTarget string, dialMode consts.DialMode) { func (c *ControlPlane) ChooseDialTarget(outbound consts.OutboundIndex, dst netip.AddrPort, domain string) (dialTarget string, shouldReroute bool) {
dialMode = consts.DialMode_Ip dialMode := consts.DialMode_Ip
if !outbound.IsReserved() && domain != "" { if !outbound.IsReserved() && domain != "" {
switch c.dialMode { switch c.dialMode {
@ -521,6 +521,9 @@ func (c *ControlPlane) ChooseDialTarget(outbound consts.OutboundIndex, dst netip
c.muRealDomainSet.Lock() c.muRealDomainSet.Lock()
c.realDomainSet.AddString(domain) c.realDomainSet.AddString(domain)
c.muRealDomainSet.Unlock() 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, "to": dialTarget,
}).Debugln("Rewrite dial target to domain") }).Debugln("Rewrite dial target to domain")
} }
return dialTarget, dialMode return dialTarget, shouldReroute
} }
type Listener struct { type Listener struct {
@ -758,7 +761,7 @@ func (c *ControlPlane) chooseBestDnsDialer(
default: default:
return nil, fmt.Errorf("unexpected ipversion: %v", ver) 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 { if err != nil {
return nil, err return nil, err
} }

View File

@ -68,6 +68,11 @@ func (c *ControlPlane) handleConn(lConn net.Conn) (err error) {
outboundIndex = consts.OutboundControlPlaneRouting outboundIndex = consts.OutboundControlPlaneRouting
} }
dialTarget, shouldReroute := c.ChooseDialTarget(outboundIndex, dst, domain)
if shouldReroute {
outboundIndex = consts.OutboundControlPlaneRouting
}
switch outboundIndex { switch outboundIndex {
case consts.OutboundDirect: case consts.OutboundDirect:
case consts.OutboundControlPlaneRouting: case consts.OutboundControlPlaneRouting:
@ -82,6 +87,8 @@ func (c *ControlPlane) handleConn(lConn net.Conn) (err error) {
outboundIndex.String(), outboundIndex.String(),
) )
} }
// Reset dialTarget.
dialTarget, _ = c.ChooseDialTarget(outboundIndex, dst, domain)
default: default:
} }
// TODO: Set-up ip to domain mapping and show domain if possible. // 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) 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) { if c.log.IsLevelEnabled(logrus.InfoLevel) {
c.log.WithFields(logrus.Fields{ c.log.WithFields(logrus.Fields{
"network": networkType.String(), "network": networkType.String(),

View File

@ -143,6 +143,11 @@ func (c *ControlPlane) handlePkt(lConn *net.UDPConn, data []byte, src, pktDst, r
outboundIndex = consts.OutboundControlPlaneRouting outboundIndex = consts.OutboundControlPlaneRouting
} }
dialTarget, shouldReroute := c.ChooseDialTarget(outboundIndex, realDst, domain)
if shouldReroute {
outboundIndex = consts.OutboundControlPlaneRouting
}
if routingResult.Must > 0 { if routingResult.Must > 0 {
isDns = false // Regard as plain traffic. isDns = false // Regard as plain traffic.
} }
@ -164,6 +169,8 @@ func (c *ControlPlane) handlePkt(lConn *net.UDPConn, data []byte, src, pktDst, r
outboundIndex.String(), outboundIndex.String(),
) )
} }
// Reset dialTarget.
dialTarget, _ = c.ChooseDialTarget(outboundIndex, realDst, domain)
default: default:
} }
if isDns { 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). // 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. // 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. // 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. // Get udp endpoint.
var ue *UdpEndpoint var ue *UdpEndpoint