19

If we have this string (IP address): 192.168.1.1

How can I derive the (DNS reverse record form) from this string, so it will be shown like 1.1.168.192.in-addr.arpa using a shell script?

4
  • It has to be with the shell?
    – Braiam
    May 30, 2014 at 22:07
  • 1
    Stop doing that Jun 8, 2014 at 8:30
  • 1
    With this amount of answers this should better be in codegolf ;)
    – tkausl
    Dec 6, 2014 at 12:59
  • @tkausl, share it there if you want to :)
    – Nidal
    Dec 6, 2014 at 23:58

19 Answers 19

33

Just for curiosity value... using tac from GNU coreutils: given a variable ip in the form 192.168.1.1 then

$(printf %s "$ip." | tac -s.)in-addr.arpa

i.e.

$ ip=192.168.1.1
$ rr=$(printf %s "$ip." | tac -s.)in-addr.arpa
$ echo "$rr"
1.1.168.192.in-addr.arpa
3
  • 9
    +1 This is definitely my favorite answer here. Thanks for introducing me to tac! May 31, 2014 at 17:41
  • Thanks are also due to @StéphaneChazelas for the elegant printf edit (I originally posted an ugly echo -n) Jun 1, 2014 at 17:07
  • 2
    Clearly simpler: printf 'arpa.in-addr.%s.' "$ip" | tac -s.
    – user232326
    Jun 20, 2018 at 21:27
32

You can do it with AWK. There are nicer ways to do it, but this is the simplest, I think.

echo '192.168.1.1' | awk 'BEGIN{FS="."}{print $4"."$3"."$2"."$1".in-addr.arpa"}'

This will reverse the order of the IP address.

Just to save a few keystrokes, as Mikel suggested, we can further shorten the upper statement:

echo '192.168.1.1' | awk -F . '{print $4"."$3"."$2"."$1".in-addr.arpa"}'

OR

echo '192.168.1.1' | awk -F. '{print $4"."$3"."$2"."$1".in-addr.arpa"}'

OR

echo '192.168.1.1' | awk -F. -vOFS=. '{print $4,$3,$2,$1,"in-addr.arpa"}'

AWK is pretty flexible. :)

1
  • If you want to save a few keystrokes, -F . should be equivalent to BEGIN{FS="."}.
    – Mikel
    May 30, 2014 at 22:03
18

If you want to use only shell (zsh, ksh93, bash), here's another way:

IFS=. read w x y z <<<'192.168.1.1'
printf '%d.%d.%d.%d.in-addr.arpa.' "$z" "$y" "$x" "$w"

Or in plain old shell:

echo '192.168.1.1' | { IFS=. read w x y z; echo "$z.$y.$w.$x.in-addr.arpa."; }
13

Easily with Perl, thusly:

$ echo 192.168.1.1|perl -nle 'print join ".",reverse(split /\./,$_)'
1.1.168.192
1
  • 6
    Can be made even more compact: perl -F'\.' -lane '$,=".";print reverse @F'
    – Joseph R.
    May 30, 2014 at 22:15
7

To round it out, Ruby:

ruby -r ipaddr -e 'puts IPAddr.new(ARGV.first).reverse' 192.168.1.1

Which also supports IPv6

2607:F8B0:4000:080A:0000:0000:0000:2000
=> 0.0.0.2.0.0.0.0.0.0.0.0.0.0.0.0.a.0.8.0.0.0.0.4.0.b.8.f.7.0.6.2.ip6.arpa
2
  • you could take the "require" out of the script: ruby -r ipaddr -e 'puts ...' Dec 5, 2014 at 19:22
  • I think the OP needs shell..
    – MaXi32
    Sep 21, 2021 at 13:52
6

Through GNU sed,

sed -r 's/^([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3})$/\4.\3.\2.\1.in-addr.arpa/g' file

It reverses any IPv4-address format.

Example:

$ echo '192.168.1.1' | sed -r 's/^([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3})$/\4.\3.\2.\1.in-addr.arpa/g'
1.1.168.192.in-addr.arpa

$ echo '192.1.1.1' | sed -r 's/^([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3})$/\4.\3.\2.\1.in-addr.arpa/g'
1.1.1.192.in-addr.arpa

$ echo '1.1.1.1' | sed -r 's/^([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3})$/\4.\3.\2.\1.in-addr.arpa/g'
1.1.1.1.in-addr.arpa

$ sed -r 's/^([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3})$/\4.\3.\2.\1.in-addr.arpa/g' <<< '192.168.189.23'
23.189.168.192.in-addr.arpa
1
  • 1
    This is the fastest solution! 45k IPs converted in just 0.794s. Oct 4, 2019 at 13:58
5

With zsh:

$ ip=192.168.1.1
$ echo ${(j:.:)${(s:.:Oa)ip}}.in-addr.arpa
1.1.168.192.in-addr.arpa

Those are variable expansion flags:

  • s:.:: split on .
  • Oa: reverse order the array
  • j:.:: join on .
4

Using Python’s standard library:

>>> ipaddress.ip_address('192.168.1.1').reverse_pointer
'1.1.168.192.in-addr.arpa'
1
  • 1
    This is in the 3.5 standard library and scheduled to be released September 2015. From a script you can do: python3.5 -c "import ipaddress; ipaddress.ip_address('192.168.1.1').reverse_pointer" (all on one line)
    – Anthon
    Nov 24, 2014 at 20:40
3

Another possibility is to use the "dig" command line tool with the "-x" switch.

It actually does a request on the PTR entry, but if you filter on "PTR" it will show you one commented line (the request) and maybe some replies.

Using "dig" can be handy for a quick writing of the PTR name, without having to write a small script. Particularly if you need it interactively (to cut and paste the result). It works on IPv6 too.

0
2

If you want it working with IPv6 as well, you can use dig -x.

For example:

$ dig -x 194.68.208.240 | egrep '^;.*PTR$' | cut -c 2- | awk '{print $1}'
240.208.68.194.in-addr.arpa.

$ dig -x 2001:db8:dc61:2a61::1 | egrep '^;.*PTR$' | cut -c 2- | awk '{print $1}'
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.6.a.2.1.6.c.d.8.b.d.0.1.0.0.2.ip6.arpa.
2

In Python

 a = "192.168.1.122"
 import re
 m = re.search(r'(\d+)\.(\d+)\.(\d+)\.(\d+)',a)
 ip = m.group(4),m.group(3),m.group(2),m.group(1)
 '.'.join(ip) + ".in-addr.arpa"
 '122.1.168.192.in-addr.arpa'
1
  • 2
    Or more idiomatically, "{}.in-addr.arpa".format(".".join(reversed(a.split(".")))) in Python2.7
    – iruvar
    Jun 8, 2014 at 11:42
2
IFS=. ; set -- ${0+192.168.1.2}
printf %b. $4 $3 $2 $1 in-addr.arpa\\c

IFS=. ; printf %s\\n \
    in-addr.arpa ${0+192.168.1.2} |    
sed '1!G;$s/\n/./gp;h;d'

IFS=. ; printf '[%b.] ' \
    ${0+192.168.1.2.]PPPPP\\c} |dc
echo in-addr.arpa
1
$ while read ip
while> do
while> n=( $(echo $ip) ) && echo "${n[4]}"'.'"${n[3]}"'.'"${n[2]}"'.'"${n[1]}"'.'"in-addr.arpa"
while> done
192.168.1.2
2.1.168.192.in-addr.arpa

This way you can type in an address and hit return for your result.

1

Assuming a var contains the ip: ip=192.168.2.1. If the value needs to be given to a new variable, just enclose any solution inside $() and assign that to the var rr=$(...).

Some solutions are possible:

Simplest : printf 'arpa.in-addr.%s.' "$ip" | tac -s.
Most shells: IFS=. eval 'set -- $ip'; echo "$4.$3.$2.$1.in-addr.arpa"
Some shells : IFS=. read d c b a <<<"$ip"; printf %s "$a.$b.$c.$d.in-addr.arpa."
: echo "$ip" | awk -F. '{OFS=FS;print $4,$3,$2,$1,"in-addr.arpa"}'
: echo "$ip" | sed -E 's/([^.]+)\.([^.]+)\.([^.]+)\.([^.]+)$/\4.\3.\2.\1.in-addr.arpa./'
: echo "arpa.in-addr.$ip" | sed 'y/./\n/' | sed 'G;$s/\n/./gp;h;d'
: echo "$ip" | perl -F\\. -lane '$,=".";print( join(".",(reverse @F),"in-addr.arpa"))'
: dig -x "$ip" | awk -F '[; \t]+' '/^;.*PTR$/{print($2)}'
: host -t ptr 192.168.2.1 | cut -d' ' -f2

Both dig and host solutions work with IPv6.

0
1
#!/bin/bash
# script file name reverseip.sh
if [ -z $1 ] || [ "help" == $1 ]
then
echo 'Convert a full ipv4 or ipv6 address to arpa notation'
echo "usage:"
echo ./reverseip.sh "help"
echo ./reverseip.sh "ipv4 address format: xxxx.xxxx.xxxx.xxxx"
echo ./reverseip.sh "ipv6 address format: xxxx:xxxx:xxxx:xxxx::xxxx"
echo "examples:"
echo ./reverseip.sh 216.58.207.35
echo ./reverseip.sh 2a00:1450:4001:824::2003
exit
fi

# if ip address passed containing ':'
if [[ $1 = *':'* ]];
then
# invert ipv6 address e.g.: 2a00:1450:4001:824::2003 to 3.0.0.2.0.0.0.0.0.0.0.0.0.0.0.0.4.2.8.0.1.0.0.4.0.5.4.1.0.0.a.2.
# @see lsowen https://gist.github.com/lsowen/4447d916fd19cbb7fce4
echo "$1" | awk -F: 'BEGIN {OFS=""; }{addCount = 9 - NF; for(i=1; i<=NF;i++){if(length($i) == 0){ for(j=1;j<=addCount;j++){$i = ($i "0000");} } else { $i = substr(("0000" $i), length($i)+5-4);}}; print}' | rev | sed -e "s/./&./g" | echo "$(</dev/stdin)ip6.arpa."
else
# invert ipv6 address e.g.: 216.58.207.35 to 35.207.58.216.in-addr.arpa
# @see Stéphane Chazelas https://unix.stackexchange.com/questions/132779/how-to-read-an-ip-address-backwards
echo $(printf %s "$1." | tac -s.)in-addr.arpa
fi
0

With host command from dnsutils:

$ host -t ptr 192.168.1.1 | cut -d' ' -f 2
1.1.168.192.in-addr.arpa.
1
  • 1
    This only works for addresses you can lookup in your DNS. If you try an unknown address you will get an error message (which however includes the reverse address but need slightly different postprocessing). Jul 11, 2017 at 13:40
0

A shorter alternative to mattbianco's answer with less tools, but using pcregrep could be:

$ dig -x 194.68.208.240 | pcregrep -o1 '^;(\S+)\s+IN\s+PTR$'
240.208.68.194.in-addr.arpa.

$ dig -x 2001:db8:dc61:2a61::1 | pcregrep -o1 '^;(\S+)\s+IN\s+PTR$'
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.6.a.2.1.6.c.d.8.b.d.0.1.0.0.2.ip6.arpa.
0

Use following one line shell:

echo '192.168.1.1' | tr '.' '\n' | tac | paste -s -d '.' -
0

Using POSIX sh:

$ ip=192.168.1.1
$ rev_ip=`
      IFS=.
      set -- $ip    # set positional parameters: $1, $2, $3, ...
      echo $4.$3.$2.$1.in-addr.arpa
  `
$ echo $rev_ip
1.1.168.192.in-addr.arpa

Note: Be careful when setting IFS. In my example, I isolated the internal field separator (IFS) in a subshell using the backtick operator, otherwise you may have to reset/restore it.

Alternatively, you could avoid IFS and use tr instead:

$ set -- `echo $ip | tr . \ `
$ echo $4.$3.$2.$1.in-addr.arpa

If you're using ksh or bash, use the $( ) subshell operator instead.

1
  • $( ... ) is to be preferred over backticks
    – roaima
    Mar 22 at 17:07

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.