IP address order in gethostbyname function

splattru picture splattru · Nov 12, 2014 · Viewed 11.5k times · Source

Since I got no answer on my previous question, I will rephrase it.

What order of IP addresses (in case when IP addresses are bound to one interface) is used when doing gethostbyname() using PC name (NetBIOS name)?

I have this code:

#include <iostream>
#include <winsock.h>
#pragma comment(lib, "Ws2_32.lib")

int main()
{
    char hostname[255];
    struct hostent *he;
    struct in_addr **addr_list;

    WSAData data;
    WSAStartup(MAKEWORD(2, 2), &data);

    gethostname(hostname, 255);
    std::cout << "Host name: " << hostname << std::endl;

    if ((he = gethostbyname(hostname)) == NULL) {
        std::cout << "gethostbyname error" << std::endl;
    } else {
        std::cout << "IP addresses: "  << std::endl;
        addr_list = (struct in_addr **)he->h_addr_list;
        for(int i = 0; addr_list[i] != NULL; i++) {
            std::cout << inet_ntoa(*addr_list[i]) << std::endl;
        }
    }
    std::cin.get();
}

And it gives me different results on Windows Server 2012 and Windows Server 2008 / Windows 7. On my home PC with Windows 7, ascending order is used:

Host name: SplattWin
IP addresses:
192.168.1.140
192.168.3.1
192.168.3.2
192.168.3.3
192.168.3.4

However, on Windows server 2012 it gives me IP addresses in descending order:

Host name: WinServ
IP addresses:
1.1.1.4
1.1.1.3
1.1.1.2
1.1.1.1

Is there any way to reorder it? I tried skipassource flag when I added these IP addresses but it doesn't seem to work in this case.

I have third party software that is using gethostname() followed by gethostbyname() to determine it's own IP address (it takes first from the list). And it's really frustrating that you need to change settings and client side every time you add new IP address to your system.

Answer

Remy Lebeau picture Remy Lebeau · Nov 12, 2014

The order of the IPs is determined by Windows based on interface priorities and such. There is no standard rule that spans across machine boundaries or Windows version boundaries. You have to treat the output list as random, and re-order the IPs yourself to your particular needs. For example:

#include <iostream>
#include <vector>
#include <algorithm>
#include <winsock.h>

#pragma comment(lib, "Ws2_32.lib")

bool SortInAddr(const in_addr &a, const in_addr &b)
{
    return (a.S_un.S_addr < b.S_un.S_addr);
} 

int main()
{
    WSAData data;
    WSAStartup(MAKEWORD(2, 2), &data);

    char hostname[256] = {0};
    if (gethostname(hostname, 255) == SOCKET_ERROR)
    {
        std::cout << "gethostname error: " << WSAGetLastError() << std::endl;
    }
    else
    {
        std::cout << "Host name: " << hostname << std::endl;

        struct hostent *he = gethostbyname(hostname);
        if (he == NULL)
        {
            std::cout << "gethostbyname error: " << WSAGetLastError() << std::endl;
        }
        else if (he->h_length != sizeof(in_addr))
        {
            std::cout << "gethostbyname did not return IPv4 addresses" << std::endl;
        }
        else
        {
            std::vector<in_addr> addrs;

            struct in_addr **addr_list = (struct in_addr **)(he->h_addr_list);
            for(int i = 0; addr_list[i] != NULL; ++i)
            {
                addrs.push_back(*(addr_list[i]));
            }

            if (addrs.size() > 1)
            {
                std::sort(addrs.begin(), addrs.end(), SortInAddr);
            }

            std::cout << "IPv4 addresses: " << std::endl;
            for(std::vector<in_addr>::iterator iter = addrs.begin();
                iter != addrs.end();
                ++iter)
            {
                std::cout << inet_ntoa(addrs[i]) << std::endl;
            }
        }
    }

    WSACleanup();
    std::cin.get();
}

That being said, don't use gethostbyname() (or getaddrinfo()) to enumerate a machine's local interfaces. Such functions are not intended for that purpose. Use GetAdaptersInfo() or GetAdaptersAddresses() instead. They are specifically intended to enumerate local interfaces, and they give you much more detailed information about the interfaces.