Feature: dns server could lookup hosts (#872)

This commit is contained in:
Kr328 2020-08-11 10:28:17 +08:00 committed by GitHub
parent 4ba6f248bc
commit 89cf06036d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 7 deletions

View file

@ -62,6 +62,7 @@ type DNS struct {
EnhancedMode dns.EnhancedMode `yaml:"enhanced-mode"` EnhancedMode dns.EnhancedMode `yaml:"enhanced-mode"`
DefaultNameserver []dns.NameServer `yaml:"default-nameserver"` DefaultNameserver []dns.NameServer `yaml:"default-nameserver"`
FakeIPRange *fakeip.Pool FakeIPRange *fakeip.Pool
Hosts *trie.DomainTrie
} }
// FallbackFilter config // FallbackFilter config
@ -88,6 +89,7 @@ type Config struct {
type RawDNS struct { type RawDNS struct {
Enable bool `yaml:"enable"` Enable bool `yaml:"enable"`
IPv6 bool `yaml:"ipv6"` IPv6 bool `yaml:"ipv6"`
UseHosts bool `yaml:"use-hosts"`
NameServer []string `yaml:"nameserver"` NameServer []string `yaml:"nameserver"`
Fallback []string `yaml:"fallback"` Fallback []string `yaml:"fallback"`
FallbackFilter RawFallbackFilter `yaml:"fallback-filter"` FallbackFilter RawFallbackFilter `yaml:"fallback-filter"`
@ -152,6 +154,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
ProxyGroup: []map[string]interface{}{}, ProxyGroup: []map[string]interface{}{},
DNS: RawDNS{ DNS: RawDNS{
Enable: false, Enable: false,
UseHosts: true,
FakeIPRange: "198.18.0.1/16", FakeIPRange: "198.18.0.1/16",
FallbackFilter: RawFallbackFilter{ FallbackFilter: RawFallbackFilter{
GeoIP: true, GeoIP: true,
@ -195,18 +198,18 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
} }
config.Rules = rules config.Rules = rules
dnsCfg, err := parseDNS(rawCfg.DNS)
if err != nil {
return nil, err
}
config.DNS = dnsCfg
hosts, err := parseHosts(rawCfg) hosts, err := parseHosts(rawCfg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Hosts = hosts config.Hosts = hosts
dnsCfg, err := parseDNS(rawCfg.DNS, hosts)
if err != nil {
return nil, err
}
config.DNS = dnsCfg
config.Users = parseAuthentication(rawCfg.Authentication) config.Users = parseAuthentication(rawCfg.Authentication)
return config, nil return config, nil
@ -494,7 +497,7 @@ func parseFallbackIPCIDR(ips []string) ([]*net.IPNet, error) {
return ipNets, nil return ipNets, nil
} }
func parseDNS(cfg RawDNS) (*DNS, error) { func parseDNS(cfg RawDNS, hosts *trie.DomainTrie) (*DNS, error) {
if cfg.Enable && len(cfg.NameServer) == 0 { if cfg.Enable && len(cfg.NameServer) == 0 {
return nil, fmt.Errorf("If DNS configuration is turned on, NameServer cannot be empty") return nil, fmt.Errorf("If DNS configuration is turned on, NameServer cannot be empty")
} }
@ -559,6 +562,10 @@ func parseDNS(cfg RawDNS) (*DNS, error) {
dnsCfg.FallbackFilter.IPCIDR = fallbackip dnsCfg.FallbackFilter.IPCIDR = fallbackip
} }
if cfg.UseHosts {
dnsCfg.Hosts = hosts
}
return dnsCfg, nil return dnsCfg, nil
} }

View file

@ -1,9 +1,11 @@
package dns package dns
import ( import (
"net"
"strings" "strings"
"github.com/Dreamacro/clash/component/fakeip" "github.com/Dreamacro/clash/component/fakeip"
"github.com/Dreamacro/clash/component/trie"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
D "github.com/miekg/dns" D "github.com/miekg/dns"
@ -12,6 +14,52 @@ import (
type handler func(w D.ResponseWriter, r *D.Msg) type handler func(w D.ResponseWriter, r *D.Msg)
type middleware func(next handler) handler type middleware func(next handler) handler
func withHosts(hosts *trie.DomainTrie) middleware {
return func(next handler) handler {
return func(w D.ResponseWriter, r *D.Msg) {
q := r.Question[0]
if !isIPRequest(q) {
next(w, r)
return
}
record := hosts.Search(strings.TrimRight(q.Name, "."))
if record == nil {
next(w, r)
return
}
ip := record.Data.(net.IP)
msg := r.Copy()
if v4 := ip.To4(); v4 != nil && q.Qtype == D.TypeA {
rr := &D.A{}
rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeA, Class: D.ClassINET, Ttl: dnsDefaultTTL}
rr.A = v4
msg.Answer = []D.RR{rr}
} else if v6 := ip.To16(); v6 != nil && q.Qtype == D.TypeAAAA {
rr := &D.AAAA{}
rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeAAAA, Class: D.ClassINET, Ttl: dnsDefaultTTL}
rr.AAAA = v6
msg.Answer = []D.RR{rr}
} else {
next(w, r)
return
}
msg.SetRcode(r, D.RcodeSuccess)
msg.Authoritative = true
msg.RecursionAvailable = true
w.WriteMsg(msg)
return
}
}
}
func withFakeIP(fakePool *fakeip.Pool) middleware { func withFakeIP(fakePool *fakeip.Pool) middleware {
return func(next handler) handler { return func(next handler) handler {
return func(w D.ResponseWriter, r *D.Msg) { return func(w D.ResponseWriter, r *D.Msg) {
@ -100,6 +148,10 @@ func compose(middlewares []middleware, endpoint handler) handler {
func newHandler(resolver *Resolver) handler { func newHandler(resolver *Resolver) handler {
middlewares := []middleware{} middlewares := []middleware{}
if resolver.hosts != nil {
middlewares = append(middlewares, withHosts(resolver.hosts))
}
if resolver.FakeIPEnabled() { if resolver.FakeIPEnabled() {
middlewares = append(middlewares, withFakeIP(resolver.pool)) middlewares = append(middlewares, withFakeIP(resolver.pool))
} }

View file

@ -14,6 +14,7 @@ import (
"github.com/Dreamacro/clash/common/picker" "github.com/Dreamacro/clash/common/picker"
"github.com/Dreamacro/clash/component/fakeip" "github.com/Dreamacro/clash/component/fakeip"
"github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/component/resolver"
"github.com/Dreamacro/clash/component/trie"
D "github.com/miekg/dns" D "github.com/miekg/dns"
"golang.org/x/sync/singleflight" "golang.org/x/sync/singleflight"
@ -37,6 +38,7 @@ type Resolver struct {
ipv6 bool ipv6 bool
mapping bool mapping bool
fakeip bool fakeip bool
hosts *trie.DomainTrie
pool *fakeip.Pool pool *fakeip.Pool
main []dnsClient main []dnsClient
fallback []dnsClient fallback []dnsClient
@ -308,6 +310,7 @@ type Config struct {
EnhancedMode EnhancedMode EnhancedMode EnhancedMode
FallbackFilter FallbackFilter FallbackFilter FallbackFilter
Pool *fakeip.Pool Pool *fakeip.Pool
Hosts *trie.DomainTrie
} }
func New(config Config) *Resolver { func New(config Config) *Resolver {
@ -323,6 +326,7 @@ func New(config Config) *Resolver {
mapping: config.EnhancedMode == MAPPING, mapping: config.EnhancedMode == MAPPING,
fakeip: config.EnhancedMode == FAKEIP, fakeip: config.EnhancedMode == FAKEIP,
pool: config.Pool, pool: config.Pool,
hosts: config.Hosts,
} }
if len(config.Fallback) != 0 { if len(config.Fallback) != 0 {

View file

@ -113,6 +113,7 @@ func updateDNS(c *config.DNS) {
IPv6: c.IPv6, IPv6: c.IPv6,
EnhancedMode: c.EnhancedMode, EnhancedMode: c.EnhancedMode,
Pool: c.FakeIPRange, Pool: c.FakeIPRange,
Hosts: c.Hosts,
FallbackFilter: dns.FallbackFilter{ FallbackFilter: dns.FallbackFilter{
GeoIP: c.FallbackFilter.GeoIP, GeoIP: c.FallbackFilter.GeoIP,
IPCIDR: c.FallbackFilter.IPCIDR, IPCIDR: c.FallbackFilter.IPCIDR,