diff --git a/constant/metadata.go b/constant/metadata.go index 1cb19033..f47a8c83 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -39,9 +39,17 @@ type Metadata struct { Port string } -func (addr *Metadata) String() string { - if addr.Host == "" { - return addr.IP.String() +func (m *Metadata) String() string { + if m.Host == "" { + return m.IP.String() } - return addr.Host + return m.Host +} + +func (m *Metadata) Valid() bool { + return m.Host != "" || m.IP != nil +} + +func (m *Metadata) NeedLoopUpHost() bool { + return m.Source == REDIR } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 4c024aba..30ce12ba 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -1,6 +1,7 @@ package tunnel import ( + "fmt" "net" "sync" "time" @@ -10,7 +11,7 @@ import ( "github.com/Dreamacro/clash/dns" "github.com/Dreamacro/clash/log" - "gopkg.in/eapache/channels.v1" + channels "gopkg.in/eapache/channels.v1" ) var ( @@ -80,6 +81,10 @@ func (t *Tunnel) SetResolver(resolver *dns.Resolver) { t.resolver = resolver } +func (t *Tunnel) hasResolver() bool { + return t.resolver != nil +} + func (t *Tunnel) process() { queue := t.queue.Out() for { @@ -106,20 +111,12 @@ func (t *Tunnel) handleConn(localConn C.ServerAdapter) { defer localConn.Close() metadata := localConn.Metadata() - if metadata.Source == C.REDIR && t.resolver != nil { + if metadata.NeedLoopUpHost() && t.hasResolver() { host, exist := t.resolver.IPToHost(*metadata.IP) if exist { metadata.Host = host metadata.AddrType = C.AtypDomainName } - } else if metadata.IP == nil && metadata.AddrType == C.AtypDomainName { - ip, err := t.resolveIP(metadata.Host) - if err != nil { - log.Debugln("[DNS] resolve %s error: %s", metadata.Host, err.Error()) - } else { - log.Debugln("[DNS] %s --> %s", metadata.Host, ip.String()) - metadata.IP = &ip - } } var proxy C.Proxy @@ -130,8 +127,18 @@ func (t *Tunnel) handleConn(localConn C.ServerAdapter) { proxy = t.proxies["GLOBAL"] // Rule default: - proxy = t.match(metadata) + var err error + proxy, err = t.match(metadata) + if err != nil { + return + } } + + if !metadata.Valid() { + log.Warnln("[Metadata] not valid: %#v", metadata) + return + } + remoConn, err := proxy.Generator(metadata) if err != nil { log.Warnln("Proxy[%s] connect [%s] error: %s", proxy.Name(), metadata.String(), err.Error()) @@ -147,20 +154,33 @@ func (t *Tunnel) handleConn(localConn C.ServerAdapter) { } } -func (t *Tunnel) match(metadata *C.Metadata) C.Proxy { +func (t *Tunnel) shouldResolveIP(rule C.Rule, metadata *C.Metadata) bool { + return (rule.RuleType() == C.GEOIP || rule.RuleType() == C.IPCIDR) && metadata.Host != "" && metadata.IP == nil +} + +func (t *Tunnel) match(metadata *C.Metadata) (C.Proxy, error) { t.configLock.RLock() defer t.configLock.RUnlock() for _, rule := range t.rules { + if t.shouldResolveIP(rule, metadata) { + ip, err := t.resolveIP(metadata.Host) + if err != nil { + return nil, fmt.Errorf("[DNS] resolve %s error: %s", metadata.Host, err.Error()) + } + log.Debugln("[DNS] %s --> %s", metadata.Host, ip.String()) + metadata.IP = &ip + } + if rule.IsMatch(metadata) { if a, ok := t.proxies[rule.Adapter()]; ok { log.Infoln("%v match %s using %s", metadata.String(), rule.RuleType().String(), rule.Adapter()) - return a + return a, nil } } } log.Infoln("%v doesn't match any rule using DIRECT", metadata.String()) - return t.proxies["DIRECT"] + return t.proxies["DIRECT"], nil } func newTunnel() *Tunnel {