This is working for me:
let packet: [UInt8] = [
0x2c, 0x91, 0xab, 0x54, 0x3c, 0xbe, 0x3c, 0x22,
0xfb, 0x0c, 0x7b, 0x27, 0x08, 0x00, 0x45, 0x00,
0x00, 0x39, 0x07, 0x3a, 0x00, 0x00, 0x40, 0x11,
0xaf, 0x89, 0xc0, 0xa8, 0x01, 0x47, 0x01, 0x01,
0x01, 0x01, 0xfc, 0x0f, 0x00, 0x35, 0x00, 0x25,
0x8c, 0xf0, 0xe3, 0x0f, 0x01, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x65,
0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63,
0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
]
let etherHeaderSize = 14
let ip4HeaderSize = 20
packet.withUnsafeBytes { buf in
let bytes = buf.baseAddress!
let udpHeader = (bytes + etherHeaderSize + ip4HeaderSize).bindMemory(to: udphdr.self, capacity: 1)
print(UInt16(bigEndian: udpHeader.pointee.uh_dport))
}
It prints 53, as expected.
In creating this test I saw two problems with your code:
-
You pass udpHeaderSize to the capacity parameter, not 1. That parameter is meant to be the number of items at that location, not the size of the item in bytes. IMO this is unlikely to be the cause of your problem.
-
You had Int(udpHeader.pointee.uh_dport).bigEndian, which is backwards. You want UInt16(bigEndian: udpHeader.pointee.uh_dport).
Having said that, I generally discourage folks from doing this sort of pointer manipulation, in Swift specifically but also in C. It’s very easy to break the rules and end up relying on undefined behaviour.
IMO you’re much better off parsing packets byte-by-byte. That might be too slow in a packet filter provider, but I recommend that you start by assuming it’s not too slow and then only mess around with pointers once you’ve proved that you have a performance problem.
Pasted in below is an example of how I’d approach this. You’d be amazed at how efficient this can be once you let the optimiser loose on it (-:
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
extension Collection where Self.SubSequence == Self {
mutating func consume(count: Int) -> Self.SubSequence? {
let result = self.prefix(count)
guard result.count == count else { return nil }
self = self.dropFirst(count)
return result
}
}
extension Collection where Self.SubSequence == Self, Self.Element == UInt8 {
mutating func consume<T>(bigEndian _: T.Type) -> T? where T: UnsignedInteger {
guard let bytes = self.consume(count: MemoryLayout<T>.size) else { return nil }
return bytes.reduce(0, { $0 << 8 | T($1) } )
}
}
packet.withUnsafeBytes { buf in
let etherHeaderSize = 14
let ip4HeaderSize = 20
var remainder = buf[...]
guard let ethernetHeader = remainder.consume(count: etherHeaderSize) else { fatalError() }
guard let ipHeader = remainder.consume(count: ip4HeaderSize) else { fatalError() }
guard
let srcPort = remainder.consume(bigEndian: UInt16.self),
let dstPort = remainder.consume(bigEndian: UInt16.self),
let length = remainder.consume(bigEndian: UInt16.self),
let checksum = remainder.consume(bigEndian: UInt16.self)
else { fatalError() }
print(srcPort) // 64527
print(dstPort) // 53
print(length) // 37
print(checksum) // 36080
}