Introduction

Here are a few programs to help us understand IPv4 addresses.

Prefix Notation

You may see ``CIDR’’ notation in the literature. The CIDR notation and the prefix notation are the same notation, i.e., the notation of ip address/prefix length. Given this notation, we can obtain the network number, the host number, and the broadcast address for the network. Below is the program (ipv4netbrdfromprefix.py) that obtains the network number and the broadcast address from a prefix notation of an IPv4 address.

import sys
import socket

def get_netnum_brdaddr(addr, plen):
    netnumi = int.from_bytes(addr, byteorder='big') >> (32 - plen) << (32 - plen)
    nmaski = 0xffffffff >> plen
    brdaddri = netnumi | nmaski
    netnum = netnumi.to_bytes(4, byteorder='big')
    brdaddr = brdaddri.to_bytes(4, byteorder='big')
    return netnum,brdaddr

def usage(prog):
    print('Usage: ' + prog + ' ipv4address/prefix', file=sys.stderr)
    
def main(argv):
    if len(argv) < 2:
        usage(argv[0])
        sys.exit(1)
    addrp,plenp = sys.argv[1].split('/')
    addr = socket.inet_pton(socket.AF_INET, addrp)
    plen = int(plenp)
    netnum,brdaddr =  get_netnum_brdaddr(addr, plen)
    print(netnum, socket.inet_ntop(socket.AF_INET, netnum))
    print(brdaddr, socket.inet_ntop(socket.AF_INET, brdaddr))

# to run as a script
if __name__ == '__main__':
    main(sys.argv)

Network Mask Notation

Network mask is a concept predates the CIDR or the prefix notation. Commonly, we choose a network mask whose binary representation consits of consecutieve 1’s followed by consecutive 0’s. In this case, there is a equivalent prefix notation with the prefix length as the number of the consecutive 1’s. However, it is we who impose such a restriction on network masks when we select one, and although uncommon, we can legitimately select a network mask that doesn’t have consecutive 1’s, e.g. 255.0.255.0 (in the dotted decimal notation). Below is a program (ipv4netbrdfrommask.py) that obtains the network number and the broadcast address from an address with its network mask.

import sys
import socket

def get_netnum_brdaddr(addr, mask):
    netl = []
    brdl = []
    for a,m in zip(addr,mask):
      netl.append(a & m)
      brdl.append(a | (~m & 0xff))

    netnum = bytes(netl)
    brdaddr = bytes(brdl)

    return netnum,brdaddr

def usage(prog):
    print('Usage: ' + prog + ' ipv4address ipv4netmask', file=sys.stderr)

def main(argv):
    if len(argv) < 3:
        usage(argv[0])
        sys.exit(1)
    addr = socket.inet_pton(socket.AF_INET, argv[1])
    mask = socket.inet_pton(socket.AF_INET, argv[2])
    netnum,brdaddr =  get_netnum_brdaddr(addr, mask)
    print(netnum, socket.inet_ntop(socket.AF_INET, netnum))
    print(brdaddr, socket.inet_ntop(socket.AF_INET, brdaddr))

# to run as a script
if __name__ == '__main__':
    main(sys.argv)

Exercises and Exploration

Let’s consider the following questions.

  1. When we run ipv4netbrdfromprefix.py as the following example,
      $ python ipv4netbrdfromprefix.py 192.168.7.101/23
      b'\xc0\xa8\x06\x00' 192.168.6.0
      b'\xc0\xa8\x07\xff' 192.168.7.255
    

    It is correctly to state that 192.168.6.0 is the network number and 192.168.7.255 is the broadcast address for 192.168.7.101/23?

  2. We make a comment in the above that a network mask does not have to be in the form of consecutive 1’s followed by consecutive 0’s. However, in practive, we almost always do. Why?
  3. Can you write a program (or a few programs) to report the type of an IPv4 address, i.e., whether the address is a unicast address, a broadcast address, a multicast address, a Document address, or a reserved address and if it is a unicast address, whether it is a private network address, a link-local address, a loop back address, or a global unicast address?.