diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | _doc/resolver.adoc | 52 | ||||
| -rw-r--r-- | _sys/usr/share/man/man1/resolver.1.gz | bin | 2973 -> 3324 bytes | |||
| -rw-r--r-- | client.go | 48 | ||||
| -rw-r--r-- | cmd/resolver/main.go | 16 | ||||
| -rw-r--r-- | cmd/resolver/resolver.go | 110 |
6 files changed, 222 insertions, 5 deletions
@@ -4,6 +4,7 @@ /_bin/linux_amd64 /_doc/*.html /_test/etc/rescached/hosts.d/hosts +/_test/etc/rescached/zone.d/ /_test/var/cache/rescached/ /cover.html /cover.out diff --git a/_doc/resolver.adoc b/_doc/resolver.adoc index b67a0e0..0ca00fc 100644 --- a/_doc/resolver.adoc +++ b/_doc/resolver.adoc @@ -213,6 +213,30 @@ zone.d delete <name>:: Delete zone file inside the zone.d directory. +=== MANAGING RECORD IN ZONE.D + +zone.d rr add <zone> <"@" | subdomain> <ttl> <type> <class> <value> ...:: ++ +-- +Add new record into the zone file. + +The domain name can be set to origin using "@" or empty string, subdomain +(without ending with "."), or fully qualified domain name (end with "."). + +If ttl is set to 0, it will default to 604800 (7 days). + +List of valid type are A, NS, CNAME, PTR, MX, TXT, and AAAA. + +List of valid class are IN, CS, HS. + +The value parameter can be more than one, for example, the MX record +we pass two parameters: + + <pref> <exchange> + +See the example below for more information. +-- + == EXIT STATUS Upon exit and success +resolver+ will return 0, or 1 otherwise. @@ -336,6 +360,34 @@ Delete record "my.hosts" from hosts file "hosts", "TTL": 604800 } + +=== MANAGING RECORD IN ZONE.D + +Assume that we have create zone "my.zone". + +Add IPv4 address "127.0.0.1" for domain my.zone, + + $ resolver zone.d rr add my.zone @ 0 A IN 127.0.0.1 + { + "Value": "127.0.0.1", + "Name": "my.zone", + "Type": 1, + "Class": 1, + "TTL": 604800 + } + +Add subdomain "www" with IPv4 address "192.168.1.2" to zone "my.zone", + + $ resolver zone.d rr add my.zone www 0 A IN 192.168.1.2 + { + "Value": "192.168.1.2", + "Name": "www.my.zone", + "Type": 1, + "Class": 1, + "TTL": 604800 + } + + == AUTHOR This software is developed by M. Shulhan (ms@kilabit.info). diff --git a/_sys/usr/share/man/man1/resolver.1.gz b/_sys/usr/share/man/man1/resolver.1.gz Binary files differindex 90dbf93..68e19f8 100644 --- a/_sys/usr/share/man/man1/resolver.1.gz +++ b/_sys/usr/share/man/man1/resolver.1.gz @@ -4,6 +4,7 @@ package rescached import ( + "encoding/base64" "encoding/json" "fmt" "net/http" @@ -473,3 +474,50 @@ func (cl *Client) ZonedDelete(name string) (zone *dns.Zone, err error) { } return zone, nil } + +// ZonedRecordAdd add new record to zone file. +func (cl *Client) ZonedRecordAdd(zone string, rreq dns.ResourceRecord) (rres *dns.ResourceRecord, err error) { + var ( + logp = "ZonedRecordAdd" + zrr = zoneRecordRequest{ + Zone: zone, + } + + res *libhttp.EndpointResponse + rawb []byte + ok bool + ) + + fmt.Printf("ZonedRecordAdd: %+v\n", rreq) + + zrr.Type, ok = dns.RecordTypeNames[rreq.Type] + if !ok { + return nil, fmt.Errorf("%s: unknown record type: %d", logp, rreq.Type) + } + + rawb, err = json.Marshal(rreq) + if err != nil { + return nil, fmt.Errorf("%s: %w", logp, err) + } + + zrr.Record = base64.StdEncoding.EncodeToString(rawb) + + _, rawb, err = cl.PostJSON(apiZonedRR, nil, zrr) + if err != nil { + return nil, fmt.Errorf("%s: %w", logp, err) + } + + rres = &dns.ResourceRecord{} + res = &libhttp.EndpointResponse{ + Data: rres, + } + err = json.Unmarshal(rawb, res) + if err != nil { + return nil, fmt.Errorf("%s: %w", logp, err) + } + if res.Code != http.StatusOK { + return nil, fmt.Errorf("%s: %d %s", logp, res.Code, res.Message) + } + + return rres, nil +} diff --git a/cmd/resolver/main.go b/cmd/resolver/main.go index 62af801..556cff1 100644 --- a/cmd/resolver/main.go +++ b/cmd/resolver/main.go @@ -148,7 +148,7 @@ query <domain / ip-address> [type] [class] Valid type are either A, NS, CNAME, SOA, MB, MG, MR, NULL, WKS, PTR, HINFO, MINFO, MX, TXT, AAAA, or SRV. - Default value is A." + Default value is A. Valid class are either IN, CS, HS. Default value is IN. @@ -246,6 +246,20 @@ zone.d delete <name> Delete zone file inside the zone.d directory. +=== MANAGING RECORD IN ZONE.D + +zone.d rr add <zone> <domain> <ttl> <type> <class> <value> ... + + Add new record into the zone file. + If domain ttl is set to 0, it will default to 604800 (7 days). + List of valid type are A, NS, CNAME, PTR, MX, TXT, and AAAA. + The value parameter can be more than one, for example, the MX record + we pass two parameters: + + <pref> <exchange> + + See the example below for more information. + == Examples === QUERY diff --git a/cmd/resolver/resolver.go b/cmd/resolver/resolver.go index 75287db..36175a1 100644 --- a/cmd/resolver/resolver.go +++ b/cmd/resolver/resolver.go @@ -10,6 +10,7 @@ import ( "log" "math/rand" "os" + "strconv" "strings" "time" @@ -475,9 +476,9 @@ func (rsol *resolver) doCmdZoned(args []string) { var ( subCmd = strings.ToLower(args[0]) + resc = rsol.newRescachedClient() - resc *rescached.Client - err error + err error ) switch subCmd { @@ -487,7 +488,6 @@ func (rsol *resolver) doCmdZoned(args []string) { log.Fatalf("resolver: %s %s: missing parameter name", rsol.cmd, subCmd) } - resc = rsol.newRescachedClient() _, err = resc.ZonedCreate(args[0]) if err != nil { log.Fatalf("resolver: %s", err) @@ -500,18 +500,120 @@ func (rsol *resolver) doCmdZoned(args []string) { log.Fatalf("resolver: %s %s: missing parameter name", rsol.cmd, subCmd) } - resc = rsol.newRescachedClient() _, err = resc.ZonedDelete(args[0]) if err != nil { log.Fatalf("resolver: %s", err) } fmt.Println("OK") + case subCmdRR: + rsol.doCmdZonedRR(resc, args[1:]) + default: log.Fatalf("resolver: %s: unknown sub command: %s", rsol.cmd, subCmd) } } +func (rsol *resolver) doCmdZonedRR(resc *rescached.Client, args []string) { + var ( + cmdAction = strings.ToLower(args[0]) + ) + + args = args[1:] + + switch cmdAction { + case subCmdAdd: + rsol.doCmdZonedRRAdd(resc, args) + + default: + log.Fatalf("resolver: %s %s: unknown action: %q", rsol.cmd, subCmdRR, cmdAction) + } +} + +// doCmdZonedRRAdd add new record to the zone. +// This command accept the following arguments: +// +// 0 1 2 3 4 5 +// <zone> <domain> <ttl> <type> <class> <value> ... +// +// List of valid type are A, NS, CNAME, PTR, MX, TXT, and AAAA. +// For the MX record we pass two parameters: +// +// 5 6 +// <pref> <exchange> +func (rsol *resolver) doCmdZonedRRAdd(resc *rescached.Client, args []string) { + if len(args) < 6 { + log.Fatalf("resolver: %s %s %s: missing arguments", rsol.cmd, subCmdRR, subCmdAdd) + } + + var ( + zone = strings.ToLower(args[0]) + rreq = dns.ResourceRecord{} + + rres *dns.ResourceRecord + vstr string + vuint uint64 + vbytes []byte + err error + ok bool + ) + + rreq.Name = strings.ToLower(args[1]) + if rreq.Name == "@" { + rreq.Name = "" + } + + vuint, err = strconv.ParseUint(args[2], 10, 64) + if err != nil { + log.Fatalf("resolver: invalid TTL: %q", args[2]) + } + + rreq.TTL = uint32(vuint) + + vstr = strings.ToUpper(args[3]) + rreq.Type, ok = dns.RecordTypes[vstr] + if !ok { + log.Fatalf("resolver: invalid record type: %q", vstr) + } + + vstr = strings.ToUpper(args[4]) + rreq.Class, ok = dns.RecordClasses[vstr] + if !ok { + log.Fatalf("resolver: invalid record class: %q", vstr) + } + + vstr = args[5] + + if rreq.Type == dns.RecordTypeMX { + if len(args) < 6 { + log.Fatalf("resolver: missing argument for MX record") + } + vuint, err = strconv.ParseUint(vstr, 10, 64) + if err != nil { + log.Fatalf("resolver: invalid MX preference: %q", vstr) + } + var rrMX = &dns.RDataMX{ + Preference: int16(vuint), + Exchange: args[6], + } + rreq.Value = rrMX + } else { + rreq.Value = args[5] + } + + rres, err = resc.ZonedRecordAdd(zone, rreq) + if err != nil { + log.Fatalf("resolver: %s", err) + } + + vbytes, err = json.MarshalIndent(rres, "", " ") + if err != nil { + log.Fatalf("resolver: %s", err) + } + + fmt.Println(string(vbytes)) +} + // initSystemResolver read the system resolv.conf to create fallback DNS // resolver. func (rsol *resolver) initSystemResolver() (err error) { |
