From 5c5e938742843e13d46f3908078fd5c0612e8f7c Mon Sep 17 00:00:00 2001 From: George Date: Sun, 17 May 2020 10:05:06 -0400 Subject: [PATCH] Simplify config and refactoring --- README.md | 10 +--- cmd/meshnamed/main.go | 49 +++++++++++----- src/meshname/server.go | 130 +++++++++++++++++++---------------------- 3 files changed, 98 insertions(+), 91 deletions(-) diff --git a/README.md b/README.md index 33d389a..9ed5723 100644 --- a/README.md +++ b/README.md @@ -39,18 +39,14 @@ Look for `meshnamed.service` in the source directory for a systemd unit file. In this example, meshnamed is configured as authoritative for two domain zones: { - "Domain":"aiag7sesed2aaxgcgbnevruwpy", - "Records": [ + "aiag7sesed2aaxgcgbnevruwpy": [ "aiag7sesed2aaxgcgbnevruwpy.meshname. AAAA 200:6fc8:9220:f400:5cc2:305a:4ac6:967e", "_xmpp-client._tcp.aiag7sesed2aaxgcgbnevruwpy.meshname. SRV 5 0 5222 xmpp.aiag7sesed2aaxgcgbnevruwpy.meshname", "_xmpp-server._tcp.aiag7sesed2aaxgcgbnevruwpy.meshname. SRV 5 0 5269 xmpp.aiag7sesed2aaxgcgbnevruwpy.meshname", "xmpp.aiag7sesed2aaxgcgbnevruwpy.meshname. AAAA 300:6fc8:9220:f400::1", "forum.aiag7sesed2aaxgcgbnevruwpy.meshname. CNAME amag7sesed2aaaaaaaaaaaaaau.meshname." - ] - } - { - "Domain":"amag7sesed2aaaaaaaaaaaaaau", - "Records":[ + ], + "amag7sesed2aaaaaaaaaaaaaau": [ "amag7sesed2aaaaaaaaaaaaaau.meshname. AAAA 300:6fc8:9220:f400::5" ] } diff --git a/cmd/meshnamed/main.go b/cmd/meshnamed/main.go index fd14671..b937c5e 100644 --- a/cmd/meshnamed/main.go +++ b/cmd/meshnamed/main.go @@ -3,9 +3,10 @@ package main import ( "flag" "fmt" + "net" "os" - "strings" "os/signal" + "strings" "syscall" "github.com/gologme/log" @@ -13,6 +14,20 @@ import ( "github.com/zhoreeq/meshname/src/meshname" ) +func parseNetworks(networksconf string) (map[string]*net.IPNet, error) { + networks := make(map[string]*net.IPNet) + for _, item := range strings.Split(networksconf, ",") { + if tokens := strings.SplitN(item, "=", 2); len(tokens) == 2 { + if _, validSubnet, err := net.ParseCIDR(tokens[1]); err == nil { + networks[tokens[0]] = validSubnet + } else { + return nil, err + } + } + } + return networks, nil +} + func main() { genconf := flag.String("genconf", "", "generate a new config for IP address") subdomain := flag.String("subdomain", "meshname.", "subdomain used to generate config") @@ -33,24 +48,28 @@ func main() { } if *genconf != "" { - confString, err := meshname.GenConf(*genconf, *subdomain) - if err != nil { - logger.Errorln(err) + if conf, err := meshname.GenConf(*genconf, *subdomain); err == nil { + fmt.Println(conf) } else { - fmt.Println(confString) + logger.Errorln(err) } return } - networks := make(map[string]string) - for _, item := range strings.Split(*networksconf, ",") { - if tokens := strings.SplitN(item, "=", 2); len(tokens) == 2 { - networks[tokens[0]] = tokens[1] - } - } s := new(meshname.MeshnameServer) - s.Init(logger, *listenAddr, *useconffile, networks) + s.Init(logger, *listenAddr) + + if networks, err := parseNetworks(*networksconf); err == nil { + s.SetNetworks(networks) + } else { + logger.Errorln(err) + } + + if *useconffile != "" { + s.LoadConfig(*useconffile) + } + s.Start() c := make(chan os.Signal, 1) @@ -63,7 +82,11 @@ func main() { case _ = <-c: return case _ = <-r: - s.UpdateConfig() + if *useconffile != "" { + s.Stop() + s.LoadConfig(*useconffile) + s.Start() + } } } } diff --git a/src/meshname/server.go b/src/meshname/server.go index 037ef48..4d257d3 100644 --- a/src/meshname/server.go +++ b/src/meshname/server.go @@ -5,9 +5,8 @@ import ( "encoding/json" "errors" "fmt" - "io" + "io/ioutil" "net" - "os" "strings" "github.com/gologme/log" @@ -43,79 +42,58 @@ func GenConf(target, zone string) (string, error) { } subDomain := DomainFromIP(&ip) selfRecord := fmt.Sprintf("\t\t\"%s.%s AAAA %s\"\n", subDomain, zone, target) - confString := fmt.Sprintf("{\n\t\"Domain\":\"%s\",\n\t\"Records\":[\n%s\t]\n}", subDomain, selfRecord) + confString := fmt.Sprintf("{\n\t\"%s\":[\n%s\t]\n}", subDomain, selfRecord) return confString, nil } -type MeshnameServer struct { - log *log.Logger - listenAddr, zoneConfigPath string - zoneConfig map[string][]dns.RR - dnsClient *dns.Client - dnsServer *dns.Server - networks map[string]*net.IPNet +// Load zoneConfig from a JSON file +func ParseConfigFile(configPath string) (map[string][]dns.RR, error) { + conf, err := ioutil.ReadFile(configPath) + if err != nil { + return nil, err + } + var dat map[string][]string + if err := json.Unmarshal(conf, &dat); err == nil { + return ParseZoneConfigMap(dat) + } else { + return nil, err + } } -func (s *MeshnameServer) Init(log *log.Logger, listenAddr string, zoneConfigPath string, networks map[string]string) { +func ParseZoneConfigMap(zoneConfigMap map[string][]string) (map[string][]dns.RR, error) { + var zoneConfig = make(map[string][]dns.RR) + for subDomain, records := range zoneConfigMap { + for _, r := range records { + if rr, err := dns.NewRR(r); err == nil { + zoneConfig[subDomain] = append(zoneConfig[subDomain], rr) + } else { + return nil, err + } + } + } + return zoneConfig, nil +} + +type MeshnameServer struct { + log *log.Logger + listenAddr string + zoneConfig map[string][]dns.RR + dnsClient *dns.Client + dnsServer *dns.Server + networks map[string]*net.IPNet +} + +func (s *MeshnameServer) Init(log *log.Logger, listenAddr string) { s.log = log s.listenAddr = listenAddr - s.networks = make(map[string]*net.IPNet) - for domain, subnet := range networks { - _, validSubnet, err := net.ParseCIDR(subnet) - if err != nil { - s.log.Errorln(err) - continue - } - s.networks[domain] = validSubnet - } - s.zoneConfigPath = zoneConfigPath s.zoneConfig = make(map[string][]dns.RR) + s.networks = make(map[string]*net.IPNet) + if s.dnsClient == nil { s.dnsClient = new(dns.Client) s.dnsClient.Timeout = 5000000000 // increased 5 seconds timeout } - s.LoadConfig() -} - -func (s *MeshnameServer) LoadConfig() { - if s.zoneConfigPath == "" { - return - } - for k := range s.zoneConfig { - delete(s.zoneConfig, k) - } - - reader, err := os.Open(s.zoneConfigPath) - if err != nil { - s.log.Errorln("Can't open config:", err) - return - } - - type Zone struct { - Domain string - Records []string - } - - dec := json.NewDecoder(reader) - for { - var m Zone - if err := dec.Decode(&m); err == io.EOF { - break - } else if err != nil { - s.log.Errorln("Syntax error in config:", err) - return - } - for _, v := range m.Records { - rr, err := dns.NewRR(v) - if err != nil { - s.log.Errorln("Invalid DNS record:", v) - continue - } - s.zoneConfig[m.Domain] = append(s.zoneConfig[m.Domain], rr) - } - } - s.log.Infoln("Meshname config loaded:", s.zoneConfigPath) } func (s *MeshnameServer) Stop() error { @@ -127,15 +105,31 @@ func (s *MeshnameServer) Stop() error { func (s *MeshnameServer) Start() error { s.dnsServer = &dns.Server{Addr: s.listenAddr, Net: "udp"} - for domain := range s.networks { - dns.HandleFunc(domain, s.handleRequest) - s.log.Debugln("Handling:", domain) + for tld, subnet := range s.networks { + dns.HandleFunc(tld, s.handleRequest) + s.log.Debugln("Handling:", tld, subnet) } go s.dnsServer.ListenAndServe() s.log.Infoln("Started meshnamed on:", s.listenAddr) return nil } +func (s *MeshnameServer) LoadConfig(confPath string) { + if zoneConf, err := ParseConfigFile(confPath); err == nil { + s.zoneConfig = zoneConf + } else { + s.log.Errorln("Can't parse config file:", err) + } +} + +func (s *MeshnameServer) SetZoneConfig(zoneConfig map[string][]dns.RR) { + s.zoneConfig = zoneConfig +} + +func (s *MeshnameServer) SetNetworks(networks map[string]*net.IPNet) { + s.networks = networks +} + func (s *MeshnameServer) handleRequest(w dns.ResponseWriter, r *dns.Msg) { var remoteLookups = make(map[string][]dns.Question) m := new(dns.Msg) @@ -192,9 +186,3 @@ func (s *MeshnameServer) isRemoteLookupAllowed(addr net.Addr) bool { return strings.HasPrefix(ra, "[::1]:") || strings.HasPrefix(ra, "127.0.0.1:") } -func (s *MeshnameServer) UpdateConfig() error { - s.Stop() - s.LoadConfig() - s.Start() - return nil -}