Files
gertdns/dns/dns.go
2021-10-18 03:03:05 +02:00

128 lines
2.8 KiB
Go

package dns
import (
"errors"
"fmt"
"log"
"strconv"
"sync"
"github.com/MarekWojt/gertdns/config"
"github.com/miekg/dns"
)
type domain struct {
Root string
Mutv4 sync.RWMutex
Mutv6 sync.RWMutex
Ipv4 map[string]string
Ipv6 map[string]string
}
var domains = []*domain{}
func parseQuery(m *dns.Msg, currentDomain *domain) {
for _, q := range m.Question {
switch q.Qtype {
case dns.TypeA:
log.Printf("Query for A record of %s\n", q.Name)
currentDomain.Mutv4.RLock()
ip := currentDomain.Ipv4[q.Name]
currentDomain.Mutv4.RUnlock()
if ip != "" {
rr, err := dns.NewRR(fmt.Sprintf("%s A %s", q.Name, ip))
if err == nil {
m.Answer = append(m.Answer, rr)
}
}
case dns.TypeAAAA:
log.Printf("Query for AAAA record of %s\n", q.Name)
currentDomain.Mutv6.RLock()
ip := currentDomain.Ipv6[q.Name]
currentDomain.Mutv6.RUnlock()
if ip != "" {
rr, err := dns.NewRR(fmt.Sprintf("%s AAAA %s", q.Name, ip))
if err == nil {
m.Answer = append(m.Answer, rr)
}
}
}
}
}
func handleDnsRequest(currentDomain *domain) func(w dns.ResponseWriter, r *dns.Msg) {
return func(w dns.ResponseWriter, r *dns.Msg) {
m := new(dns.Msg)
m.SetReply(r)
m.Compress = false
switch r.Opcode {
case dns.OpcodeQuery:
parseQuery(m, currentDomain)
}
w.WriteMsg(m)
}
}
func Init() {
for _, currentDomain := range config.Config.DNS.Domains {
log.Printf("Added domain root: %s\n", currentDomain)
domains = append(domains, &domain{
Root: currentDomain,
Ipv4: make(map[string]string),
Ipv6: make(map[string]string),
})
}
}
func Run() (*dns.Server, error) {
// attach request handler func
for _, currentDomain := range domains {
dns.HandleFunc(currentDomain.Root, handleDnsRequest(currentDomain))
}
// start server
server := &dns.Server{Addr: ":" + strconv.Itoa(int(config.Config.DNS.Port)), Net: "udp"}
log.Printf("Starting DNS at %d\n", config.Config.DNS.Port)
err := server.ListenAndServe()
if err != nil {
server.Shutdown()
return server, err
}
return server, nil
}
func UpdateIpv6(domain string, ipv6 string) error {
for _, currentDomain := range domains {
if dns.IsSubDomain(currentDomain.Root, domain) {
log.Printf("Updating domain %s AAAA %s\n", domain, ipv6)
currentDomain.Mutv6.Lock()
currentDomain.Ipv6[domain] = ipv6
currentDomain.Mutv6.Unlock()
return nil
}
}
return errors.New("no root found")
}
func UpdateIpv4(domain string, ipv4 string) (err error) {
for _, currentDomain := range domains {
if dns.IsSubDomain(currentDomain.Root, domain) {
log.Printf("Updating domain %s A %s\n", domain, ipv4)
currentDomain.Mutv4.Lock()
currentDomain.Ipv4[domain] = ipv4
currentDomain.Mutv4.Unlock()
return nil
}
}
return errors.New("no root found")
}
func Get() []*domain {
return domains
}