6.9 KiB
go-dns guide
How to use the library. Symbol signatures and doc comments are in API. Words for the domain are in CONTEXT.md. Operators who configure BIND follow BIND TSIG configuration.
Session
Purpose
A session is a Client bound to one nameserver address, one zone name, and one TSIG key. AXFR and UPDATE both use that session. There is no unsigned mode.
When to use it
Create one client per nameserver, zone, and key. A second key, even for the same zone, is a second client.
Call sequence
- Fill a
TSIGwith the key name, algorithm, and base64 secret. - Call
NewClientwith the server, the zone, and that key. - Call
AXFRorUpdateon the returned client.
server is a host or host:port. A missing port becomes 53. An IPv6 host must be written in brackets, such as [2001:db8::1]:53.
Errors
NewClient returns an error when the server, zone, or any TSIG field is empty, when the zone or the key name is not ASCII, or when the server is a bare IPv6 address. It does not contact the nameserver.
Example
key := godns.TSIG{
Name: "exapp-key.",
Algorithm: "hmac-sha256",
Secret: "base64-secret-from-bind",
}
client, err := godns.NewClient("ns.example:53", "example.com.", key)
if err != nil {
return err
}
_ = client
AXFR
Purpose
AXFR reads the full zone over TCP and returns it as a Zone plus the SOA serial.
When to use it
Use AXFR when the caller needs the nameserver's current records for the session's zone. Incremental transfer (IXFR) is not available.
Call sequence
- Start a session.
- Call
Client.AXFRwith a context. - Read
TransferResult.ZoneandTransferResult.Serial.Serialis the same value stored on the zone.
The request is signed with the session TSIG key. The closing SOA of the transfer is not appended a second time.
Errors
AXFR returns an error when the context is done, the transfer fails, a record owner is not ASCII, or the stream contains no SOA. Transport errors are wrapped with the server address.
Example
tr, err := client.AXFR(ctx)
if err != nil {
return err
}
zone := tr.Zone
_ = zone.Serial
UPDATE
Purpose
UPDATE sends one RFC 2136 batch that adds records, deletes records, or does both. The nameserver applies the batch.
When to use it
Use UPDATE to change the session's zone. Each change is one record, built with Add or Delete.
Call sequence
- Build records with the typed builders.
- Wrap each record in
AddorDelete. - Call
Client.Updatewith a context and the changes. - On success,
UpdateResult.RcodeisNOERROR.
The client tries UDP first. It retries on TCP when the UDP exchange fails or the response is truncated. An empty change list returns success and does not contact the nameserver. Delete removes one record that matches owner, type, and rdata. It does not delete a whole RRset by type alone.
Errors
Update returns an error when the context is done, a record cannot be encoded, the exchange fails, or the nameserver rcode is not NOERROR. An Action other than ActionAdd or ActionDelete is rejected before the exchange. A refused or badly signed update comes back as an rcode error such as REFUSED or BADSIG.
Example
rec, err := godns.A("www.example.com.", 300, net.ParseIP("192.0.2.10"))
if err != nil {
return err
}
result, err := client.Update(ctx, godns.Add(rec))
if err != nil {
return err
}
_ = result.Rcode
TSIG
Purpose
TSIG is the caller-supplied key that signs AXFR and UPDATE. The library checks the fields and sends them. It does not generate keys or write BIND configuration.
When to use it
Fill a TSIG before NewClient. The same value is used for every call on that client.
Call sequence
- Take the key name, algorithm, and base64 secret from the operator's BIND key.
- Store them on
TSIG. - Pass the value to
NewClient.
Algorithms the client maps to known TSIG names are hmac-md5, hmac-sha1, hmac-sha224, hmac-sha256, hmac-sha384, and hmac-sha512. Any other non-empty algorithm is sent as a trailing-dot name. Prefer hmac-sha256 for new keys. How to create the key on BIND is in BIND TSIG configuration.
Errors
A missing name, algorithm, or secret fails in NewClient, as does a non-ASCII key name. A wrong secret does not fail at construction. The nameserver reports it on AXFR or UPDATE, usually as BADSIG.
Example
key := godns.TSIG{
Name: "go-dns-key.",
Algorithm: "hmac-sha256",
Secret: os.Getenv("TSIG_SECRET"),
}
client, err := godns.NewClient("192.0.2.53", "example.com", key)
Typed RR builders
Purpose
The builders turn an owner, a TTL, and typed fields into one Record of class IN. The owner is stored as a trailing-dot FQDN. RData is presentation-format rdata.
When to use it
Use a builder when the caller has an address, a target name, or text and wants a record for UPDATE or for an in-memory zone. The builders are A, AAAA, MX, TXT, CNAME, NS, SRV, PTR, and CAA.
Call sequence
- Call the builder for the record type.
- Pass the
RecordtoAddorDelete, or store it on aZone.
A takes an IPv4 net.IP. AAAA takes an IPv6 net.IP. Name targets (MX, CNAME, NS, SRV, PTR) are ASCII domain names. CAA takes a flag, a tag, and a value (RFC 8659).
Errors
A builder returns an error when the owner is empty or not ASCII. A returns an error when the address is not IPv4. AAAA returns an error when the address is missing or is IPv4. Builders that take a target name return an error when that name is empty or not ASCII.
Example
a, err := godns.A("www.example.com.", 300, net.ParseIP("192.0.2.10"))
if err != nil {
return err
}
mx, err := godns.MX("example.com.", 300, 10, "mail.example.com.")
if err != nil {
return err
}
_, err = client.Update(ctx, godns.Add(a), godns.Add(mx))
Zone, RRSet, and Record
Purpose
Record is one resource record: owner, class, type, TTL, and presentation-format rdata. Zone is an origin, an SOA serial, and a flat record list. RRSet groups records that share owner, class, and type.
When to use it
AXFR returns a Zone. Call Zone.RRSets when the caller wants records grouped. A caller can also assemble a Zone from builder output and group it the same way. Grouping does not contact the nameserver.
Call sequence
- Take
TransferResult.Zonefrom AXFR, or fillZone.Origin,Zone.Serial, andZone.Records. - Call
RRSetsto get groups in first-seen order. - Read each group's
Owner,Class,Type, andRecords.
Errors
RRSets does not return an error. It copies the records already on the zone. Bad names are reported earlier, by AXFR or by a builder.
Example
tr, err := client.AXFR(ctx)
if err != nil {
return err
}
for _, set := range tr.Zone.RRSets() {
fmt.Println(set.Owner, set.Type, len(set.Records))
}