Reputation: 457
Per this question:
How to get local IP address of Windows system?
@Remy Lebeau answered that GetAdaptersAddresses()
was a way to get the IP address of the local machine in Windows using C++.
I compiled the example and the example does not print out the local IP address of the machine. I took a look at the struct that the function returns (IP_ADAPTER_ADDRESSES_LH
) and I was surprised to find that I did not see any references to where the actual IP address is.
My question is, where is the IP address located in the IP_ADAPTER_ADDRESSES_LH
struct?
Upvotes: 0
Views: 1313
Reputation: 595971
I compiled the example and the example does not print out the local IP address of the machine.
GetAdaptersAddresses()
has always worked fine for me.
where is the IP address located in the IP_ADAPTER_ADDRESSES_LH struct?
There are potentially many IP addresses in the struct, depending on what kind of IP address you are interested in - Unicast, Anycast, Multicast, or DnsServer. For local assigned IPs, you would typically use the Unicast addresses only:
The IP_ADAPTER_ADDRESSES_LH::FirstUnicastAddress
field points to a linked list of IP_ADAPTER_UNICAST_ADDRESS_LH
structs, one entry for each IP address. Use the IP_ADAPTER_UNICAST_ADDRESS_LH::Next
field to loop through the list (the MSDN example shows such a loop, but it only counts the number of elements in the list, it does not print out the content of the list).
The IP_ADAPTER_UNICAST_ADDRESS_LH::Address
field contains the actual IP address, in SOCKET_ADDRESS
format.
the SOCKET_ADDRESS::lpSockaddr
field is a SOCKADDR*
pointer. You can pass it as-is to socket APIs like bind()
.
If you want to do something with the IP address (like display it), you have to type-cast the SOCKET_ADDRESS::lpSockAddr
pointer to either sockaddr_in*
or sockaddr_in6*
, depending on whether the IP address is IPv4 or IPv6, respectively (use the SOCKADDR::sa_family
field to determine the correct type - AF_INET
for sockaddr_in
, AF_INET6
for sockaddr_in6
). Then you can access the sockaddr_in::sin_addr
or sockaddr_in6::sin6_addr
field as needed, which contain the actual bytes of the IP address.
For example:
PIP_ADAPTER_ADDRESSES pAddresses = ...; // allocate buffer as needed...
ULONG ulSize = ...; // size of allocated buffer...
if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, NULL, pAddresses, &ulSize) == 0)
{
for (PIP_ADAPTER_UNICAST_ADDRESS_LH *pAddress = pAddresses->FirstUnicastAddress;
pAddress != NULL;
pAddress = pAddress->Next)
{
SOCKADDR *pSockAddr = pAddress->Address.lpSockaddr;
switch (pSockAddr->sa_family)
{
case AF_INET: {
sockaddr_in *pInAddr = (sockaddr_in*) pSockAddr;
// use pInAddr->sin_addr as needed...
break;
}
case AF_INET6: {
sockaddr_in6 *pIn6Addr = (sockaddr_in6*) pSockAddr;
// use pIn6Addr->sin6_addr as needed...
break;
}
}
}
}
// free pAddresses as needed ...
Upvotes: 6