mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
moving a bunch of packages under pkg (#124)
* moving a bunch of packages under pkg * fix gen * fix tst * oops * fix test fo real * parse mx/a
This commit is contained in:
71
cmd/convertzone/README.md
Normal file
71
cmd/convertzone/README.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# convertzone -- Converts a standard DNS zonefile into tsv, pretty, or DSL
|
||||
|
||||
## Building the software
|
||||
|
||||
Build the software and install in your personal bin:
|
||||
|
||||
```cmd
|
||||
$ cd misc/convertzone/
|
||||
$ go build
|
||||
$ cp convertzone ~/bin/.
|
||||
```
|
||||
|
||||
|
||||
## Usage Overview
|
||||
|
||||
convertzone converts an old-style DNS zone file into one of three formats:
|
||||
|
||||
convertzone [-mode=MODE] zonename [filename]
|
||||
|
||||
-mode=tsv Output the zone recoreds as tab-separated values
|
||||
-mode=pretty Output the zone pretty-printed.
|
||||
-mode=dsl Output the zone records as the DNSControl DSL language.
|
||||
|
||||
zonename The FQDN of the zone name.
|
||||
filename File to read (optional. Defaults to stdin)
|
||||
|
||||
Output is sent to stdout.
|
||||
|
||||
The zonename is required as it can not be guessed automatically from the input.
|
||||
|
||||
Example:
|
||||
|
||||
convertzone stackoverflow.com zone.stackoverflow.com >new/stackoverflow.com
|
||||
|
||||
|
||||
### -mode=tsv:
|
||||
|
||||
This is useful for `awk` and other systems that expect a very
|
||||
uniform set of input.
|
||||
|
||||
Example: Print all CNAMEs:
|
||||
|
||||
convertzone -mode=tsv foo.com <zone.foo.com | awk '$4 == "CNAME" { print $1 " -> " $5 }'
|
||||
|
||||
|
||||
### -mode=pretty:
|
||||
|
||||
This is useful for cleaning up a zonefile. It sorts the records,
|
||||
moving SOA and NS records to the top of the zone; all other records
|
||||
are alphabetically sorted; if a label has mutiple records, they are
|
||||
listed in a logical (not numeric) order, multiple A records are
|
||||
listed sorted by IP address, MX records are sorted by priority,
|
||||
etc. Use `-ttl` to set a default TTL.
|
||||
|
||||
Example: Clean up a zone file:
|
||||
|
||||
convertzone -mode=pretty foo.com <old/zone.foo.com >new/zone.foo.com
|
||||
|
||||
|
||||
### -mode=dsl:
|
||||
|
||||
This is useful for generating your draft `dnsconfig.js` configuration.
|
||||
The output can be appended to the `dnsconfig.js` file as a good first draft.
|
||||
|
||||
Example: Generate statements for a dnsconfig.js file:
|
||||
|
||||
convertzone -mode=dsl foo.com <old/zone.foo.com >first-draft.js
|
||||
|
||||
Note: The conversion is not perfect. You'll need to manually clean
|
||||
it up and insert it into `dnsconfig.js`. More instructions in the
|
||||
DNSControl [migration doc]({site.github.url}}/migration).
|
||||
156
cmd/convertzone/main.go
Normal file
156
cmd/convertzone/main.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
convertzone: Read BIND-style zonefile and output.
|
||||
|
||||
convertzone [-mode=MODE] zonename [filename]
|
||||
|
||||
-mode=tsv TAB-separated values (default)
|
||||
-mode=dsl DNSControl DSL
|
||||
-mode=pretty Sort and pretty-print records.
|
||||
|
||||
zonename The FQDN of the zone name.
|
||||
filename File to read (default: stdin)
|
||||
*/
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/providers/bind"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/miekg/dns/dnsutil"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var flagMode = flag.String("mode", "tsv", "tsv|dsl|pretty")
|
||||
var flagDefaultTTL = flag.Uint("ttl", 300, "Default TTL")
|
||||
var flagRegText = flag.String("registrar", "REG_FILL_IN", "registrar text")
|
||||
var flagProviderText = flag.String("provider", "DNS_FILL_IN", "provider text")
|
||||
|
||||
// parseargs parses the non-flag arguments.
|
||||
func parseargs(args []string) (zonename string, filename string, r io.Reader, err error) {
|
||||
// 1 args: first arg is the zonename. Read stdin.
|
||||
// 2 args: first arg is the zonename. 2nd is the filename.
|
||||
// Anything else returns an error.
|
||||
|
||||
if len(args) < 1 {
|
||||
return "", "", nil, fmt.Errorf("no command line parameters. Zone name required")
|
||||
}
|
||||
|
||||
zonename = args[0]
|
||||
|
||||
if len(args) == 1 {
|
||||
filename = "stdin"
|
||||
r = bufio.NewReader(os.Stdin)
|
||||
} else if len(args) == 2 {
|
||||
filename = flag.Arg(1)
|
||||
r, err = os.Open(filename)
|
||||
if err != nil {
|
||||
return "", "", nil, errors.Wrapf(err, "Could not open file: %s", filename)
|
||||
}
|
||||
} else {
|
||||
return "", "", nil, fmt.Errorf("too many command line parameters")
|
||||
}
|
||||
|
||||
return zonename, filename, r, nil
|
||||
}
|
||||
|
||||
// pretty outputs the zonefile using the prettyprinter.
|
||||
func pretty(zonename string, filename string, r io.Reader, defaultTTL uint32) {
|
||||
var l []dns.RR
|
||||
for x := range dns.ParseZone(r, zonename, filename) {
|
||||
if x.Error == nil {
|
||||
l = append(l, x.RR)
|
||||
}
|
||||
}
|
||||
bind.WriteZoneFile(os.Stdout, l, zonename)
|
||||
}
|
||||
|
||||
// rrFormat outputs the zonefile in either DSL or TSV format.
|
||||
func rrFormat(zonename string, filename string, r io.Reader, defaultTTL uint32, dsl bool) {
|
||||
zonenamedot := zonename + "."
|
||||
|
||||
for x := range dns.ParseZone(r, zonename, filename) {
|
||||
if x.Error != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip comments. Parse the formatted version.
|
||||
line := x.String()
|
||||
if line[0] == ';' {
|
||||
continue
|
||||
}
|
||||
items := strings.SplitN(line, "\t", 5)
|
||||
if len(items) < 5 {
|
||||
log.Fatalf("Too few items in: %v", line)
|
||||
}
|
||||
|
||||
target := items[4]
|
||||
|
||||
hdr := x.Header()
|
||||
nameFqdn := hdr.Name
|
||||
name := dnsutil.TrimDomainName(nameFqdn, zonenamedot)
|
||||
ttl := strconv.FormatUint(uint64(hdr.Ttl), 10)
|
||||
classStr := dns.ClassToString[hdr.Class]
|
||||
typeStr := dns.TypeToString[hdr.Rrtype]
|
||||
|
||||
// MX records should split out the prio vs. target.
|
||||
if hdr.Rrtype == dns.TypeMX {
|
||||
target = strings.Replace(target, " ", "\t", 1)
|
||||
}
|
||||
|
||||
if !dsl { // TSV format:
|
||||
fmt.Printf("%s\t%s\t%s\t%s\t%s\n", name, ttl, classStr, typeStr, target)
|
||||
} else { // DSL format:
|
||||
switch hdr.Rrtype {
|
||||
case dns.TypeMX:
|
||||
m := strings.SplitN(target, "\t", 2)
|
||||
target = m[0] + ", '" + m[1] + "'"
|
||||
case dns.TypeSOA:
|
||||
continue
|
||||
case dns.TypeTXT:
|
||||
// Leave target as-is.
|
||||
default:
|
||||
target = "'" + target + "'"
|
||||
}
|
||||
if hdr.Ttl == defaultTTL {
|
||||
ttl = ""
|
||||
} else {
|
||||
ttl = fmt.Sprintf(", TTL(%d)", hdr.Ttl)
|
||||
}
|
||||
fmt.Printf(",\n\t%s('%s', %s%s)", typeStr, name, target, ttl)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
zonename, filename, reader, err := parseargs(flag.Args())
|
||||
if err != nil {
|
||||
flag.Usage()
|
||||
}
|
||||
|
||||
defTTL := uint32(*flagDefaultTTL)
|
||||
|
||||
switch *flagMode {
|
||||
case "pretty":
|
||||
pretty(zonename, filename, reader, defTTL)
|
||||
case "dsl":
|
||||
fmt.Printf(`D("%s", %s, DnsProvider(%s)`, zonename, *flagRegText, *flagProviderText)
|
||||
rrFormat(zonename, filename, reader, defTTL, true)
|
||||
fmt.Println("\n)")
|
||||
case "tsv":
|
||||
rrFormat(zonename, filename, reader, defTTL, false)
|
||||
default:
|
||||
flag.Usage()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/dnsresolver"
|
||||
"github.com/StackExchange/dnscontrol/spflib"
|
||||
"github.com/StackExchange/dnscontrol/pkg/dnsresolver"
|
||||
"github.com/StackExchange/dnscontrol/pkg/spflib"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -27,9 +27,11 @@ func main() {
|
||||
fmt.Println("---------------------")
|
||||
fmt.Println()
|
||||
|
||||
res := dnsresolver.NewResolverLive("preload-dns.json")
|
||||
//res := dnsresolver.NewResolverPreloaded("preload-dns.json")
|
||||
|
||||
//res := dnsresolver.NewResolverLive("spf-store2.json")
|
||||
res, err := dnsresolver.NewResolverPreloaded("spf-store2.json")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
rec, err := spflib.Parse(strings.Join([]string{"v=spf1",
|
||||
"ip4:198.252.206.0/24",
|
||||
"ip4:192.111.0.0/24",
|
||||
@@ -50,15 +52,15 @@ func main() {
|
||||
fmt.Println("---------------------")
|
||||
fmt.Println()
|
||||
|
||||
var spfs []string
|
||||
spfs, err = spflib.Lookup("stackex.com", res)
|
||||
var spf string
|
||||
spf, err = spflib.Lookup("whatexit.org", res)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
rec, err = spflib.Parse(strings.Join(spfs, " "), res)
|
||||
rec, err = spflib.Parse(spf, res)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
spflib.DumpSPF(rec, "")
|
||||
|
||||
//res.Close()
|
||||
}
|
||||
|
||||
12
cmd/spftest/spf-store.json
Normal file
12
cmd/spftest/spf-store.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"_spf.google.com": {
|
||||
"txt": [
|
||||
"v=spf1 include:_netblocks.google.com include:_netblocks2.google.com include:_netblocks3.google.com ~all"
|
||||
]
|
||||
},
|
||||
"spf-basic.fogcreek.com": {
|
||||
"txt": [
|
||||
"v=spf1 ip4:64.34.80.172 -all"
|
||||
]
|
||||
}
|
||||
}
|
||||
69
cmd/spftest/spf-store2.json
Normal file
69
cmd/spftest/spf-store2.json
Normal file
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"_netblocks.google.com": {
|
||||
"txt": [
|
||||
"v=spf1 ip4:64.18.0.0/20 ip4:64.233.160.0/19 ip4:66.102.0.0/20 ip4:66.249.80.0/20 ip4:72.14.192.0/18 ip4:74.125.0.0/16 ip4:108.177.8.0/21 ip4:173.194.0.0/16 ip4:207.126.144.0/20 ip4:209.85.128.0/17 ip4:216.58.192.0/19 ip4:216.239.32.0/19 ~all"
|
||||
]
|
||||
},
|
||||
"_netblocks2.google.com": {
|
||||
"txt": [
|
||||
"v=spf1 ip6:2001:4860:4000::/36 ip6:2404:6800:4000::/36 ip6:2607:f8b0:4000::/36 ip6:2800:3f0:4000::/36 ip6:2a00:1450:4000::/36 ip6:2c0f:fb50:4000::/36 ~all"
|
||||
]
|
||||
},
|
||||
"_netblocks3.google.com": {
|
||||
"txt": [
|
||||
"v=spf1 ip4:172.217.0.0/19 ip4:108.177.96.0/19 ~all"
|
||||
]
|
||||
},
|
||||
"_spf.google.com": {
|
||||
"txt": [
|
||||
"v=spf1 include:_netblocks.google.com include:_netblocks2.google.com include:_netblocks3.google.com ~all"
|
||||
]
|
||||
},
|
||||
"mail.zendesk.com": {
|
||||
"txt": [
|
||||
"v=spf1 ip4:192.161.144.0/20 ip4:185.12.80.0/22 ip4:96.46.150.192/27 ip4:174.137.46.0/24 ip4:188.172.128.0/20 ip4:216.198.0.0/18 ~all"
|
||||
]
|
||||
},
|
||||
"mailgun.org": {
|
||||
"txt": [
|
||||
"google-site-verification=FIGVOKZm6lQFDBJaiC2DdwvBy8TInunoGCt-1gnL4PA",
|
||||
"v=spf1 include:spf1.mailgun.org include:spf2.mailgun.org ~all"
|
||||
]
|
||||
},
|
||||
"sendgrid.net": {
|
||||
"txt": [
|
||||
"v=spf1 ip4:167.89.0.0/17 ip4:208.117.48.0/20 ip4:50.31.32.0/19 ip4:198.37.144.0/20 ip4:198.21.0.0/21 ip4:192.254.112.0/20 ip4:168.245.0.0/17 ~all",
|
||||
"google-site-verification=NxyooVvVaIgddVa23KTlOEuVPuhffcDqJFV8RzWrAys"
|
||||
]
|
||||
},
|
||||
"servers.mcsv.net": {
|
||||
"txt": [
|
||||
"v=spf1 ip4:205.201.128.0/20 ip4:198.2.128.0/18 ip4:148.105.8.0/21 ?all"
|
||||
]
|
||||
},
|
||||
"spf-basic.fogcreek.com": {
|
||||
"txt": [
|
||||
"v=spf1 ip4:64.34.80.172 -all"
|
||||
]
|
||||
},
|
||||
"spf.mtasv.net": {
|
||||
"txt": [
|
||||
"v=spf1 ip4:50.31.156.96/27 ip4:104.245.209.192/26 ~all"
|
||||
]
|
||||
},
|
||||
"spf1.mailgun.org": {
|
||||
"txt": [
|
||||
"v=spf1 ip4:173.193.210.32/27 ip4:50.23.218.192/27 ip4:174.37.226.64/27 ip4:208.43.239.136/30 ip4:184.173.105.0/24 ip4:184.173.153.0/24 ip4:104.130.122.0/23 ip4:146.20.112.0/26 ~all"
|
||||
]
|
||||
},
|
||||
"spf2.mailgun.org": {
|
||||
"txt": [
|
||||
"v=spf1 ip4:209.61.151.0/24 ip4:166.78.68.0/22 ip4:198.61.254.0/23 ip4:192.237.158.0/23 ip4:23.253.182.0/23 ip4:104.130.96.0/28 ip4:146.20.113.0/24 ip4:146.20.191.0/24 ~all"
|
||||
]
|
||||
},
|
||||
"whatexit.org": {
|
||||
"txt": [
|
||||
"v=spf1 ip6:2607:f2f8:a9c0::3 ip4:174.136.107.195 include:servers.mcsv.net include:_spf.google.com mx:evite.com -all"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user