1
0
mirror of https://github.com/mje-nz/zerotier-dns.git synced 2024-05-11 05:55:15 +00:00

Add roundrobin record via mtaches (#4)

This commit is contained in:
Artem Iarmoliuk
2018-12-27 20:43:47 +02:00
committed by Ihor Borodin
parent 861793b69f
commit 80bd0116b9
7 changed files with 90 additions and 10 deletions

View File

@ -17,3 +17,5 @@ Dockerfile
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
.DS_Store

2
.gitignore vendored
View File

@ -15,3 +15,5 @@
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
.DS_Store

View File

@ -19,3 +19,11 @@ URL = "https://my.zerotier.com/api"
# Domain does not have to match the configured network name
[Networks]
# Match section contains zero or more match pairs to create Round robin dns
# Format is: "regexp to match hosts" = "hostname"
# Example 1:
# "k8s-node-\w" = "k8s-nodes"
# From nodes with names k8s-node-23refw, k8s-node-09sf8g
# will create round robin record k8s-nodes
[RoundRobin]

View File

@ -51,6 +51,13 @@ URL = "https://my.zerotier.com/api"
# Domain does not have to match the configured network name
[Networks]
# Match section contains zero or more match pairs to create Round robin dns
# Format is: "regexp to match hosts" = "hostname"
# Example 1:
# "k8s-node-\w" = "k8s-nodes"
# From nodes with names k8s-node-23refw, k8s-node-09sf8g
# will create round robin record k8s-nodes
[RoundRobin]
`)
}

View File

@ -43,17 +43,20 @@ func init() {
// initConfig reads in config file and ENV variables if set.
func initConfig() {
viper.SetConfigName(".ztdns") // name of config file (without extension)
viper.AddConfigPath(".") // adding current directory as first search path
viper.AddConfigPath("$HOME") // adding home directory as second search path
if cfgFile != "" { // enable ability to specify config file via flag
viper.SetConfigFile(cfgFile)
} else {
viper.SetConfigName(".ztdns") // name of config file (without extension)
viper.AddConfigPath(".") // adding current directory as first search path
viper.AddConfigPath("$HOME") // adding home directory as second search path
}
viper.SetEnvPrefix("ztdns")
viper.AutomaticEnv() // read in environment variables that match
// If a config file is found, read it in.
viper.ReadInConfig()
if err := viper.ReadInConfig(); err != nil {
fmt.Println("Can't read config:", err)
os.Exit(1)
}
}

View File

@ -6,6 +6,7 @@ package cmd
import (
"fmt"
"net"
"regexp"
"time"
log "github.com/sirupsen/logrus"
@ -78,6 +79,14 @@ func updateDNS() time.Time {
URL := viper.GetString("ZT.URL")
suffix := viper.GetString("suffix")
rrDNSPatterns := make(map[string]*regexp.Regexp)
rrDNSRecords := make(map[string][]dnssrv.Records)
for re, host := range viper.GetStringMapString("RoundRobin") {
rrDNSPatterns[host] = regexp.MustCompile(re)
log.Debugf("Creating match '%s' for %s host", re, host)
}
// Get all configured networks:
for domain, id := range viper.GetStringMapString("Networks") {
// Get ZeroTier Network info
@ -115,16 +124,51 @@ func updateDNS() time.Time {
for _, a := range n.Config.IPAssignments {
ip4 = append(ip4, net.ParseIP(a))
}
// Add the record to the database
log.Infof("Updating %-15s IPv4: %-15s IPv6: %s", record, ip4, ip6)
dnssrv.DNSDatabase[record] = dnssrv.Records{
dnsRecord := dnssrv.Records{
A: ip4,
AAAA: ip6,
}
// Add the record to the database
log.Infof("Updating %-15s IPv4: %-15s IPv6: %s", record, ip4, ip6)
dnssrv.DNSDatabase[record] = dnsRecord
// Finding matches for RoundRobin dns
for host, re := range rrDNSPatterns {
log.Debugf("Checking matches for %s host", host)
if match := re.FindStringSubmatch(n.Name); match != nil {
// prefix := fmt.Sprintf(host, iface(match[1:]))
rrRecord := host + "." + domain + "." + suffix + "."
log.Infof("Adding ips to RR record %-15s IPv4: %-15s IPv6: %s, from host %s", rrRecord, ip4, ip6, n.Name)
rrDNSRecords[rrRecord] = append(rrDNSRecords[rrRecord], dnsRecord)
}
}
}
}
for rrRecord, dnsRecords := range rrDNSRecords {
rrRecordIps := dnssrv.Records{}
for _, ips := range dnsRecords {
rrRecordIps.A = append(rrRecordIps.A, ips.A...)
rrRecordIps.AAAA = append(rrRecordIps.AAAA, ips.AAAA...)
}
log.Infof("Updating %-15s IPv4: %-15s IPv6: %s", rrRecord, rrRecordIps.A, rrRecordIps.AAAA)
dnssrv.DNSDatabase[rrRecord] = rrRecordIps
}
}
// Return the current update time
return time.Now()
}
// Convert slice of string to interface for fmt
func iface(list []string) []interface{} {
vals := make([]interface{}, len(list))
for i, v := range list {
vals[i] = v
}
return vals
}

View File

@ -6,6 +6,7 @@ package dnssrv
import (
"fmt"
"math/rand"
"net"
"time"
@ -112,14 +113,14 @@ func parseQuery(m *dns.Msg) {
if rec, ok := DNSDatabase[q.Name]; ok {
switch q.Qtype {
case dns.TypeA:
for _, ip := range rec.A {
for _, ip := range shuffle(rec.A) {
rr, err := dns.NewRR(fmt.Sprintf("%s A %s", q.Name, ip.String()))
if err == nil {
m.Answer = append(m.Answer, rr)
}
}
case dns.TypeAAAA:
for _, ip := range rec.AAAA {
for _, ip := range shuffle(rec.AAAA) {
rr, err := dns.NewRR(fmt.Sprintf("%s AAAA %s", q.Name, ip.String()))
if err == nil {
m.Answer = append(m.Answer, rr)
@ -129,3 +130,16 @@ func parseQuery(m *dns.Msg) {
}
}
}
// shuffle ip addresses for Round Robin dns
func shuffle(ips []net.IP) []net.IP {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
ret := make([]net.IP, len(ips))
perm := r.Perm(len(ips))
for i, randIndex := range perm {
ret[i] = ips[randIndex]
}
return ret
}