Skip to content

Commit 95fda89

Browse files
torinmrTorin Rudeen
andauthored
Fix bug in DNSSD IPv6 address string conversion. (#14)
* Fix bug in DNSSD IPv6 address string conversion. The old implementation converted each byte to a hexadecimal number separately, meaning that leading zeros in a byte would be dropped even in the middle of a group. For example, the address 2620:149:110b:470e:0:0:0:e1a was incorrectly rendered as 2620:149:11b:47e:0:0:0:e1a, with zeros dropped in the 3rd and 4th octets. I figured the most robust fix would be to use inet_ntop to format the address, which produces a correctly abbreviated address like 2620:149:110b:470e::e1a. This is the approach used in DNSResolver_c-ares.swift. * Throw error when too-short address is returned * Fix formatting issues * Print an error in soundness.sh if swiftformat is not installed --------- Co-authored-by: Torin Rudeen <[email protected]>
1 parent 5aa112c commit 95fda89

File tree

5 files changed

+51
-24
lines changed

5 files changed

+51
-24
lines changed

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ var caresExclude = [
1212
]
1313

1414
do {
15-
if !(try FileManager.default.contentsOfDirectory(atPath: "./Sources/CAsyncDNSResolver/c-ares/CMakeFiles").isEmpty) {
15+
if try !(FileManager.default.contentsOfDirectory(atPath: "./Sources/CAsyncDNSResolver/c-ares/CMakeFiles").isEmpty) {
1616
caresExclude.append("./c-ares/CMakeFiles/")
1717
}
1818
} catch {

Sources/AsyncDNSResolver/AsyncDNSResolver.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public struct AsyncDNSResolver {
2626
#if canImport(Darwin)
2727
self.init(DNSSDDNSResolver())
2828
#else
29-
self.init(try CAresDNSResolver())
29+
try self.init(CAresDNSResolver())
3030
#endif
3131
}
3232

@@ -44,7 +44,7 @@ public struct AsyncDNSResolver {
4444
/// - Parameters:
4545
/// - options: Options to create ``CAresDNSResolver`` with.
4646
public init(options: CAresDNSResolver.Options) throws {
47-
self.init(try CAresDNSResolver(options: options))
47+
try self.init(CAresDNSResolver(options: options))
4848
}
4949

5050
/// See ``DNSResolver/queryA(name:)``.

Sources/AsyncDNSResolver/dnssd/DNSResolver_dnssd.swift

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -220,19 +220,14 @@ extension DNSSD {
220220
throw AsyncDNSResolver.Error.noData()
221221
}
222222

223-
let bufferPtr = UnsafeBufferPointer(start: ptr, count: Int(length))
224-
var buffer = ByteBuffer(bytes: bufferPtr)
225-
226-
guard let addressBytes = buffer.readInteger(as: UInt32.self) else {
227-
throw AsyncDNSResolver.Error.badResponse("failed to read address")
228-
}
229-
230-
let address = withUnsafeBytes(of: addressBytes) { buffer in
231-
let buffer = buffer.bindMemory(to: UInt8.self)
232-
return "\(buffer[3]).\(buffer[2]).\(buffer[1]).\(buffer[0])"
223+
guard length >= MemoryLayout<in_addr>.size else {
224+
throw AsyncDNSResolver.Error.badResponse()
233225
}
234226

235-
return ARecord(address: .IPv4(address), ttl: nil)
227+
var parsedAddressBytes = [CChar](repeating: 0, count: Int(INET_ADDRSTRLEN))
228+
inet_ntop(AF_INET, ptr, &parsedAddressBytes, socklen_t(INET_ADDRSTRLEN))
229+
let parsedAddress = String(cString: parsedAddressBytes)
230+
return ARecord(address: .IPv4(parsedAddress), ttl: nil)
236231
}
237232

238233
func generateReply(records: [ARecord]) throws -> [ARecord] {
@@ -248,18 +243,14 @@ extension DNSSD {
248243
throw AsyncDNSResolver.Error.noData()
249244
}
250245

251-
let bufferPtr = UnsafeBufferPointer(start: ptr, count: Int(length))
252-
var buffer = ByteBuffer(bytes: bufferPtr)
253-
254-
guard let addressBytes = buffer.readBytes(length: 16) else {
255-
throw AsyncDNSResolver.Error.badResponse("failed to read address")
246+
guard length >= MemoryLayout<in6_addr>.size else {
247+
throw AsyncDNSResolver.Error.badResponse()
256248
}
257249

258-
let address = stride(from: 0, to: addressBytes.endIndex, by: 2).map {
259-
"\(String(addressBytes[$0], radix: 16))\(String(addressBytes[$0.advanced(by: 1)], radix: 16))"
260-
}.joined(separator: ":")
261-
262-
return AAAARecord(address: .IPv6(address), ttl: nil)
250+
var parsedAddressBytes = [CChar](repeating: 0, count: Int(INET6_ADDRSTRLEN))
251+
inet_ntop(AF_INET6, ptr, &parsedAddressBytes, socklen_t(INET6_ADDRSTRLEN))
252+
let parsedAddress = String(cString: parsedAddressBytes)
253+
return AAAARecord(address: .IPv6(parsedAddress), ttl: nil)
263254
}
264255

265256
func generateReply(records: [AAAARecord]) throws -> [AAAARecord] {

Tests/AsyncDNSResolverTests/dnssd/DNSSDDNSResolverTests.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,36 @@ final class DNSSDDNSResolverTests: XCTestCase {
104104
XCTAssertFalse(reply.isEmpty, "should have SRV record(s)")
105105
}
106106

107+
func test_parseA() throws {
108+
let addrBytes: [UInt8] = [38, 32, 1, 73]
109+
try addrBytes.withUnsafeBufferPointer {
110+
let record = try DNSSD.AQueryReplyHandler.instance.parseRecord(data: $0.baseAddress, length: UInt16($0.count))
111+
XCTAssertEqual(record, ARecord(address: .IPv4("38.32.1.73"), ttl: nil))
112+
}
113+
}
114+
115+
func test_parseATooShort() throws {
116+
let addrBytes: [UInt8] = [38, 32, 1]
117+
try addrBytes.withUnsafeBufferPointer {
118+
XCTAssertThrowsError(
119+
try DNSSD.AQueryReplyHandler.instance.parseRecord(
120+
data: $0.baseAddress, length: UInt16($0.count)
121+
)
122+
)
123+
}
124+
}
125+
126+
func test_parseAAAATooShort() throws {
127+
let addrBytes: [UInt8] = [38, 32, 1, 73, 17, 11, 71, 14, 0, 0, 0, 0, 0, 0, 14]
128+
try addrBytes.withUnsafeBufferPointer {
129+
XCTAssertThrowsError(
130+
try DNSSD.AAAAQueryReplyHandler.instance.parseRecord(
131+
data: $0.baseAddress, length: UInt16($0.count)
132+
)
133+
)
134+
}
135+
}
136+
107137
func test_concurrency() async throws {
108138
func run(
109139
times: Int = 100,

scripts/soundness.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ function replace_acceptable_years() {
2121
sed -e 's/202[012]-202[123]/YEARS/' -e 's/202[0123]/YEARS/'
2222
}
2323

24+
if ! hash swiftformat &> /dev/null
25+
then
26+
printf "\033[0;31mPlease install swiftformat (https://github.com/nicklockwood/SwiftFormat) and run again.\033[0m\n"
27+
exit 1
28+
fi
29+
2430
printf "=> Checking format... "
2531
FIRST_OUT="$(git status --porcelain)"
2632
swiftformat . > /dev/null 2>&1

0 commit comments

Comments
 (0)