How do I find the current machine's full hostname in C (hostname and domain information)?
Asked Answered
S

5

37

In a C project (POSIX), how do I get the fully qualified name for the current system?

For example, I can get just the hostname of my machine by doing gethostname() from unistd.h. This might give me machine3 in return, but I'm actually looking for machine3.somedomain.com for example.

How do I go about getting this information? I do not want to use a call to system() to do this, if possible.

Scrutator answered 2/2, 2009 at 20:44 Comment(1)
gethostname is the right answer. If you called system for hostname --fqdn it would simply call gethostname under the hood. Your problem is different: gethostname isn't returning the "host name" (aka FQDN) because you're not participating in the DNS, possibly because of an issue with /etc/hosts. In this case gethostname simply returns the "hostname" (no space), which is correctly machine3, rather than the FQDN, because you don't have an FQDN.Firstrate
S
65

To get a fully qualified name for a machine, we must first get the local hostname, and then lookup the canonical name.

The easiest way to do this is by first getting the local hostname using uname() or gethostname() and then performing a lookup with gethostbyname() and looking at the h_name member of the struct it returns. If you are using ANSI c, you must use uname() instead of gethostname().

Example:

char hostname[1024];
hostname[1023] = '\0';
gethostname(hostname, 1023);
printf("Hostname: %s\n", hostname);
struct hostent* h;
h = gethostbyname(hostname);
printf("h_name: %s\n", h->h_name);

Unfortunately, gethostbyname() is deprecated in the current POSIX specification, as it doesn't play well with IPv6. A more modern version of this code would use getaddrinfo().

Example:

struct addrinfo hints, *info, *p;
int gai_result;

char hostname[1024];
hostname[1023] = '\0';
gethostname(hostname, 1023);

memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; /*either IPV4 or IPV6*/
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_CANONNAME;

if ((gai_result = getaddrinfo(hostname, "http", &hints, &info)) != 0) {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(gai_result));
    exit(1);
}

for(p = info; p != NULL; p = p->ai_next) {
    printf("hostname: %s\n", p->ai_canonname);
}

freeaddrinfo(info);

Of course, this will only work if the machine has a FQDN to give - if not, the result of the getaddrinfo() ends up being the same as the unqualified hostname.

Scrutator answered 3/2, 2009 at 0:8 Comment(6)
I believe you skipped your call to freeaddrinfo() when getaddrinfo() succeeds!Dulciedulcify
By the way here pubs.opengroup.org/onlinepubs/7908799/xns/gethostname.html is said that Host names are limited to 255 bytes.. You use 1024.Backpack
@skwllsp: 255 was the limit in SUSv2 (1997); since 2001, the limit is technically HOST_NAME_MAX / sysconf(_SC_HOST_NAME_MAX), which might exceed 255 (the absolute minimum value for _POSIX_HOST_NAME_MAX, #defined in <limits.h>), and in fact might exceed 1023 as well; of course this is just theory; but in practice, 1023 is just as correct as 255 here :^)Springspringboard
On an IX'ish box the "hostname" does not need to correlated at all to the result of a DNS query for any of its interfaces' network addresses! The command hostname might return box1 where as the the ip assigned to eth0 would resolve to return box2.test2.net and the one on eth1 would resolve to return box3.test3.net.Fireworks
This solution won't work if hostname is set to not map to any FDQN for any interfaces' address.Fireworks
You don't need to cycle through all the addrinfos returned by getaddrinfo(), as only the first one will contain the canonical name; citing POSIX: if requested by the AI_CANONNAME flag, the ai_canonname field of the first returned addrinfo structure shall point to a null-terminated string containing the canonical name corresponding to the input nodenameAnetteaneurin
G
12

My solution:

#ifdef WIN32
    #include <Windows.h>
    #include <tchar.h>
#else
    #include <unistd.h>
#endif

void GetMachineName(char machineName[150])
{
    char Name[150];
    int i=0;

    #ifdef WIN32
        TCHAR infoBuf[150];
        DWORD bufCharCount = 150;
        memset(Name, 0, 150);
        if( GetComputerName( infoBuf, &bufCharCount ) )
        {
            for(i=0; i<150; i++)
            {
                Name[i] = infoBuf[i];
            }
        }
        else
        {
            strcpy(Name, "Unknown_Host_Name");
        }
    #else
        memset(Name, 0, 150);
        gethostname(Name, 150);
    #endif
    strncpy(machineName,Name, 150);
}
Gemoets answered 25/11, 2011 at 10:50 Comment(0)
A
3

gethostname() is POSIX way to get local host name. Check out man.

BSD function getdomainname() can give you domain name so you can build fully qualified hostname. There is no POSIX way to get a domain I'm afraid.

Aestivation answered 2/2, 2009 at 21:17 Comment(2)
gethostname only returns the local hostname. I'm looking for the fully qualified name.Scrutator
getdomainname returns the NIS domain name, which may not necessarily match the DNS domain name, or even be set at allCelle
D
0

I believe you are looking for:

gethostbyaddress

Just pass it the localhost IP.

There is also a gethostbyname function, that is also usefull.

Donelson answered 2/2, 2009 at 20:50 Comment(1)
if you give it 127.0.0.1 as IP address you are likely to get localhost or localhost.localdomain as answer. It is not common to assign the machines full hostname to a loopback interface.Cabalism
S
-1

The easy way, try uname()

If that does not work, use gethostname() then gethostbyname() and finally gethostbyaddr()

The h_name of hostent{} should be your FQDN

Subdominant answered 2/2, 2009 at 20:49 Comment(1)
uname gives me the same result as gethostbyname. I haven't tried gethostbyaddr yet.Scrutator

© 2022 - 2024 — McMap. All rights reserved.