New Post has been published on Kernel | IT Security & Applications
New Post has been published on http://www.kernelops.com/cidr-notation-from-mac-os-x-shell/
CIDR Notation From Mac OS X Shell
I recently had a time-and-ahalf trying to find a simple shell script for retrieving the CIDR notation net address on Mac OS X. There are several apps on the App Store that will do this for you known as CIDR Calculators, but I needed a shell script to do this. I personally needed this to auto-configure Snort’s HOME_NET variable when Snort boots from a ‘.plist’ file, but I’m sure there are other reasons someone might want to use this.
First, what is CIDR notation?
Something to make note of first is, if you don’t already know the answer to this question you might have some trouble the remaining steps to implement this solution; they get fairly technical…
But anyway, CIDR notation is when you see your net address look something like this ’192.168.1.0/24′. Basically, the ‘/24′ is a shorthand reference to your subnet mask which probably looks something like this (at least in our example) ’255.255.255.0′ or on a Mac, using the ‘ifconfig’ command it probably looks like this, ’0xffffff00′ which is the same thing in hexadecimal format.
Next, why do we care about CIDR notation?
There are lots of different reasons you might want to find out the CIDR notation of your net address. As I stated, my reasoning is because Snort needs a HOME_NET variable set so it knows what to monitor traffic on. If I set Snort’s HOME_NET variable to ’192.168.1.5′ then it will only monitor traffic for that particular IP address; however, if I provide ’192.168.1.0/24′ then magically Snort will monitor traffic on my entire private network. Which is what I want in this case.
Now, let’s get to the nitty-gritty!
I’ll first show you the code, then break it apart, piece-by-piece, so you can understand what is going on–oh and, by-all-means, if someone has a better way of doing this please let me know! I searched and searched and couldn’t find another script based solution for OS X.
CIDR=$(while read y; do echo $y%.*".0/$(m=0; while read -n 1 x && [ $x = f ]; do m=$[m+4]; done < <(ifconfig en0 | awk '/mask/$4=substr($4,3);print $4'); echo $m )"; done < <(ifconfig en0 | awk '/inet[ ]/print $2'))
Eeeek! That looks intimidating! No worries, I’ll go over each portion. To summarize what is happening: we are converting the hexadecimal version of the subnet mask provided by ‘ifconfig [your interface]‘ to a number based on how many ‘f’ characters are in the hexadecimal string. In this case, each ‘f’ is worth 4 points; so loop over the hex string and add 4 to a zero-based variable every time an ‘f’ is encountered. Then get the inet IP address from the ‘ifconfig [your interface]‘ command, substring off the last octet and replace it with ‘.0/[the CIDR that we just calculated]‘. Sounds simple enough, let’s dive in!
Here we are simply assigning the results of our entire command to a variable called CIDR so we can reference our CIDR notation net address later if desired. You could also ‘echo’ the results if you don’t need it in a variable.
#2. < <(ifconfig en0 | awk '/inet[ ]/print $2'))
Ok, here we are using an awk expression to get the inet IP address from ifconfig en0. The ‘< <( )' will pipe whatever results from within the parenthesis to whatever is on the left side of the arrows, which means in this case the left side (the rest of our function) will now get the string '192.168.1.5' to work with.
while read y; do echo $y%.*”.0/$(m=0; while read -n 1 x && [ $x = f ]; do m=$[m+4]; done < <(ifconfig en0 | awk ‘/mask/$4=substr($4,3);print $4’); echo $m )”; done
And, here is the remainder of the code that would be on the left side of the arrows. There are really two main parts to this command, first:
#3. while read y; do echo $y%.*".0/ ........ ; done
This is reading in the inet IP address string that got piped from our #2 command. The while loop is reading in the string in the 'y' variable and '$y%.*' is simply stripping off the last octet to leave us with '192.168.1'. Naturally, we now concatenate that substring command with ".0/" to set the stage for our CIDR number now. Which is our next step.
#4. < <(ifconfig en0 | awk '/mask/$4=substr($4,3);print $4')
Similar to what we've already seen from step #2, we want to get the subnet mask from the 'ifconfig en0' command which will result in '0xffffff00' and strip off the first two characters with 'substr($4,3)'; resulting in 'ffffff00' and pipe this string into the while loop on the left side of the '< <( )' arrows.
#5. m=0; while read -n 1 x && [ $x = f ]; do m=$[m+4]; done
This is our left side of the arrows from step #4 that 'ffffff00' is being passed. First, we need an empty variable created that will hold our incrementing CIDR number 'm=0;'. Next, the while statement will read in the passed string 'ffffff00' into individual characters called 'x' using the '-n 1 x' syntax. Then we also only want to perform our addition arithmetic if the character is an 'f' so '&& [ $x = f ];'. Finally, the inside of the while loop performs the arithmetic 'm=$[m+4];'.
Next, notice that inside our subshell, and after the while loop and awk pipe we finally echo the 'm' variable back, which will simply append the results into the string from step #3. Making step #3 look something like this essentially:
while read y; do echo $y%.*".0/24"; done since '24' is what got returned (in this case) from the subshell.
An that is it! Although the command is rather lengthy, it seems to get the job done. Obviously, some constants that this assumes is that your ifconfig field placements are the same, meaning your subnet mask doesn't show up before your inet ip address for some reason, and so on. Also, this seems to only work on Mac OS X, probably because of the varying versions of bash/sh across other *nix distos. I wasn't worried about other distros though because I'm only deploying Macs that need this functionality.
Hopefully, this saves someone else a ton of time. Thanks for listening...