]> go.fuhry.dev Git - runtime.git/commitdiff
add //thirdparty/coredns and fix cross compilation
authorDan Fuhry <dan@fuhry.com>
Wed, 3 Jun 2026 04:07:56 +0000 (00:07 -0400)
committerDan Fuhry <dan@fuhry.com>
Wed, 3 Jun 2026 04:07:56 +0000 (00:07 -0400)
bazel/cross.bzl
machines/coredns_plugin/registry.go
machines/coredns_plugin/registry_store.go
machines/coredns_plugin/setup.go
thirdparty/coredns/BUILD.bazel [new file with mode: 0644]
thirdparty/coredns/coremain.go [new file with mode: 0644]
thirdparty/coredns/plugin.cfg.in [new file with mode: 0644]
thirdparty/coredns/plugin/BUILD.bazel [new file with mode: 0644]
thirdparty/coredns/plugin/generate.go [new file with mode: 0644]

index 93828ef7a1b6545ac52f9a06e16bb8ff79caaf1c..e3b7f72cf73abf16e4851f1176c084e9047063a0 100644 (file)
@@ -49,19 +49,19 @@ def go_cross_binaries(
 
     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",
index b4da6632f5cad7617c45090f0a068d684ad306fb..bef9aa7cb36f6c4dd59eff413571453d69a44dbd 100644 (file)
@@ -26,6 +26,7 @@ type Registry interface {
        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
 }
@@ -53,12 +54,16 @@ type registry struct {
        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 {
@@ -138,9 +143,6 @@ func (r *registry) Shutdown() 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
@@ -204,10 +206,14 @@ func (r *registry) defaultDomain() *machines.Domain {
        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) {
@@ -219,6 +225,9 @@ func (r *registry) domainFromQuestion(ques dns.Question) *machines.Domain {
 }
 
 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
@@ -263,6 +272,9 @@ func (r *registry) LookupRecord(ques dns.Question) (int, []dns.RR) {
        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
@@ -278,9 +290,6 @@ func (r *registry) LookupRecord(ques dns.Question) (int, []dns.RR) {
                }
        }
 
-       r.store.mu.RLock()
-       defer r.store.mu.RUnlock()
-
        for _, domain := range r.store.Domains {
                myfqdn := fmt.Sprintf("%s.%s", myHostname, domain.Name)
 
@@ -340,6 +349,9 @@ func (r *registry) LookupRecord(ques dns.Question) (int, []dns.RR) {
 }
 
 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")
        }
@@ -353,9 +365,6 @@ func (r *registry) LookupHost(qname string) (*Result, error) {
                return r.lookupReverseIPv6(fqdn)
        }
 
-       r.store.mu.RLock()
-       defer r.store.mu.RUnlock()
-
        var basename, domainName string
 
        var domain *machines.Domain
@@ -386,9 +395,6 @@ func (r *registry) LookupHost(qname string) (*Result, error) {
 }
 
 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
@@ -432,9 +438,6 @@ func (r *registry) lookupHostLastSeenIface(basename string) (*Result, error) {
 }
 
 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
@@ -495,9 +498,6 @@ func (r *registry) lookupReverseIPv4(ptrName string) (*Result, error) {
                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()) {
@@ -573,9 +573,6 @@ func (r *registry) lookupReverseIPv6(ptrName string) (*Result, error) {
 
        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()) {
@@ -755,7 +752,6 @@ func (r *registry) processHostSeen(hostID, ifaceID, newIP string) {
        iface.LastSeen = machines.Timestamp(now)
        if ip.IsIPv4() {
                iface.LastIPv4 = ip
-
        } else {
                iface.LastIPv6 = ip
        }
index 37df43d68b1fd38234732fcd39b632b8f186b60e..5a3001f78f5dbd4eb863688554533be0458414ab 100644 (file)
@@ -4,7 +4,6 @@ import (
        "encoding/json"
        "flag"
        "fmt"
-       "net"
        "os"
        "strings"
        "sync"
@@ -35,7 +34,7 @@ type recordKey string
 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:], ".")))
        }
@@ -54,10 +53,11 @@ func init() {
 }
 
 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 {
@@ -65,21 +65,20 @@ 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
        }
@@ -277,34 +276,3 @@ func (rs *registryStore) patchIface(iface *machines.Iface) {
 
        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
-}
index 7a01073fbd16f73b01c9470c14affbd45585f20d..5418182f1429b2c2579ac634aa4411e75484cae0 100644 (file)
@@ -3,6 +3,7 @@ package coredns_plugin
 import (
        "context"
        "fmt"
+       "time"
 
        "github.com/coredns/caddy"
        "github.com/coredns/coredns/core/dnsserver"
@@ -17,6 +18,9 @@ import (
 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{
@@ -62,7 +66,7 @@ func (m *Machines) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Ms
 
        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,
@@ -88,7 +92,7 @@ func (m *Machines) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Ms
                                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 {
diff --git a/thirdparty/coredns/BUILD.bazel b/thirdparty/coredns/BUILD.bazel
new file mode 100644 (file)
index 0000000..38b97d8
--- /dev/null
@@ -0,0 +1,36 @@
+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
diff --git a/thirdparty/coredns/coremain.go b/thirdparty/coredns/coremain.go
new file mode 100644 (file)
index 0000000..f37d998
--- /dev/null
@@ -0,0 +1,14 @@
+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()
+}
diff --git a/thirdparty/coredns/plugin.cfg.in b/thirdparty/coredns/plugin.cfg.in
new file mode 100644 (file)
index 0000000..140b2f5
--- /dev/null
@@ -0,0 +1,76 @@
+# 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
diff --git a/thirdparty/coredns/plugin/BUILD.bazel b/thirdparty/coredns/plugin/BUILD.bazel
new file mode 100644 (file)
index 0000000..ee610d5
--- /dev/null
@@ -0,0 +1,89 @@
+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",
+    ],
+)
diff --git a/thirdparty/coredns/plugin/generate.go b/thirdparty/coredns/plugin/generate.go
new file mode 100644 (file)
index 0000000..6b461ff
--- /dev/null
@@ -0,0 +1,122 @@
+//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"
+)