Skip to content

Commit 2dc31ac

Browse files
committed
Update config to be ordered JSON instead of json5 (canonically)
This includes a fallback so that existing configs do not break. This also refactors a lot of data handling to be more sane (less shared objects).
1 parent cf22bdc commit 2dc31ac

File tree

3 files changed

+59
-44
lines changed

3 files changed

+59
-44
lines changed

cmd/rawdns/main.go

Lines changed: 56 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,23 @@ package main
33
import (
44
"crypto/tls"
55
"crypto/x509"
6+
"encoding/json"
67
"fmt"
78
"io/ioutil"
89
"log"
910
"net"
1011
"os"
1112
"os/signal"
1213
"runtime"
14+
"slices"
1315
"strings"
1416

17+
"github.com/docker-library/meta-scripts/om"
1518
"github.com/miekg/dns"
1619
"github.com/titanous/json5"
1720
)
1821

19-
type Config map[string]DomainConfig // { "docker.": { ... }, ".": { ... } }
22+
// config like { "docker.": { ... }, ".": { ... } }
2023

2124
type DomainConfig struct {
2225
Type string `json:"type"` // "containers", "forwarding", "static"
@@ -29,6 +32,8 @@ type DomainConfig struct {
2932
TLSCACert string `json:"tlscacert"`
3033
TLSCert string `json:"tlscert"`
3134
TLSKey string `json:"tlskey"`
35+
// parsed/loaded
36+
tlsConfig *tls.Config
3237

3338
// IP address strategy
3439
SwarmNode bool `json:"swarmnode"`
@@ -57,8 +62,6 @@ type DomainConfigSrv struct {
5762
Target string `json:"target"`
5863
}
5964

60-
var config Config
61-
6265
func main() {
6366
log.Printf("rawdns v%s (%s on %s/%s; %s)\n", VERSION, runtime.Version(), runtime.GOOS, runtime.GOARCH, runtime.Compiler)
6467

@@ -71,76 +74,85 @@ func main() {
7174
if err != nil {
7275
log.Fatalf("error: unable to read config file %s: %v\n", configFile, err)
7376
}
74-
err = json5.Unmarshal(configData, &config)
75-
if err != nil {
76-
log.Fatalf("error: unable to process config file data from %s: %v\n", configFile, err)
77+
78+
config := om.OrderedMap[DomainConfig]{}
79+
if err := json.Unmarshal(configData, &config); err != nil {
80+
// if it isn't stock JSON, it might be json5; we'll try that (for backwards compatibility)
81+
var configMap map[string]DomainConfig
82+
if err5 := json5.Unmarshal(configData, &configMap); err5 != nil {
83+
log.Fatalf("error: unable to process config file data from %s: %v\n", configFile, err)
84+
}
85+
domains := make([]string, 0, len(configMap))
86+
for domain := range configMap {
87+
domains = append(domains, domain)
88+
}
89+
slices.Sort(domains)
90+
for _, domain := range domains {
91+
config.Set(domain, configMap[domain])
92+
}
7793
}
7894

79-
for domain := range config {
80-
if config[domain].Randomize == nil {
81-
domainConfig := config[domain]
95+
for _, domain := range config.Keys() {
96+
domain := domain // https://github.com/golang/go/discussions/56010
97+
domainConfig := config.Get(domain)
98+
99+
if domainConfig.Randomize == nil {
82100
randomize := true
83101
domainConfig.Randomize = &randomize
84-
config[domain] = domainConfig
85102
}
86103

87-
switch config[domain].Type {
104+
switch domainConfig.Type {
88105
case "containers":
89-
// TODO there must be a better way to pass "domain" along without an anonymous function AND copied variable
90-
var tlsConfig *tls.Config
91-
if config[domain].TLSCert != "" && config[domain].TLSKey != "" {
106+
if domainConfig.TLSCert != "" && domainConfig.TLSKey != "" {
92107
var err error
93-
tlsConfig, err = loadTLSConfig(config[domain].TLSCACert, config[domain].TLSCert, config[domain].TLSKey, config[domain].TLSVerify)
108+
domainConfig.tlsConfig, err = loadTLSConfig(domainConfig.TLSCACert, domainConfig.TLSCert, domainConfig.TLSKey, domainConfig.TLSVerify)
94109
if err != nil {
95110
log.Fatalf("error: Unable to load tls config for %s: %s\n", domain, err)
96111
}
97112
}
98113

99-
dCopy := domain
100-
dns.HandleFunc(dCopy, func(w dns.ResponseWriter, r *dns.Msg) {
101-
handleDockerRequest(dCopy, tlsConfig, w, r)
114+
dns.HandleFunc(domain, func(w dns.ResponseWriter, r *dns.Msg) {
115+
handleDockerRequest(domain, domainConfig, w, r)
102116
})
117+
103118
case "forwarding":
104-
// TODO there must be a better way to pass "domain" along without an anonymous function AND copied variable
105-
nameservers := config[domain].Nameservers
106-
randomize := *config[domain].Randomize
107119
dns.HandleFunc(domain, func(w dns.ResponseWriter, r *dns.Msg) {
108-
handleForwarding(nameservers, randomize, w, r)
120+
handleForwarding(domainConfig.Nameservers, *domainConfig.Randomize, w, r)
109121
})
110-
case "static":
111-
cCopy := config[domain]
112122

113-
cCopy.addrs = make([]net.IP, len(cCopy.Addrs))
114-
for i, addr := range cCopy.Addrs {
115-
cCopy.addrs[i] = net.ParseIP(addr)
123+
case "static":
124+
domainConfig.addrs = make([]net.IP, len(domainConfig.Addrs))
125+
for i, addr := range domainConfig.Addrs {
126+
domainConfig.addrs[i] = net.ParseIP(addr)
116127
}
117128

118-
cCopy.cnames = make([]string, len(cCopy.Cnames))
119-
for i, cname := range cCopy.Cnames {
120-
cCopy.cnames[i] = dns.Fqdn(cname)
129+
domainConfig.cnames = make([]string, len(domainConfig.Cnames))
130+
for i, cname := range domainConfig.Cnames {
131+
domainConfig.cnames[i] = dns.Fqdn(cname)
121132
}
122133

123-
cCopy.ptrs = make([]string, len(cCopy.Ptrs))
124-
for i, ptr := range cCopy.Ptrs {
125-
cCopy.ptrs[i] = dns.Fqdn(ptr)
134+
domainConfig.ptrs = make([]string, len(domainConfig.Ptrs))
135+
for i, ptr := range domainConfig.Ptrs {
136+
domainConfig.ptrs[i] = dns.Fqdn(ptr)
126137
}
127138

128-
cCopy.txts = make([][]string, len(cCopy.Txts))
129-
for i, txts := range cCopy.Txts {
130-
cCopy.txts[i] = make([]string, len(txts))
139+
domainConfig.txts = make([][]string, len(domainConfig.Txts))
140+
for i, txts := range domainConfig.Txts {
141+
domainConfig.txts[i] = make([]string, len(txts))
131142
for j, txt := range txts {
132-
cCopy.txts[i][j] = strings.Replace(txt, `\`, `\\`, -1)
143+
domainConfig.txts[i][j] = strings.Replace(txt, `\`, `\\`, -1)
133144
}
134145
}
135146

136147
dns.HandleFunc(domain, func(w dns.ResponseWriter, r *dns.Msg) {
137-
handleStaticRequest(cCopy, w, r)
148+
handleStaticRequest(domainConfig, w, r)
138149
})
150+
139151
default:
140-
log.Printf("error: unknown domain type on %s: %q\n", domain, config[domain].Type)
141-
continue
152+
log.Fatalf("error: unknown domain type on %s: %q\n", domain, domainConfig.Type)
142153
}
143-
log.Printf("listening on domain: %s\n", domain)
154+
155+
log.Printf("listening on domain [% -10s]: %s\n", domainConfig.Type, domain)
144156
}
145157

146158
go serve("tcp", ":53")
@@ -197,7 +209,7 @@ func dnsAppend(q dns.Question, m *dns.Msg, rr dns.RR) {
197209
}
198210
}
199211

200-
func handleDockerRequest(domain string, tlsConfig *tls.Config, w dns.ResponseWriter, r *dns.Msg) {
212+
func handleDockerRequest(domain string, domainConfig DomainConfig, w dns.ResponseWriter, r *dns.Msg) {
201213
m := new(dns.Msg)
202214
m.SetReply(r)
203215
defer w.WriteMsg(m)
@@ -211,15 +223,15 @@ func handleDockerRequest(domain string, tlsConfig *tls.Config, w dns.ResponseWri
211223
}
212224
containerName := name[:len(name)-len(domainSuffix)]
213225

214-
ips, err := dockerGetIpList(config[domain].Socket, containerName, tlsConfig, config[domain].SwarmNode)
226+
ips, err := dockerGetIpList(domainConfig.Socket, containerName, domainConfig.tlsConfig, domainConfig.SwarmNode)
215227
if err != nil && strings.Contains(containerName, ".") {
216228
// we have something like "db.app", so let's try looking up a "app/db" container (linking!)
217229
parts := strings.Split(containerName, ".")
218230
var linkedContainerName string
219231
for i := range parts {
220232
linkedContainerName += "/" + parts[len(parts)-i-1]
221233
}
222-
ips, err = dockerGetIpList(config[domain].Socket, linkedContainerName, tlsConfig, config[domain].SwarmNode)
234+
ips, err = dockerGetIpList(domainConfig.Socket, linkedContainerName, domainConfig.tlsConfig, domainConfig.SwarmNode)
223235
}
224236
if err != nil {
225237
m.SetRcode(r, dns.RcodeNameError)

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/tianon/rawdns
33
go 1.21
44

55
require (
6+
github.com/docker-library/meta-scripts v0.0.0-20240308032004-96ed6a9b2bad
67
github.com/miekg/dns v1.1.58
78
github.com/titanous/json5 v1.0.0
89
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
github.com/docker-library/meta-scripts v0.0.0-20240308032004-96ed6a9b2bad h1:47H9uVRqdgq6lLd2XMVRg+K3KuYKmGF6jkzDVlPLZy8=
2+
github.com/docker-library/meta-scripts v0.0.0-20240308032004-96ed6a9b2bad/go.mod h1:Lxb/5IT8JwRt7wtvC5uRWDgiIyBKxl7J4Y4OytutTlE=
13
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
24
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
35
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=

0 commit comments

Comments
 (0)