From faec69e1fe9db183fdae8b43398817004f1def9e Mon Sep 17 00:00:00 2001 From: Dan Fuhry Date: Wed, 3 Jun 2026 00:07:56 -0400 Subject: [PATCH] add //thirdparty/coredns and fix cross compilation --- bazel/cross.bzl | 8 +- machines/coredns_plugin/registry.go | 52 +++++---- machines/coredns_plugin/registry_store.go | 52 ++------- machines/coredns_plugin/setup.go | 8 +- thirdparty/coredns/BUILD.bazel | 36 +++++++ thirdparty/coredns/coremain.go | 14 +++ thirdparty/coredns/plugin.cfg.in | 76 ++++++++++++++ thirdparty/coredns/plugin/BUILD.bazel | 89 ++++++++++++++++ thirdparty/coredns/plugin/generate.go | 122 ++++++++++++++++++++++ 9 files changed, 381 insertions(+), 76 deletions(-) create mode 100644 thirdparty/coredns/BUILD.bazel create mode 100644 thirdparty/coredns/coremain.go create mode 100644 thirdparty/coredns/plugin.cfg.in create mode 100644 thirdparty/coredns/plugin/BUILD.bazel create mode 100644 thirdparty/coredns/plugin/generate.go diff --git a/bazel/cross.bzl b/bazel/cross.bzl index 93828ef..e3b7f72 100644 --- a/bazel/cross.bzl +++ b/bazel/cross.bzl @@ -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", diff --git a/machines/coredns_plugin/registry.go b/machines/coredns_plugin/registry.go index b4da663..bef9aa7 100644 --- a/machines/coredns_plugin/registry.go +++ b/machines/coredns_plugin/registry.go @@ -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 } diff --git a/machines/coredns_plugin/registry_store.go b/machines/coredns_plugin/registry_store.go index 37df43d..5a3001f 100644 --- a/machines/coredns_plugin/registry_store.go +++ b/machines/coredns_plugin/registry_store.go @@ -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 -} diff --git a/machines/coredns_plugin/setup.go b/machines/coredns_plugin/setup.go index 7a01073..5418182 100644 --- a/machines/coredns_plugin/setup.go +++ b/machines/coredns_plugin/setup.go @@ -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 index 0000000..38b97d8 --- /dev/null +++ b/thirdparty/coredns/BUILD.bazel @@ -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 index 0000000..f37d998 --- /dev/null +++ b/thirdparty/coredns/coremain.go @@ -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 index 0000000..140b2f5 --- /dev/null +++ b/thirdparty/coredns/plugin.cfg.in @@ -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: +# +# : +# Or +# : +# +# 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 index 0000000..ee610d5 --- /dev/null +++ b/thirdparty/coredns/plugin/BUILD.bazel @@ -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 index 0000000..6b461ff --- /dev/null +++ b/thirdparty/coredns/plugin/generate.go @@ -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" +) -- 2.52.0