How do I ask "dig" to only return the IP from a CNAME record?

The dig +short command (such as described in "dig show only answer") is great for batch processing names into IP addresses. It does a simple job and does it well.

Unfortunately when there's a CNAME even +short isn't short enough. For example:

$ dig +short docs.sbonds.org
ghs.google.com.
173.194.69.121

I've tried +noall but it doesn't seem like it changes the behavior of +short. I've also tried specifying -t a just to ensure it didn't think I meant an A record or CNAME, but that (unsurprisingly) changes nothing.

$ dig +noall +short docs.sbonds.org
ghs.google.com.
173.194.69.121

I'm using RedHat 7's dig:

# dig -v
DiG 9.9.4-RedHat-9.9.4-73.el7_6

I can filter out the CNAMEs with trusty grep, but it seems like dig should have some way to give "Just the IP, ma'am."

What is that way?


dig is a troubleshooting tool, so it sends DNS queries and receives DNS answers and as Andreas said the answer is both CNAME and A records, as designed. Your wish is to give "Just the IP, ma'am.", so that is not a DNS troubleshooting, it is "just" the resolution, for which dig is too much.

nslookup

nslookup is inferior to dig but will still give you too much:

$ nslookup docs.sbonds.org
Server:     192.0.2.254
Address:    192.0.2.254#53

Non-authoritative answer:
docs.sbonds.org canonical name = ghs.google.com.
Name:   ghs.google.com
Address: 172.217.4.179

host

host is simpler but will still return "too much" for you (but note that it returns also the IPv6 address which is good):

$ host docs.sbonds.org
docs.sbonds.org is an alias for ghs.google.com.
ghs.google.com has address 172.217.15.83
ghs.google.com has IPv6 address 2607:f8b0:4004:815::2013

getent

Depending on your Unix system, getent can be used. Note however that this may or may not do a DNS query because you configure in /etc/nsswitch.conf the source of data per service, and for hosts it will probably be a mix of both files (which is the venerable /etc/hosts) and the DNS.

$ getent hosts docs.sbonds.org
2607:f8b0:4007:801::2013 ghs.google.com docs.sbonds.org

Observe also that on a proper Unix setup it will favor IPv6 over IPv4 so that may be a problem for you (this should depend on the configuration in /etc/gai.conf)

In fact hosts does not honor /etc/gai.conf, you need to use ahosts instead, which will use getaddrinfo and hence gai.conf. Observe that you get a list (whose order depends on gai.conf configuration):

$ getent ahosts docs.sbonds.org
172.217.4.179   STREAM ghs.google.com
172.217.4.179   DGRAM
172.217.4.179   RAW
2607:f8b0:4007:801::2013 STREAM
2607:f8b0:4007:801::2013 DGRAM
2607:f8b0:4007:801::2013 RAW

Perl

If you are allowed to write a simple script, you have many solutions, like:

$ perl -MSocket -E 'say inet_ntoa(inet_aton("docs.sbonds.org"))'
172.217.4.179

DOH

Or use any DOH (DNS over HTTPS) endpoint (or similar) with any HTTP client. Examples:

$ curl --silent 'https://dns.google.com/resolve?name=docs.sbonds.org&type=A' | jq -c '.Answer[] | select(.type == 1) | .data'
"172.217.3.83"


$ curl --silent -H 'accept: application/dns-json' 'https://cloudflare-dns.com/dns-query?name=docs.sbonds.org&type=A' | jq -c '.Answer[] | select(.type == 1) | .data'
"172.217.12.147"

Systemd

Systemd has its own resolver application:

$ systemd-resolve docs.sbonds.org
docs.sbonds.org: 172.217.9.51
                 2607:f8b0:4009:801::2013
                 (ghs.google.com)

-- Information acquired via protocol DNS in 239.1ms.
-- Data is authenticated: no

You still need to parse it in some way, but it does give the direct final IP addresses (there is a flag when you invoke it to make it not follow CNAME records for whatever use cases that need that)


Both the CNAME and the corresponding A (or whatever type you asked for) belong to the answer-section. As such there is no dig option (at least not in RHEL7's dig) that could filter out the CNAME response.

I think you will have to rely on dig +short [...] | grep -v '\.$' to remove the CNAME responses.