Skip to content

Commit

Permalink
working dns server
Browse files Browse the repository at this point in the history
  • Loading branch information
mrhaoxx committed Feb 13, 2024
1 parent 988f7ec commit 1034d54
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 37 deletions.
112 changes: 81 additions & 31 deletions dns/server.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package dns

import (
"net"
"strconv"
"sync"
"strings"
"sync/atomic"
"time"

Expand All @@ -13,37 +14,52 @@ import (
)

type record struct {
rr dns.RR
name *regexp2.Regexp
rtype uint16
rvalue string
name *regexp2.Regexp
}
type filter struct {
name *regexp2.Regexp
allowance bool
}

type server struct {
records []*record
records_lock sync.RWMutex
filters []*filter
upstreamDNS string
records []*record
filters []*filter
domain string

count uint64
}

func joinNames(questions []dns.Question) string {
var names []string
for _, q := range questions {
names = append(names, q.Name)
}
return strings.Join(names, " ")
}

func joinTypes(questions []dns.Question) string {
var types []string
for _, q := range questions {
types = append(types, dns.TypeToString[q.Qtype])
}
return strings.Join(types, " ")
}

func (s *server) ServeDNS(w dns.ResponseWriter, req *dns.Msg) {
m := new(dns.Msg)
m.SetReply(req)
m := new(dns.Msg).SetReply(req)

id := atomic.AddUint64(&s.count, 1)
startTime := time.Now()
defer func() {
log.Println("d"+strconv.FormatUint(id, 10), w.RemoteAddr().String(), time.Since(startTime).Round(1*time.Microsecond), m.Rcode, m.Question[0].Name, m.Answer)
log.Println("d"+strconv.FormatUint(id, 10), w.RemoteAddr().String(), time.Since(startTime).Round(1*time.Microsecond), RcodeTypeMap[m.Rcode], joinTypes(req.Question), joinNames(req.Question))
}()

for _, q := range req.Question {
for _, r := range s.filters {
if ok, _ := r.name.MatchString(q.Name); ok {
if r.allowance {
m.Rcode = dns.RcodeSuccess
break
} else {
m.Rcode = dns.RcodeRefused
Expand All @@ -52,11 +68,32 @@ func (s *server) ServeDNS(w dns.ResponseWriter, req *dns.Msg) {
}
}
}
{
c := new(dns.Client)
in, _, _ := c.Exchange(req, s.upstreamDNS)
w.WriteMsg(in)
return

for _, q := range req.Question {
for _, r := range s.records {
if q.Qtype == r.rtype {
if ok, _ := r.name.MatchString(q.Name); ok {
var ret dns.RR
switch r.rtype {
case dns.TypeA:
ret = &dns.A{
Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 60},
A: net.ParseIP(r.rvalue)}
case dns.TypePTR:
ret = &dns.PTR{
Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: 60},
Ptr: r.rvalue}
default:
m.Rcode = dns.RcodeNotImplemented
goto _end
}
m.Answer = append(m.Answer, ret)
}
}
}
}
if len(m.Answer) == 0 {
m.Rcode = dns.RcodeNameError
}
_end:
w.WriteMsg(m)
Expand All @@ -72,22 +109,35 @@ func (s *server) AddFilter(name *regexp2.Regexp, allowance bool) error {
s.filters = append(s.filters, &filter{name: name, allowance: allowance})
return nil
}
func (s *server) AddRecord(name *regexp2.Regexp, rtype uint16, rvalue string) error {
s.records = append(s.records, &record{name: name, rtype: rtype, rvalue: rvalue})
return nil
}

func (s *server) AddRecordWithIP(name string, ip string) error {
real_subdomain := name + "." + s.domain + "."
real_ptr := reverseIP(ip) + ".in-addr.arpa." + s.domain + "."

s.AddRecord(regexp2.MustCompile(Dnsname2Regexp(real_subdomain), 0), dns.TypeA, ip)
s.AddRecord(regexp2.MustCompile(Dnsname2Regexp(real_ptr), 0), dns.TypePTR, real_subdomain)

return nil
}

// func (s *server) AddRecord(domain string, rr dns.RR) error {
// r, err := regexp2.Compile(domain, 0)
// if err != nil {
// return err
// }
// s.records_lock.Lock()
// s.records = append(s.records, &record{rr: rr, domain: r})
// s.records_lock.Unlock()
// return nil
// }

func NewServer(upstreamDNS string) *server {
func NewServer(domain string) *server {
return &server{
records: []*record{},
filters: []*filter{},
upstreamDNS: upstreamDNS,
records: []*record{},
filters: []*filter{},
domain: domain,
}
}

func reverseIP(ipAddr string) string {
segments := strings.Split(ipAddr, ".")

for i, j := 0, len(segments)-1; i < j; i, j = i+1, j-1 {
segments[i], segments[j] = segments[j], segments[i]
}

return strings.Join(segments, ".")
}
39 changes: 38 additions & 1 deletion dns/utils.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package dns

import "strings"
import (
"strings"

"github.com/miekg/dns"
)

func Dnsnames2Regexps(dnsnames []string) []string {
var out []string
Expand All @@ -16,3 +20,36 @@ func Dnsname2Regexp(dnsname string) (v string) {
v = strings.ReplaceAll(v, "*", ".*")
return "^" + v + "$"
}

func DnsStringTypeToInt(s string) uint16 {
switch s {
case "A":
return dns.TypeA
case "AAAA":
return dns.TypeAAAA
case "CNAME":
return dns.TypeCNAME
case "MX":
return dns.TypeMX
case "NS":
return dns.TypeNS
case "PTR":
return dns.TypePTR
case "SOA":
return dns.TypeSOA
case "SRV":
return dns.TypeSRV
case "TXT":
return dns.TypeTXT
default:
return 0
}
}

var DnsTypeMap = []string{
"None", "A", "NS", "MD", "MF", "CNAME", "SOA", "MB", "MG", "MR", "NULL", "PTR", "HINFO", "MINFO", "MX", "TXT", "RP", "AFSDB", "X25", "ISDN", "RT", "NSAPPTR", "SIG", "KEY", "PX", "GPOS", "AAAA", "LOC", "NXT", "EID", "NIMLOC", "SRV", "ATMA", "NAPTR", "KX", "CERT", "DNAME", "OPT", "APL", "DS", "SSHFP", "IPSECKEY", "RRSIG", "NSEC", "DNSKEY", "DHCID", "NSEC3", "NSEC3PARAM", "TLSA", "SMIMEA", "HIP", "NINFO", "RKEY", "TALINK", "CDS", "CDNSKEY", "OPENPGPKEY", "CSYNC", "ZONEMD", "SVCB", "HTTPS", "SPF", "UINFO", "UID", "GID", "UNSPEC", "NID", "L32", "L64", "LP", "EUI48", "EUI64", "TKEY", "TSIG", "IXFR", "AXFR", "MAILB", "MAILA", "ANY", "URI", "CAA", "AVC", "DOA", "AMTRELAY", "TA", "DLV", "RESERVED",
}

var RcodeTypeMap = []string{
"NoError", "FormErr", "ServFail", "NXDomain", "NotImp", "Refused", "YXDomain", "YXRRSet", "NXRRSet", "NotAuth", "NotZone", "RESERVED11", "RESERVED12", "RESERVED13", "RESERVED14", "RESERVED15", "BADVERS", "BADSIG", "BADKEY", "BADTIME", "BADMODE", "BADNAME", "BADALG", "BADTRUNC", "BADCOOKIE", "RESERVED25", "RESERVED26", "RESERVED27", "RESERVED28", "RESERVED29", "RESERVED30", "RESERVED31",
}
13 changes: 9 additions & 4 deletions ui/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,11 @@ type UdpLoggerConfig struct {
}

type DnsConfig struct {
Bind string `yaml:"Bind"`
Upstream string `yaml:"Upstream"`
Records []DnsRecord `yaml:"Records,flow"`
Filters []DnsFilterRule `yaml:"Filters,flow"`
Bind string `yaml:"Bind"`
Domain string `yaml:"Domain"`
Records []DnsRecord `yaml:"Records,flow"`
Filters []DnsFilterRule `yaml:"Filters,flow"`
Binds []DnsBind `yaml:"Binds,flow"`
}

type DnsRecord struct {
Expand All @@ -106,3 +107,7 @@ type DnsFilterRule struct {
Name string `yaml:"Name"`
Allowance bool `yaml:"Allowance"`
}
type DnsBind struct {
Name string `yaml:"Name"`
Addr string `yaml:"Addr"`
}
15 changes: 14 additions & 1 deletion ui/myservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ func LoadCfg(cfgs []byte) error {
log.Println("sys", "tcp", err)
os.Exit(-1)
}
var Dns = dns.NewServer(cfg.DNS.Upstream)
var Dns = dns.NewServer(cfg.DNS.Domain)
log.Println("sys", "dns", "domain is", cfg.DNS.Domain)
for _, f := range cfg.DNS.Filters {
log.Println("sys", "dns", "Filter", f.Name, f.Allowance)
r, err := regexp2.Compile(dns.Dnsname2Regexp(f.Name), 0)
Expand All @@ -252,6 +253,18 @@ func LoadCfg(cfgs []byte) error {
}
Dns.AddFilter(r, f.Allowance)
}
for _, r := range cfg.DNS.Records {
log.Println("sys", "dns", "Record", r.Domain, r.Type, r.Value)
Dns.AddRecord(regexp2.MustCompile(dns.Dnsname2Regexp(r.Domain), 0), dns.DnsStringTypeToInt(r.Type), r.Value)
}
for _, b := range cfg.DNS.Binds {
log.Println("sys", "dns", b.Name, "->", b.Addr)
err := Dns.AddRecordWithIP(b.Name, b.Addr)
if err != nil {
log.Println("sys", "dns", err)
os.Exit(-1)
}
}

if cfg.DNS.Bind != "" {
go func() {
Expand Down

0 comments on commit 1034d54

Please sign in to comment.