clash/dns/middleware.go

200 lines
4.5 KiB
Go
Raw Normal View History

2019-07-14 11:29:58 +00:00
package dns
import (
2022-04-05 20:25:53 +00:00
"net/netip"
2019-07-14 11:29:58 +00:00
"strings"
"time"
2019-07-14 11:29:58 +00:00
"github.com/Dreamacro/clash/common/cache"
2022-04-19 09:46:13 +00:00
"github.com/Dreamacro/clash/common/nnip"
2019-07-14 11:29:58 +00:00
"github.com/Dreamacro/clash/component/fakeip"
"github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/context"
2019-07-14 11:29:58 +00:00
"github.com/Dreamacro/clash/log"
D "github.com/miekg/dns"
)
2021-10-10 15:44:09 +00:00
type (
handler func(ctx *context.DNSContext, r *D.Msg) (*D.Msg, error)
middleware func(next handler) handler
)
2019-07-14 11:29:58 +00:00
func withHosts(hosts *trie.DomainTrie[netip.Addr], mapping *cache.LruCache[netip.Addr, string]) middleware {
return func(next handler) handler {
return func(ctx *context.DNSContext, r *D.Msg) (*D.Msg, error) {
q := r.Question[0]
if !isIPRequest(q) {
return next(ctx, r)
}
2022-04-10 22:28:42 +00:00
host := strings.TrimRight(q.Name, ".")
record := hosts.Search(host)
if record == nil {
return next(ctx, r)
}
2022-04-05 20:25:53 +00:00
ip := record.Data
msg := r.Copy()
2022-04-05 20:25:53 +00:00
if ip.Is4() && q.Qtype == D.TypeA {
rr := &D.A{}
2022-04-10 22:28:42 +00:00
rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeA, Class: D.ClassINET, Ttl: 10}
2022-04-05 20:25:53 +00:00
rr.A = ip.AsSlice()
msg.Answer = []D.RR{rr}
} else if q.Qtype == D.TypeAAAA {
rr := &D.AAAA{}
2022-04-10 22:28:42 +00:00
rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeAAAA, Class: D.ClassINET, Ttl: 10}
ip := ip.As16()
rr.AAAA = ip[:]
msg.Answer = []D.RR{rr}
} else {
return next(ctx, r)
}
2022-04-10 22:28:42 +00:00
if mapping != nil {
mapping.SetWithExpire(ip, host, time.Now().Add(time.Second*10))
2022-04-10 22:28:42 +00:00
}
ctx.SetType(context.DNSTypeHost)
msg.SetRcode(r, D.RcodeSuccess)
msg.Authoritative = true
msg.RecursionAvailable = true
return msg, nil
}
}
}
func withMapping(mapping *cache.LruCache[netip.Addr, string]) middleware {
return func(next handler) handler {
return func(ctx *context.DNSContext, r *D.Msg) (*D.Msg, error) {
q := r.Question[0]
if !isIPRequest(q) {
return next(ctx, r)
}
msg, err := next(ctx, r)
if err != nil {
return nil, err
}
host := strings.TrimRight(q.Name, ".")
for _, ans := range msg.Answer {
2022-04-19 17:52:51 +00:00
var ip netip.Addr
var ttl uint32
switch a := ans.(type) {
case *D.A:
2022-04-19 17:52:51 +00:00
ip = nnip.IpToAddr(a.A)
ttl = a.Hdr.Ttl
case *D.AAAA:
2022-04-19 17:52:51 +00:00
ip = nnip.IpToAddr(a.AAAA)
ttl = a.Hdr.Ttl
default:
continue
}
2022-04-19 17:52:51 +00:00
mapping.SetWithExpire(ip, host, time.Now().Add(time.Second*time.Duration(ttl)))
}
return msg, nil
}
}
}
2019-09-11 09:00:55 +00:00
func withFakeIP(fakePool *fakeip.Pool) middleware {
return func(next handler) handler {
return func(ctx *context.DNSContext, r *D.Msg) (*D.Msg, error) {
2019-09-11 09:00:55 +00:00
q := r.Question[0]
2020-10-08 16:04:24 +00:00
host := strings.TrimRight(q.Name, ".")
2021-10-11 12:48:58 +00:00
if fakePool.ShouldSkipped(host) {
return next(ctx, r)
2020-10-08 16:04:24 +00:00
}
switch q.Qtype {
case D.TypeAAAA, D.TypeSVCB, D.TypeHTTPS:
return handleMsgWithEmptyAnswer(r), nil
}
if q.Qtype != D.TypeA {
return next(ctx, r)
2019-09-11 09:00:55 +00:00
}
rr := &D.A{}
rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeA, Class: D.ClassINET, Ttl: dnsDefaultTTL}
ip := fakePool.Lookup(host)
rr.A = ip.AsSlice()
2019-09-11 09:00:55 +00:00
msg := r.Copy()
msg.Answer = []D.RR{rr}
ctx.SetType(context.DNSTypeFakeIP)
2019-09-11 09:00:55 +00:00
setMsgTTL(msg, 1)
msg.SetRcode(r, D.RcodeSuccess)
msg.Authoritative = true
msg.RecursionAvailable = true
return msg, nil
2019-09-11 09:00:55 +00:00
}
2019-07-14 11:29:58 +00:00
}
}
func withResolver(resolver *Resolver) handler {
return func(ctx *context.DNSContext, r *D.Msg) (*D.Msg, error) {
ctx.SetType(context.DNSTypeRaw)
2020-06-18 10:11:02 +00:00
q := r.Question[0]
// return a empty AAAA msg when ipv6 disabled
if !resolver.ipv6 && q.Qtype == D.TypeAAAA {
return handleMsgWithEmptyAnswer(r), nil
2020-06-18 10:11:02 +00:00
}
2019-07-14 11:29:58 +00:00
msg, err := resolver.Exchange(r)
if err != nil {
2019-09-11 09:00:55 +00:00
log.Debugln("[DNS Server] Exchange %s failed: %v", q.String(), err)
return msg, err
2019-07-14 11:29:58 +00:00
}
msg.SetRcode(r, msg.Rcode)
msg.Authoritative = true
2022-05-17 10:21:18 +00:00
log.Debugln("[DNS] %s --> %s", msgToDomain(r), msgToIP(msg))
return msg, nil
2019-07-14 11:29:58 +00:00
}
}
2019-09-11 09:00:55 +00:00
func compose(middlewares []middleware, endpoint handler) handler {
length := len(middlewares)
h := endpoint
for i := length - 1; i >= 0; i-- {
middleware := middlewares[i]
h = middleware(h)
2019-07-14 11:29:58 +00:00
}
2019-09-11 09:00:55 +00:00
return h
2019-07-14 11:29:58 +00:00
}
2021-11-17 08:03:47 +00:00
func NewHandler(resolver *Resolver, mapper *ResolverEnhancer) handler {
2019-09-11 09:00:55 +00:00
middlewares := []middleware{}
2019-07-14 11:29:58 +00:00
if resolver.hosts != nil {
2022-04-10 22:28:42 +00:00
middlewares = append(middlewares, withHosts(resolver.hosts, mapper.mapping))
}
if mapper.mode == C.DNSFakeIP {
middlewares = append(middlewares, withFakeIP(mapper.fakePool))
}
if mapper.mode != C.DNSNormal {
middlewares = append(middlewares, withMapping(mapper.mapping))
2019-07-14 11:29:58 +00:00
}
2019-09-11 09:00:55 +00:00
return compose(middlewares, withResolver(resolver))
2019-07-14 11:29:58 +00:00
}