1
0
Fork 0
mirror of https://github.com/Luzifer/rootzone.git synced 2024-11-09 16:30:05 +00:00
rootzone/main.go
Knut Ahlers 3143b16225
Fix broken record and exit on error
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2019-05-25 17:22:20 +02:00

143 lines
3.9 KiB
Go

package main
import (
"fmt"
"os"
"sort"
"strings"
"sync"
"text/template"
log "github.com/sirupsen/logrus"
"github.com/Luzifer/go_helpers/v2/str"
"github.com/Luzifer/rconfig/v2"
)
var (
cfg = struct {
ConcurrencyLimit int `flag:"concurrency-limit" default:"50" description:"How many queries to execute in parallel"`
IANATldList string `flag:"iana-tld-list" vardefault:"iana-tld-list" description:"IANA TLD list file"`
IANAFilter []string `flag:"iana-filter" vardefault:"iana-filter" description:"IANA TLDs to igore"`
InternicRootFile string `flag:"internic-root-file" vardefault:"internic-root" description:"Internic root nameserver file"`
LogLevel string `flag:"log-level" default:"info" description:"Log level (debug, info, warn, error, fatal)"`
OpenNICFilter []string `flag:"opennic-filter" vardefault:"opennic-filter" description:"OpenNIC TLDs to ignore"`
OpenNICRoot string `flag:"opennic-root" vardefault:"opennic-root" description:"OpenNIC root server"`
VersionAndExit bool `flag:"version" default:"false" description:"Prints current version and exits"`
}{}
version = "dev"
)
const stubTpl = `# Autogenerated with rootzone {{.version}}
#{{ range $tld, $ips := .roots }}
zone "{{ $tld }}" in {
type static-stub;
server-addresses { {{ range $ips }}{{ . }}; {{ end }}};
};
#{{ end }}
# vim: set ft=named:
`
func init() {
rconfig.SetVariableDefaults(map[string]string{
"iana-filter": strings.Join([]string{"arpa."}, ","),
"iana-tld-list": "https://data.iana.org/TLD/tlds-alpha-by-domain.txt",
"internic-root": "https://www.internic.net/domain/named.root",
"opennic-filter": strings.Join([]string{".", "opennic.glue."}, ","),
"opennic-root": "75.127.96.89",
})
if err := rconfig.ParseAndValidate(&cfg); err != nil {
log.Fatalf("Unable to parse commandline options: %s", err)
}
if cfg.VersionAndExit {
fmt.Printf("rootzone %s\n", version)
os.Exit(0)
}
if l, err := log.ParseLevel(cfg.LogLevel); err != nil {
log.WithError(err).Fatal("Unable to parse log level")
} else {
log.SetLevel(l)
}
}
func main() {
var (
cLimiter = make(chan struct{}, cfg.ConcurrencyLimit)
rootServersMutex = new(sync.Mutex)
wg = new(sync.WaitGroup)
)
// Initialize nameserver list before first request
getRandomInternicRoot()
rootServers := map[string][]string{
"opennic.glue.": {cfg.OpenNICRoot},
}
// Fetch IANA TLDs
ianaTLDs, err := getIANATLDs()
if err != nil {
log.WithError(err).Fatal("Unable to retrieve IANA TLDs")
}
setRootsFromTLDs(rootServers, rootServersMutex, ianaTLDs, cfg.IANAFilter, getIANAZoneMasters, wg, cLimiter)
// Fetch OpenNIC TLDs
opennicTLDs, err := getOpenNICTLDs()
if err != nil {
log.WithError(err).Fatal("Unable to retrieve OpenNIC TLDs")
}
setRootsFromTLDs(rootServers, rootServersMutex, opennicTLDs, cfg.OpenNICFilter, getOpenNICZoneMasters, wg, cLimiter)
wg.Wait()
tpl, err := template.New("stub").Parse(stubTpl)
if err != nil {
log.WithError(err).Fatal("Unable to parse template")
}
if err := tpl.Execute(os.Stdout, map[string]interface{}{
"roots": rootServers,
"version": version,
}); err != nil {
log.WithError(err).Fatal("Unable to generate stub file")
}
}
func setRootsFromTLDs(roots map[string][]string, rootsMutex *sync.Mutex, tlds []string, filter []string, resolver func(string) ([]string, error), wg *sync.WaitGroup, cLimiter chan struct{}) {
for _, tld := range tlds {
if !strings.HasSuffix(tld, ".") {
tld = tld + "."
}
if str.StringInSlice(tld, filter) {
continue
}
wg.Add(1)
cLimiter <- struct{}{}
go func(tld string) {
defer func() {
wg.Done()
<-cLimiter
}()
masters, err := resolver(tld)
if err != nil {
log.WithError(err).WithField("zone", tld).Fatal("Unable to retrieve zone masters")
return
}
rootsMutex.Lock()
defer rootsMutex.Unlock()
sort.Strings(masters)
roots[tld] = masters
}(tld)
}
}