Skip to content

Commit c778d70

Browse files
committed
Additional PR feedback.
- Fold labels to lowercase. - Reject compression pointer recursion.
1 parent f716800 commit c778d70

2 files changed

Lines changed: 61 additions & 3 deletions

File tree

Sources/DNSServer/Records/DNSName.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public struct DNSName: Sendable, Hashable, CustomStringConvertible {
3333
public init(_ string: String) {
3434
// Remove trailing dot if present, then split
3535
let normalized = string.hasSuffix(".") ? String(string.dropLast()) : string
36-
self.labels = normalized.isEmpty ? [] : normalized.split(separator: ".").map(String.init)
36+
self.labels = normalized.isEmpty ? [] : normalized.split(separator: ".").map { String($0).lowercased() }
3737
}
3838

3939
/// The wire format size of this name in bytes.
@@ -112,7 +112,11 @@ public struct DNSName: Sendable, Hashable, CustomStringConvertible {
112112

113113
// Calculate pointer offset from message start
114114
let pointer = Int(length & 0x3F) << 8 | Int(buffer[offset + 1])
115-
offset = messageStart + pointer
115+
let pointerTarget = messageStart + pointer
116+
guard pointerTarget < offset else {
117+
throw DNSBindError.unmarshalFailure(type: "DNSName", field: "compression pointer not prior")
118+
}
119+
offset = pointerTarget
116120
jumped = true
117121
continue
118122
}
@@ -133,7 +137,7 @@ public struct DNSName: Sendable, Hashable, CustomStringConvertible {
133137
throw DNSBindError.unmarshalFailure(type: "DNSName", field: "label encoding")
134138
}
135139

136-
labels.append(label)
140+
labels.append(label.lowercased())
137141
offset += Int(length)
138142
}
139143

Tests/DNSServerTests/RecordsTests.swift

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,60 @@ struct RecordsTests {
9696
_ = try name.appendBuffer(&buffer, offset: 0)
9797
}
9898
}
99+
100+
@Test("Lowercase labels on init")
101+
func lowercaseLabelsOnInit() {
102+
let name = DNSName("EXAMPLE.COM")
103+
#expect(name.labels == ["example", "com"])
104+
}
105+
106+
@Test("Lowercase labels on init with trailing dot")
107+
func lowercaseLabelsOnInitTrailingDot() {
108+
let name = DNSName("Example.Com.")
109+
#expect(name.labels == ["example", "com"])
110+
}
111+
112+
@Test("Lowercase labels from wire format")
113+
func lowercaseLabelsFromWire() throws {
114+
// Wire-encode "EXAMPLE.COM" with uppercase bytes, then decode
115+
let upper = DNSName(labels: ["EXAMPLE", "COM"])
116+
var buffer = [UInt8](repeating: 0, count: 64)
117+
_ = try upper.appendBuffer(&buffer, offset: 0)
118+
119+
var parsed = DNSName()
120+
_ = try parsed.bindBuffer(&buffer, offset: 0)
121+
#expect(parsed.labels == ["example", "com"])
122+
}
123+
124+
@Test("Reject forward compression pointer")
125+
func rejectForwardCompressionPointer() throws {
126+
// Craft a packet with a forward compression pointer at offset 12 pointing to offset 20
127+
// Header (12 bytes) + pointer bytes
128+
var buffer = [UInt8](repeating: 0, count: 32)
129+
// At offset 0: compression pointer to offset 20 (forward)
130+
buffer[0] = 0xC0
131+
buffer[1] = 0x14 // points to offset 20, which is > 0
132+
133+
#expect(throws: DNSBindError.self) {
134+
var b = buffer
135+
var name = DNSName()
136+
_ = try name.bindBuffer(&b, offset: 0)
137+
}
138+
}
139+
140+
@Test("Reject self-referential compression pointer")
141+
func rejectSelfReferentialCompressionPointer() throws {
142+
var buffer = [UInt8](repeating: 0, count: 16)
143+
// At offset 0: compression pointer pointing back to offset 0 (same location)
144+
buffer[0] = 0xC0
145+
buffer[1] = 0x00 // points to offset 0 == current offset, not prior
146+
147+
#expect(throws: DNSBindError.self) {
148+
var b = buffer
149+
var name = DNSName()
150+
_ = try name.bindBuffer(&b, offset: 0)
151+
}
152+
}
99153
}
100154

101155
// MARK: - Question Tests

0 commit comments

Comments
 (0)