I am trying to fetch static routes added on my mac machine by DHCP server. I am able to get DHCP info using SCDynamicStoreCopyDHCPInfo and then get DHCP options using DHCPInfoGetOptionData. However, I could not find any API that can help me parse the raw data returned by DHCPInfoGetOptionData. Since macOS is parsing and adding these static routes and also displaying them in AdditionalRoutes of service, is there any API available to developers to parse this raw data into destination, mask and gateway?
is there any API available to developers to parse this raw data into destination, mask and gateway?
No. You’re right that macOS has this code, but it’s not exposed as an API.
Having said that, the structure defined in RFC 3442 isn’t to too hard to parse. I’ve included a snippet below that should do the trick.
Note This code relies on the helpers from this post.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
func parseDCHPOption121(_ input: Data) throws -> [DHCPOption121Entry] {
var result: [DHCPOption121Entry] = []
var residual = input
while !residual.isEmpty {
guard let prefix = residual.parseBigEndian(UInt8.self) else {
throw DHCPOptionError.prefixExpected
}
let prefixByteCount: Int
switch prefix {
case 0: prefixByteCount = 0
case 1...8: prefixByteCount = 1
case 9...16: prefixByteCount = 2
case 17...24: prefixByteCount = 3
case 25...32: prefixByteCount = 4
default:
throw DHCPOptionError.prefixOutOfRange
}
guard var networkBytes = residual.parseBytes(count: prefixByteCount) else {
throw DHCPOptionError.desinationExpected
}
networkBytes.append(contentsOf: .init(repeating: 0, count: 4 - prefixByteCount))
let network = networkBytes.parseBigEndian(UInt32.self)!
guard var routerBytes = residual.parseBytes(count: 4) else {
throw DHCPOptionError.routerExpected
}
let router = routerBytes.parseBigEndian(UInt32.self)!
result.append(.init(prefix: prefix, network: .init(s_addr: network.bigEndian), router: .init(s_addr: router.bigEndian)))
}
return result
}
struct DHCPOption121Entry: CustomDebugStringConvertible {
var prefix: UInt8
var network: in_addr
var router: in_addr
var debugDescription: String {
"\(String(cString: inet_ntoa(self.network)))/\(self.prefix) -> \(String(cString: inet_ntoa(self.router)))"
}
}
enum DHCPOptionError: Error {
case prefixExpected
case prefixOutOfRange
case desinationExpected
case routerExpected
}
let input = Data([
// destination N router N
0, 1, 2, 3, 4,
8, 10, 4, 5, 6, 7,
24, 10, 0, 0, 8, 9, 10, 11,
16, 10, 17, 12, 13, 14, 15,
24, 10, 27, 129, 16, 17, 18, 19,
25, 10, 229, 0, 128, 20, 21, 22, 23,
32, 10, 198, 122, 47, 24, 25, 26, 27,
])
func test() throws {
let result = try parseDCHPOption121(input)
for r in result {
print(r)
}
// prints:
//
// 0.0.0.0/0 -> 1.2.3.4
// 10.0.0.0/8 -> 4.5.6.7
// 10.0.0.0/24 -> 8.9.10.11
// 10.17.0.0/16 -> 12.13.14.15
// 10.27.129.0/24 -> 16.17.18.19
// 10.229.0.128/25 -> 20.21.22.23
// 10.198.122.47/32 -> 24.25.26.27
}