Differences between revisions 3 and 4
Revision 3 as of 2016-09-25 20:28:41
Size: 1816
Editor: tor2
Comment: simplify
Revision 4 as of 2016-09-25 20:35:05
Size: 1809
Editor: tor2
Comment: remove ugly extra whitespace
Deletions are marked like this. Additions are marked like this.
Line 10: Line 10:
  IFS=. read -ra o <<< "$1"   IFS=. read -ra o <<<"$1"
Line 37: Line 37:
$ echo $(( 3232238081 & 4294967040 )) $ echo $((3232238081 & 4294967040))
Line 46: Line 46:
$ echo $(( ~4294967040 & 0xffffffff )) $ echo $((~4294967040 & 0xffffffff))
Line 48: Line 48:
$ echo $(( 3232238081 & 255 )) $ echo $((3232238081 & 255))

How do I operate on IP addresses and netmasks?

IPv4 addresses are 32-bit unsigned integers. The "dotted quad" notation (192.168.1.2) is only one means of representing such an address. When applying netmasks, it's easier if we first convert the dotted quad format into a plain integer.

There are several ways we can do this, but here's one of the simplest ways:

ip2int() {
  local o       # array of octets (bytes)
  IFS=. read -ra o <<<"$1"
  echo "$(((o[0] << 24) + (o[1] << 16) + (o[2] << 8) + o[3]))"
}

int2ip() {
  echo "\
$((($1 >> 24) & 0xFF)).\
$((($1 >> 16) & 0xFF)).\
$((($1 >>  8) & 0xFF)).\
$(($1 & 0xFF))"
}

Using these functions, we can convert back and forth:

$ ip2int 192.168.10.1
3232238081
$ int2ip 3232238081
192.168.10.1

To apply a netmask, we convert the netmask to an integer, and then perform a bitwise AND operation to get the network portion:

$ ip2int 255.255.255.0
4294967040
$ echo $((3232238081 & 4294967040))
3232238080
$ int2ip 3232238080
192.168.10.0

The host portion is similar: first we negate the netmask, and then we do the same bitwise AND. After negating, we have to grab only the lowest 32 bits; otherwise, bash's 64-bit integers might give us some odd-looking results.

$ echo $((~4294967040 & 0xffffffff))
255
$ echo $((3232238081 & 255))
1
$ int2ip 1
0.0.0.1

The same principle applies to a netmask of any size. For example, a /23 netmask looks like:

$ int2ip $((0xfffffe00))
255.255.254.0
$ int2ip $((2#11111111111111111111111000000000))
255.255.254.0

The hexadecimal constant 0xfffffe00 is the same as the binary constant 2#11111111111111111111111000000000 but is more convenient to write, and easier for a human to verify.

BashFAQ/114 (last edited 2016-09-25 20:35:05 by tor2)