Bash script to calculate subnet address from IP and netmask

An area of the forum to discuss router binaries (utilities and applications that run on routers) etc.
mstombs
RouterTech Team
RouterTech Team
Posts: 3753
Joined: Wed Jan 10, 2007 11:54 pm

Bash script to calculate subnet address from IP and netmask

Post by mstombs » Mon Dec 03, 2007 10:12 pm

Not a binary - but maybe I need one to test?

For a certain option I need to calculate the Network address from an IP address and a given netmask - on a router with Routertech Busybox bash (for a "route -net" command)

There are some examples on the web - but only for /24 to /32 and they use "awk" which we don't have, also plenty of javascript type web pages which didn't prove much use...

I think this does script extract does it, but do not know how to exhaustively test - and I'm sure there must be an easier way...

Code: Select all

#!/bin/sh
if [ "$2" ]; then
	NM="$2"
else
	NM="248.0.0.0"
fi
if [ "$1" ]; then
	IP="$1"
else
	IP="255.253.252.100"
fi
#
n="${NM%.*}";m="${NM##*.}"
l="${IP%.*}";r="${IP##*.}";c=""
if [ "$m" = "0" ]; then
	c=".0"
	m="${n##*.}";n="${n%.*}"
	r="${l##*.}";l="${l%.*}"
	if [ "$m" = "0" ]; then
		c=".0$c"
		m="${n##*.}";n="${n%.*}"
		r="${l##*.}";l="${l%.*}"
		if [ "$m" = "0" ]; then
			c=".0$c"
			m=$n
			r=$l;l=""
		fi
	fi
fi
let s=256-$m
let r=$r/$s*$s
if [ "$l" ]; then
	SNW="$l.$r$c"
else
	SNW="$r$c"
fi
#		
echo $SNW
With no parameters, it does a silly example calculation

with IP=255.253.252.100, NM=248.0.0.0
ans = 248.0.0.0

For others say

Code: Select all

/var # ./subnet 192.168.100.1 255.255.255.0
192.168.100.0
Apologies for lack of comments and instructive variable names - IP address is handled as l.r and netmask as n.m - I don't want to waste too much memory in the router firmware...!

Constructive criticism anyone?

Edit: Not a big problem, but if I get it wrong you get that wonderful error message

Code: Select all

MASQUERADE: No route: Rusty's brain broke!
User avatar
thechief
RouterTech Team
RouterTech Team
Posts: 12064
Joined: Wed Feb 01, 2006 10:22 pm
Location: England, the Centre of Africa
Contact:

Post by thechief » Tue Dec 04, 2007 12:36 am

To be honest, I am not sure I understand fully why this script is needed. Maybe I am just being thick, but can you please elaborate on what precisely you are trying to do?
The Chief: :afro: Be sure to read the Firmware FAQ and do a Forum Search before posting!
No support via PM. Ask all questions on the open forum.
mstombs
RouterTech Team
RouterTech Team
Posts: 3753
Joined: Wed Jan 10, 2007 11:54 pm

Post by mstombs » Tue Dec 04, 2007 1:13 am

he he that is the weak point - its all pretty academic - I only need the bit between #'s!. There's a 'pure half bridge mode' but many routers can't handle the single Ip address and out-of network gateway this requires (can be fixed in routers with 3rd party firmware...). One way to get around this is to 'spoof' the netmask so the ISP gateway is in the network defined by the IP address and netmask. A downside of this is that the receiving router/PC thinks all those addresses are in the local network, and won't be accessible. I can make the router advertize and route these addresses correctly using proxy arp to those addresses if I can do this calculation and add an extra route command. [edit] see also http://forums.whirlpool.net.au/forum-re ... #r12250396

Some other routers use this netmask spoof method, I don't know if they also use use the proxy arp but if I can - I want to! I think I know how D-Link ZIPB works it effectively proxy-arps the whole of the internet but this needs a kernel patch in arp.c so I am not going there...

The 'experimental' half bridge script in RT2.3 has an option of the netmask spoof - but not this refinement. I also now have 1-2-1 NAT and Gateway spoof working but both need to keep iptables netfilter running for snat /dnat but not masquerade..... have I lost you yet?
Last edited by mstombs on Thu Dec 06, 2007 3:19 pm, edited 3 times in total.
User avatar
Shotokan101
RouterTech Team
RouterTech Team
Posts: 4772
Joined: Thu Jan 26, 2006 3:17 pm
Location: Glasgow, Scotland

Post by Shotokan101 » Tue Dec 04, 2007 1:19 am

Yet ? :lol:
Jim

.....I'm Sorry But I Can't Do That Dave.....
User avatar
thechief
RouterTech Team
RouterTech Team
Posts: 12064
Joined: Wed Feb 01, 2006 10:22 pm
Location: England, the Centre of Africa
Contact:

Post by thechief » Tue Dec 04, 2007 7:45 am

You lost me after the first line. :shock:
The Chief: :afro: Be sure to read the Firmware FAQ and do a Forum Search before posting!
No support via PM. Ask all questions on the open forum.
User avatar
biro
RouterTech Team
RouterTech Team
Posts: 1274
Joined: Wed Jan 25, 2006 10:03 pm
Location: Letchworth Garden City, ENGLAND
Contact:

Post by biro » Tue Dec 04, 2007 3:14 pm

Maybe try something like this

Code: Select all

ip=192.168.2.1
nm=255.255.255.0
 
ip4="${ip##*.}" ; x="${ip%.*}" 
ip3="${x##*.}" ; x="${x%.*}"
ip2="${x##*.}" ; x="${x%.*}"
ip1="${x##*.}"   

nm4="${nm##*.}" ; x="${nm%.*}"
nm3="${x##*.}" ; x="${x%.*}"
nm2="${x##*.}" ; x="${x%.*}"
nm1="${x##*.}"

let sn1="$ip1&$nm1" 
let sn2="$ip2&$nm2"
let sn3="$ip3&$nm3"
let sn4="$ip1&$nm4"

subnet=$sn1.$sn2.$sn3.$sn4 

echo $subnet
ImageImageImage
All my posts on RouterTech.org are Copyright RouterTech.org
G'Day Laura
User avatar
Shotokan101
RouterTech Team
RouterTech Team
Posts: 4772
Joined: Thu Jan 26, 2006 3:17 pm
Location: Glasgow, Scotland

Post by Shotokan101 » Tue Dec 04, 2007 3:21 pm

Biro - you're Nationality isn't "hsiloP" by any chance ? :shock:
Jim

.....I'm Sorry But I Can't Do That Dave.....
mstombs
RouterTech Team
RouterTech Team
Posts: 3753
Joined: Wed Jan 10, 2007 11:54 pm

Post by mstombs » Tue Dec 04, 2007 5:45 pm

biro wrote:Maybe try something like this
Great thanks, seems to work on Debian at least here in the office. Come to think of it I probably first saw the string handling commands in your localnat script biro - thanks again!
User avatar
biro
RouterTech Team
RouterTech Team
Posts: 1274
Joined: Wed Jan 25, 2006 10:03 pm
Location: Letchworth Garden City, ENGLAND
Contact:

Post by biro » Tue Dec 04, 2007 6:02 pm

The AND (&) function is the important bit, works at binary level the way the network mask does.
ImageImageImage
All my posts on RouterTech.org are Copyright RouterTech.org
G'Day Laura
User avatar
biro
RouterTech Team
RouterTech Team
Posts: 1274
Joined: Wed Jan 25, 2006 10:03 pm
Location: Letchworth Garden City, ENGLAND
Contact:

Post by biro » Wed Dec 05, 2007 11:44 am

Possibly something that could be useful to be added to above code, to show the highest IP for a given IP and subnet mask ( may be useful calculating DHCP start / end IP etc.)

Code: Select all

let en1="$ip1|(255-$nm1)"
let en2="$ip2|(255-$nm2)"
let en3="$ip3|(255-$nm3)"
let en4="$ip4|(255-$nm4)"

endnet=$en1.$en2.$en3.$en4

echo "end IP="$endnet
ImageImageImage
All my posts on RouterTech.org are Copyright RouterTech.org
G'Day Laura
mstombs
RouterTech Team
RouterTech Team
Posts: 3753
Joined: Wed Jan 10, 2007 11:54 pm

Post by mstombs » Wed Dec 05, 2007 12:18 pm

Now you've lost me - looks useful but I don't yet understand how it works... ahh I see bitwise OR. Did you know it is really hard to google for bash AND! although the info is out there somewhere ie

http://tldp.org/LDP/Bash-Beginners-Guid ... index.html

For a challenge can you calculate in a script the smallest valid subnet that includes 2 given IP addresses without abusing the start network or end broadcast IP address?
User avatar
Shotokan101
RouterTech Team
RouterTech Team
Posts: 4772
Joined: Thu Jan 26, 2006 3:17 pm
Location: Glasgow, Scotland

Post by Shotokan101 » Wed Dec 05, 2007 12:29 pm

Nope ! :rofls:
Jim

.....I'm Sorry But I Can't Do That Dave.....
User avatar
biro
RouterTech Team
RouterTech Team
Posts: 1274
Joined: Wed Jan 25, 2006 10:03 pm
Location: Letchworth Garden City, ENGLAND
Contact:

Post by biro » Wed Dec 05, 2007 1:02 pm

A starting point would be to use the 'exclusive or' function (^) on start and end IP.

Code: Select all

ips=    #start ip
ipe=    #end ip 
 

ips4="${ips##*.}" ; x="${ips%.*}" 
ips3="${x##*.}" ; x="${x%.*}" 
ips2="${x##*.}" ; x="${x%.*}" 
ips1="${x##*.}"    

ipe4="${ipe##*.}" ; x="${ipe%.*}" 
ipe3="${x##*.}" ; x="${x%.*}" 
ipe2="${x##*.}" ; x="${x%.*}" 
ipe1="${x##*.}" 

let nm1="${ips1^ipe1}
let nm2="${ips2^ipe2}
let nm3="${ips3^ipe3}
let nm4="${ips4^ipe4}

nm=$nm1.$nm2.$nm3.$nm4

echo $nm 
Not sure if it will allow for start network / end broadcast IPs (not tried it)
ImageImageImage
All my posts on RouterTech.org are Copyright RouterTech.org
G'Day Laura
mstombs
RouterTech Team
RouterTech Team
Posts: 3753
Joined: Wed Jan 10, 2007 11:54 pm

Post by mstombs » Thu Dec 06, 2007 6:46 pm

Exclusive OR doesn't seem to work...

BUT I have reduced your Bitwise OR to do the original function I wanted in a couple of unintelligible lines for shoto to gawp at!

Code: Select all

l="${IP%.*}";r="${IP#*.}";n="${NM%.*}";m="${NM#*.}"
subnet=$((${IP%%.*}&${NM%%.*})).$((${r%%.*}&${m%%.*})).$((${l##*.}&${n##*.})).$((${IP##*.}&${NM##*.}))
User avatar
thechief
RouterTech Team
RouterTech Team
Posts: 12064
Joined: Wed Feb 01, 2006 10:22 pm
Location: England, the Centre of Africa
Contact:

Post by thechief » Thu Dec 06, 2007 7:06 pm

:shock:
The Chief: :afro: Be sure to read the Firmware FAQ and do a Forum Search before posting!
No support via PM. Ask all questions on the open forum.
Post Reply