Given the IP and netmask, how can I calculate the network address using bash?
Asked Answered
A

7

18

In a bash script I have an IP address like 192.168.1.15 and a netmask like 255.255.0.0. I now want to calculate the start address of this network, that means using the &-operator on both addresses. In the example, the result would be 192.168.0.0. Does someone have something like this ready? I'm looking for an elegant way to deal with ip addresses from bash

Adenoidectomy answered 15/3, 2013 at 10:3 Comment(4)
You may consider ipcalc.Christianna
ipcalc is a perl cgi script that can be downloaded. Thanks, that is a great source for anyone who wants to implement it in PERL. I was looking for a solution in bash though, but perl would work in a shell script, too.Adenoidectomy
no I mean the unix command line to ipcalc. see answers.oreilly.com/topic/… for more information. As an alternative you could also use sipcalc (also a cli tool) which supports IPv6Christianna
I would have added this as a comment if I had the rep... Usage for cevings answer... # usage: netmask #bits # eg. netmask 24 => 255.255.255.0 # usage: broadcast address mask # eg. broadcast 192.168.0.1 24 => 192.168.0.255 # usage: network address mask # eg. network 192.168.0.123 24 => 192.168.0.0Ellswerth
C
45

Use bitwise & (AND) operator:

$ IFS=. read -r i1 i2 i3 i4 <<< "192.168.1.15"
$ IFS=. read -r m1 m2 m3 m4 <<< "255.255.0.0"
$ printf "%d.%d.%d.%d\n" "$((i1 & m1))" "$((i2 & m2))" "$((i3 & m3))" "$((i4 & m4))"
192.168.0.0

Example with another IP and mask:

$ IFS=. read -r i1 i2 i3 i4 <<< "10.0.14.97"
$ IFS=. read -r m1 m2 m3 m4 <<< "255.255.255.248"
$ printf "%d.%d.%d.%d\n" "$((i1 & m1))" "$((i2 & m2))" "$((i3 & m3))" "$((i4 & m4))"
10.0.14.96
Courtney answered 15/3, 2013 at 10:18 Comment(1)
This is brilliant. Thank you for taking the time to develop it.Archduchess
T
16

Some Bash functions summarizing all other answers.

ip2int()
{
    local a b c d
    { IFS=. read a b c d; } <<< $1
    echo $(((((((a << 8) | b) << 8) | c) << 8) | d))
}

int2ip()
{
    local ui32=$1; shift
    local ip n
    for n in 1 2 3 4; do
        ip=$((ui32 & 0xff))${ip:+.}$ip
        ui32=$((ui32 >> 8))
    done
    echo $ip
}

netmask()
# Example: netmask 24 => 255.255.255.0
{
    local mask=$((0xffffffff << (32 - $1))); shift
    int2ip $mask
}


broadcast()
# Example: broadcast 192.0.2.0 24 => 192.0.2.255
{
    local addr=$(ip2int $1); shift
    local mask=$((0xffffffff << (32 -$1))); shift
    int2ip $((addr | ~mask))
}

network()
# Example: network 192.0.2.0 24 => 192.0.2.0
{
    local addr=$(ip2int $1); shift
    local mask=$((0xffffffff << (32 -$1))); shift
    int2ip $((addr & mask))
}
Trellis answered 21/9, 2015 at 8:35 Comment(5)
Nice but an example line would have saved me 15mins of figuring out your parameter expectations.. "network 192.168.8.1 31" or "netmask 16"Irritable
So be it, back to the way it was.Indebtedness
in broadcast and network functions there are two arguments. Shouldn't the bit 32 - $1 be 32 - $2 instead? I added the possibility of use cidr notation with something like [ $# -eq 1 ] && echo "$1" | grep -E '[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/[0-9]{1,2}' && IFS=/ read -ra cidr <<< "$1" to be able to use it with the output of ip -o -f inet addr show dev enp3s0 | awk '/scope global/ {print $4}'Posse
@Posse The call of shift makes $2 to $1.Trellis
Ah! I missed that. I have my own version of the script and at some point I must have changed that for clarity. Thanks anyway for your answer and codePosse
L
10

Just adding an alternative if you have only network prefix available (no netmask):

IP=10.20.30.240
PREFIX=26
IFS=. read -r i1 i2 i3 i4 <<< $IP
IFS=. read -r xx m1 m2 m3 m4 <<< $(for a in $(seq 1 32); do if [ $(((a - 1) % 8)) -eq 0 ]; then echo -n .; fi; if [ $a -le $PREFIX ]; then echo -n 1; else echo -n 0; fi; done)
printf "%d.%d.%d.%d\n" "$((i1 & (2#$m1)))" "$((i2 & (2#$m2)))" "$((i3 & (2#$m3)))" "$((i4 & (2#$m4)))"
Lydialydian answered 24/7, 2015 at 15:20 Comment(0)
E
3

For people who hit this while googling and need an answer that works in ash, the sh that's included in BusyBox and therefore on many routers, here's something for that case:

IP=10.20.30.240
MASK=255.255.252.0
IFS=. read -r i1 i2 i3 i4 << EOF
$IP
EOF
IFS=. read -r m1 m2 m3 m4 << EOF
$MASK
EOF
read masked << EOF
$(( $i1 & $m1 )).$(( $i2 & $m2 )).$(( $i3 & $m3 )).$(( $i4 & $m4 ))
EOF
echo $masked

And here's what to do if you only have the prefix length:

IP=10.20.30.240
PREFIX=22
IFS=. read -r i1 i2 i3 i4 << EOF
$IP
EOF
mask=$(( ((1<<32)-1) & (((1<<32)-1) << (32 - $PREFIX)) ))
read masked << EOF
$(( $i1 & ($mask>>24) )).$(( $i2 & ($mask>>16) )).$(( $i3 & ($mask>>8) )).$(( $i4 & $mask ))
EOF
echo $masked
Excursus answered 17/11, 2020 at 15:0 Comment(0)
P
1

Great answer, though minor typo in answer above.

$ printf "%d.%d.%d.%d\n" "$((i1 & m1))" "$(($i2  <-- $i2 should be i2

If anyone knows how to calculate the broadcast address (XOR the network), then calculate the usable nodes between network and broadcast I'd be interested in those next steps. I have to find addresses in a list within a /23.

Poteat answered 25/8, 2014 at 21:34 Comment(1)
Which answer is above? there are severalDeploy
B
0

In addition to @Janci answer

IP=10.20.30.240
PREFIX=26
IFS=. read -r i1 i2 i3 i4 <<< $IP
D2B=({0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1})
binIP=${D2B[$i1]}${D2B[$i2]}${D2B[$i3]}${D2B[$i4]}
binIP0=${binIP::$PREFIX}$(printf '0%.0s' $(seq 1 $((32-$PREFIX))))
# binIP1=${binIP::$PREFIX}$(printf '0%.0s' $(seq 1 $((31-$PREFIX))))1
echo $((2#${binIP0::8})).$((2#${binIP0:8:8})).$((2#${binIP0:16:8})).$((2#${binIP0:24:8}))
Briefless answered 18/2, 2016 at 22:1 Comment(0)
D
0

Based on https://mcmap.net/q/472758/-given-the-ip-and-netmask-how-can-i-calculate-the-network-address-using-bash I tried to simplify and came up with

IP=10.20.30.240
PREFIX=22
IFS=. read -r i1 i2 i3 i4 <<< $IP
mask=$(( ((1<<32)-1) & (((1<<32)-1) << (32 - $PREFIX)) ))
masked=$(( $i1 & ($mask>>24) )).$(( $i2 & ($mask>>16) )).$(( $i3 & ($mask>>8) )).$(( $i4 & $mask ))
echo $masked
Deploy answered 14/7, 2021 at 18:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.