if mac:
for arch in ["amd64", "arm64"]:
- _cross(lib_target, "darwin_{}".format(arch))
+ _cross(base_target, "darwin_{}".format(arch))
if openbsd:
- _cross(lib_target, "openbsd_amd64")
+ _cross(base_target, "openbsd_amd64")
if linux_arm:
- _cross(lib_target, "linux_arm64")
+ _cross(base_target, "linux_arm64")
if linux_amd64_alpine:
go_cross_binary(
name = "{}_linux_amd64_alpine".format(base_target),
platform = "@rules_go//go/toolchain:linux_amd64",
- target = lib_target,
+ target = base_target,
features = [
"pure",
"fully_static_link",
LookupRecord(dns.Question) (int, []dns.RR)
AuthorityRecords(dns.Question) []dns.RR
AdditionalRecords(dns.Question, []dns.RR) []dns.RR
+ DomainFromQuestion(dns.Question) *machines.Domain
Startup() error
Shutdown() error
}
store *registryStore
}
-var ErrUnmanagedDomain = errors.New("domain is not managed by this plugin")
-var ErrRecordsNoneMatch = errors.New("no custom records match this query")
-var ErrUninitialized = errors.New("registry has not finished initializing yet")
+var (
+ ErrUnmanagedDomain = errors.New("domain is not managed by this plugin")
+ ErrRecordsNoneMatch = errors.New("no custom records match this query")
+ ErrUninitialized = errors.New("registry has not finished initializing yet")
+)
-var refreshInterval = 15 * time.Minute
-var refreshSplay = 30 * time.Second
+var (
+ refreshInterval = 15 * time.Minute
+ refreshSplay = 30 * time.Second
+)
func init() {
setRefresh := func(durVar *time.Duration) func(string) error {
}
func (r *registry) defaultDomain() *machines.Domain {
- r.store.mu.RLock()
- defer r.store.mu.RUnlock()
-
if r.defDomain != "" {
if d, ok := r.store.Domains[r.defDomain]; ok && d != nil {
return d
return lowestDomain
}
-func (r *registry) domainFromQuestion(ques dns.Question) *machines.Domain {
+func (r *registry) DomainFromQuestion(ques dns.Question) *machines.Domain {
r.store.mu.RLock()
defer r.store.mu.RUnlock()
+ return r.domainFromQuestion(ques)
+}
+
+func (r *registry) domainFromQuestion(ques dns.Question) *machines.Domain {
qname := strings.ToLower(strings.TrimSuffix(ques.Name, "."))
for _, domain := range r.store.Domains {
if qname == domain.Name || strings.HasSuffix(qname, "."+domain.Name) {
}
func (r *registry) AuthorityRecords(origQues dns.Question) []dns.RR {
+ r.store.mu.RLock()
+ defer r.store.mu.RUnlock()
+
qDomain := r.domainFromQuestion(origQues)
if qDomain == nil {
return nil
qname := strings.ToLower(strings.TrimSuffix(ques.Name, "."))
r.log.V(2).Debugf("LookupRecord(%s)", qname)
+ r.store.mu.RLock()
+ defer r.store.mu.RUnlock()
+
if !r.store.initialized() {
r.log.V(1).Debugf(" store not initialized, returning NXDOMAIN")
return dns.RcodeNameError, nil
}
}
- r.store.mu.RLock()
- defer r.store.mu.RUnlock()
-
for _, domain := range r.store.Domains {
myfqdn := fmt.Sprintf("%s.%s", myHostname, domain.Name)
}
func (r *registry) LookupHost(qname string) (*Result, error) {
+ r.store.mu.RLock()
+ defer r.store.mu.RUnlock()
+
if !r.store.initialized() {
return nil, fmt.Errorf("plugin not yet initialized")
}
return r.lookupReverseIPv6(fqdn)
}
- r.store.mu.RLock()
- defer r.store.mu.RUnlock()
-
var basename, domainName string
var domain *machines.Domain
}
func (r *registry) lookupHostLastSeenIface(basename string) (*Result, error) {
- r.store.mu.RLock()
- defer r.store.mu.RUnlock()
-
hostID, ok := r.store.HostNames[basename]
if !ok {
// host not found
}
func (r *registry) lookupHostWithIface(basename string) (*Result, error) {
- r.store.mu.RLock()
- defer r.store.mu.RUnlock()
-
ifaceID, ok := r.store.HostInterfaceNames[basename]
if !ok {
// host not found
return nil, fmt.Errorf("failed to parse IP")
}
- r.store.mu.RLock()
- defer r.store.mu.RUnlock()
-
var domain *machines.Domain
for _, d := range r.store.Domains {
if !ip.Mask(d.IPv4PrefixLength.IPMask()).Equal(d.IPv4Address.AsIP()) {
r.log.V(3).Debugf("processing PTR lookup for IP %s", ip.String())
- r.store.mu.RLock()
- defer r.store.mu.RUnlock()
-
var domain *machines.Domain
for _, d := range r.store.Domains {
if !ip.Mask(d.IPv6PrefixLength.IPMask()).Equal(d.IPv6Address.AsIP()) {
iface.LastSeen = machines.Timestamp(now)
if ip.IsIPv4() {
iface.LastIPv4 = ip
-
} else {
iface.LastIPv6 = ip
}
"encoding/json"
"flag"
"fmt"
- "net"
"os"
"strings"
"sync"
func (rk recordKey) Wildcards() []recordKey {
parts := strings.Split(string(rk), ".")
wildcards := make([]recordKey, len(parts))
- for i, _ := range parts {
+ for i := range parts {
parts[i] = "*"
wildcards = append(wildcards, recordKey(strings.Join(parts[i:], ".")))
}
}
func (rs *registryStore) initialized() bool {
- rs.mu.RLock()
- defer rs.mu.RUnlock()
-
- return rs.Sites != nil && rs.Domains != nil && rs.Hosts != nil && rs.Ifaces != nil && rs.Records != nil
+ return (rs.Sites != nil &&
+ rs.Domains != nil &&
+ rs.Hosts != nil &&
+ rs.Ifaces != nil &&
+ rs.Records != nil)
}
func (rs *registryStore) fresh() bool {
}
func (rs *registryStore) saveState() error {
+ rs.mu.RLock()
+ defer rs.mu.RUnlock()
+
if !rs.initialized() {
return nil
}
- // wait to acquire lock until after initialization check to avoid deadlock
- rs.mu.RLock()
- defer rs.mu.RUnlock()
-
contents, err := json.Marshal(rs)
if err != nil {
rs.log.Error("failed to save state to %s: %v", machinesRegistryStorePath, err)
return err
}
- err = os.WriteFile(machinesRegistryStorePath, contents, os.FileMode(0600))
+ err = os.WriteFile(machinesRegistryStorePath, contents, os.FileMode(0o600))
if err != nil {
return err
}
rs.Ifaces[iface.ID()] = iface
}
-
-func (rs *registryStore) DomainForFqdn(qname string) *machines.Domain {
- rs.mu.RLock()
- defer rs.mu.RUnlock()
-
- for _, domain := range rs.Domains {
- if strings.HasSuffix(qname, "."+domain.Name) {
- return domain
- }
- }
-
- return nil
-}
-
-func (rs *registryStore) DomainForAddress(addr net.Addr) *machines.Domain {
- rs.mu.RLock()
- defer rs.mu.RUnlock()
-
- udpAddr, ok := addr.(*net.UDPAddr)
- if !ok {
- return nil
- }
-
- for _, domain := range rs.Domains {
- if domain.ContainsIP(udpAddr.IP) {
- return domain
- }
- }
-
- return nil
-}
import (
"context"
"fmt"
+ "time"
"github.com/coredns/caddy"
"github.com/coredns/coredns/core/dnsserver"
func init() { plugin.Register(constants.OrgSlug+"_machines", setup) }
func setup(c *caddy.Controller) error {
+ log.WithPrefix(fmt.Sprintf("plugin/%s_machines", constants.OrgSlug)).Noticef(
+ "%s_machines plugin loaded, build date: %s", constants.OrgSlug, constants.BuildTimestampTime().Format(time.RFC3339),
+ )
reg := NewRegistry(context.Background())
m := &Machines{
for _, ques := range r.Question {
if rc, rrs := m.r.LookupRecord(ques); rc != dns.RcodeNameError {
- domain := m.r.(*registry).domainFromQuestion(ques)
+ domain := m.r.DomainFromQuestion(ques)
if domain != nil {
m.r.(*registry).stats.recordLookups.WithLabelValues(mbclient.KV{
"domain": domain.Name,
rcode = dns.RcodeNameError
m.r.(*registry).stats.hostLookups.WithLabelValues(mbclient.KV{
- "domain": m.r.(*registry).domainFromQuestion(ques).Name,
+ "domain": m.r.DomainFromQuestion(ques).Name,
"rcode": rcodeToStr(rcode),
}).Add(1)
} else {
--- /dev/null
+load("//bazel:go.bzl", "go_multi_binary", "go_multi_library")
+load("//bazel:cross.bzl", "go_cross_binaries")
+load("//bazel:subst.bzl", "subst")
+
+subst(
+ name = "plugin_cfg",
+ src = "plugin.cfg.in",
+ out = "plugin.cfg",
+ visibility = [
+ "//thirdparty/coredns/plugin:__pkg__",
+ ],
+)
+
+go_multi_library(
+ name = "coredns_lib",
+ srcs = ["coremain.go"],
+ importpath = "go.fuhry.dev/runtime/thirdparty/coredns",
+ visibility = ["//visibility:private"],
+ deps = [
+ "//thirdparty/coredns/plugin",
+ "@com_github_coredns_coredns//core/dnsserver",
+ "@com_github_coredns_coredns//coremain",
+ ],
+)
+
+go_multi_binary(
+ name = "coredns",
+ embed = [":coredns_lib"],
+ visibility = ["//visibility:public"],
+)
+
+go_cross_binaries(
+ base_target = "coredns",
+ linux_arm = True,
+ openbsd = True,
+)
\ No newline at end of file
--- /dev/null
+package main
+
+import (
+ "github.com/coredns/coredns/core/dnsserver"
+ "github.com/coredns/coredns/coremain"
+
+ "go.fuhry.dev/runtime/thirdparty/coredns/plugin"
+)
+
+func main() {
+ dnsserver.Directives = plugin.Directives
+
+ coremain.Run()
+}
--- /dev/null
+# Directives are registered in the order they should be executed.
+#
+# Ordering is VERY important. Every plugin will feel the effects of all other
+# plugin below (after) them during a request, but they must not care what plugin
+# above them are doing.
+
+# How to rebuild with updated plugin configurations: Modify the list below and
+# run `go generate && go build`
+
+# The parser takes the input format of:
+#
+# <plugin-name>:<package-name>
+# Or
+# <plugin-name>:<fully-qualified-package-name>
+#
+# External plugin example:
+#
+# log:github.com/coredns/coredns/plugin/log
+# Local plugin example:
+# log:log
+
+root:root
+metadata:metadata
+geoip:geoip
+cancel:cancel
+tls:tls
+timeouts:timeouts
+reload:reload
+nsid:nsid
+bufsize:bufsize
+bind:bind
+debug:debug
+trace:trace
+ready:ready
+health:health
+pprof:pprof
+prometheus:metrics
+errors:errors
+log:log
+dnstap:dnstap
+local:local
+dns64:dns64
+acl:acl
+any:any
+chaos:chaos
+loadbalance:loadbalance
+tsig:tsig
+no6:github.com/fuhry/coredns-no6
+cache:cache
+rewrite:rewrite
+header:header
+dnssec:dnssec
+autopath:autopath
+minimal:minimal
+template:template
+transfer:transfer
+hosts:hosts
+route53:route53
+azure:azure
+clouddns:clouddns
+k8s_external:k8s_external
+kubernetes
+file:file
+${const:OrgSlug}_machines:go.fuhry.dev/runtime/machines/coredns_plugin
+records:github.com/coredns/records
+forward:forward
+auto:auto
+secondary:secondary
+etcd:etcd
+loop:loop
+grpc:grpc
+erratic:erratic
+whoami:whoami
+on:github.com/coredns/caddy/onevent
+sign:sign
+view:view
--- /dev/null
+load("//bazel:go.bzl", "go_multi_binary", "go_multi_library")
+
+go_multi_library(
+ name = "generate_lib",
+ srcs = ["generate.go"],
+ importpath = "go.fuhry.dev/runtime/thirdparty/coredns/plugin",
+)
+go_multi_binary(
+ name = "generate",
+ embed = [":generate_lib"],
+ gotags = ["generate"],
+ visibility = ["//thirdparty/coredns:__subpackages__"],
+)
+genrule(
+ name = "zplugin_go",
+ outs = ["zplugin.go"],
+ srcs = [
+ "//thirdparty/coredns:plugin_cfg",
+ ],
+ tools = [
+ ":generate",
+ ],
+ cmd = """
+ ./$(location :generate) -plugin-cfg "$<" > "$@"
+ """
+)
+
+go_multi_library(
+ name = "plugin",
+ srcs = ["zplugin.go"],
+ importpath = "go.fuhry.dev/runtime/thirdparty/coredns/plugin",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//machines/coredns_plugin",
+ "@com_github_coredns_caddy//onevent",
+ "@com_github_coredns_coredns//plugin/acl",
+ "@com_github_coredns_coredns//plugin/any",
+ "@com_github_coredns_coredns//plugin/auto",
+ "@com_github_coredns_coredns//plugin/autopath",
+ "@com_github_coredns_coredns//plugin/azure",
+ "@com_github_coredns_coredns//plugin/bind",
+ "@com_github_coredns_coredns//plugin/bufsize",
+ "@com_github_coredns_coredns//plugin/cache",
+ "@com_github_coredns_coredns//plugin/cancel",
+ "@com_github_coredns_coredns//plugin/chaos",
+ "@com_github_coredns_coredns//plugin/clouddns",
+ "@com_github_coredns_coredns//plugin/debug",
+ "@com_github_coredns_coredns//plugin/dns64",
+ "@com_github_coredns_coredns//plugin/dnssec",
+ "@com_github_coredns_coredns//plugin/dnstap",
+ "@com_github_coredns_coredns//plugin/erratic",
+ "@com_github_coredns_coredns//plugin/errors",
+ "@com_github_coredns_coredns//plugin/etcd",
+ "@com_github_coredns_coredns//plugin/file",
+ "@com_github_coredns_coredns//plugin/forward",
+ "@com_github_coredns_coredns//plugin/geoip",
+ "@com_github_coredns_coredns//plugin/grpc",
+ "@com_github_coredns_coredns//plugin/header",
+ "@com_github_coredns_coredns//plugin/health",
+ "@com_github_coredns_coredns//plugin/hosts",
+ "@com_github_coredns_coredns//plugin/k8s_external",
+ "@com_github_coredns_coredns//plugin/loadbalance",
+ "@com_github_coredns_coredns//plugin/local",
+ "@com_github_coredns_coredns//plugin/log",
+ "@com_github_coredns_coredns//plugin/loop",
+ "@com_github_coredns_coredns//plugin/metadata",
+ "@com_github_coredns_coredns//plugin/metrics",
+ "@com_github_coredns_coredns//plugin/minimal",
+ "@com_github_coredns_coredns//plugin/nsid",
+ "@com_github_coredns_coredns//plugin/pprof",
+ "@com_github_coredns_coredns//plugin/ready",
+ "@com_github_coredns_coredns//plugin/reload",
+ "@com_github_coredns_coredns//plugin/rewrite",
+ "@com_github_coredns_coredns//plugin/root",
+ "@com_github_coredns_coredns//plugin/route53",
+ "@com_github_coredns_coredns//plugin/secondary",
+ "@com_github_coredns_coredns//plugin/sign",
+ "@com_github_coredns_coredns//plugin/template",
+ "@com_github_coredns_coredns//plugin/timeouts",
+ "@com_github_coredns_coredns//plugin/tls",
+ "@com_github_coredns_coredns//plugin/trace",
+ "@com_github_coredns_coredns//plugin/transfer",
+ "@com_github_coredns_coredns//plugin/tsig",
+ "@com_github_coredns_coredns//plugin/view",
+ "@com_github_coredns_coredns//plugin/whoami",
+ "@com_github_coredns_records//:go_default_library",
+ "@com_github_fuhry_coredns_no6//:go_default_library",
+ ],
+)
--- /dev/null
+//go:build generate
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "flag"
+ "fmt"
+ "go/format"
+ "io"
+ "log"
+ "os"
+ "strings"
+)
+
+func main() {
+ pluginFile := flag.String("plugin-cfg", "", "input plugin.cfg file")
+ flag.Parse()
+
+ mi := make(map[string]string, 0)
+ md := []string{}
+
+ file, err := os.Open(*pluginFile)
+ if err != nil {
+ log.Fatalf("Failed to open %s: %q", *pluginFile, err)
+ }
+
+ defer file.Close()
+
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ line := scanner.Text()
+ if strings.HasPrefix(line, "#") {
+ continue
+ }
+
+ items := strings.Split(line, ":")
+ if len(items) != 2 {
+ // ignore empty lines
+ continue
+ }
+ name, repo := items[0], items[1]
+
+ if _, ok := mi[name]; ok {
+ log.Fatalf("Duplicate entry %q", name)
+ }
+
+ md = append(md, name)
+ if strings.Contains(repo, "/") {
+ mi[name] = repo
+ } else {
+ mi[name] = pluginPath + repo
+ }
+ }
+
+ genHeader("plugin")
+ genImports(mi)
+ genDirectives(md)
+}
+
+func genHeader(pack string) {
+ fmt.Print(header)
+ fmt.Printf("package %s\n", pack)
+}
+
+func genImports(mi map[string]string) {
+ outs := "import ("
+
+ if len(mi) > 0 {
+ outs += "\n"
+ }
+
+ outs += "// Include all plugins.\n"
+ for _, v := range mi {
+ outs += `_ "` + v + `"` + "\n"
+ }
+ outs += ")\n"
+
+ if err := formatAndWrite(outs); err != nil {
+ log.Fatalf("Failed to format and write: %q", err)
+ }
+}
+
+func genDirectives(md []string) {
+ outs := `
+// Directives are registered in the order they should be
+// executed.
+//
+// Ordering is VERY important. Every plugin will
+// feel the effects of all other plugin below
+// (after) them during a request, but they must not
+// care what plugin above them are doing.
+var Directives = []string{
+`
+
+ for i := range md {
+ outs += `"` + md[i] + `",` + "\n"
+ }
+
+ outs += "}\n"
+
+ if err := formatAndWrite(outs); err != nil {
+ log.Fatalf("Failed to format and write: %q", err)
+ }
+}
+
+func formatAndWrite(data string) error {
+ res, err := format.Source([]byte(data))
+ if err != nil {
+ return err
+ }
+
+ buf := bytes.NewBuffer(res)
+ io.Copy(os.Stdout, buf)
+ return nil
+}
+
+const (
+ pluginPath = "github.com/coredns/coredns/plugin/"
+ header = "// generated by directives_generate.go; DO NOT EDIT\n\n"
+)