2

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?

6

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)

  • "Write a simple script" is where I've always ended up before. It seemed like there must be a better way, but it looks like there is not. – Steve Bonds May 2 at 0:39
  • 1
    @SteveBonds see my update with a DOH case (similar to) – Patrick Mevzek May 2 at 0:59
  • You have no idea how much I wish "jq" was more widely installed. Nonetheless, that was an excellent addition to the solution! – Steve Bonds May 2 at 13:50
2

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.

  • 1
    Or dig +short ... | tail -1 – Patrick Mevzek May 1 at 23:14
  • not exactly. |tail -1 will show the last line. If there is more than one address in the RRset the CNAME points to this will give the wrong result. – Andreas Rogge May 2 at 18:14
  • I agree but the user request could be understood as the IP, singular, not all :-). Indeed, whatever filtering is applied can have edge cases (filtering on end dot can fail if remote nameserver is broken in some way, like returning IP addresses there too; not supposed to happen but in DNS world everything can happen) – Patrick Mevzek May 2 at 18:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.