5

For monitoring purposes, I'd like to find out all public IPv4 and IPv6 addresses of a mobile-warrior UNIX box.

Note that this is different from Finding the Public IP address in a shell script because of the following extra requirements:

  • the mobile warrior itself probably does not have any public IPv4 addresses at all;
  • it may or may not have IPv6 (but we're only interested in active ones that would be used in actual outgoing connections);
  • the underlying internet connection might be load-balanced, details unknown, where a combination of UDP, TCP, ICMP and source/destination IP address, may determine which upstream will be used; we need to try our best to find out all such IP addresses for a complete picture on the underlying internet connectivity of the gateway, without having direct access to the gateway itself.
cnst
  • 12,948
  • 7
  • 51
  • 75

1 Answers1

5

Explanation

We can determine the public IP address through DNS with dig (the DNS lookup utility from BIND), this lets us try out both UDP (with the +notcp option) and TCP (+tcp option), leaving only ICMP behind. However, we can try sending all these queries to multiple independent destination IPv4 and IPv6 addresses, making it more likely that the load-balancing of the connection will take place, returning more unique responses.

It would appear that the positioning of the -4 and -6 options with dig might also be handled differently depending on the order of the arguments — if positioned right after dig before the @ specifier, then it's enforced as a hard requirement; if positioned past the @ specifier and/or as a final argument, then it's enforced as a soft requirement (IPv4 will be used if IPv6 connectivity is missing); the snippet below uses it as a soft requirement to avoid having to implement error-handling.

We can use GNU Parallel to mix-and-match several commands and options that are at stake here.

Solution

Here's the full solution:

parallel -kj16 dig -t txt o-o.myaddr.l.google.com +short \
::: @ns{1,2,3,4}.google.com ::: -4 -6 ::: +notcp +tcp

Here's the same snippet as a single line:

parallel -kj16 dig -t txt o-o.myaddr.l.google.com +short ::: @ns{1,2,3,4}.google.com ::: -4 -6 ::: +notcp +tcp

Here's the same snippet SO inline:

parallel -kj16 dig -t txt o-o.myaddr.l.google.com +short ::: @ns{1,2,3,4}.google.com ::: -4 -6 ::: +notcp +tcp


Testing

Here's a demonstration of what the above parallel invocation would work to accomplish:

% parallel -k echo dig -t txt o-o.myaddr.l.google.com +short \
? ::: @ns{1,2,3,4}.google.com ::: -4 -6 ::: +notcp +tcp
dig -t txt o-o.myaddr.l.google.com +short @ns1.google.com -4 +notcp
dig -t txt o-o.myaddr.l.google.com +short @ns1.google.com -4 +tcp
dig -t txt o-o.myaddr.l.google.com +short @ns1.google.com -6 +notcp
dig -t txt o-o.myaddr.l.google.com +short @ns1.google.com -6 +tcp
dig -t txt o-o.myaddr.l.google.com +short @ns2.google.com -4 +notcp
dig -t txt o-o.myaddr.l.google.com +short @ns2.google.com -4 +tcp
dig -t txt o-o.myaddr.l.google.com +short @ns2.google.com -6 +notcp
dig -t txt o-o.myaddr.l.google.com +short @ns2.google.com -6 +tcp
dig -t txt o-o.myaddr.l.google.com +short @ns3.google.com -4 +notcp
dig -t txt o-o.myaddr.l.google.com +short @ns3.google.com -4 +tcp
dig -t txt o-o.myaddr.l.google.com +short @ns3.google.com -6 +notcp
dig -t txt o-o.myaddr.l.google.com +short @ns3.google.com -6 +tcp
dig -t txt o-o.myaddr.l.google.com +short @ns4.google.com -4 +notcp
dig -t txt o-o.myaddr.l.google.com +short @ns4.google.com -4 +tcp
dig -t txt o-o.myaddr.l.google.com +short @ns4.google.com -6 +notcp
dig -t txt o-o.myaddr.l.google.com +short @ns4.google.com -6 +tcp
%

P.S. More of GNU Parallel

To extend on our solution above, the following could be used to perform whois and rDNS lookups on all found addresses; note that for IPv6 lookups to work on BSDs and macOS, one might have to specify -a for ARIN, -A for APNIC or -r for RIPE as an option to whois:

parallel -kj16 dig -t txt o-o.myaddr.l.google.com +short ::: @ns{1,2,3,4}.google.com ::: -4 -6 ::: +notcp +tcp | sort -n | uniq | parallel -vk ::: "echo" "host" "whois -a" :::: /dev/stdin

cnst
  • 12,948
  • 7
  • 51
  • 75
  • 1
    `:::: /dev/stdin` can also be written `:::: -` which will also work on systems that do not support `/dev/stdin`. – Ole Tange Dec 16 '19 at 16:24