Network.framework: Custom IP protocols with multicast and non-physical interfaces

I've been exploring custom IP protocols with Network.framework on macOS and have run into a couple of problems:

Loopback & bridge interfaces

let parameters = NWParameters(customIPProtocolNumber: 123)

let destination = NWEndpoint.hostPort(host: "127.0.0.1", port: 0)
let connection = NWConnection(to: destination, using: parameters)

connection.start(queue: .main)
connection.send(content: Data([1, 2, 3, 4]), completion: .contentProcessed({ error in
    print("error", error)
}))

Yields this error when host is directly connected to a virtual interface like bridge100 (the other end of my connection is a Linux VM) or lo0 (as in the example above):

[connection] nw_socket_connect [C1:1] connectx(12 (guarded), [srcif=0, srcaddr=<NULL>, dstaddr=127.0.0.1], SAE_ASSOCID_ANY, 0, NULL, 0, NULL, SAE_CONNID_ANY) failed: [49: Can't assign requested address]

If I change host to an address directly connected to en0 (my MacBook's Wi-Fi), I get no errors, and I can see the packet in Wireshark.

Multicast listeners

guard let allSPFRouters = try? NWMulticastGroup(for: [NWEndpoint.hostPort(host: "224.0.0.5", port: 0)]) else {
    print("Couldn't create NWMulticastGroup")
    return
}

let parameters = NWParameters(customIPProtocolNumber: 123)
let group = NWConnectionGroup(with: allSPFRouters, using: parameters)

group.setReceiveHandler(maximumMessageSize: 16384, rejectOversizedMessages: true) { (message, content, isComplete) in
    print("received", message, content, isComplete)
}
group.stateUpdateHandler = { print("state", $0) }
group.start(queue: .main)

Yields a number of errors, of which this one seems like the most relevant:

-[nw_listener_inbox_socket initWithParameters:delegate:] Cannot create listener with IP Protocol 123, dumping backtrace:

I did some spelunking in Ghidra, and it seems like nw_listener_inbox_socket_initWithParameters:delegate: might only allows you to join a multicast group if your protocol number is 6 (TCP) or 17 (UDP). 


So, the questions are:

  1. Is there something obvious I’m doing wrong?
  2. Are there any clever workarounds?

Here’s a repo with a repro. All the relevant code is in AppDelegate.swift. Tested on macOS 13.0.1 on a 14-inch MacBook Pro, with App Sandbox and Hardened Runtime disabled and an Xcoded-managed provisioning profile with the com.apple.developer.networking.custom-protocol entitlement.

Thanks in advance!

Network.framework: Custom IP protocols with multicast and non-physical interfaces
 
 
Q