aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/dns/dns.go6
-rw-r--r--lib/dns/dns_test.go7
-rw-r--r--lib/dns/rdata_soa.go31
-rw-r--r--lib/dns/server_options_test.go12
-rw-r--r--lib/dns/testdata/zone/with_soa_test.txt2
-rw-r--r--lib/dns/testdata/zone_soa_test.txt11
-rw-r--r--lib/dns/zone.go22
-rw-r--r--lib/dns/zone_test.go53
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())
+}