Feature: dns server could lookup hosts (#872)
This commit is contained in:
parent
13e5b1263b
commit
b61e1cd00c
4 changed files with 71 additions and 7 deletions
|
@ -62,6 +62,7 @@ type DNS struct {
|
|||
EnhancedMode dns.EnhancedMode `yaml:"enhanced-mode"`
|
||||
DefaultNameserver []dns.NameServer `yaml:"default-nameserver"`
|
||||
FakeIPRange *fakeip.Pool
|
||||
Hosts *trie.DomainTrie
|
||||
}
|
||||
|
||||
// FallbackFilter config
|
||||
|
@ -88,6 +89,7 @@ type Config struct {
|
|||
type RawDNS struct {
|
||||
Enable bool `yaml:"enable"`
|
||||
IPv6 bool `yaml:"ipv6"`
|
||||
UseHosts bool `yaml:"use-hosts"`
|
||||
NameServer []string `yaml:"nameserver"`
|
||||
Fallback []string `yaml:"fallback"`
|
||||
FallbackFilter RawFallbackFilter `yaml:"fallback-filter"`
|
||||
|
@ -152,6 +154,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
|
|||
ProxyGroup: []map[string]interface{}{},
|
||||
DNS: RawDNS{
|
||||
Enable: false,
|
||||
UseHosts: true,
|
||||
FakeIPRange: "198.18.0.1/16",
|
||||
FallbackFilter: RawFallbackFilter{
|
||||
GeoIP: true,
|
||||
|
@ -195,18 +198,18 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
|||
}
|
||||
config.Rules = rules
|
||||
|
||||
dnsCfg, err := parseDNS(rawCfg.DNS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.DNS = dnsCfg
|
||||
|
||||
hosts, err := parseHosts(rawCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.Hosts = hosts
|
||||
|
||||
dnsCfg, err := parseDNS(rawCfg.DNS, hosts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.DNS = dnsCfg
|
||||
|
||||
config.Users = parseAuthentication(rawCfg.Authentication)
|
||||
|
||||
return config, nil
|
||||
|
@ -494,7 +497,7 @@ func parseFallbackIPCIDR(ips []string) ([]*net.IPNet, error) {
|
|||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
if cfg.UseHosts {
|
||||
dnsCfg.Hosts = hosts
|
||||
}
|
||||
|
||||
return dnsCfg, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/Dreamacro/clash/component/fakeip"
|
||||
"github.com/Dreamacro/clash/component/trie"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
|
||||
D "github.com/miekg/dns"
|
||||
|
@ -12,6 +14,52 @@ import (
|
|||
type handler func(w D.ResponseWriter, r *D.Msg)
|
||||
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 {
|
||||
return func(next handler) handler {
|
||||
return func(w D.ResponseWriter, r *D.Msg) {
|
||||
|
@ -100,6 +148,10 @@ func compose(middlewares []middleware, endpoint handler) handler {
|
|||
func newHandler(resolver *Resolver) handler {
|
||||
middlewares := []middleware{}
|
||||
|
||||
if resolver.hosts != nil {
|
||||
middlewares = append(middlewares, withHosts(resolver.hosts))
|
||||
}
|
||||
|
||||
if resolver.FakeIPEnabled() {
|
||||
middlewares = append(middlewares, withFakeIP(resolver.pool))
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/Dreamacro/clash/common/picker"
|
||||
"github.com/Dreamacro/clash/component/fakeip"
|
||||
"github.com/Dreamacro/clash/component/resolver"
|
||||
"github.com/Dreamacro/clash/component/trie"
|
||||
|
||||
D "github.com/miekg/dns"
|
||||
"golang.org/x/sync/singleflight"
|
||||
|
@ -37,6 +38,7 @@ type Resolver struct {
|
|||
ipv6 bool
|
||||
mapping bool
|
||||
fakeip bool
|
||||
hosts *trie.DomainTrie
|
||||
pool *fakeip.Pool
|
||||
main []dnsClient
|
||||
fallback []dnsClient
|
||||
|
@ -308,6 +310,7 @@ type Config struct {
|
|||
EnhancedMode EnhancedMode
|
||||
FallbackFilter FallbackFilter
|
||||
Pool *fakeip.Pool
|
||||
Hosts *trie.DomainTrie
|
||||
}
|
||||
|
||||
func New(config Config) *Resolver {
|
||||
|
@ -323,6 +326,7 @@ func New(config Config) *Resolver {
|
|||
mapping: config.EnhancedMode == MAPPING,
|
||||
fakeip: config.EnhancedMode == FAKEIP,
|
||||
pool: config.Pool,
|
||||
hosts: config.Hosts,
|
||||
}
|
||||
|
||||
if len(config.Fallback) != 0 {
|
||||
|
|
|
@ -113,6 +113,7 @@ func updateDNS(c *config.DNS) {
|
|||
IPv6: c.IPv6,
|
||||
EnhancedMode: c.EnhancedMode,
|
||||
Pool: c.FakeIPRange,
|
||||
Hosts: c.Hosts,
|
||||
FallbackFilter: dns.FallbackFilter{
|
||||
GeoIP: c.FallbackFilter.GeoIP,
|
||||
IPCIDR: c.FallbackFilter.IPCIDR,
|
||||
|
|
Loading…
Reference in a new issue