refactor(dns): replace dnsmessage with miekg/dns (#188)

This commit is contained in:
mzz
2023-07-09 16:02:17 +08:00
committed by GitHub
parent b82b31e350
commit 00cf4bc3cd
20 changed files with 327 additions and 427 deletions

View File

@ -6,98 +6,44 @@
package control
import (
"encoding/binary"
"fmt"
"hash/fnv"
"math/rand"
"net/netip"
"strconv"
"strings"
"golang.org/x/net/dns/dnsmessage"
dnsmessage "github.com/miekg/dns"
)
// FlipDnsQuestionCase is used to reduce dns pollution.
func FlipDnsQuestionCase(dm *dnsmessage.Message) {
if len(dm.Questions) == 0 {
return
}
q := &dm.Questions[0]
// For reproducibility, we use dm.ID as input and add some entropy to make the results more discrete.
h := fnv.New64()
var buf [4]byte
binary.BigEndian.PutUint16(buf[:], dm.ID)
h.Write(buf[:2])
binary.BigEndian.PutUint32(buf[:], 20230204) // entropy
h.Write(buf[:])
r := rand.New(rand.NewSource(int64(h.Sum64())))
perm := r.Perm(int(q.Name.Length))
for i := 0; i < int(q.Name.Length/3); i++ {
j := perm[i]
// Upper to lower; lower to upper.
if q.Name.Data[j] >= 'a' && q.Name.Data[j] <= 'z' {
q.Name.Data[j] -= 'a' - 'A'
} else if q.Name.Data[j] >= 'A' && q.Name.Data[j] <= 'Z' {
q.Name.Data[j] += 'a' - 'A'
}
}
}
// EnsureAdditionalOpt makes sure there is additional record OPT in the request.
func EnsureAdditionalOpt(dm *dnsmessage.Message, isReqAdd bool) (bool, error) {
// Check healthy resp.
if isReqAdd == dm.Response || dm.RCode != dnsmessage.RCodeSuccess || len(dm.Questions) == 0 {
return false, UnsupportedQuestionTypeError
}
q := dm.Questions[0]
switch q.Type {
case dnsmessage.TypeA, dnsmessage.TypeAAAA:
default:
return false, UnsupportedQuestionTypeError
}
for _, ad := range dm.Additionals {
if ad.Header.Type == dnsmessage.TypeOPT {
// Already has additional record OPT.
return true, nil
}
}
if !isReqAdd {
return false, nil
}
// Add one.
dm.Additionals = append(dm.Additionals, dnsmessage.Resource{
Header: dnsmessage.ResourceHeader{
Name: dnsmessage.MustNewName("."),
Type: dnsmessage.TypeOPT,
Class: 512, TTL: 0, Length: 0,
},
Body: &dnsmessage.OPTResource{
Options: nil,
},
})
return false, nil
}
type RscWrapper struct {
Rsc dnsmessage.Resource
Rsc dnsmessage.RR
}
func (w RscWrapper) String() string {
var strBody string
switch body := w.Rsc.Body.(type) {
case *dnsmessage.AResource:
strBody = netip.AddrFrom4(body.A).String()
case *dnsmessage.AAAAResource:
strBody = netip.AddrFrom16(body.AAAA).String()
switch body := w.Rsc.(type) {
case *dnsmessage.A:
strBody = body.A.String()
case *dnsmessage.AAAA:
strBody = body.AAAA.String()
case *dnsmessage.CNAME:
strBody = body.Target
default:
strBody = body.GoString()
strBody = body.String()
}
return fmt.Sprintf("%v(%v): %v", w.Rsc.Header.Name.String(), w.Rsc.Header.Type.String(), strBody)
return fmt.Sprintf("%v(%v): %v", w.Rsc.Header().Name, QtypeToString(w.Rsc.Header().Rrtype), strBody)
}
func FormatDnsRsc(ans []dnsmessage.Resource) string {
func FormatDnsRsc(ans []dnsmessage.RR) string {
var w []string
for _, a := range ans {
w = append(w, RscWrapper{Rsc: a}.String())
}
return strings.Join(w, "; ")
}
func QtypeToString(qtype uint16) string {
str, ok := dnsmessage.TypeToString[qtype]
if !ok {
str = strconv.Itoa(int(qtype))
}
return str
}