powerdns-remote-http-example/dns.go
2024-06-30 11:51:09 +03:00

118 lines
2.3 KiB
Go

package main
import (
"errors"
"fmt"
"log"
"net"
"strings"
"sync"
"time"
"github.com/miekg/dns"
)
var (
dnsStringToType sync.Map
)
func dnsQtypeStringToValue(qtype string) uint16 {
x, found_qtype := dnsStringToType.Load(qtype)
if found_qtype {
return x.(uint16)
}
for k, v := range dns.TypeToString {
if v == qtype {
dnsStringToType.Store(qtype, k)
return k
}
}
log.Printf("qtype %#v is not known or found", qtype)
return dns.TypeNone
}
func dnsCustomResolve(qname string, qtype uint16) (*dns.Msg, error) {
qtype_s, qtype_known := dns.TypeToString[qtype]
if !qtype_known {
log.Printf("qtype is not known (%v) for %v", qtype, qname)
return nil, fmt.Errorf("qtype is not known: %v", qtype)
}
c := new(dns.Client)
c.Net = cfgResolverProto
c.Dialer = &net.Dialer{
Timeout: cfgResolverTimeout,
}
req := new(dns.Msg)
req.Id = dns.Id()
req.RecursionDesired = true
req.Question = make([]dns.Question, 1)
req.Question[0] = dns.Question{Name: qname, Qtype: qtype, Qclass: dns.ClassINET}
var resp *dns.Msg
var rtt time.Duration
var err error
for i := 0; i < 2; i++ {
resp, rtt, err = c.Exchange(req, cfgResolverEndpoint)
if err == nil {
break
}
}
if err != nil {
log.Printf("resolving %v/%v (rtt %v) with error: %v", qname, qtype_s, rtt, err)
return nil, err
}
log.Printf("resolved %v/%v (rtt %v)", qname, qtype_s, rtt)
return resp, nil
}
func dnsClipTtl(ttl uint32) uint32 {
if ttl < cfgTtlMin {
return cfgTtlMin
}
if ttl > cfgTtlMax {
return cfgTtlMax
}
return ttl
}
type PowerDnsAnswer struct {
Qname string `json:"qname"`
Qtype string `json:"qtype"`
Ttl uint32 `json:"ttl"`
Content string `json:"content"`
}
func dnsToPowerDnsAnswer(response *dns.Msg) ([]PowerDnsAnswer, error) {
if response == nil {
return nil, errors.New("response is nil")
}
result := make([]PowerDnsAnswer, 0, len(response.Answer))
for i := range response.Answer {
cont, ok := strings.CutPrefix(response.Answer[i].String(), response.Answer[i].Header().String())
if !ok {
continue
}
qtype, ok := dns.TypeToString[response.Answer[i].Header().Rrtype]
if !ok {
continue
}
rec := PowerDnsAnswer{
Qname: response.Answer[i].Header().Name,
Qtype: qtype,
Ttl: dnsClipTtl(response.Answer[i].Header().Ttl),
Content: cont,
}
result = append(result, rec)
}
return result, nil
}