11

When you call ping name.domain, it goes through both /etc/hosts and the DNS resolver to obtain an IP. It could be an IP hard-coded in /etc/hosts, or it could be one from the DNS server. It does so by calling getaddrinfo() or equivalent, not directly, of course.

How do I call getaddrinfo() from shell? How do I reproduce the effect of "normal" net utilities to obtain an IP from an address?

This is not about using dig/host which only go through DNS, or getent which only goes through hosts. I want to reproduce common application behavior (e.g. ping) when it receives a name it needs to resolve. There are other questions about dig/host. This question is not a duplicate of those.

Update: here are my findings (based partly on answers to other Qs)

  • on Ubuntu (and Debian?) there is gethostip -d name.domain from syslinux.
  • perl -MSocket -le 'print inet_ntoa inet_aton shift' name.domain works reliably and is terser than the accepted answer.
  • Using getent may also work: getent ahostsv4 name.domain | grep STREAM | head -1 | cut -f1 -d' '

This seems to be the best one can do.

dan3
  • 660
  • 6
  • 16
  • 1
    Was wondering if you were gonna ask this question 8-) – slm Nov 03 '13 at 18:24
  • Might be a reason you don't want to do this: http://unix.stackexchange.com/questions/67627/method-to-perform-dns-lookup-step-very-quickly-during-wget – slm Nov 03 '13 at 18:25
  • I'll keep that in mind, meanwhile I need to debug existing behavior of existing applications. But please be sure to add this bit to your answer. – dan3 Nov 03 '13 at 18:26
  • What's the application you're debugging? – slm Nov 03 '13 at 18:27
  • Custom app. On some servers domains are hard-coded in /etc/hosts, in others there's a tinydns server. I'd still like to know what's the shortest way to obtain the IP that getaddrinfo() returns for a domain. – dan3 Nov 03 '13 at 18:32
  • Afraid you were going to say that. I had this exact same issue with a setup when I used to work at Kodak. Everything was consistently inconsistent. – slm Nov 03 '13 at 18:33
  • 1
    Related: http://unix.stackexchange.com/questions/71379/host-lookup-that-respects-etc-hosts – slm Nov 03 '13 at 20:15

1 Answers1

6

If you have access to Perl I rolled my own (well found it on the internet and used it):

#!/usr/bin/perl
use Socket;

$host = shift @ARGV;
die("usage: gethostbyname hostname\n") unless(defined($host));

$packed_ip = gethostbyname($host);

if (defined $packed_ip) {
    $ip_address = inet_ntoa($packed_ip);
    print "$ip_address\n";
    exit 0
} else {
    warn "$host not found\n";
    exit 1
}

This code comes from this SF Q&A titled: Linux command line utility to resolve host names using /etc/hosts first.

Examples

$ ./gethostbyname.pl skinner
192.168.1.3

$ ./gethostbyname.pl www.google.com
74.125.225.84

$ ./gethostbyname.pl localhost
127.0.0.1

I've used the above method when code was running on multiple Unix machines, not just Linux, and so getent wasn't an option.

getent

I know the man page for getent leaves you thinking that getent will only look in the file databases, but I believe it goes through whatever means are defined in /etc/nsswitch.conf. So if it states dns as a value there, then I believe it will interrogate the DNS server that's configured in /etc/resolv.conf. Assuming there is one defined in that file.

In my testing I do not have an entry in my file, /etc/hosts, for the host "skinner" and yet getent resolves it just fine via DNS.

$ getent hosts skinner
192.168.1.3     skinner.bubba.net

$ grep skinner /etc/hosts
$
slm
  • 363,520
  • 117
  • 767
  • 871
  • I don't know what the hell `getent hosts google.com` returns: `2a00:1450:4001:806::10042a00:1450:4001:806::1004` – dan3 Nov 03 '13 at 19:24
  • OK, this is one answer (I could have also called getaddrinfo() or the obsolete gethostbyname() directly from C of course). Let's see if there's anything shorter. – dan3 Nov 03 '13 at 19:25
  • That's the IPv6 IP address. – slm Nov 03 '13 at 19:30
  • @dan3 - correct you can call the functions writing your own, I guess is my point. – slm Nov 03 '13 at 19:32
  • @dan3 - though obsolete it's likely in your stack of Perl, other ways may not be. – slm Nov 03 '13 at 19:39
  • OK. It doesn't seem I can get getent to always print one single IPv4 address (if one is available). – dan3 Nov 03 '13 at 19:48
  • @dan3 - what does it print? If you post it in your Q perhaps I can help further. – slm Nov 03 '13 at 19:55
  • thanks, let's not expand on getent, unless you really believe it can handle all cases on Linux (i.e. print a **single** IPv4 line when one exists, even if multiple IPv4 addresses exist and even if at least one IPv6 address exists); as you can see for google.com `getent hosts ...` prints an IPv6 address and `getent ahosts ...` prints tens of lines. – dan3 Nov 03 '13 at 20:04
  • The Socket module included with Perl didn't include getaddrinfo() until Perl 5.16+, http://www.perlmonks.org/?node_id=996408. Says the same here too: http://www.perlmonks.org/?node_id=996406 – slm Nov 03 '13 at 21:45
  • Instead of providing this simple answer in the other question I asked yesterday you harassed me and tried to confuse issues until I was forced to ask this new Q with a "slm-proof" title. Even now, your answer is longer than it needs to be: `perl -MSocket -le 'print inet_ntoa inet_aton shift'` (as per the Q you linked) – dan3 Nov 04 '13 at 07:10
  • @dan3- if you bothered to read the original source to the Perl example I gave you that is what I found 1st. I did no such thing as harass you, I tried to assist you in solving your problem. I won't bother you anymore. Your welcome! – slm Nov 04 '13 at 08:06
  • I was talking about the previous question (which I have since deleted) which was marked incorrectly as a duplicate because some (including you) thought dig/hosts was acceptable and just *wouldn't give up* even when I explained the difference. Now *this* question is *correctly* marked as a duplicate, and I've also accepted your answer – dan3 Nov 04 '13 at 09:51
  • @dan3 - OK. I hope you understand that it is not a personal attack by me or anyone here. We are all volunteers and when Q's appear to be duplicates we label them as such and then if it is discovered it was an error we work to fix/undo it. Many of us spend a lot of time trying to help others and make your visit enjoyable. I can understand your frustration but these are the tools available to us as purveyors of the SE sites. I was trying to find your other Q and saw that it was deleted. – slm Nov 04 '13 at 09:58
  • @dan3 - we deal with a large range of users and so unfortunately Q's and askers of these Q's have to bare with everyone as things are vetted. It's no different than when you call a support desk. There is a script in that scenario, and so things need to be checked off of the list before moving on. I hope we haven't driven you away from the site. We do appreciate Q's since they are what drive it and I personally hope to see you here again asking and answering Q's again! – slm Nov 04 '13 at 10:01
  • This answer does not seem to work, calling getaddrinfo from C returns an IPv6 ddress as the first entry, (as I have a native IPv6 connection) while this just return an IPv4 address – Ferrybig Apr 08 '21 at 06:39
  • 1
    `getent` works perfectly. – RonJohn Jan 17 '23 at 23:07