Coder Social home page Coder Social logo

libdns's Introduction

libdns - Universal DNS provider APIs for Go

โš ๏ธ Work-in-progress. Exported APIs are subject to change.

libdns is a collection of free-range DNS provider client implementations written in Go! With libdns packages, your Go program can manage DNS records across any supported providers. A "provider" is a service or program that manages a DNS zone.

This repository defines the core interfaces that provider packages should implement. They are small and idiomatic Go interfaces with well-defined semantics.

The interfaces include:

See full godoc for detailed documentation.

Example

To work with DNS records managed by Cloudflare, for example, we can use libdns/cloudflare:

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

ctx := context.TODO()

zone := "example.com."

// configure the DNS provider (choose any from github.com/libdns)
provider := cloudflare.Provider{APIToken: "topsecret"}

// list records
recs, err := provider.GetRecords(ctx, zone)

// create records (AppendRecords is similar)
newRecs, err := provider.SetRecords(ctx, zone, []libdns.Record{
	{
		Type:  "A",
		Name:  "sub",
		Value: "1.2.3.4",
	},
})

// delete records (this example uses provider-assigned ID)
deletedRecs, err := provider.DeleteRecords(ctx, zone, []libdns.Record{
	{
		ID: "foobar",
	},
})

// no matter which provider you use, the code stays the same!
// (some providers have caveats; see their package documentation)

Implementing new provider packages

Provider packages are 100% written and maintained by the community! Collectively, we all maintain the packages for providers we individually use.

Instructions for adding new libdns packages are on this repo's wiki. Please feel free to contribute yours!

Similar projects

OctoDNS is a suite of tools written in Python for managing DNS. However, its approach is a bit heavy-handed when all you need are small, incremental changes to a zone:

WARNING: OctoDNS assumes ownership of any domain you point it to. When you tell it to act it will do whatever is necessary to try and match up states including deleting any unexpected records. Be careful when playing around with OctoDNS.

This is incredibly useful when you are maintaining your own zone file, but risky when you just need incremental changes.

StackExchange/dnscontrol is written in Go, but is similar to OctoDNS in that it tends to obliterate your entire zone and replace it with your input. Again, this is very useful if you are maintaining your own master list of records, but doesn't do well for simply adding or removing records.

go-acme/lego has support for a huge number of DNS providers (75+!), but their APIs are only capable of setting and deleting TXT records for ACME challenges.

libdns takes inspiration from the above projects but aims for a more generally-useful set of APIs that homogenize pretty well across providers. In contrast to the above projects, libdns can add, set, delete, and get arbitrary records from a zone without obliterating it (although syncing up an entire zone is also possible!). Its APIs also include context so long-running calls can be cancelled early, for example to accommodate on-line config changes downstream. libdns interfaces are also smaller and more composable. Additionally, libdns can grow to support a nearly infinite number of DNS providers without added bloat, because each provider implementation is a separate Go module, which keeps your builds lean and fast.

In summary, the goal is that libdns providers can do what the above libraries/tools can do, but with more flexibility: they can create and delete TXT records for ACME challenges, they can replace entire zones, but they can also do incremental changes or simply read records.

Record abstraction

How records are represented across providers varies widely, and each kind of record has different fields and semantics. In time, our goal is for the libdns.Record type to be able to represent most of them as concisely and simply as possible, with the interface methods able to deliver on most of the possible zone operations.

Realistically, libdns should enable most common record manipulations, but may not be able to fit absolutely 100% of all possibilities with DNS in a provider-agnostic way. That is probably OK; and given the wide varieties in DNS record types and provider APIs, it would be unreasonable to expect otherwise. We are not aiming for 100% fulfillment of 100% of users' requirements; more like 100% fulfillment of ~90% of users' requirements.

libdns's People

Contributors

balki avatar mholt avatar xinayder avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libdns's Issues

Handling records with multiple answers

How should provider implementations handle records with multiple answers? In particular, how should rec1 be mapped to libdns.Records?

rec1.multiexample.com.   3600 IN A 1.1.1.1
rec1.multiexample.com.   3600 IN A 2.2.2.2
rec1.multiexample.com.   3600 IN A 3.3.3.3

I can envision a couple of solutions, but I'm wondering: What do (or should) consumers of the libdns API expect? I wasn't 100% clear from reading the docs.

Permission to libdns/nicrudns

Hi!
Some time ago I have contributed (#68) nic.ru DNS API, you have created repo https://github.com/libdns/nicrudns , but I ahve not permission for publish:

$ git push origin master
ERROR: Permission to libdns/nicrudns.git denied to maetx777.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

Can u help me? What I am doing wrong?

Loopia provider

I am in the process of implementing a provider for loopia.se

pdns provider

I have initial support for a powerdns (pdns) libdns provider. PR incoming.

Provider template

It would be nice to have a template for new providers with some basic tests.
This would reduce the effort required to implementing a new provider.

The template could also include a provider.go some basic example, a README and a LICENCE.

Netcup Provider

Hi,
it seems as if there is no netcup provider implementation yet, so I'm starting one :)

Validation of inputs?

Hi ๐Ÿ‘‹

I've recently built a CoreDNS library for libdns over at libdns-coredns.

For some background, CoreDNS has a backend plugin called etcd that is capable of serving records and entire zones out of an etcd kv cluster. Turns out this is pretty generally useful (and actually CoreDNS is widely used).

So I built the library for it, and then built a Terraform Provider for it too over at terraform-provider-coredns.

My question is actually two-fold:

  • What validations should we as libdns implementers be adding implementations that conform to the libdns interface?

I don't see any examples of any validation happening in other implementations or any guidance on this. I feel like there should be some because right now it's entirely possible to create rubbish records.

  • Feedback! I'd love for some feedback from anyone on what I've built above so far.

Thanks!

Explanation of 'zone' arguments and 'Name' in Record

I'm trying to understand better how libdns is supposed to work by using an example.

  • What is supposed to be contained in the zone string in the methods? Can this be any of example.com, subdomain.example.com and foo.subdomain.example.com?
  • What is the Name field in a Record? Is it supposed to have the fqdn or just the sub part for this zone (guessing that would make the most sense)

In practice: my provider (TransIP) only gives me the ability to change the zones for a domain in the form of example.com, so I will always need to know the "domainname" of any zone. But if libdns supplies subdomain.example.com as zone argument and wants to change the record with the name 'foo' I'll have to implement some subdomain mangling.

Unit tests for providers (and template)

I've skimmed across your implementation doc and especially your template repo, and I wonder whether some simple unit tests (included in the template) would not be a good idea?
Maybe also directly include a GitHub Action to run these tests in a CI.

As such, IMHO; this would make developing a new provider even easier by having a verification whether everything works (somewhat, at least) and support proper development practices.
This could make it easier to test the providers.

google domains

wondering if a plugin for google domains and its DNS is needed ?

Clarify libdns API regarding DNS records names being absolute or relative

Hi,

It is unclear whether the DNS record names (libdns.Record.Name):

  1. use the standard "dot-suffix" relative/absolute notation (eg if zone FQDN is example.org. then subdomain.example.org. -> subdomain.example.org ; subdomain -> subdomain.example.org)
  2. always use absolute paths implicitly (subdomain.example.org -> subdomain.example.org)

I think 1) is better as it directly reflects what a DNS server actually returns, but it seems that currently the API contract is implicitly 2).

Examples:

  • the gandi provider has to manually trim the .example.org part to get a relative notation to pass that to Gandi (notice how it expects to receive subdomain.example.org without an ending dot suffix) which uses the standard dot-suffix notation
  • the dnspod provider behaves the same (but is buggier because it replaces all instances of the zone in the domain name which is incorrect)
  • the cloudflare provider passes the value as-is to the API, but the API docs clearly show that the API uses absolue paths implicitly (see example.org, should be example.org. if using the dot-suffix notation, but here's it's just example.org)
  • the digitalocean provider does not work becauses libdns passes implicitly absolute paths without a dot suffix and the provider passes it as is to the API which expects the dot-suffix notation (1))

I suggest to choose which syntax/semantics we want to use for DNS record names, document it clearly and update the various libdns providers as necessary. I think using the standard absolute/relative notation depending on a final dot is better as it better correponds to what a DNS server returns.

Joohoi's ACME-DNS provider

ACME-DNS is a simplified DNS server that only allows setting TXT values. Only up to two records exist at a time, the older ones get deleted automatically. It is meant to be used for solving ACME DNS challenges. More information:

Any implementation of this provider will be extremely limited. However, Caddy and certmagic only uses RecordAppender and RecordDeleter interfaces for obtaining certificates (and it's okay if RecordDeleted returns an error), so it would still be useful.

RFC2136 provider

Hello, I'm implementing rfc2136 provider and I have a question regarding how TXT records should be handled in libdns.
By DNS specification TXT record can have multiple values, which in zone file are separated by spaces and quoted if they contain spaces themselves. How does this correlates with Record's Value field?

Implementing AcmeProxy provider which doesn't support getting or updating records

I'm planning on using libdns for acmeproxy, which "proxies" TXT record Present/Cleanup requests at a central location to prevent spreading API credentials all over my network. I'm positive this will work fine using libdns internally to append/delete/set those records.

The other side of this to provide an Acmeproxy implementation of libdns for tools that use libdns for ACME validation, e.g. Caddy. How can I best implement this as GetRecords is not implemented in acmeproxy (just Present and Cleanup) and AppendRecords is equal to SetRecords. Would it be okay just to implement it with GetRecords returning nil?

Any chance of adding additional interfaces?

I'm fiddling around with building a "frontend" for libdns (think rclone for DNS). It would be useful (maybe necessary) for the tool to be able to list all available zones for a given provider account. Is something like this within the scope of the project? If not, any suggestions for where to look next?

CoreDNS/Redis provider

Hello,

CoreDNS has a feature to query a Redis instance for zone information. It seems support for managing the data in Redis is useful in libdns. You can see what the CoreDNS plugin expects here: https://coredns.io/explugins/redis/

I will start work on this sometime next week.

Sincerely,
Bertold

GoDaddy Provider

GoDaddy module for Caddy

This package contains a DNS provider module for Caddy. It can be used to manage DNS records with GoDaddy accounts.

Caddy module name

dns.providers.godaddy

Config examples

To use this module for the ACME DNS challenge, configure the ACME issuer in your Caddy JSON like so:

{
	"module": "acme",
	"challenges": {
		"dns": {
			"provider": {
				"name": "goddady",
				"api_token": "YOUR_Godaddy_API_TOKEN" // key:secret
			}
		}
	}
}

or with the Caddyfile:

tls {
	dns godaddy {env.GODADDY_TOKEN}
}

You can replace {env.GODADDY_TOKEN} with the actual auth token if you prefer to put it directly in your config instead of an environment variable.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.