2

While troubleshooting an occasional network "stall" on my home internet, I came across this technical tip from Dell. They suggest using ping -n to avoid a stall caused by DNS resolution. This got me thinking, what does the -n switch actually do? It seems to me that DNS resolution is required if you ping a DNS name, but not required if you ping an IP.

From the man page:
-n Numeric output only. No attempt will be made to lookup symbolic names for host addresses.

If I ping an IP address like ping 8.8.8.8 how is there any DNS lookup here? Does ping -n 8.8.8.8 do something different?

Elliott B
  • 1,347
  • 5
  • 17
  • 44

2 Answers2

2

If I ping an IP address like ping 8.8.8.8 how is there any DNS lookup here? Does ping -n 8.8.8.8 do something different?

It may depend on the implementation. If ping without -n includes dns.google in its output, ping -n probably doesn't, this is the difference. But it's possible that neither output includes the string.


In my Ubuntu 18.04.4 LTS man 8 ping reads:

ping is part of iputils package and the latest versions are available in source form at http://www.skbuff.net/iputils/iputils-current.tar.bz2.

This exact address seems not to work, still http://www.skbuff.net/iputils provides other links, including the one to SourceForge. I have downloaded iputils-s20151218 and read the code.

-n is handled in ping_common.c:

case 'n':
        options |= F_NUMERIC;
        break;

Then the option (options & F_NUMERIC) is important in ping.c:

pr_addr(__u32 addr)
{
        …
    if (exiting || (options & F_NUMERIC) ||
        !(hp = gethostbyaddr((char *)&addr, 4, AF_INET)))
            sprintf(buf, "%s", inet_ntoa(*(struct in_addr *)&addr));
    else {
            …

To get to gethostbyaddr, both exiting and options & F_NUMERIC must be false (because a || b does will not evaluate b if a is true). The latter depends on whether -n was or wasn't used.

gethostbyaddr is the "attempt to lookup symbolic names for host addresses". See man 3 gethostbyaddr. This is the same library call getent hosts uses when you provide an IP address (see man 1 getent).

See the difference:

$ getent hosts 8.8.8.8
8.8.8.8         dns.google
$ ping -c 1 dns.google
…
64 bytes from dns.google (8.8.8.8): icmp_seq=1 ttl=120 time=10.6 ms
…
$ ping -n -c 1 dns.google
…
64 bytes from 8.8.8.8: icmp_seq=1 ttl=120 time=11.3 ms
…
$

It may seem ping without -n just uses the string the user provided; but no:

$ getent hosts poczta.wp.pl
193.17.41.99    poczta.wp.pl
$ getent hosts 193.17.41.99
193.17.41.99    poczta.o2.pl
$ ping -c 1 poczta.wp.pl
…
64 bytes from poczta.o2.pl (193.17.41.99): icmp_seq=1 ttl=60 time=9.71 ms
…
$

Here poczta.wp.pl was resolved to 193.17.41.99 and then 193.17.41.99 was resolved to poczta.o2.pl (note o2 instead of wp). Usage of -n would suppress the latter step.

For some addresses this happens:

$ getent hosts superuser.com
151.101.1.69    superuser.com
151.101.193.69  superuser.com
151.101.65.69   superuser.com
151.101.129.69  superuser.com
$ getent hosts 151.101.1.69 151.101.193.69 151.101.65.69 151.101.129.69        
$        # the output was empty
$ ping -c 1 superuser.com
…
64 bytes from 151.101.1.69 (151.101.1.69): icmp_seq=1 ttl=58 time=37.1 ms
…
$ ping -n -c 1 superuser.com
…
64 bytes from 151.101.1.69: icmp_seq=1 ttl=58 time=36.8 ms
…
$

But if I provide a numeric address then there will be no difference:

$ getent hosts 8.8.8.8
8.8.8.8         dns.google
$ ping -c 1 8.8.8.8
…
64 bytes from 8.8.8.8: icmp_seq=1 ttl=120 time=10.8 ms
…
$ ping -n -c 1 8.8.8.8
…
64 bytes from 8.8.8.8: icmp_seq=1 ttl=120 time=8.91 ms
…
$ 

It's because of this fragment from ping.c:

if (inet_aton(target, &whereto.sin_addr) == 1) {
        hostname = target;
         if (argc == 1)
                 options |= F_NUMERIC;
} else

inet_aton converts from the IPv4 numbers-and-dots notation into binary form. It returns 1 on success. If the last argument given to ping can be converted, the fragment evaluates options |= F_NUMERIC as if -n was used.

I actually compiled ping from the source in two versions: the original and with if … options |= F_NUMERIC; commented out. The modified version behaves like this:

$ ./ping -c 1 8.8.8.8
…
64 bytes from dns.google (8.8.8.8): icmp_seq=1 ttl=120 time=9.67 ms
…
$ ./ping -n -c 1 8.8.8.8
…
64 bytes from 8.8.8.8: icmp_seq=1 ttl=120 time=8.69 ms
…
$ 

Now I can explicitly answer the question:

Does ping -n 8.8.8.8 do something different [than ping 8.8.8.8]?

No. The address in the IPv4 numbers-and-dots notation makes ping (from iputils on Linux) work as if -n was used.


If I ping an IP address like ping 8.8.8.8 how is there any DNS lookup here?

I created a separate network namespace (to make sure as little traffic as possible interferes) with a veth pair, then used wireshark there. (If you want to replicate my results and need help with the procedure, see this answer, example 2).

With the original ping:

  • ping -n -c 1 8.8.8.8 generates ICMP echo request and receives ICMP echo reply. No DNS involved.
  • ping -c 1 8.8.8.8 does the same (no surprise here, explained above).

This means there is no DNS lookup. Below are some tests for comparison.

With my modified ping:

  • ping -n -c 1 8.8.8.8 behaves like the original.
  • ping -c 1 8.8.8.8 queries the DNS server after ICMP and receives a response. This is to get dns.google.

Again with the original ping:

  • ping -n -c 1 dns.google queries the DNS server and receives a response before ICMP. This is to translate dns.google to 8.8.8.8 or 8.8.4.4.
  • ping -c 1 dns.google queries the DNS sever and receives a response before ICMP (to translate to 8.8.8.8 or to 8.8.4.4) and separately after ICMP (to translate back).
1

From the man page:

-n Numeric output only. No attempt will be made to lookup symbolic names for host addresses

so the difference is in the output:

>ping  whitehouse.gov
PING whitehouse.gov(g2a02-26f0-0082-02b2-0000-0000-0000-2add.deploy.static.akamaitechnologies.com (2a02:26f0:82:2b2::2add)) 56 data bytes
64 bytes from g2a02-26f0-0082-02b2-0000-0000-0000-2add.deploy.static.akamaitechnologies.com (2a02:26f0:82:2b2::2add): icmp_seq=1 ttl=52 time=7.38 ms
64 bytes from g2a02-26f0-0082-02b2-0000-0000-0000-2add.deploy.static.akamaitechnologies.com (2a02:26f0:82:2b2::2add): icmp_seq=2 ttl=52 time=6.91 ms
64 bytes from g2a02-26f0-0082-02b2-0000-0000-0000-2add.deploy.static.akamaitechnologies.com (2a02:26f0:82:2b2::2add): icmp_seq=3 ttl=52 time=21.6 ms
64 bytes from g2a02-26f0-0082-02b2-0000-0000-0000-2add.deploy.static.akamaitechnologies.com (2a02:26f0:82:2b2::2add): icmp_seq=4 ttl=52 time=7.60 ms
>ping  -n whitehouse.gov
PING whitehouse.gov(2a02:26f0:82:280::2add) 56 data bytes
64 bytes from 2a02:26f0:82:280::2add: icmp_seq=1 ttl=52 time=10.0 ms
64 bytes from 2a02:26f0:82:280::2add: icmp_seq=2 ttl=52 time=5.63 ms
64 bytes from 2a02:26f0:82:280::2add: icmp_seq=3 ttl=52 time=10.4 ms
64 bytes from 2a02:26f0:82:280::2add: icmp_seq=4 ttl=52 time=12.5 ms
xenoid
  • 10,597