objective-cmacosnetwork-programmingbroadcastbootp

How to send UDP broadcast packets through all interfaces in Objective-C / OS X 10.8 (DHCP)


I am creating a small utillity which has to serve an IP address and parameters over BOOTP on my MacBook Pro.

I have used the AsyncUdpSocket library from GitHub (thanks RobbieHanson) and when I have my machine configured with just the wired ethernet connected (Airport Off) then it works. However, as soon as I enable my Wifi as well, all the broadcast replys go down the Wifi interface instead. This causes the wired clients to get no answer.

Initialise/Receive Code:

if (![socket bindToAddress:@"0.0.0.0" port:67 error:&err])
    NSLog(@"Error: unable to bind (%@)", [err localizedDescription]);
[socket enableBroadcast:YES error:&err];
[socket receiveWithTimeout:-1 tag:0];

Send Code:

[sock sendData:packetData toHost:@"255.255.255.255" port:68 withTimeout:-1 tag:0];

I am sure there must be a way to do this, but this is my first OS X program and I am struggling to master my google-search etiquette to suit the frameworks :)

UPDATE

I have messed about with my code tonight and inspected what the AsyncUdpSocket is doing when I am calling it. Essentially I have the following situation; if I call bindToAddress and supply 10.0.0.1 (the address assigned to my ETH NIC) then I neither receive any packets NOR can I send them. However, if I pass nil into the method then I can send a message AND receive the broadcasts - the downside being that the sending goes out over my WIFI NIC (default route)

In the background - the AsyncUdpSocket library is calling CFSocketSetAddress with either IFADDR_ANY when supplied a nil value OR a populated IFADDR struct of 10.0.0.1 if that is supplied. No errors are thrown and so it should be expected to work.

Any ideas? I am going up the wall and just want this solved. I really like the async nature of teh library so I don't want to throw it out.


Solution

  • I think you have to

    1. Get the list of all network interfaces on your machine,
    2. For each interface, create a socket and bind it to the interface address.
    3. Send/receive on all sockets, one for each interface.

    Part 1 can e.g. done with getifaddrs() (type "man getifaddrs" in the Terminal). I don't know if there is also a easier-to-use function in CoreFoundation.