Lookup IP Address by User Defined Ethernet Name on Mac OS X

December 19th, 2012 by Cody

This proved to be far more tricky than I thought it would. The documentation not being clear to me and lack of example code made things convoluted. So this involved a lot of trial and error with the SCNetworkConfiguration APIs and reading the System Configuration Schema. I had found examples in our code base on how to look up the BSD name based on the user defined name by iterating through the kSCPrefNetworkServices in SCNetworkSetRef returned from SCNetworkSetCopyCurrent(). Once you have the BSD name, it’s pretty simple to lookup the IP address and subnet mask from it.

The problem I ran into is if the user has two network services configured on the same ethernet device. So say the user has two network services, Ethernet 1 and Ethernet 2, both configured on en0. I want the IP address for Ethernet 2 network service. So I fetch it’s BSD name which is en0, and then see en0 has two IP Addresses with no way to link back which IP address belongs to which network service. My first attempt was to go through SCNetworkProtocolGetConfiguration(). Which sort of worked, however quickly realized that if the ConfigMethod was set to DHCP, I couldn’t get any IPv4 info from the protocol configuration dictionary.

Finally realized the trick was to use the System Configuration Schema. The solution is to look up the NetworkServiceRef using the user defined name. Then access the dynamic store information for the network service using SCDynamicStoreKeyCreateNetworkServiceEntity() and SCDynamicStoreCopyValue(). The information is stored down in State:/Network/Service/ServiceID/IPv4.

I’m worried that I might be shaving a yak here. The whole reason I’m doing this is because I need to be able to broadcast messages on the ethernet device that the user specifies. The solution I came up with was to calculate the broadcast address based on the selected device, and use sendto() to broadcast to that destination. This will fall through the routing table and out the proper device. If I was on Linux, I could just SO_BINDTODEVICE, but Mac will be having none of that SO_BINDTODEVICE hooligans. If you know of a better solution for Mac to broadcast on a specific device or get the broadcast address, please let me know.

Enough talk, here is the code I use to fetch the IP address and broadcast address. Note that CopyIPv4NetworkProtocolWithUserDefinedName() isn’t actually used or needed for this solution. I created it when trying to solve this another way and thought it would prove useful to leave in. Enjoy!

Update (04/25/2013): Fixed an issue where the System Configuration could end up with zombie network services. So if you had named a service the same name as one of the zombie services, then there was a good chance it would attempt to pull IP info from that zombie service which has no IP info. Also fixed some memory leaks.

You really make it appear really easy together with your presentation but I to find this matter to be really something which I feel I’d never understand. It seems too complex and very large for me. I am taking a look ahead for your subsequent post, I will attempt to get the dangle of it!

Thanks, I think it's just a lot of information to sift through. Lot of reading documentation and trial and error to make sense of it all. I need to update the code, as I did find an issue where there can be zombie service names which means it can't find IPv4 address information even if you have proper name. Also found out there is an IP_BOUND_IF for Mac OSX which I believe would be a much simpler solution to binding outbound broadcast messages to a specific interface. Wish I could find more time to post more code snippets!