libdns / libdns/cloudflare

SetRecords only sets the last record provided

Open Beginner friendly
#31 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Go
Stars
80
Forks
31
PR merge metrics
No merged PRs in 30d

Description

The SetRecords function only sets the last element provided even though it takes a []libdns.Record.

I've attached a quick and dirty demonstration

example code
package main

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

	"github.com/libdns/cloudflare"
	"github.com/libdns/libdns"
)

func main() {
	var apiKey = ""
	var domain = ""
	var subdomain = "cf-set-example"

	p := &cloudflare.Provider{
		APIToken: apiKey,
	}

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	s6 := [][16]byte{{15: 1}, {15: 2}, {15: 3}}
	addrs := MakeAddr(s6)
	recs := MakeAddrRecords(addrs, subdomain)

	fmt.Printf("Input data: %q\n", GetRecordData(recs))

	result, err := p.SetRecords(ctx, domain, recs)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("SetRecords returned result: %q\n", GetRecordData(result))

	actual, err := p.GetRecords(ctx, domain)
	if err != nil {
		log.Fatal(err)
	}
	filtered := Filter(actual, subdomain, "AAAA")

	fmt.Printf("Actual result: %q\n", GetRecordData(filtered))
}

func MakeAddr(slices [][16]byte) []netip.Addr {
	var addrs = make([]netip.Addr, 0, len(slices))
	for _, slice := range slices {
		addrs = append(addrs, netip.AddrFrom16(slice))
	}
	return addrs
}

func MakeAddrRecords(addrs []netip.Addr, name string) []libdns.Record {
	recs := make([]libdns.Record, 0, len(addrs))
	for _, addr := range addrs {
		recs = append(recs, libdns.Address{
			Name: name,
			IP:   addr,
			TTL:  5 * time.Minute,
		})
	}

	return recs
}

func Filter(recs []libdns.Record, recName string, recType string) []libdns.Record {
	filteredRecs := make([]libdns.Record, 0, len(recs))
	for _, rec := range recs {
		if rec.RR().Name == recName &&
			rec.RR().Type == recType {
			filteredRecs = append(filteredRecs, rec)
		}
	}

	return filteredRecs
}

func GetRecordData(recs []libdns.Record) []string {
	data := make([]string, 0, len(recs))
	for _, rec := range recs {
		data = append(data, rec.RR().Data)
	}

	return data
}
output
Input data: ["::1" "::2" "::3"]
SetRecords returned result: ["::1" "::2" "::3"]
Actual result: ["::3"]

The input data and return from SetRecords both have three records but when retrieved with GetRecords only the last element is present. I have manually checked this is the case as well.

https://github.com/libdns/cloudflare/blob/57f633acd7561b44660889b0428d608e52e850f9/provider.go#L164
Checking the source, changing matchContent to true here solves this issue, but maybe it causes other issues.

output matchContent
Input data: ["::1" "::2" "::3"]
SetRecords returned result: ["::1" "::2" "::3"]
Actual result: ["::3" "::2" "::1"]

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in provider.go around line 164, where SetRecords passes matchContent to the Cloudflare record operation. Reproduce the issue with the example's three AAAA records and verify that retrieval returns all records rather than only the last one. Check that the change does not alter the returned SetRecords result or other record behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
cloud
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.