Documentation
¶
Overview ¶
Package forwardddns is the DNS provider layer of forwarding entry high availability (docs/architecture/forward-sdk.md section 7.4, L2): Control keeps a route's entry name on the healthy entry nodes' addresses by writing A and AAAA records through a DNS provider's API. The providers are those of H21: Cloudflare (API token), Alibaba Cloud DNS (AccessKey, signature V3 ACS3-HMAC-SHA256), DNSPod (Tencent Cloud API 3.0, TC3-HMAC-SHA256), Huawei Cloud DNS (AK/SK, SDK-HMAC-SHA256) and a generic webhook (an HMAC-SHA256-signed JSON POST).
Every client is the standard library's HTTP client with hand-written request signing; no vendor SDK is linked. A Provider sets a whole record set (one name and type): it adds the new values before it deletes the old ones, so the name never resolves to nothing while it changes. Credentials never appear in an error, a log line or a metric label.
Index ¶
- Constants
- Variables
- func CheckSet(set RecordSet, allowEmpty bool) error
- func InZone(name, zone string) bool
- func Kinds() []string
- func NormalizeName(name string) string
- func ValidName(name string) bool
- func WebhookSignature(secret string, timestamp int64, body []byte) string
- type APIError
- type FieldError
- type Options
- type Provider
- type RecordSet
- type Spec
- type WebhookPayload
Constants ¶
const ( KindCloudflare = "cloudflare" KindAliDNS = "alidns" KindDNSPod = "dnspod" KindHuaweiCloud = "huaweicloud" KindWebhook = "webhook" )
Provider kinds (H21).
const ( TypeA = "A" TypeAAAA = "AAAA" TypeCNAME = "CNAME" )
Record types.
const ( ConfigEndpoint = "endpoint" ConfigURL = "url" )
ConfigEndpoint overrides a provider API's host; ConfigURL is a webhook's URL.
const ( CredentialAPIToken = "api_token" CredentialAccessKeyID = "access_key_id" CredentialAccessKeySecret = "access_key_secret" // #nosec G101 -- a credential's field name, not a credential. CredentialSecretID = "secret_id" CredentialSecretKey = "secret_key" CredentialAccessKey = "access_key" CredentialSecret = "secret" )
Credential names.
const ( CodeRequired = "required" CodeInvalidFormat = "invalid_format" CodeUnknownField = "unknown_field" )
Field error codes.
const ( WebhookEvent = "forward.dns" WebhookHeaderEvent = "X-AnixOps-Event" WebhookHeaderTimestamp = "X-AnixOps-Timestamp" WebhookHeaderSignature = "X-AnixOps-Signature" )
The generic webhook: Control POSTs each change as JSON to the operator's HTTPS URL, signed with the shared secret.
POST <url>
Content-Type: application/json
X-AnixOps-Event: forward.dns
X-AnixOps-Timestamp: <Unix seconds>
X-AnixOps-Signature: sha256=<hex HMAC-SHA256(secret, timestamp + "." + body)>
{"version":1,"action":"set","zone":"example.com","name":"hk.example.com",
"type":"A","values":["192.0.2.10"],"ttl":60,"timestamp":1759579200}
action "delete" carries no values. Any 2xx answer is success. The receiver should refuse a timestamp more than 5 minutes old.
const DefaultTimeout = 15 * time.Second
DefaultTimeout bounds one provider HTTP call.
Variables ¶
var ErrNotFound = errors.New("dns zone not found in the provider account")
ErrNotFound: the zone is not in the account.
Functions ¶
func NormalizeName ¶
NormalizeName lowercases a DNS name and drops its trailing dot.
Types ¶
type APIError ¶
APIError is a provider's refusal. It carries the provider's code and message, never a credential.
type FieldError ¶
FieldError is one reason a provider's settings are refused.
type Options ¶
type Options struct {
// Client is the HTTP client; one with DefaultTimeout by default.
Client *http.Client
// Now defaults to time.Now; Nonce to 16 random bytes in hex.
Now func() time.Time
Nonce func() string
}
Options are a provider's runtime dependencies.
type Provider ¶
type Provider interface {
// Kind is the provider's kind.
Kind() string
// SetRecords makes the records of set.Type at set.Name exactly
// set.Values with set.TTL. New values are added before removed ones
// are deleted. Values must not be empty: use DeleteRecords.
SetRecords(ctx context.Context, set RecordSet) error
// DeleteRecords removes every record of rtype at name.
DeleteRecords(ctx context.Context, zone, name, rtype string) error
}
Provider writes records through one DNS provider account.
type RecordSet ¶
RecordSet is the records of one name and type. Name is fully qualified, inside Zone, without the trailing dot.
type Spec ¶
type Spec struct {
Kind string
// Config are the settings it accepts; Required those it needs.
Config []string
Required []string
// Credentials are the secrets it needs.
Credentials []string
}
Spec is what a kind of provider takes.
type WebhookPayload ¶
type WebhookPayload struct {
Version int `json:"version"`
Action string `json:"action"`
Zone string `json:"zone"`
Name string `json:"name"`
Type string `json:"type"`
Values []string `json:"values,omitempty"`
TTL uint32 `json:"ttl,omitempty"`
Timestamp int64 `json:"timestamp"`
}
WebhookPayload is the body of a webhook call.