Add CONTEXT.md, consumer README skeleton, and package Examples.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+25
@@ -0,0 +1,25 @@
|
|||||||
|
# go-dns
|
||||||
|
|
||||||
|
Shared Go Library for authoritative DNS against BIND-compatible nameservers: full zone transfer (AXFR) and RFC 2136 dynamic UPDATE with caller-supplied TSIG. ExApps and Services import `gitea.neitzel.de/konrad/go-dns`.
|
||||||
|
|
||||||
|
## Language
|
||||||
|
|
||||||
|
**Session**:
|
||||||
|
A `Client` bound to one nameserver address, one zone name, and one TSIG key. AXFR and UPDATE both use that Session; there is no anonymous or unsigned mode in this Library.
|
||||||
|
_Avoid_: resolver client, stub, recursive lookup API
|
||||||
|
|
||||||
|
**Zone / RRSet / Record**:
|
||||||
|
A Zone is the in-memory result of an AXFR (origin, SOA serial, flat record list). An RRSet groups Records that share owner, class, and type. A Record is one resource record with presentation-format rdata.
|
||||||
|
_Avoid_: zone file on disk as the Library's primary type, miekg/dns RR as the public model
|
||||||
|
|
||||||
|
**UPDATE**:
|
||||||
|
An RFC 2136 dynamic DNS change batch (add and/or delete Records) sent through the Session. The Library builds and signs the message; the nameserver applies it.
|
||||||
|
_Avoid_: nsupdate script files, unsigned updates
|
||||||
|
|
||||||
|
**AXFR**:
|
||||||
|
A full zone transfer over TCP for the Session's zone, returning a Zone. Incremental transfer (IXFR) is out of scope.
|
||||||
|
_Avoid_: AXFR over UDP, treating AXFR as a recursive query
|
||||||
|
|
||||||
|
**TSIG key**:
|
||||||
|
Caller-supplied key name, algorithm (e.g. hmac-sha256), and base64 secret used to authenticate AXFR and UPDATE. The Library does not generate keys or write BIND configuration.
|
||||||
|
_Avoid_: API token, shared AppAPI secret, auto-provisioned keys
|
||||||
@@ -1,24 +1,61 @@
|
|||||||
# go-dns
|
# go-dns
|
||||||
|
|
||||||
Go library for authoritative DNS operations against BIND (and compatible) nameservers:
|
Shared Go library for authoritative DNS against BIND-compatible nameservers: full zone transfer (AXFR) and RFC 2136 dynamic UPDATE, authenticated with caller-supplied TSIG.
|
||||||
|
|
||||||
- **Dynamic updates** — `nsupdate`-style changes (RFC 2136)
|
Import: `gitea.neitzel.de/konrad/go-dns` (package `godns`).
|
||||||
- **Zone transfer** — full zone read via **AXFR** (IXFR out of scope for v1)
|
|
||||||
- **TSIG key authentication** (callers provide keys; generation out of scope)
|
|
||||||
|
|
||||||
## Status
|
|
||||||
|
|
||||||
Library: AXFR over TCP, RFC 2136 UPDATE (UDP with TCP fallback), caller-supplied TSIG, typed RR builders. ASCII names only.
|
|
||||||
|
|
||||||
## Module
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go get gitea.neitzel.de/konrad/go-dns
|
go get gitea.neitzel.de/konrad/go-dns
|
||||||
```
|
```
|
||||||
|
|
||||||
Module path: `gitea.neitzel.de/konrad/go-dns` — import as **`godns`**.
|
## Scope
|
||||||
|
|
||||||
## Documentation
|
**Included**
|
||||||
|
|
||||||
|
- **Session (`Client`)** — one nameserver + zone + TSIG key
|
||||||
|
- **AXFR** — full zone read over TCP
|
||||||
|
- **RFC 2136 UPDATE** — typed add/delete changes (UDP with TCP fallback)
|
||||||
|
- **TSIG** — caller-supplied key name, algorithm, and base64 secret
|
||||||
|
- **Typed RR builders** — A, AAAA, MX, TXT, CNAME, NS, SRV, PTR (ASCII names)
|
||||||
|
- **Zone / RRSet / Record** — in-memory zone model from AXFR
|
||||||
|
|
||||||
|
**Excluded**
|
||||||
|
|
||||||
|
- IXFR / incremental transfer
|
||||||
|
- TSIG key generation or BIND config writing (see docs for operator notes)
|
||||||
|
- DNSSEC signing / validation as a product feature
|
||||||
|
- Non-ASCII / IDN domain names (v1)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
key := godns.TSIG{
|
||||||
|
Name: "exapp-key.",
|
||||||
|
Algorithm: "hmac-sha256",
|
||||||
|
Secret: "base64-secret-from-bind",
|
||||||
|
}
|
||||||
|
client, err := godns.NewClient("ns.example:53", "example.com.", key)
|
||||||
|
|
||||||
|
// AXFR
|
||||||
|
tr, err := client.AXFR(ctx)
|
||||||
|
|
||||||
|
// UPDATE
|
||||||
|
rec, err := godns.A("www.example.com.", 300, net.ParseIP("192.0.2.10"))
|
||||||
|
_, err = client.Update(ctx, godns.Add(rec))
|
||||||
|
```
|
||||||
|
|
||||||
|
Runnable package examples (construction only, no live nameserver): `go test -run Example`.
|
||||||
|
|
||||||
|
## Domain language
|
||||||
|
|
||||||
|
See [CONTEXT.md](./CONTEXT.md) for Session, Zone / RRSet / Record, UPDATE, AXFR, and TSIG key terminology.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
Unit tests cover message construction and record builders. Optional BIND integration tests live behind build tags / env (see `bind_integration_test.go`).
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- **CheckDNS** — ExApp that consumes this library
|
||||||
- [Project specification](docs/project-specification.md)
|
- [Project specification](docs/project-specification.md)
|
||||||
- [BIND TSIG configuration](docs/bind-tsig-configuration.md)
|
- [BIND TSIG configuration](docs/bind-tsig-configuration.md)
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package godns_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
godns "gitea.neitzel.de/konrad/go-dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleNewClient() {
|
||||||
|
key := godns.TSIG{
|
||||||
|
Name: "exapp-key.",
|
||||||
|
Algorithm: "hmac-sha256",
|
||||||
|
Secret: "dGVzdA==", // base64; construction only — no network call
|
||||||
|
}
|
||||||
|
client, err := godns.NewClient("127.0.0.1:53", "example.com.", key)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_ = client
|
||||||
|
fmt.Println("ok")
|
||||||
|
// Output: ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleAdd() {
|
||||||
|
rec, err := godns.A("www.example.com.", 300, net.ParseIP("192.0.2.10"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
change := godns.Add(rec)
|
||||||
|
fmt.Println(change.Action == godns.ActionAdd, change.Record.Type, change.Record.RData)
|
||||||
|
// Output: true A 192.0.2.10
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleDelete() {
|
||||||
|
rec, err := godns.TXT("note.example.com.", 60, "retire")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
change := godns.Delete(rec)
|
||||||
|
fmt.Println(change.Action == godns.ActionDelete, change.Record.Type)
|
||||||
|
// Output: true TXT
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user