Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IP address order in gethostbyname function

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.

like image 553
splattru Avatar asked Nov 12 '14 14:11

splattru


People also ask

How does gethostbyname work?

The GETHOSTBYNAME call returns the alias name and the internet address of a host whose domain name is specified in the call. A given TCP/IP host can have multiple alias names and multiple host internet addresses. TCP/IP tries to resolve the host name through a name server, if one is present.

How does socket gethostbyname work?

This program uses the socket call, gethostbyname to return an IP address that corresponds to the supplied hostname. gethostbyname will determine if a nameserver or local host tables are being used for name resolution. The answer is returned in the hostent structure, hp and then printed.

What does gethostbyname return c?

The gethostbyname() function returns a structure of type hostent for the given host name.

What does socket gethostbyname return?

Python socket module gethostbyname() function accepts hostname argument and returns the IP address in the string format.


1 Answers

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.

like image 165
Remy Lebeau Avatar answered Oct 19 '22 10:10

Remy Lebeau