I am tasked with listing all unicast interfaces (IP-address & subnet via netmask (IPv4) or prefix length (IPv6)) on the local machine. Being new to win32 API, I am reading GetAdaptersAddress docs. There is an example which is quite clear:
GetAdaptersAddresses
with increasing buffer size until the results fit into the allocated memory chunkpCurrAddresses
):
pCurrAddresses->FirstUnicastAddresses
linked list to retrieve all IP addresses (SOCKET_ADDRESS and its LPSOCKADDR Address->lpSockAddr
member); it is a sockaddr_in*
or sockaddr_in6*
depending on lpSockAddr.sa_family
(AF_INET
or AF_INET6
)At this moment, I have IP addresses.
How about netmask/prefix? This seems to be what PIP_ADAPTER_PREFIX_XP (and its SOCKET_ADDRESS Address
field) is about. That is another linked list, accessible from PIP_ADAPTER_ADDRESSES
through ->FirstPrefix
.
Unhelpfully, the docs state that prefixes may not be ordered the same as addresses:
In addition, the linked IP_ADAPTER_UNICAST_ADDRESS structures pointed to by the FirstUnicastAddress member and the linked IP_ADAPTER_PREFIX structures pointed to by the FirstPrefix member are maintained as separate internal linked lists by the operating system. As a result, the order of linked IP_ADAPTER_UNICAST_ADDRESS structures pointed to by the FirstUnicastAddress member does not have any relationship with the order of linked IP_ADAPTER_PREFIX structures pointed to by the FirstPrefix member.
What is the solution? Am I missing something obvious?
Some code (e.g. zeroMQ) only uses, for each adapter, the first unicast address and the first prefix. Is that approach safe? Am I going to miss interfaces?
The IP_ADAPTER_ADDRESSES::FirstPrefix
field gives you a list of subnets/prefixes that are assigned to the adapter, but as the documentation states, GetAdaptersAddresses()
doesn't tell you which specific IP address on the adapter corresponds to which subnet/prefix. So, to determine each IP address's particular subnet/prefix, you have to look at the individual entries in the IP_ADAPTER_ADDRESSES::FirstUnicastAddresses
list.
On Windows Vista and later, the IP_ADAPTER_UNICAST_ADDRESS::OnLinkPrefixLength
field provides the length of the IPv4 subnet mask for an AF_INET
address, and the length of the IPv6 prefix for an AF_INET6
address. For IPv4, the length can be passed to the ConvertLengthToIpv4Mask()
function if you need the actual subnet mask.
On Windows XP, the OnLinkPrefixLength
field does not exist. Fortunately, an AF_INET
address's IPv4 subnet mask can be retrieved by calling the GetIpAddrTable()
function and then looking for the IP address in the table (in the MIB_IPADDRROW::dwAddr
field - the subnet mask will be in the MIB_IPADDRROW::dwMask
field).
I don't know how to get an AF_INET6
address's IPv6 prefix length on XP, if you need that.