diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/dns/dns.go | 6 | ||||
| -rw-r--r-- | lib/dns/dns_test.go | 7 | ||||
| -rw-r--r-- | lib/dns/rdata_soa.go | 31 | ||||
| -rw-r--r-- | lib/dns/server_options_test.go | 12 | ||||
| -rw-r--r-- | lib/dns/testdata/zone/with_soa_test.txt | 2 | ||||
| -rw-r--r-- | lib/dns/testdata/zone_soa_test.txt | 11 | ||||
| -rw-r--r-- | lib/dns/zone.go | 22 | ||||
| -rw-r--r-- | lib/dns/zone_test.go | 53 |
8 files changed, 114 insertions, 30 deletions
diff --git a/lib/dns/dns.go b/lib/dns/dns.go index f7a9df17..31bfec8d 100644 --- a/lib/dns/dns.go +++ b/lib/dns/dns.go @@ -134,3 +134,9 @@ var rcodeNames = map[ResponseCode]string{ RCodeNotImplemented: "ERR_NOT_IMPLEMENTED", RCodeRefused: "ERR_REFUSED", } + +// timeNow return the current time. +// This variable provides to help mocking the test that require time value. +var timeNow = func() time.Time { + return time.Now() +} diff --git a/lib/dns/dns_test.go b/lib/dns/dns_test.go index 1d9bac6a..207b5a3c 100644 --- a/lib/dns/dns_test.go +++ b/lib/dns/dns_test.go @@ -15,6 +15,9 @@ const ( testServerAddress = "127.0.0.1:5300" testDoTServerAddress = "127.0.0.1:18053" testTLSPort = 18053 + + // Equal to 2023-08-05 07:53:20 +0000 UTC. + testNowEpoch = 1691222000 ) var ( @@ -24,6 +27,10 @@ var ( func TestMain(m *testing.M) { log.SetFlags(0) + timeNow = func() time.Time { + return time.Unix(testNowEpoch, 0) + } + var ( serverOptions = &ServerOptions{ ListenAddress: "127.0.0.1:5300", diff --git a/lib/dns/rdata_soa.go b/lib/dns/rdata_soa.go index f6964c5e..86a8c02f 100644 --- a/lib/dns/rdata_soa.go +++ b/lib/dns/rdata_soa.go @@ -6,14 +6,14 @@ package dns import ( "strings" - "time" ) +// Default SOA record value. const ( - defaultRName string = "root" - defaultRefresh int32 = 1 * 24 * 60 * 60 // 1 Day. - defaultRetry int32 = 1 * 60 * 60 // 1 Hour. - defaultMinimumTTL uint32 = 1 * 60 * 60 // 1 Hour. + DefaultSoaRName string = `root` + DefaultSoaRefresh int32 = 1 * 24 * 60 * 60 // 1 Day. + DefaultSoaRetry int32 = 1 * 60 * 60 // 1 Hour. + DefaultSoaMinimumTtl uint32 = 1 * 60 * 60 // 1 Hour. ) // RDataSOA contains the authority of zone. @@ -52,6 +52,17 @@ type RDataSOA struct { Minimum uint32 } +// NewRDataSOA create and initialize the new SOA record using default values +// for Serial, Refresh, Retry, Expiry, and Minimum. +func NewRDataSOA(mname, rname string) (soa *RDataSOA) { + soa = &RDataSOA{ + MName: mname, + RName: rname, + } + soa.init() + return soa +} + // init initialize the SOA record by setting fields to its default value if // its empty. func (soa *RDataSOA) init() { @@ -61,18 +72,18 @@ func (soa *RDataSOA) init() { if len(soa.RName) > 0 { soa.RName = strings.ToLower(soa.RName) } else { - soa.RName = defaultRName + soa.RName = DefaultSoaRName } if soa.Serial == 0 { - soa.Serial = uint32(time.Now().Unix()) + soa.Serial = uint32(timeNow().Unix()) } if soa.Refresh == 0 { - soa.Refresh = defaultRefresh + soa.Refresh = DefaultSoaRefresh } if soa.Retry == 0 { - soa.Retry = defaultRetry + soa.Retry = DefaultSoaRetry } if soa.Minimum == 0 { - soa.Minimum = defaultMinimumTTL + soa.Minimum = DefaultSoaMinimumTtl } } diff --git a/lib/dns/server_options_test.go b/lib/dns/server_options_test.go index dee0ba5f..9dddcb44 100644 --- a/lib/dns/server_options_test.go +++ b/lib/dns/server_options_test.go @@ -22,13 +22,7 @@ func TestServerOptionsInit(t *testing.T) { var ( ip = net.ParseIP("0.0.0.0") - defSoa = RDataSOA{ - RName: defaultRName, - Serial: uint32(time.Now().Unix()), - Refresh: defaultRefresh, - Retry: defaultRetry, - Minimum: defaultMinimumTTL, - } + defSoa = NewRDataSOA(``, ``) cases []testCase c testCase @@ -41,7 +35,7 @@ func TestServerOptionsInit(t *testing.T) { exp: &ServerOptions{ ListenAddress: "0.0.0.0:53", HTTPIdleTimeout: defaultHTTPIdleTimeout, - SOA: defSoa, + SOA: *defSoa, PruneDelay: time.Hour, PruneThreshold: -1 * time.Hour, ip: ip, @@ -74,7 +68,7 @@ func TestServerOptionsInit(t *testing.T) { NameServers: []string{ "udp://127.0.0.1", }, - SOA: defSoa, + SOA: *defSoa, PruneDelay: time.Hour, PruneThreshold: -1 * time.Hour, ip: ip, diff --git a/lib/dns/testdata/zone/with_soa_test.txt b/lib/dns/testdata/zone/with_soa_test.txt index d63ba4ea..632d4058 100644 --- a/lib/dns/testdata/zone/with_soa_test.txt +++ b/lib/dns/testdata/zone/with_soa_test.txt @@ -7,7 +7,7 @@ b 604800 IN A 192.1.1.1 <<< zone_out.txt $ORIGIN test.dev. -@ SOA test.dev. . 0 0 0 0 0 +@ SOA test.dev. . 1691222000 86400 3600 0 3600 b 604800 IN A 192.1.1.1 <<< message_0.hex diff --git a/lib/dns/testdata/zone_soa_test.txt b/lib/dns/testdata/zone_soa_test.txt new file mode 100644 index 00000000..355ac40f --- /dev/null +++ b/lib/dns/testdata/zone_soa_test.txt @@ -0,0 +1,11 @@ +<<< NewZone +$ORIGIN test.soa +@ SOA test.soa root 1691222000 86400 3600 0 3600 + +<<< Add_SOA +$ORIGIN test.soa +@ SOA new.soa admin 1691222000 86400 3600 0 3600 + +<<< Remove_SOA +$ORIGIN test.soa +@ SOA test.soa root 1691222000 86400 3600 0 3600 diff --git a/lib/dns/zone.go b/lib/dns/zone.go index c28ae9e2..59b58619 100644 --- a/lib/dns/zone.go +++ b/lib/dns/zone.go @@ -21,19 +21,18 @@ type Zone struct { Path string `json:"-"` Name string messages []*Message - SOA RDataSOA + SOA *RDataSOA } // NewZone create and initialize new zone. -func NewZone(file, name string) *Zone { - return &Zone{ - Path: file, - Name: name, - SOA: RDataSOA{ - MName: name, - }, +func NewZone(file, name string) (zone *Zone) { + zone = &Zone{ + Path: file, + Name: name, + SOA: NewRDataSOA(name, ``), Records: make(ZoneRecords), } + return zone } // LoadZoneDir load DNS record from zone formatted files in @@ -157,7 +156,9 @@ func (zone *Zone) Add(rr *ResourceRecord) (err error) { if rr.Type == RecordTypeSOA { soa, _ = rr.Value.(*RDataSOA) if soa != nil { - zone.SOA = *soa + var cloneSoa = *soa + zone.SOA = &cloneSoa + zone.SOA.init() } } else { zone.Records.add(rr) @@ -204,9 +205,10 @@ func (zone *Zone) Messages() []*Message { } // Remove a ResourceRecord from zone file. +// If the RR is SOA it will reset the value back to default. func (zone *Zone) Remove(rr *ResourceRecord) (err error) { if rr.Type == RecordTypeSOA { - zone.SOA = RDataSOA{} + zone.SOA = NewRDataSOA(zone.Name, ``) } else { if zone.Records.remove(rr) { err = zone.Save() diff --git a/lib/dns/zone_test.go b/lib/dns/zone_test.go index 13a8deee..3b713f68 100644 --- a/lib/dns/zone_test.go +++ b/lib/dns/zone_test.go @@ -236,3 +236,56 @@ func TestZoneParseDirectiveTTL(t *testing.T) { test.Assert(t, `ttl`, c.exp, m.ttl) } } + +// TestZone_SOA test related to SOA, when SOA record updated, removed, or +// other records added or removed. +func TestZone_SOA(t *testing.T) { + var ( + tdata *test.Data + err error + ) + + tdata, err = test.LoadData(`testdata/zone_soa_test.txt`) + if err != nil { + t.Fatal(err) + } + + var ( + zone = NewZone(``, `test.soa`) + buf bytes.Buffer + exp []byte + ) + + _, _ = zone.WriteTo(&buf) + exp = tdata.Output[`NewZone`] + test.Assert(t, `NewZone`, string(exp), buf.String()) + + // Add SOA. + var ( + rdataSoa = NewRDataSOA(`new.soa`, `admin`) + rrSoa = &ResourceRecord{ + Value: rdataSoa, + Name: zone.Name, + Type: RecordTypeSOA, + Class: RecordClassIN, + } + ) + + err = zone.Add(rrSoa) + if err != nil { + t.Fatal(err) + } + + buf.Reset() + _, _ = zone.WriteTo(&buf) + exp = tdata.Output[`Add_SOA`] + test.Assert(t, `Add_SOA`, string(exp), buf.String()) + + // Remove SOA. + _ = zone.Remove(rrSoa) + + buf.Reset() + _, _ = zone.WriteTo(&buf) + exp = tdata.Output[`Remove_SOA`] + test.Assert(t, `Remove_SOA`, string(exp), buf.String()) +} |
