Skip to content

Repository files navigation

Njalla for libdns

Go Reference

Manage Njalla DNS records through the libdns interfaces. Implements RecordGetter, RecordAppender, RecordSetter, RecordDeleter, and ZoneLister.

Install

go get github.com/libdns/njalla

Authentication

Create a token under Settings → API:

provider := njalla.Provider{APIToken: "your-njalla-api-token"}

Grant the token the methods you call:

libdns method Njalla API methods
GetRecords list-records
AppendRecords add-record
SetRecords list-records, add-record, edit-record, remove-record
DeleteRecords remove-record
ListZones list-domains

Njalla's token editor offers an ACME option for the DNS-01 challenge. It grants the four record methods, scoped to TXT records under _acme-challenge. That scope also narrows list-records to the same prefix, so GetRecords returns nothing outside it. DeleteRecords never lists, so challenge cleanup keeps working.

Usage

package main

import (
	"context"
	"fmt"
	"net/netip"
	"time"

	"github.com/libdns/libdns"
	"github.com/libdns/njalla"
)

func main() {
	provider := njalla.Provider{APIToken: "your-njalla-api-token"}
	ctx := context.Background()
	zone := "example.com."

	added, err := provider.AppendRecords(ctx, zone, []libdns.Record{
		libdns.Address{
			Name: "test",
			IP:   netip.MustParseAddr("192.0.2.1"),
			TTL:  time.Hour,
		},
	})
	if err != nil {
		fmt.Printf("adding record: %v\n", err)
		return
	}

	records, err := provider.GetRecords(ctx, zone)
	if err != nil {
		fmt.Printf("getting records: %v\n", err)
		return
	}
	fmt.Printf("%d records in %s\n", len(records), zone)

	if _, err := provider.DeleteRecords(ctx, zone, added); err != nil {
		fmt.Printf("deleting records: %v\n", err)
	}
}

Record types

A, AAAA, CAA, CNAME, MX, NS, TXT, and HTTPS map to their libdns types. Anything else, including Njalla's Redirect and Dynamic pseudo-types, arrives as libdns.RR. You can pass any type as input.

Limitations

Njalla refuses these records. The provider checks each one before sending the request, so the error names the cause.

Record Constraint
SRV Zone apex only
SVCB Unsupported
MX Preference 0
TXT Empty values, and values containing "

SRV. Njalla validates the last two labels of the name, so it takes _sip._tcp and rejects the RFC 2782 form _sip._tcp.voice. Reordering to voice._sip._tcp passes validation and publishes an invalid SRV location, so the provider sends the name unchanged.

SVCB. libdns names a SVCB record _scheme.name, and Njalla rejects underscore labels for this type. HTTPS carries no such prefix and works.

Behaviour

Trailing dots. Njalla stores hostname values as you send them and matches them byte for byte, so the provider passes them through untouched in both directions. Deleting a record tries both spellings.

TXT encoding. Values round trip as sent, including spaces, semicolons, non-ASCII text, and lengths past 255 bytes. The provider adds no escaping or chunking.

TTL. A TTL of 0 leaves the field unset, and Njalla applies 10800 seconds. Pass a sub-second duration to ask for 0, as libdns.RR describes.

Underscore names. Njalla refuses them for A, AAAA, and MX. TXT, CNAME, and SRV accept them.

Atomicity. Njalla has no batch endpoint, so AppendRecords, SetRecords, and DeleteRecords apply one change at a time. When one returns an error, it also returns the records it already changed.

DNSSEC. GetRecords omits DNSSEC records, and SetRecords does not handle them.

Testing

Unit tests need no credentials:

go test ./...

libdnstest/ is a separate module running the shared libdns conformance suite against a real zone. It creates and deletes records, so point it at a zone you can afford to modify.

cd libdnstest
NJALLA_API_TOKEN=your-token NJALLA_TEST_ZONE=example.com. go test -v ./...

The suite skips SRV and SVCB for the reasons under Limitations.

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

2 watching

Forks

Releases

Used by

Contributors

Languages