Feature: dns server could lookup hosts (#872)
This commit is contained in:
parent
4ba6f248bc
commit
89cf06036d
4 changed files with 71 additions and 7 deletions
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue