The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My work

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,816 other followers

Getting your local IPv4 addresses, netmasks and CIDRs

Posted by jpluimers on 2017/04/11

In order to scan some local networks for unknown hosts (yes, on some sites you need to perform archeology), I needed the local IPv4 addresses, netmasks and CIDRs on my Mac running OS X.

Part of that is using ifconfig to get local inet information which however uses hexadecimal network masks and delivers no CIDRs.

SoI was a bit premature when I wrote about “This could be done by creating bash functions mask2cdr and cdr2mask, but that’s a bit too convoluted right now” in Getting the IP addresses of gmail MX servers – via Super User – dig isn’t enough.

netmask to CIDR and CIDR to netmask conversion

I need mask2cdr now, so lets start with these two bash functions and their aliases:

mask2cdr ()
{
   # Assumes there's no "255." after a non-255 byte in the mask
   local x=${1##*255.}
   set -- 0^^^128^192^224^240^248^252^254^ $(( (${#1} - ${#x})*2 )) ${x%%.*}
   x=${1%%$3*}
   echo $(( $2 + (${#x}/4) ))
}
alias mask2cidr='mask2cdr'

cdr2mask ()
{
   # Number of args to shift, 255..255, first non-255 byte, zeroes
   set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0
   [ $1 -gt 1 ] && shift $1 || shift
   echo ${1-0}.${2-0}.${3-0}.${4-0}
}
alias cidr2mask='cdr2mask'

I tracked these above functions back from bash – Explanation of convertor of cidr to netmask in linux shell netmask2cdir and cdir2netmask – Stack Overflow which – despite the question being closed – has an excellent answer by ThisSuitIsBlackOrNot explaining their inner workings.

The CIDR (or prefix) is the number of 1 bits in the network mask or subnet mask.

The code came from Convert netmask IP format Nbr of set bits (Page 1) — General Discussion — OpenWrt which was based on the thread at Gentoo Forums :: View topic – OpenRC: converting netmask/CIDR without loops!

NB: Other varieties of these functions (including netcalc and bcastcalc to calculate network addresses and broadcast addresses) are at http://rather.puzzling.org/~tconnors/code/cidr2mask

Converting a hexadecimal netmask to dotted netmask

One of the peculiarities of Mac OS X ifconfig is that it delivers the subnet mask in hex (as it’s BSD derived, and BSD ifconfig does hex netmasks):

$ ifconfig | grep -w inet
    inet 127.0.0.1 netmask 0xff000000 
    inet 192.168.71.116 netmask 0xffffff00 broadcast 192.168.71.255
    inet 172.16.149.1 netmask 0xffffff00 broadcast 172.16.149.255
    inet 172.16.172.1 netmask 0xffffff00 broadcast 172.16.172.255

Since mask2cdr takes a dotted quad as input, we need to do the conversion. Luckily, Tim Kennedy has written the basics of a bash script to convert hex netmask to dotted quad which I fixed and converted to this bash function:

netmaskhex2dotted()
{
  # read the mask, and strip leading 0x if it's there
  hexmask=$( echo $1 | sed -e 's/^0x//' )

  # loop through $hexmask in pairs
  #
  for (( i=0; i<${#hexmask}; i+=2 )); do if (( $i > 1 )); then
            # use a . to separate octets
            # but don't print a leading .
            printf "%s" "."
    fi
    # print decimal %d equivalent of hex octet at position $i in hexmask
    printf "%d" "0x${hexmask:$i:2}"
done

printf "\n"
}

The fix is in the last printf: it printed out the $1 parameter but should print the current ${hexmask} iteration.

Now it works (:

Parsing the ifconfig output to get IPv4, netmask, CIDR

Now we get to the final piece: the ifconfig parsing.

First it’s limiting the ifconfig output to only connected networks. Which is pretty easy as they always have both the word inet and the word broadcast in them. Actually: only broadcast will do.

Then it’s basically getting the various fields: b and d:

  1. a: literal inet
  2. b: localIPV4
  3. c: literal netmask
  4. d: netmask
  5. e: literal broadcast
  6. f: broadcast

I started with ifconfig | grep -w broadcast | tr -s ' ' | cut -d ' ' -f 2,4 but that gave problems parsing in the bash script (somehow, newlines were being converted to spaces. I need to figure out that one day).

So I used the “shell functions” solution of linux – bash: split output of command by columns – Stack Overflow (thanks Xennex81) which means you need to read up until e (anything from the broadcast literal text).

A final, but very important aspect is to preserve the multi-line behaviour of the ifconfig output. The trick here is to have double quotes around the outer echo parameter: that preserves it. Jonathan Leffler explains that very well in his answer on Capturing multiple line output to a bash variable – Stack Overflow

get-local-ip-addresses-netmasks-cidrs()
{
  echo "$(ifconfig | grep -w broadcast | \
    while read a b c d e; \
    do \
      echo $b $d $(netmaskhex2dotted $d) $(mask2cidr $(netmaskhex2dotted $d)) ; \
    done )"
}

So final output is like this on my system:

$ get-local-ip-addresses-netmasks-cidrs
192.168.71.116 0xffffff00 255.255.255.0 24
172.16.149.1 0xffffff00 255.255.255.0 24
172.16.172.1 0xffffff00 255.255.255.0 24

–jeroen

via:

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: