Skip to content

Commit bb38b1e

Browse files
committed
Add support for multiple zones
* Fix dstapp#7 dstapp#18 by allowing updates by fqdn
1 parent 00fba17 commit bb38b1e

File tree

5 files changed

+140
-21
lines changed

5 files changed

+140
-21
lines changed

rest-api/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func (flagsConf *ConfigFlags) setupFlags() {
3737
flag.BoolVar(&flagsConf.DoNotLoadConfig, "noConfig", false, "Do not load the config file")
3838
flag.StringVar(&flagsConf.ConfigFile, "c", "/etc/dyndns.json", "The configuration file")
3939
flag.StringVar(&flagsConf.Server, "server", "localhost", "The address of the bind server")
40-
flag.StringVar(&flagsConf.Zone, "zone", "localhost", "Zone")
40+
flag.StringVar(&flagsConf.Zone, "zone", "", "Configuring a default zone will allow to send request with the hostname only as the domain")
4141
flag.StringVar(&flagsConf.NsupdateBinary, "nsupdateBinary", "nsupdate", "Path to nsupdate program")
4242
flag.IntVar(&flagsConf.RecordTTL, "recordTTL", 300, "RecordTTL")
4343
flag.IntVar(&flagsConf.Port, "p", 8080, "Port")

rest-api/main.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ const (
1919
var appConfig = &ConfigFlags{}
2020

2121
func main() {
22-
defaultExtractor := defaultRequestDataExtractor{}
23-
dynExtractor := dynRequestDataExtractor{}
22+
defaultExtractor := defaultRequestDataExtractor{appConfig: &appConfig.Config}
23+
dynExtractor := dynRequestDataExtractor{defaultRequestDataExtractor{appConfig: &appConfig.Config}}
2424

2525
appConfig.LoadConfig()
2626

@@ -90,6 +90,9 @@ func updateDomains(r *http.Request, response *WebserviceResponse, onError func()
9090
ipAddr: address.Address,
9191
addrType: address.AddrType,
9292
secret: extractor.Secret(r),
93+
ddnsKeyName: extractor.DdnsKeyName(r, domain),
94+
zone: extractor.Zone(r, domain),
95+
fqdn: extractor.Fqdn(r, domain),
9396
}
9497
result := recordUpdate.updateRecord()
9598

rest-api/nsupdate.go

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -104,21 +104,14 @@ func escape(s string) string {
104104

105105
// UpdateRecord sends the record update request to the nsupdate program
106106
func (nsupdate *NSUpdate) UpdateRecord(r RecordUpdateRequest) {
107-
fqdn := escape(r.domain)
108-
if appConfig.Zone != "" {
109-
fqdn = escape(r.domain) + "." + appConfig.Zone
107+
nsupdate.write("server %s\n", appConfig.Server)
108+
if r.zone != "" {
109+
nsupdate.write("zone %s\n", r.zone+".")
110110
}
111-
112-
if r.secret != "" {
113-
fqdnN := strings.TrimLeft(appConfig.Zone, ".")
114-
nsupdate.write("key hmac-sha256:ddns-key.%s %s\n", fqdnN, escape(r.secret))
111+
if r.ddnsKeyName != "" {
112+
nsupdate.write("key hmac-sha256:ddns-key.%s %s\n", escape(r.ddnsKeyName), escape(r.secret))
115113
}
116-
117-
nsupdate.write("server %s\n", appConfig.Server)
118-
if appConfig.Zone != "" {
119-
nsupdate.write("zone %s\n", appConfig.Zone)
120-
}
121-
nsupdate.write("update delete %s %s\n", fqdn, r.addrType)
122-
nsupdate.write("update add %s %v %s %s\n", fqdn, appConfig.RecordTTL, r.addrType, escape(r.ipAddr))
114+
nsupdate.write("update delete %s %s\n", r.fqdn, r.addrType)
115+
nsupdate.write("update add %s %v %s %s\n", r.fqdn, appConfig.RecordTTL, r.addrType, escape(r.ipAddr))
123116
nsupdate.write("send\n")
124117
}

rest-api/request_data_extractor.go

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,21 @@ package main
33
import (
44
"context"
55
"net/http"
6+
"strings"
67
)
78

89
type requestDataExtractor interface {
910
Address(r *http.Request) string
1011
Secret(r *http.Request) string
1112
Domain(r *http.Request) string
12-
DdnsKey(r *http.Request) string
13+
DdnsKeyName(r *http.Request, domain string) string
14+
Zone(r *http.Request, domain string) string
15+
Fqdn(r *http.Request, domain string) string
1316
}
1417

15-
type defaultRequestDataExtractor struct{}
18+
type defaultRequestDataExtractor struct {
19+
appConfig *Config
20+
}
1621

1722
func (e defaultRequestDataExtractor) Address(r *http.Request) string {
1823
return r.URL.Query().Get("addr")
@@ -23,8 +28,31 @@ func (e defaultRequestDataExtractor) Secret(r *http.Request) string {
2328
func (e defaultRequestDataExtractor) Domain(r *http.Request) string {
2429
return r.URL.Query().Get("domain")
2530
}
26-
func (e defaultRequestDataExtractor) DdnsKey(r *http.Request) string {
27-
return r.URL.Query().Get("ddnskey")
31+
func (e defaultRequestDataExtractor) DdnsKeyName(r *http.Request, domain string) string {
32+
ddnsKeyName := r.URL.Query().Get("ddnskeyname")
33+
if ddnsKeyName != "" {
34+
return ddnsKeyName
35+
}
36+
ddnsKeyName = e.Zone(r, domain)
37+
if ddnsKeyName != "" {
38+
return ddnsKeyName
39+
}
40+
ddnsKeyName = e.Fqdn(r, domain)
41+
return ddnsKeyName
42+
}
43+
func (e defaultRequestDataExtractor) Zone(r *http.Request, domain string) string {
44+
zone := r.URL.Query().Get("zone")
45+
if zone != "" {
46+
return zone
47+
}
48+
zone = strings.TrimRight(e.appConfig.Zone, ".")
49+
if domain[len(domain)-1:] == "." {
50+
zone = ""
51+
}
52+
return zone
53+
}
54+
func (e defaultRequestDataExtractor) Fqdn(r *http.Request, domain string) string {
55+
return strings.TrimRight(escape(domain)+"."+e.Zone(r, domain), ".")
2856
}
2957

3058
type dynRequestDataExtractor struct{ defaultRequestDataExtractor }
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package main
2+
3+
import (
4+
"net/http"
5+
"testing"
6+
)
7+
8+
func verify(t *testing.T, r *http.Request, extractor requestDataExtractor, domain string, expected RecordUpdateRequest) {
9+
rru := RecordUpdateRequest{
10+
ddnsKeyName: extractor.DdnsKeyName(r, domain),
11+
zone: extractor.Zone(r, domain),
12+
fqdn: extractor.Fqdn(r, domain),
13+
}
14+
if rru.zone != expected.zone {
15+
t.Fatalf("Zone not configured but not empty: %s != %s", rru.zone, expected.zone)
16+
}
17+
18+
if rru.fqdn != expected.fqdn {
19+
t.Fatalf("Wrong fqdn: %s != %s", rru.fqdn, expected.fqdn)
20+
}
21+
22+
if rru.ddnsKeyName != expected.ddnsKeyName {
23+
t.Fatalf("Wrong ddnskeyname: %s != %s", rru.ddnsKeyName, expected.ddnsKeyName)
24+
}
25+
}
26+
27+
func TestExtractorUnconfiguredZone(t *testing.T) {
28+
var e = defaultRequestDataExtractor{appConfig: &Config{
29+
Zone: "",
30+
}}
31+
32+
domain := "foo.example.org"
33+
req, _ := http.NewRequest("GET", "/update?secret=changeme&domain="+domain+"&addr=1.2.3.4", nil)
34+
verify(t, req, e, domain, RecordUpdateRequest{
35+
zone: "",
36+
fqdn: "foo.example.org",
37+
ddnsKeyName: "foo.example.org",
38+
})
39+
}
40+
41+
func TestExtractorUnconfiguredZoneWithZoneInRequest(t *testing.T) {
42+
var e = defaultRequestDataExtractor{appConfig: &Config{
43+
Zone: "",
44+
}}
45+
46+
domain := "foo"
47+
req, _ := http.NewRequest("GET", "/update?secret=changeme&domain="+domain+"&addr=1.2.3.4&zone=example.org", nil)
48+
verify(t, req, e, domain, RecordUpdateRequest{
49+
zone: "example.org",
50+
fqdn: "foo.example.org",
51+
ddnsKeyName: "example.org",
52+
})
53+
}
54+
55+
func TestExtractorUnconfiguredZoneWithDDnskeyInRequest(t *testing.T) {
56+
var e = defaultRequestDataExtractor{appConfig: &Config{
57+
Zone: "",
58+
}}
59+
60+
domain := "foo.example.org"
61+
req, _ := http.NewRequest("GET", "/update?secret=changeme&domain="+domain+"&addr=1.2.3.4&ddnskeyname=example.org", nil)
62+
verify(t, req, e, domain, RecordUpdateRequest{
63+
zone: "",
64+
fqdn: "foo.example.org",
65+
ddnsKeyName: "example.org",
66+
})
67+
}
68+
69+
func TestExtractorConfiguredZoneAndOnlyWithHostname(t *testing.T) {
70+
var e = defaultRequestDataExtractor{appConfig: &Config{
71+
Zone: "example.org.",
72+
}}
73+
74+
domain := "foo"
75+
req, _ := http.NewRequest("GET", "/update?secret=changeme&domain="+domain+"&addr=1.2.3.4", nil)
76+
verify(t, req, e, domain, RecordUpdateRequest{
77+
zone: "example.org",
78+
fqdn: "foo.example.org",
79+
ddnsKeyName: "example.org",
80+
})
81+
}
82+
83+
func TestExtractorConfiguredZoneAndOnlyWithFQDN(t *testing.T) {
84+
var e = defaultRequestDataExtractor{appConfig: &Config{
85+
Zone: "example.org.",
86+
}}
87+
88+
domain := "foo.example.org."
89+
req, _ := http.NewRequest("GET", "/update?secret=changeme&domain="+domain+"&addr=1.2.3.4", nil)
90+
verify(t, req, e, domain, RecordUpdateRequest{
91+
zone: "",
92+
fqdn: "foo.example.org",
93+
ddnsKeyName: "foo.example.org",
94+
})
95+
}

0 commit comments

Comments
 (0)