@@ -3,20 +3,23 @@ package main
33import (
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
2124type 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-
6265func 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 )
0 commit comments