LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Go Back   LinuxQuestions.org > Blogs > Notes on Linux
User Name
Password

Notices

I leave notes here that I find particularly worth remembering myself.
Rate this Entry

CIDR to Netmask conversion with Python (convert short netmask to long, dotted format)

Posted 09-03-2010 at 05:43 AM by bittner
Updated 09-03-2010 at 10:20 AM by bittner

When you write scripts dealing with setting up or analyzing network interfaces you will eventually run into the task of converting a netmask from one format into another.

Typically, the setup of an ethernet TCP/IP network interface consists of an IP address, a netmask, and a broadcast address. Unfortunately for you as a novice, the two tools ifconfig and ip show the same (or similar) information in a different format.

Quote:
$ /sbin/ifconfig
eth0 Link encap:Ethernet HWaddr 00:d0:c9:a5:99:f4
inet addr:146.112.129.3 Bcast:146.112.159.255 Mask:255.255.224.0
inet6 addr: fe80::2d0:c9ff:fea5:99f4/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:14706157 errors:0 dropped:0 overruns:0 frame:0
TX packets:11728631 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:3127295322 (2.9 GiB) TX bytes:984587855 (938.9 MiB)
Memory:fd8e0000-fd900000

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:890946 errors:0 dropped:0 overruns:0 frame:0
TX packets:890946 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:433573498 (413.4 MiB) TX bytes:433573498 (413.4 MiB)
Here, ifconfig says "addr:146.112.129.3 ... Mask:255.255.224.0", ...

Quote:
$ /sbin/ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 100
link/ether 00:d0:c9:a5:99:f4 brd ff:ff:ff:ff:ff:ff
inet 146.112.129.3/19 brd 146.112.159.255 scope global eth0
inet6 fe80::2d0:c9ff:fea5:99f4/64 scope link
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
link/ether 00:d0:c9:a5:99:f5 brd ff:ff:ff:ff:ff:ff
... whereas ip addr spits out "146.112.129.3/19" for one and the same network interface. I usually refer to the above output as "dotted notation" and the latter one as the "short netmask", officially called "CIDR format" to my knowledge, which is practically the number of 1's (0-32) in the binary netmask.

If your software expects a dotted notation, but all you get from the source you analyze is the short CIDR number, go and convert it. But how?

Some Python code to make you happy

Don't be surprised, I've found no small and easy-to-grasp code snippet on the Internet, you won't probably either. That's a bit strange, especially because in the end a simple solution is not that difficult to implement. Here is my approach using Python:

Code:

# CIDR to Netmask conversion
# (c) 2010 Peter Bittner, http://linux.bittner.it/blog
# 
# Tip for an excellent background read: "IP subnetting made easy"
# http://articles.techrepublic.com.com/5100-10878_11-6089187.html

def len2mask(len):
    """Convert a bit length to a dotted netmask (aka. CIDR to netmask)"""
    mask = ''
    if not isinstance(len, int) or len < 0 or len > 32:
        print "Illegal subnet length: %s (which is a %s)" % (str(len), type(len).__name__)
        return None
    
    for t in range(4):
        if len > 7:
            mask += '255.'
        else:
            dec = 255 - (2**(8 - len) - 1)
            mask += str(dec) + '.'
        len -= 8
        if len < 0:
            len = 0
    
    return mask[:-1]

# Example
for len in range(32,-1,-1):
    print '/%d = %s' % (len, len2mask(len))
The main idea is: The binary netmask contains all 1-bits on the left side, and all 0-bits on the right side - no mixing -, and the CIDR number counts those 1-bits. So, from left to right, ...
  • As long as we can subtract 8 bits we have a byte full of ones, which corresponds to '255' in decimal. Dot (full stop).
  • As soon as we hit zero all other pieces in the dotted format will be '0'.
  • The tricky part comes when the CIDR netmask is not a multiple of 8, then we must calculate the power of the remainder (= CIDR number modulo 8) to the base of 2 - BUT: the 1-bits in the binary string are on the wrong side here, beware! That's how we arrive at: 255 - (2^(8 - remainder) - 1)

Of course, you can implement this simple algorithm in any other language you like. All by yourself, naturally.

Side note
Note in the above sample output of ifconfig and ip that ip lists an additional network interface as compared to ifconfig. Both commands have been executed on one and the same machine, directly one after the other.

The reason for this may be one of the reasons you may start considering ip as a tool over ipconfig for some tasks, as I did: ip also list interfaces that are not active or configured. With ip -o link, for example, you can get the MAC addresses of all available interfaces (in a single-line format convenient for post-processing), regardless to whether they are already configured or not.

References
Posted in Uncategorized
Views 5757 Comments 0
« Prev     Main     Next »
Total Comments 0

Comments

 

  



All times are GMT -5. The time now is 02:24 AM.

Main Menu
Advertisement

My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration