Files
dns-go/main.go

154 lines
3.6 KiB
Go
Raw Normal View History

2021-10-28 23:11:51 +02:00
package main
import (
"flag"
"github.com/miekg/dns"
"log"
"net"
"os"
2021-10-29 00:58:40 +02:00
"strconv"
2021-10-28 23:11:51 +02:00
"strings"
"time"
)
var (
2021-12-14 11:34:33 +01:00
listen_addr = flag.String("addr", "0.0.0.0:8053", "ip:port")
2021-10-29 01:59:30 +02:00
zone_file = flag.String("zone", "zone.db", "zone file")
2021-10-28 23:11:51 +02:00
)
2021-10-28 23:23:37 +02:00
var zone = map[string]map[uint16][]dns.RR{}
2021-10-28 23:11:51 +02:00
func serve_dns(w dns.ResponseWriter, r *dns.Msg) {
msg := dns.Msg{}
msg.SetReply(r)
msg.Authoritative = true
domain := msg.Question[0].Name
println(" -> ", msg.Question[0].String(), domain)
if _, zok := zone[domain]; zok { // serve zone file
if rr_resp, rok := zone[domain][msg.Question[0].Qtype]; rok {
2021-10-28 23:23:37 +02:00
msg.Answer = rr_resp
2021-10-28 23:11:51 +02:00
w.WriteMsg(&msg)
return
}
}
start := strings.SplitN(domain, ".", 2)[0]
if start == "reload-zone" { // reload hook
msg.Answer = []dns.RR{&dns.TXT{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 60},
Txt: []string{"reloaded"},
}}
reload_zone()
w.WriteMsg(&msg)
return
}
if start == "time" { // return local time
switch r.Question[0].Qtype {
case dns.TypeA:
msg.Answer = []dns.RR{&dns.A{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 60},
A: time_ip(),
}}
case dns.TypeTXT:
msg.Answer = []dns.RR{&dns.TXT{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 60},
Txt: []string{time.Now().Format("15h04")},
}}
}
w.WriteMsg(&msg)
return
}
switch r.Question[0].Qtype {
case dns.TypeA:
2021-10-29 00:58:40 +02:00
// sub.domains.192.168.1.1.xip.sub.domain.tld returns 192.168.1.1
parts := strings.Split(domain, ".")
xindex := -1
for i := 0; i < len(parts); i++ {
if parts[i] == "nip" {
xindex = i
}
}
if xindex-4 >= 0 {
ip0, er0 := strconv.ParseInt(parts[xindex-1], 10, 16)
ip1, er1 := strconv.ParseInt(parts[xindex-2], 10, 16)
ip2, er2 := strconv.ParseInt(parts[xindex-3], 10, 16)
ip3, er3 := strconv.ParseInt(parts[xindex-4], 10, 16)
if er0 != nil || er1 != nil || er2 != nil || er3 != nil {
msg.SetRcode(r, dns.RcodeServerFailure)
}
ip := net.IPv4(byte(ip3), byte(ip2), byte(ip1), byte(ip0))
msg.Answer = append(msg.Answer, &dns.A{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 60},
A: ip,
})
} else {
msg.SetRcode(r, dns.RcodeServerFailure)
}
2021-10-28 23:23:37 +02:00
2021-10-28 23:11:51 +02:00
case dns.TypeTXT:
msg.Answer = append(msg.Answer, &dns.TXT{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 60},
Txt: []string{"hey texte dynamique: " + domain, "lol"},
})
}
w.WriteMsg(&msg)
}
func time_ip() net.IP {
now := time.Now()
return net.IPv4(byte(now.Hour()), byte(now.Minute()), byte(now.Second()), 0)
}
func parsezone() {
2021-10-29 01:59:30 +02:00
f, ferr := os.Open(*zone_file)
2021-10-28 23:11:51 +02:00
if ferr != nil {
2021-12-14 11:34:33 +01:00
println("failed to open file", ferr)
return
2021-10-29 00:58:40 +02:00
} else {
defer f.Close()
2021-10-28 23:11:51 +02:00
}
zp := dns.NewZoneParser(f, ".", "zone.db")
2021-12-14 11:34:33 +01:00
//zp := dns.NewZoneParser(f, ".", *zone_file)
2021-10-28 23:11:51 +02:00
ok := true
var rr dns.RR
for ok {
rr, ok = zp.Next()
if ok {
hdr := rr.Header()
2021-10-28 23:23:37 +02:00
if _, ok := zone[hdr.Name]; ok {
zone[hdr.Name][hdr.Rrtype] = append(zone[hdr.Name][hdr.Rrtype], rr)
2021-10-28 23:11:51 +02:00
} else {
2021-10-28 23:23:37 +02:00
zone[hdr.Name] = map[uint16][]dns.RR{}
zone[hdr.Name][hdr.Rrtype] = []dns.RR{rr}
2021-10-28 23:11:51 +02:00
}
println(rr.String())
}
}
if er := zp.Err(); er != nil {
println(er.Error())
}
}
func reload_zone() {
2021-10-29 00:58:40 +02:00
defer func() { recover() }()
2021-10-28 23:23:37 +02:00
zone = map[string]map[uint16][]dns.RR{}
2021-10-28 23:11:51 +02:00
parsezone()
}
func main() {
flag.Parse()
parsezone()
dns.HandleFunc(".", serve_dns)
srv := &dns.Server{Addr: *listen_addr, Net: "udp"}
if err := srv.ListenAndServe(); err != nil {
log.Fatalf("Failed to set udp listener %s\n", err.Error())
}
}