Repository: miekg/dns
Pull request #1374 (2022-05-17 14:24:44)

Add more detail to NSEC packing errors
Add 'in the type bitmap' to make clear where in the RR the error occurs.
Also use 'NSEC(3)' - as this code is shared between NSEC and NSEC3, the
first error used NSECx.

Technically backwards incompatible, but checking strings in errors as
bad practice (although this lib lacks library types).

See #1373

Signed-off-by: Miek Gieben <miek@miek.nl>



Patch:
diff --git a/defaults.go b/defaults.go
index d47b0b1f..f2cdbf43 100644
--- a/defaults.go
+++ b/defaults.go
@@ -218,6 +218,11 @@ func IsDomainName(s string) (labels int, ok bool) {
 
 			wasDot = false
 		case '.':
+			if i == 0 && len(s) > 1 {
+				// leading dots are not legal except for the root zone
+				return labels, false
+			}
+
 			if wasDot {
 				// two dots back to back is not legal
 				return labels, false
diff --git a/msg.go b/msg.go
index 60a2e8c3..89ebb64a 100644
--- a/msg.go
+++ b/msg.go
@@ -265,6 +265,11 @@ loop:
 
 			wasDot = false
 		case '.':
+			if i == 0 && len(s) > 1 {
+				// leading dots are not legal except for the root zone
+				return len(msg), ErrRdata
+			}
+
 			if wasDot {
 				// two dots back to back is not legal
 				return len(msg), ErrRdata
diff --git a/msg_helpers.go b/msg_helpers.go
index b049028b..ea2035cd 100644
--- a/msg_helpers.go
+++ b/msg_helpers.go
@@ -476,7 +476,7 @@ func unpackDataNsec(msg []byte, off int) ([]uint16, int, error) {
 	length, window, lastwindow := 0, 0, -1
 	for off < len(msg) {
 		if off+2 > len(msg) {
-			return nsec, len(msg), &Error{err: "overflow unpacking nsecx"}
+			return nsec, len(msg), &Error{err: "overflow unpacking NSEC(3)"}
 		}
 		window = int(msg[off])
 		length = int(msg[off+1])
@@ -484,17 +484,17 @@ func unpackDataNsec(msg []byte, off int) ([]uint16, int, error) {
 		if window <= lastwindow {
 			// RFC 4034: Blocks are present in the NSEC RR RDATA in
 			// increasing numerical order.
-			return nsec, len(msg), &Error{err: "out of order NSEC block"}
+			return nsec, len(msg), &Error{err: "out of order NSEC(3) block in type bitmap"}
 		}
 		if length == 0 {
 			// RFC 4034: Blocks with no types present MUST NOT be included.
-			return nsec, len(msg), &Error{err: "empty NSEC block"}
+			return nsec, len(msg), &Error{err: "empty NSEC(3) block in type bitmap"}
 		}
 		if length > 32 {
-			return nsec, len(msg), &Error{err: "NSEC block too long"}
+			return nsec, len(msg), &Error{err: "NSEC(3) block too long in type bitmap"}
 		}
 		if off+length > len(msg) {
-			return nsec, len(msg), &Error{err: "overflowing NSEC block"}
+			return nsec, len(msg), &Error{err: "overflowing NSEC(3) block in type bitmap"}
 		}
 
 		// Walk the bytes in the window and extract the type bits


Test patch:
diff --git a/labels_test.go b/labels_test.go
index 3e672fec..dbe9a229 100644
--- a/labels_test.go
+++ b/labels_test.go
@@ -176,7 +176,10 @@ func TestIsDomainName(t *testing.T) {
 		lab int
 	}
 	names := map[string]*ret{
-		"..":                     {false, 1},
+		".":                      {true, 1},
+		"..":                     {false, 0},
+		"double-dot..test":       {false, 1},
+		".leading-dot.test":      {false, 0},
 		"@.":                     {true, 1},
 		"www.example.com":        {true, 3},
 		"www.e%ample.com":        {true, 3},