Feature: add experimental config for resolving ip fail behavior

This commit is contained in:
Dreamacro 2019-04-24 12:02:52 +08:00
parent 90e3dccacd
commit cec2206774
5 changed files with 65 additions and 30 deletions

View File

@ -105,6 +105,10 @@ external-controller: 127.0.0.1:9090
# Secret for RESTful API (Optional)
# secret: ""
# experimental feature
experimental:
ignore-resolve-fail: true # ignore dns reslove fail, default value is true
# dns:
# enable: true # set true to enable dns (default is false)
# ipv6: false # default is false

View File

@ -43,12 +43,18 @@ type DNS struct {
EnhancedMode dns.EnhancedMode `yaml:"enhanced-mode"`
}
// Experimental config
type Experimental struct {
IgnoreResolveFail bool `yaml:"ignore-resolve-fail"`
}
// Config is clash config manager
type Config struct {
General *General
DNS *DNS
Rules []C.Rule
Proxies map[string]C.Proxy
General *General
DNS *DNS
Experimental *Experimental
Rules []C.Rule
Proxies map[string]C.Proxy
}
type rawDNS struct {
@ -71,10 +77,11 @@ type rawConfig struct {
ExternalUI string `yaml:"external-ui"`
Secret string `yaml:"secret"`
DNS rawDNS `yaml:"dns"`
Proxy []map[string]interface{} `yaml:"Proxy"`
ProxyGroup []map[string]interface{} `yaml:"Proxy Group"`
Rule []string `yaml:"Rule"`
DNS rawDNS `yaml:"dns"`
Experimental Experimental `yaml:"experimental"`
Proxy []map[string]interface{} `yaml:"Proxy"`
ProxyGroup []map[string]interface{} `yaml:"Proxy Group"`
Rule []string `yaml:"Rule"`
}
func readConfig(path string) (*rawConfig, error) {
@ -98,6 +105,9 @@ func readConfig(path string) (*rawConfig, error) {
Rule: []string{},
Proxy: []map[string]interface{}{},
ProxyGroup: []map[string]interface{}{},
Experimental: Experimental{
IgnoreResolveFail: true,
},
DNS: rawDNS{
Enable: false,
},
@ -114,6 +124,7 @@ func Parse(path string) (*Config, error) {
if err != nil {
return nil, err
}
config.Experimental = &rawCfg.Experimental
general, err := parseGeneral(rawCfg)
if err != nil {

View File

@ -27,6 +27,7 @@ func ApplyConfig(cfg *config.Config, force bool) {
updateProxies(cfg.Proxies)
updateRules(cfg.Rules)
updateDNS(cfg.DNS)
updateExperimental(cfg.Experimental)
}
func GetGeneral() *config.General {
@ -41,6 +42,10 @@ func GetGeneral() *config.General {
}
}
func updateExperimental(c *config.Experimental) {
T.Instance().UpdateExperimental(c.IgnoreResolveFail)
}
func updateDNS(c *config.DNS) {
if c.Enable == false {
T.Instance().SetResolver(nil)

View File

@ -1 +0,0 @@
package socks

View File

@ -21,12 +21,15 @@ var (
// Tunnel handle relay inbound proxy and outbound proxy
type Tunnel struct {
queue *channels.InfiniteChannel
rules []C.Rule
proxies map[string]C.Proxy
configLock *sync.RWMutex
traffic *C.Traffic
resolver *dns.Resolver
queue *channels.InfiniteChannel
rules []C.Rule
proxies map[string]C.Proxy
configMux *sync.RWMutex
traffic *C.Traffic
resolver *dns.Resolver
// experimental features
ignoreResolveFail bool
// Outbound Rule
mode Mode
@ -49,9 +52,9 @@ func (t *Tunnel) Rules() []C.Rule {
// UpdateRules handle update rules
func (t *Tunnel) UpdateRules(rules []C.Rule) {
t.configLock.Lock()
t.configMux.Lock()
t.rules = rules
t.configLock.Unlock()
t.configMux.Unlock()
}
// Proxies return all proxies
@ -61,9 +64,16 @@ func (t *Tunnel) Proxies() map[string]C.Proxy {
// UpdateProxies handle update proxies
func (t *Tunnel) UpdateProxies(proxies map[string]C.Proxy) {
t.configLock.Lock()
t.configMux.Lock()
t.proxies = proxies
t.configLock.Unlock()
t.configMux.Unlock()
}
// UpdateExperimental handle update experimental config
func (t *Tunnel) UpdateExperimental(ignoreResolveFail bool) {
t.configMux.Lock()
t.ignoreResolveFail = ignoreResolveFail
t.configMux.Unlock()
}
// Mode return current mode
@ -174,17 +184,23 @@ func (t *Tunnel) shouldResolveIP(rule C.Rule, metadata *C.Metadata) bool {
}
func (t *Tunnel) match(metadata *C.Metadata) (C.Proxy, error) {
t.configLock.RLock()
defer t.configLock.RUnlock()
t.configMux.RLock()
defer t.configMux.RUnlock()
var resolved bool
for _, rule := range t.rules {
if t.shouldResolveIP(rule, metadata) {
if !resolved && 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())
if !t.ignoreResolveFail {
return nil, fmt.Errorf("[DNS] resolve %s error: %s", metadata.Host, err.Error())
}
log.Debugln("[DNS] resolve %s error: %s", metadata.Host, err.Error())
} else {
log.Debugln("[DNS] %s --> %s", metadata.Host, ip.String())
metadata.IP = &ip
}
log.Debugln("[DNS] %s --> %s", metadata.Host, ip.String())
metadata.IP = &ip
resolved = true
}
if rule.IsMatch(metadata) {
@ -207,11 +223,11 @@ func (t *Tunnel) match(metadata *C.Metadata) (C.Proxy, error) {
func newTunnel() *Tunnel {
return &Tunnel{
queue: channels.NewInfiniteChannel(),
proxies: make(map[string]C.Proxy),
configLock: &sync.RWMutex{},
traffic: C.NewTraffic(time.Second),
mode: Rule,
queue: channels.NewInfiniteChannel(),
proxies: make(map[string]C.Proxy),
configMux: &sync.RWMutex{},
traffic: C.NewTraffic(time.Second),
mode: Rule,
}
}