#!/usr/bin/env python # vim: set ts=8 sw=4 sts=4 et ai: # Walter Doekes, Public Domain, 2013, version:1 from re import compile as re_compile from socket import inet_aton from struct import unpack from sys import argv, exit, stdin # The "program" def main(): items = extract_ips(stdin) items = [ipmask_to_tuple(i) for i in items] items = prune_tuples(items) print_tuples(items) # Read IPs def extract_ips(file): extract_ips = re_compile(r'(\d+\.\d+\.\d+\.\d+/\d+)') ipmasks = [] for line in file: ipmasks.extend(extract_ips.findall(line)) return ipmasks # Translate IP def ipmask_to_tuple(string): ip, mask = string.split('/', 1) ip = unpack('>I', inet_aton(ip))[0] mask = int(mask) assert 0 <= mask <= 32, '%d?' % (mask,) mask = (0xffffffff << (32 - mask)) & 0xffffffff assert (ip & mask) == ip, '%08x/%08x' % (ip, mask) return ip, mask, string # Remove dupes / overlap def prune_tuples(items): # Sort and remove direct dupes items = list(set(items)) items.sort() # See if there are larger blocks that encompass smaller ones # in a nice O(N^2) loop large_tuples = [] for ip, mask, string in items: # For each IP, check if there is a bigger range for large_ip, large_mask, _ in items: # Don't check if our mask is bigger or is self # (a bigger mask is a smaller value!) if mask <= large_mask: continue # If the bigger mask encompasses us, ignore if (ip & large_mask) == large_ip: break else: # No break? Then we have an active one large_tuples.append((ip, mask, string)) return large_tuples # Print list def print_tuples(items): print '(' for ip, mask, string in items: print ' (0x%08x, 0x%08x), # %s' % (ip, mask, string) print ')' # Go go go if __name__ == '__main__': if len(argv) > 1: print 'Usage: %s < file_with_ip_mask.txt' % (argv[0],) print ' input data which contains one or more IP-blocks in' print ' CIDR notation (e.g. 1.2.3.0/24), will print output ' print ' usable by python' print 'Example:' print ' (printf "1.2.3.0/24\\n1.2.4.0/24\\n1.2.2.0/23\\n"' print ' printf "1.2.2.0/24\\n1.2.0.0/22") | python %s' % (argv[0],) exit(0) main()