aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--_doc/resolver.adoc52
-rw-r--r--_sys/usr/share/man/man1/resolver.1.gzbin2973 -> 3324 bytes
-rw-r--r--client.go48
-rw-r--r--cmd/resolver/main.go16
-rw-r--r--cmd/resolver/resolver.go110
6 files changed, 222 insertions, 5 deletions
diff --git a/.gitignore b/.gitignore
index 2e5d9f4..0fa8a44 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
index 90dbf93..68e19f8 100644
--- a/_sys/usr/share/man/man1/resolver.1.gz
+++ b/_sys/usr/share/man/man1/resolver.1.gz
Binary files differ
diff --git a/client.go b/client.go
index bfec2fa..2833768 100644
--- a/client.go
+++ b/client.go
@@ -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) {