Skip to content

Commit

Permalink
Feature: support PTR records
Browse files Browse the repository at this point in the history
Signed-off-by: Fxzx micah <[email protected]>
  • Loading branch information
fxzxmicah committed Jan 20, 2024
1 parent a04e81c commit 598547f
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 24 deletions.
16 changes: 10 additions & 6 deletions dns/hosts.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"path"
"runtime"
"strings"
"unicode/utf8"

"github.com/Dreamacro/clash/component/trie"
)
Expand All @@ -18,9 +17,11 @@ func LoadHosts() *trie.DomainTrie {
if err != nil {
return nil
}
defer f.Close()

t := trie.New()
h := map[string][]net.IP{}
p := map[string][]string{}

sc := bufio.NewScanner(f)
for sc.Scan() {
Expand All @@ -32,10 +33,8 @@ func LoadHosts() *trie.DomainTrie {
}

// ignore records with non-ascii character
for i := 0; i < len(line); i++ {
if line[i] >= utf8.RuneSelf {
continue
}
if containNonASCII(line) {
continue
}

buf := bytes.NewBuffer([]byte(line))
Expand All @@ -54,14 +53,19 @@ func LoadHosts() *trie.DomainTrie {
}

h[name] = append(h[name], ip)
ptr := IPtoPTR(ip)
p[ptr] = append(p[ptr], name+".")
}
}

for name, ips := range h {
t.Insert(strings.ToLower(name), ips)
}

defer f.Close()
for ptr, names := range p {
t.Insert(ptr, names)
}

return t
}

Expand Down
49 changes: 31 additions & 18 deletions dns/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func withHosts(hosts *trie.DomainTrie) middleware {
return func(ctx *context.DNSContext, r *D.Msg) (*D.Msg, error) {
q := r.Question[0]

if !isIPRequest(q) {
if !isIPorPTRRequest(q) {
return next(ctx, r)
}

Expand All @@ -35,19 +35,32 @@ func withHosts(hosts *trie.DomainTrie) middleware {
}

msg := r.Copy()
for _, data := range record.Data.([]net.IP) {
if v4 := data.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: 10}
rr.A = v4

msg.Answer = append(msg.Answer, rr)
} else if v6 := data.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: 10}
rr.AAAA = v6

msg.Answer = append(msg.Answer, rr)
switch data := record.Data.(type) {
case []net.IP:
for _, ip := range data {
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: 60}
rr.A = v4

msg.Answer = append(msg.Answer, 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: 60}
rr.AAAA = v6

msg.Answer = append(msg.Answer, rr)
}
}
case []string:
for _, ptr := range data {
if q.Qtype == D.TypePTR {
rr := &D.PTR{}
rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypePTR, Class: D.ClassINET, Ttl: 60}
rr.Ptr = ptr

msg.Answer = append(msg.Answer, rr)
}
}
}

Expand Down Expand Up @@ -177,14 +190,14 @@ func compose(middlewares []middleware, endpoint handler) handler {
func newHandler(resolver *Resolver, mapper *ResolverEnhancer) handler {
middlewares := []middleware{}

if resolver.hosts != nil {
middlewares = append(middlewares, withHosts(resolver.hosts))
}

if resolver.localHosts != nil {
middlewares = append(middlewares, withHosts(resolver.localHosts))
}

if resolver.hosts != nil {
middlewares = append(middlewares, withHosts(resolver.hosts))
}

if mapper.mode == C.DNSFakeIP {
middlewares = append(middlewares, withFakeIP(mapper.fakePool))
}
Expand Down
29 changes: 29 additions & 0 deletions dns/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net"
"strings"
"time"
"unicode/utf8"

"github.com/Dreamacro/clash/common/cache"
"github.com/Dreamacro/clash/common/picker"
Expand Down Expand Up @@ -57,6 +58,10 @@ func isIPRequest(q D.Question) bool {
return q.Qclass == D.ClassINET && (q.Qtype == D.TypeA || q.Qtype == D.TypeAAAA)
}

func isIPorPTRRequest(q D.Question) bool {
return q.Qclass == D.ClassINET && (q.Qtype == D.TypeA || q.Qtype == D.TypeAAAA || q.Qtype == D.TypePTR)
}

func transform(servers []NameServer, resolver *Resolver) []dnsClient {
ret := []dnsClient{}
for _, s := range servers {
Expand Down Expand Up @@ -141,3 +146,27 @@ func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.M
msg = elm.(*D.Msg)
return
}

func containNonASCII(s string) bool {
for _, c := range s {
if c >= utf8.RuneSelf {
return true
}
}
return false
}

func IPtoPTR(ip net.IP) string {
if v4 := ip.To4(); v4 != nil {
// IPv4
return fmt.Sprintf("%d.%d.%d.%d.in-addr.arpa", v4[3], v4[2], v4[1], v4[0])
} else {
// IPv6
ptr := make([]string, len(ip)*2)
for i := 0; i < len(ip); i++ {
ptr[i*2] = fmt.Sprintf("%x", ip[len(ip)-i-1]&0xF)
ptr[i*2+1] = fmt.Sprintf("%x", ip[len(ip)-i-1]>>4)
}
return strings.Join(ptr, ".") + ".ip6.arpa"
}
}

0 comments on commit 598547f

Please sign in to comment.