ktb92677
ktb92677

Reputation: 457

Where is the ip address in IP_ADAPTER_ADDRESSES_LH

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

Answers (1)

Remy Lebeau
Remy Lebeau

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

Related Questions