From 216116e128925559a40ddadd99402e608ace63ae Mon Sep 17 00:00:00 2001 From: gVisor bot Date: Thu, 18 Jun 2020 18:11:02 +0800 Subject: [PATCH] Change: ipv6 logic --- README.md | 4 +- component/resolver/resolver.go | 18 +++++++- config/config.go | 79 ++++++++++++++++++---------------- dns/middleware.go | 16 ++++++- dns/server.go | 1 + hub/executor/executor.go | 39 +++++++++++------ 6 files changed, 104 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 80c02f9c..a1bfaaf2 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,8 @@ allow-lan: false # "[aaaa::a8aa:ff:fe09:57d8]": bind a single IPv6 address # bind-address: "*" +# ipv6: false # when ipv6 is false, each clash dial with ipv6, but it's not affect the response of the dns server, default is false + # rule / global / direct (default is rule) mode: rule @@ -133,7 +135,7 @@ experimental: # dns: # enable: true # set true to enable dns (default is false) - # ipv6: false # default is false + # ipv6: false # it only affect the dns server response, default is false # listen: 0.0.0.0:53 # # default-nameserver: # resolve dns nameserver host, should fill pure IP # # - 114.114.114.114 diff --git a/component/resolver/resolver.go b/component/resolver/resolver.go index da9fed21..61258898 100644 --- a/component/resolver/resolver.go +++ b/component/resolver/resolver.go @@ -12,13 +12,18 @@ var ( // DefaultResolver aim to resolve ip DefaultResolver Resolver + // DisableIPv6 means don't resolve ipv6 host + // default value is true + DisableIPv6 = true + // DefaultHosts aim to resolve hosts DefaultHosts = trie.New() ) var ( - ErrIPNotFound = errors.New("couldn't find ip") - ErrIPVersion = errors.New("ip version error") + ErrIPNotFound = errors.New("couldn't find ip") + ErrIPVersion = errors.New("ip version error") + ErrIPv6Disabled = errors.New("ipv6 disabled") ) type Resolver interface { @@ -63,6 +68,10 @@ func ResolveIPv4(host string) (net.IP, error) { // ResolveIPv6 with a host, return ipv6 func ResolveIPv6(host string) (net.IP, error) { + if DisableIPv6 { + return nil, ErrIPv6Disabled + } + if node := DefaultHosts.Search(host); node != nil { if ip := node.Data.(net.IP).To16(); ip != nil { return ip, nil @@ -102,7 +111,12 @@ func ResolveIP(host string) (net.IP, error) { } if DefaultResolver != nil { + if DisableIPv6 { + return DefaultResolver.ResolveIPv4(host) + } return DefaultResolver.ResolveIP(host) + } else if DisableIPv6 { + return ResolveIPv4(host) } ip := net.ParseIP(host) diff --git a/config/config.go b/config/config.go index f18d0369..7b3913c4 100644 --- a/config/config.go +++ b/config/config.go @@ -25,18 +25,29 @@ import ( // General config type General struct { - Port int `json:"port"` - SocksPort int `json:"socks-port"` - RedirPort int `json:"redir-port"` - MixedPort int `json:"mixed-port"` - Authentication []string `json:"authentication"` - AllowLan bool `json:"allow-lan"` - BindAddress string `json:"bind-address"` - Mode T.TunnelMode `json:"mode"` - LogLevel log.LogLevel `json:"log-level"` - ExternalController string `json:"-"` - ExternalUI string `json:"-"` - Secret string `json:"-"` + Inbound + Controller + Mode T.TunnelMode `json:"mode"` + LogLevel log.LogLevel `json:"log-level"` + IPv6 bool `json:"ipv6"` +} + +// Inbound +type Inbound struct { + Port int `json:"port"` + SocksPort int `json:"socks-port"` + RedirPort int `json:"redir-port"` + MixedPort int `json:"mixed-port"` + Authentication []string `json:"authentication"` + AllowLan bool `json:"allow-lan"` + BindAddress string `json:"bind-address"` +} + +// Controller +type Controller struct { + ExternalController string `json:"-"` + ExternalUI string `json:"-"` + Secret string `json:"-"` } // DNS config @@ -104,6 +115,7 @@ type RawConfig struct { BindAddress string `yaml:"bind-address"` Mode T.TunnelMode `yaml:"mode"` LogLevel log.LogLevel `yaml:"log-level"` + IPv6 bool `yaml:"ipv6"` ExternalController string `yaml:"external-controller"` ExternalUI string `yaml:"external-ui"` Secret string `yaml:"secret"` @@ -216,18 +228,9 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { } func parseGeneral(cfg *RawConfig) (*General, error) { - port := cfg.Port - socksPort := cfg.SocksPort - redirPort := cfg.RedirPort - mixedPort := cfg.MixedPort - allowLan := cfg.AllowLan - bindAddress := cfg.BindAddress - externalController := cfg.ExternalController externalUI := cfg.ExternalUI - secret := cfg.Secret - mode := cfg.Mode - logLevel := cfg.LogLevel + // checkout externalUI exist if externalUI != "" { externalUI = C.Path.Resolve(externalUI) @@ -236,20 +239,24 @@ func parseGeneral(cfg *RawConfig) (*General, error) { } } - general := &General{ - Port: port, - SocksPort: socksPort, - RedirPort: redirPort, - MixedPort: mixedPort, - AllowLan: allowLan, - BindAddress: bindAddress, - Mode: mode, - LogLevel: logLevel, - ExternalController: externalController, - ExternalUI: externalUI, - Secret: secret, - } - return general, nil + return &General{ + Inbound: Inbound{ + Port: cfg.Port, + SocksPort: cfg.SocksPort, + RedirPort: cfg.RedirPort, + MixedPort: cfg.MixedPort, + AllowLan: cfg.AllowLan, + BindAddress: cfg.BindAddress, + }, + Controller: Controller{ + ExternalController: cfg.ExternalController, + ExternalUI: cfg.ExternalUI, + Secret: cfg.Secret, + }, + Mode: cfg.Mode, + LogLevel: cfg.LogLevel, + IPv6: cfg.IPv6, + }, nil } func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[string]provider.ProxyProvider, err error) { diff --git a/dns/middleware.go b/dns/middleware.go index 4d97e65d..7cafe7f9 100644 --- a/dns/middleware.go +++ b/dns/middleware.go @@ -58,9 +58,23 @@ func withFakeIP(fakePool *fakeip.Pool) middleware { func withResolver(resolver *Resolver) handler { return func(w D.ResponseWriter, r *D.Msg) { + q := r.Question[0] + + // return a empty AAAA msg when ipv6 disabled + if !resolver.ipv6 && q.Qtype == D.TypeAAAA { + msg := &D.Msg{} + msg.Answer = []D.RR{} + + msg.SetRcode(r, D.RcodeSuccess) + msg.Authoritative = true + msg.RecursionAvailable = true + + w.WriteMsg(msg) + return + } + msg, err := resolver.Exchange(r) if err != nil { - q := r.Question[0] log.Debugln("[DNS Server] Exchange %s failed: %v", q.String(), err) D.HandleFailed(w, r) return diff --git a/dns/server.go b/dns/server.go index 7af83f96..6e6a02b6 100644 --- a/dns/server.go +++ b/dns/server.go @@ -43,6 +43,7 @@ func ReCreateServer(addr string, resolver *Resolver) error { if server.Server != nil { server.Shutdown() + server = &Server{} address = "" } diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 2612ee9e..584191ac 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "os" "path/filepath" + "sync" "github.com/Dreamacro/clash/adapters/provider" "github.com/Dreamacro/clash/component/auth" @@ -20,6 +21,10 @@ import ( "github.com/Dreamacro/clash/tunnel" ) +var ( + mux sync.Mutex +) + // forward compatibility before 1.0 func readRawConfig(path string) ([]byte, error) { data, err := ioutil.ReadFile(path) @@ -77,10 +82,11 @@ func ParseWithBytes(buf []byte) (*config.Config, error) { // ApplyConfig dispatch configure to all parts func ApplyConfig(cfg *config.Config, force bool) { + mux.Lock() + defer mux.Unlock() + updateUsers(cfg.Users) - if force { - updateGeneral(cfg.General) - } + updateGeneral(cfg.General, force) updateProxies(cfg.Proxies, cfg.Providers) updateRules(cfg.Rules) updateDNS(cfg.DNS) @@ -96,15 +102,17 @@ func GetGeneral() *config.General { } general := &config.General{ - Port: ports.Port, - SocksPort: ports.SocksPort, - RedirPort: ports.RedirPort, - MixedPort: ports.MixedPort, - Authentication: authenticator, - AllowLan: P.AllowLan(), - BindAddress: P.BindAddress(), - Mode: tunnel.Mode(), - LogLevel: log.Level(), + Inbound: config.Inbound{ + Port: ports.Port, + SocksPort: ports.SocksPort, + RedirPort: ports.RedirPort, + MixedPort: ports.MixedPort, + Authentication: authenticator, + AllowLan: P.AllowLan(), + BindAddress: P.BindAddress(), + }, + Mode: tunnel.Mode(), + LogLevel: log.Level(), } return general @@ -166,9 +174,14 @@ func updateRules(rules []C.Rule) { tunnel.UpdateRules(rules) } -func updateGeneral(general *config.General) { +func updateGeneral(general *config.General, force bool) { log.SetLevel(general.LogLevel) tunnel.SetMode(general.Mode) + resolver.DisableIPv6 = !general.IPv6 + + if !force { + return + } allowLan := general.AllowLan P.SetAllowLan(allowLan)