how to calculate netwrk from IP address and netmask using Bitwise AND in shell script

Hi,

I am having two variables
IP="10.150.12.1"
netmask="255.255.255.0"

To get network number, I know that a bitwise & will help.
networkno=IP & netmask

My code is
#!/usr/bin/ksh
ip="10.150.12.1"
netmask="255.255.255.0"
networkno="$ip" & "$netmask"
echo $networkno

I am getting the following error
./try.sh[5]: 255.255.255.0: not found.

What's the mistake in the code.

The ampersand (&) puts processes in the background, so you are putting networkno=$ip in the background, then trying to execute 255.255.255.0.

What is it that you want to accomplish? What's the output you are expecting?
If you give 10.150.12.1 and 255.255.255.0, are you expecting the output to be 10.150.12.0? Or .1? Or .0 ? or 10.150.12.1/24 ?

Actually you have 2 mistakes

  1. To do bitwise operations, you have to do it within the delimiters for arithmetic evaluation $(( ... ))
  2. You'll first have to convert your IP address to it's integer representation (10.150.12.1 would become 177605633 [0x0A960C01]), since you can't do arithmetic on strings.

You probably could do it in the shell, but I guess you'll be quicker writing a small C program that does that for you.

Hi System Shock & pludi,

thanks for the inputs.
What I want is
if IP="10.150.12.1" and netmask="255.255.255.0",
I want networkno to be 10.150.12.

I do not know how to change strings into integers.
Also, I have to use shell scripting only.

Please help me with the code to accomplish the above requirement

Why Shell code only? A C program to calculate IP-Address related stuff (or about anything on a bit manipulation level) can easily be written in ANSI C which will compile on any platform, and it's quite trivial to do so (was one of my first C assignments in school)

As for the conversion, it would be something like this pseudo-code.

Split on '.'
Result=0
For each element
    Result *= 256
    Result += element

So 10.150.20.1 would be converted to 177605633. Do this for both the IP and the Netmask and do your &-magic. To get something back do:

Result=177605632 # IP & NM
While Result > 256
    Byte = Result % 256
    Result /= 256

which will give you the least significant byte first, so you'll probably have to switch them.

Here is how to do it using ksh93.

#!/bin/ksh93

typeset -i2 mask=255

[[ $# != 2 ]] && {
   echo "Usage: $0 ipaddress subnetmask"
   exit 1
}

SaveIFS=$IFS
IFS=.
typeset -a IParr=($1)
typeset -a NMarr=($2)
IFS=$SaveIFS

typeset -i2 ipbin1=${IParr[0]}
typeset -i2 ipbin2=${IParr[1]}
typeset -i2 ipbin3=${IParr[2]}
typeset -i2 ipbin4=${IParr[3]}

typeset -i2 nmbin1=${NMarr[0]}
typeset -i2 nmbin2=${NMarr[1]}
typeset -i2 nmbin3=${NMarr[2]}
typeset -i2 nmbin4=${NMarr[3]}

echo
echo "       IP Address: $1"
echo "      Subnet Mask: $2"
echo "  Network Address: $((ipbin1 & nmbin1)).$((ipbin2 & nmbin2)).$((ipbin3 & nmbin3)).$((ipbin4 & nmbin4))"
echo "Broadcast Address: $((ipbin1 | (mask ^ nmbin1))).$((ipbin2 | (mask ^ nmbin2))).$((ipbin3 | (mask ^ nmbin3))).$((ipbin4 | (mask ^ nmbin4)))"
echo

exit 0

Here is the output for the IP address and subnet mask you supplied followed by the output for a sightly different subnet mask (just to show the difference)

$ ./calculate-address 10.150.12.1 255.255.255.0

       IP Address: 10.150.12.1
      Subnet Mask: 255.255.255.0
  Network Address: 10.150.12.0
Broadcast Address: 10.150.12.255

$ ./calculate-address 10.150.12.1 255.255.254.0

       IP Address: 10.150.12.1
      Subnet Mask: 255.255.254.0
  Network Address: 10.150.12.0
Broadcast Address: 10.150.13.255
1 Like

Hi fpmurhy,
The code worked fine ..:slight_smile:

fpmurphy, thanks for your code. I've now changed it to work with bash and included a few other IP/CIDR/Subnet mask related functions.

Sorry if my code is not so optimized, but this was my first try :slight_smile:
I'm trying to put together code to run on a WRT54G router with DD-WRT firmware. Eventually I want it to remove redundant/encapsulated routing table entries.

#!/bin/bash

# Convert IP to int
function ip_to_int() {
    SaveIFS=$IFS
    IFS=.
    typeset -a IParr=($1)
    IFS=$SaveIFS

    result=0
    for ((i=0;i<4;i+=1)); do
        result=$(($result * 256))
        result=$((${IParr[$i]} + $result))
    done

    echo $result
}

# Convert IP from int
function int_to_ip() {
    result=$1
    byte=""
    for ((i=0;i<3;i+=1)); do
        byte=.$(($result % 256))$byte
        result=$(($result / 256))
    done
    echo $result$byte
}

# Calculate number of addresses in subnet 
function cidr_to_netsize() {
    echo $((1 << 32 - $1))
}

# Calculate bitmask for the 'host' part
function cidr_to_hostmask() {
    echo $(($(($((1 << $1)) - 1)) << $((32 - $1))))
}

# Get the Network destination from the IP & Subnet mask
function get_network_address() {
    SaveIFS=$IFS
    IFS=.
    typeset -a IParr=($1)
    typeset -a NMarr=($2)
    IFS=$SaveIFS

    echo $((${IParr[0]} & ${NMarr[0]})).$((${IParr[1]} & ${NMarr[1]})).$((${IParr[2]} & ${NMarr[2]})).$((${IParr[3]} & ${NMarr[3]}))
}

# Get the broadcast address from the IP & Subnet mask
function get_broadcast_address() {
    SaveIFS=$IFS
    IFS=.
    typeset -a IParr=($1)
    typeset -a NMarr=($2)
    IFS=$SaveIFS

    echo $((${IParr[0]} | (255 ^ ${NMarr[0]}))).$((${IParr[1]} | (255 ^ ${NMarr[1]}))).$((${IParr[2]} | (255 ^ ${NMarr[2]}))).$((${IParr[3]} | (255 ^ ${NMarr[3]})))
}

[[ $# != 2 ]] && {
   echo "Usage: $0 CIDR IP-Address"
   exit 1
}

# Given values
cidr=$1
ip=$2

# Calculations
netsize=$(cidr_to_netsize $cidr)
hostmask=$(cidr_to_hostmask $cidr)
subnet=$(int_to_ip $hostmask)
int_ip=$(ip_to_int $2)
ip_from_int=$(int_to_ip $int_ip)
netaddr=$(get_network_address $ip $subnet)
broadcast=$(get_broadcast_address $ip $subnet)

# Output
echo "Given CIDR: $cidr"
echo "    CIDR to NETWORK SIZE: $netsize"
echo "    CIDR to HOST MASK: $hostmask"
echo "    HOST MASK to SUBNET MASK: $subnet"
echo 
echo "Given IP: $ip"
echo "    IP to INT: $int_ip"
echo "    INT to IP: $ip_from_int"
echo
echo "Given IP & SUBNET MASK: $ip & $subnet"
echo "    IP & SUBNET MASK to NETWORK ADDRESS: $netaddr"
echo "    IP & SUBNET MASK to BROADCAST ADDRESS: $broadcast"
exit 0

Sample output:

$ ./ip2int 16 192.168.10.15
Given CIDR: 16
        CIDR to NETWORK SIZE: 65536
        CIDR to HOST MASK: 4294901760
        HOST MASK to SUBNET MASK: 255.255.0.0

Given IP: 192.168.10.15
        IP to INT: 3232238095
        INT to IP: 192.168.10.15

Given IP & SUBNET MASK: 192.168.10.15 & 255.255.0.0
        IP & SUBNET MASK to NETWORK ADDRESS: 192.168.0.0
        IP & SUBNET MASK to BROADCAST ADDRESS: 192.168.255.255