From fb4926df1e6d4f99fbe22ab77e7af8be2db10464 Mon Sep 17 00:00:00 2001 From: Matt Burchett Date: Mon, 26 Nov 2018 22:56:21 -0600 Subject: [PATCH] Initial commit --- cmd/main.go | 30 ++++++++++++++++ config.json | 5 +++ pkg/config/config.go | 43 +++++++++++++++++++++++ pkg/model/model.go | 13 +++++++ pkg/resolver/resolver.go | 74 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 165 insertions(+) create mode 100644 cmd/main.go create mode 100644 config.json create mode 100644 pkg/config/config.go create mode 100644 pkg/model/model.go create mode 100644 pkg/resolver/resolver.go diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..1320e3b --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,30 @@ +package main + +import ( + "flag" + "log" + + "git.linuxrocker.com/mattburchett/go_tab-magic/pkg/config" + "git.linuxrocker.com/mattburchett/go_tab-magic/pkg/resolver" +) + +func main() { + var c string + var debug bool + + flag.StringVar(&c, "config", "", "Configuration to load") + flag.BoolVar(&debug, "debug", false, "Enables Debugging Mode") + flag.Parse() + + // Stop the app if they're missing required flags. + if c == "" { + log.Fatal("You need to specify a configuration file.") + } + + cfg, err := config.GetConfig(c, debug) + if err != nil { + log.Fatal(err) + } + + resolver.PerformZoneTransfer(cfg) +} diff --git a/config.json b/config.json new file mode 100644 index 0000000..98a04ce --- /dev/null +++ b/config.json @@ -0,0 +1,5 @@ +{ + "resolver": "172.19.0.5", + "resolverPort": 53, + "domains": [ "kc.linuxrocker.com"] +} \ No newline at end of file diff --git a/pkg/config/config.go b/pkg/config/config.go new file mode 100644 index 0000000..2b35286 --- /dev/null +++ b/pkg/config/config.go @@ -0,0 +1,43 @@ +package config + +import ( + "encoding/json" + "fmt" + "log" + "os" +) + +// Config - This struct will hold configuration components. +type Config struct { + Resolver string `json:"resolver"` + ResolverPort int `json:"resolverPort"` + Domains []string `json:"domains"` +} + +//GetConfig gets the configuration values for the api using the file in the supplied configPath. +func GetConfig(configPath string, debug bool) (Config, error) { + if _, err := os.Stat(configPath); os.IsNotExist(err) { + return Config{}, fmt.Errorf("could not find the config file at path %s", configPath) + } + if debug { + log.Println("Loading Configuration File: " + configPath) + } + return loadConfigFromFile(configPath) +} + +//if the config loaded from the file errors, no defaults will be loaded and the app will exit. +func loadConfigFromFile(configPath string) (conf Config, err error) { + file, err := os.Open(configPath) + if err != nil { + log.Printf("Error opening config file: %v", err) + } else { + defer file.Close() + + err = json.NewDecoder(file).Decode(&conf) + if err != nil { + log.Printf("Error decoding config file: %v", err) + } + } + + return conf, err +} diff --git a/pkg/model/model.go b/pkg/model/model.go new file mode 100644 index 0000000..2a886fa --- /dev/null +++ b/pkg/model/model.go @@ -0,0 +1,13 @@ +package model + +type Results struct { + IP string `json:"ip"` + Hostname string `json:"hostname"` + TXT string `json:"TXT,omitempty"` +} + +type UniqResults struct { + IP string `json:"ip"` + Hostname string `json:"hostname"` + TXT string `json:"TXT,omitempty"` +} diff --git a/pkg/resolver/resolver.go b/pkg/resolver/resolver.go new file mode 100644 index 0000000..c3cf426 --- /dev/null +++ b/pkg/resolver/resolver.go @@ -0,0 +1,74 @@ +package resolver + +import ( + "errors" + "fmt" + "log" + "strings" + + "git.linuxrocker.com/mattburchett/go_tab-magic/pkg/config" + "github.com/miekg/dns" +) + +// LookupName returns IPv4 address from A record or error. +func lookupName(fqdn, serverAddr string) (string, error) { + m := &dns.Msg{} + m.SetQuestion(dns.Fqdn(fqdn), dns.TypeA) + in, err := dns.Exchange(m, serverAddr) + if err != nil { + return "", err + } + if len(in.Answer) < 1 { + return "", errors.New("no Answer") + } + if a, ok := in.Answer[0].(*dns.A); ok { + ip := a.A.String() + return ip, nil + } + return "", errors.New("no A record returned") +} + +func PerformZoneTransfer(config config.Config) { + data := make([]string, 0) + + // Do the transfer + for _, i := range config.Domains { + server := fmt.Sprintf("%s:%d", config.Resolver, config.ResolverPort) + tr := dns.Transfer{} + m := &dns.Msg{} + m.SetAxfr(dns.Fqdn(i)) + in, err := tr.In(m, server) + if err != nil { + log.Fatal(err) + } + for ex := range in { + for _, a := range ex.RR { + var ip, hostname, txt string + switch v := a.(type) { + case *dns.TXT: + txt = string(v.Txt[0]) + hostname = v.Hdr.Name + cip, err := lookupName(strings.TrimRight(v.Hdr.Name, "."), server) + if err != nil || cip == "" { + continue + } + ip = cip + case *dns.A: + ip = v.A.String() + hostname = v.Hdr.Name + case *dns.CNAME: + cip, err := lookupName(v.Target, server) + if err != nil || cip == "" { + continue + } + ip = cip + hostname = v.Hdr.Name + default: + continue + } + data = append(data, fmt.Sprintf("%v %v %v", hostname, ip, txt)) + } + } + } + fmt.Println(data) +}