Improve: lazy resolve ip
This commit is contained in:
parent
cac0fbaa5c
commit
4ae154494c
2 changed files with 46 additions and 18 deletions
|
@ -39,9 +39,17 @@ type Metadata struct {
|
||||||
Port string
|
Port string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (addr *Metadata) String() string {
|
func (m *Metadata) String() string {
|
||||||
if addr.Host == "" {
|
if m.Host == "" {
|
||||||
return addr.IP.String()
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package tunnel
|
package tunnel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -10,7 +11,7 @@ import (
|
||||||
"github.com/Dreamacro/clash/dns"
|
"github.com/Dreamacro/clash/dns"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
|
|
||||||
"gopkg.in/eapache/channels.v1"
|
channels "gopkg.in/eapache/channels.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -80,6 +81,10 @@ func (t *Tunnel) SetResolver(resolver *dns.Resolver) {
|
||||||
t.resolver = resolver
|
t.resolver = resolver
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Tunnel) hasResolver() bool {
|
||||||
|
return t.resolver != nil
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Tunnel) process() {
|
func (t *Tunnel) process() {
|
||||||
queue := t.queue.Out()
|
queue := t.queue.Out()
|
||||||
for {
|
for {
|
||||||
|
@ -106,20 +111,12 @@ func (t *Tunnel) handleConn(localConn C.ServerAdapter) {
|
||||||
defer localConn.Close()
|
defer localConn.Close()
|
||||||
metadata := localConn.Metadata()
|
metadata := localConn.Metadata()
|
||||||
|
|
||||||
if metadata.Source == C.REDIR && t.resolver != nil {
|
if metadata.NeedLoopUpHost() && t.hasResolver() {
|
||||||
host, exist := t.resolver.IPToHost(*metadata.IP)
|
host, exist := t.resolver.IPToHost(*metadata.IP)
|
||||||
if exist {
|
if exist {
|
||||||
metadata.Host = host
|
metadata.Host = host
|
||||||
metadata.AddrType = C.AtypDomainName
|
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
|
var proxy C.Proxy
|
||||||
|
@ -130,8 +127,18 @@ func (t *Tunnel) handleConn(localConn C.ServerAdapter) {
|
||||||
proxy = t.proxies["GLOBAL"]
|
proxy = t.proxies["GLOBAL"]
|
||||||
// Rule
|
// Rule
|
||||||
default:
|
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)
|
remoConn, err := proxy.Generator(metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnln("Proxy[%s] connect [%s] error: %s", proxy.Name(), metadata.String(), err.Error())
|
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()
|
t.configLock.RLock()
|
||||||
defer t.configLock.RUnlock()
|
defer t.configLock.RUnlock()
|
||||||
|
|
||||||
for _, rule := range t.rules {
|
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 rule.IsMatch(metadata) {
|
||||||
if a, ok := t.proxies[rule.Adapter()]; ok {
|
if a, ok := t.proxies[rule.Adapter()]; ok {
|
||||||
log.Infoln("%v match %s using %s", metadata.String(), rule.RuleType().String(), rule.Adapter())
|
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())
|
log.Infoln("%v doesn't match any rule using DIRECT", metadata.String())
|
||||||
return t.proxies["DIRECT"]
|
return t.proxies["DIRECT"], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTunnel() *Tunnel {
|
func newTunnel() *Tunnel {
|
||||||
|
|
Loading…
Reference in a new issue