shorewall_code/contrib/iana_reserved/getreserved.py

207 lines
6.0 KiB
Python
Raw Normal View History

#!/usr/bin/env python2
"""
getreserved.py - Copyright (c) 2002 by Andy Wiggin
Licenced under the GPL
Script to write a stream of reserved addresses
from an IANA address allocation file. This list
is apparently similiar to RFC 1466.
The file can be obtained at
http://www.iana.org/assignments/ipv4-address-space
Download this file to a local file, then run the following:
cat local_file | ./getreserved.py
to produce a list of reserved subnets which can be used
in a shell script.
"""
import sys
__script_debug = 0
__output_style = 'rfc1918'
class IpNet:
def __init__(self):
self.netnum = 0
self.maskind = 0
def __str__(self):
return "%u.%u.%u.%u/%d"%\
(self.GetNetByte(3), self.GetNetByte(2),
self.GetNetByte(1), self.GetNetByte(0), self.maskind)
def Set(self, netnum, maskind):
self.netnum = int(netnum)
self.maskind = int(maskind)
def GetNetNum(self): return self.netnum
def GetMaskIndex(self): return self.maskind
def GetMaskBits(self):
numbits = 32 - self.maskind
retmask = 0
for i in range(numbits):
retmask = (retmask << 1) + 0x1
return retmask
def GetNetByte(self, byteind):
if byteind < 0 or byteind > 3:
raise RuntimeError, "bad byte index"
shiftcount = 8 * byteind
mask = 0xff << shiftcount
byte = self.netnum & mask
return (byte >> shiftcount) & 0xff
def GetIpNetList(fd):
ipnets = []
for l in fd.xreadlines():
if l.find('IANA - Reserved') > 0 or \
l.find('IANA - Private Use') > 0:
# Get the range and net size from the first field
fields = l.split()
(ip_range, mask_size) = fields[0].split('/')
if __script_debug:
print '\t\t', ip_range, mask_size
# Convert the range to numbers
ip_range = ip_range.split('-')
ip_min = int(ip_range[0])
if len(ip_range) > 1:
ip_max = int(ip_range[1])
else:
ip_max = ip_min
# For each number in the range, add an ip net string to the output
# list
for ip_num in range(ip_min, ip_max+1):
#ipel = "%d.0.0.0/%s"%(ip_num, mask_size)
ipel = IpNet()
ipel.Set(ip_num << 24, int(mask_size))
if __script_debug:
print str(ipel)
ipnets.append(ipel)
return ipnets
def CompactIpNetList(ipnets):
"""
Combine an many nets as possible.
"""
done = 0
ipnets.sort(IpCmpFunc)
oldlist = ipnets
while not done:
done = 1
newlist = []
head = None
while len(oldlist) > 0:
if not head:
# Consume one item from the list
head = oldlist.pop(0)
else:
# Consume head, and maybe an item from the list
next = oldlist.pop(0)
# Determine of head and next can be merged
# The merge condition is that two element have the same netmask,
# their net numbers are different by just one bit, and that
# bit is the least significant bit after the mask bits.
canmerge = 0
if head.GetMaskIndex() == next.GetMaskIndex():
# Get the net numbers
nnxor = head.GetNetNum() ^ next.GetNetNum()
# Calculate what the XOR would have to be for a merge
mask = head.GetMaskBits()
nextbit = (mask << 1) & ~mask
if nnxor == nextbit:
canmerge = 1
if canmerge:
# Because the list is sorted and we know that the xor was
# different by just one bit, the element occuring earier
# in the list (head) already has the correct net number,
# since it must have a 0 in the bit being merged. Therefore
# we can just use head, and decrease the mask index by one
nn = head.GetNetNum()
mindex = head.GetMaskIndex()
head.Set(nn, mindex-1)
newlist.append(head)
head = None
next = None # This element is just abandoned
# We'll need to loop again
done = 0
else:
newlist.append(head)
head = next
# There might be a valid head element sitting around at the end
if head:
newlist.append(head)
# Make newlist the current list
oldlist = newlist
return oldlist
def IpCmpFunc(el1, el2):
n1 = el1.GetNetNum()
n2 = el2.GetNetNum()
# Not sure how to do unsigned comparisons in python, so
# if the 32'nd bit is set, create a long out of it, add
# twice the value of the 32 bit (the 33rd bit), and compare.
if n1 < 0:
n1 = long(n1) + 0x100000000L
if n2 < 0:
n2 = long(n2) + 0x100000000L
v = n1 - n2
if v < 0:
return -1
elif v > 0:
return 1
else:
return 0
def main():
infd = sys.stdin
outfd = sys.stdout
# Get the list
iplist = GetIpNetList(infd)
iplist = CompactIpNetList(iplist)
if __output_style == 'shlist':
# Write a list of strings, compatible with a shell script list.
# Fomats four on each line, indented by one TAB.
numperline = 4
numinline = 0
for ip in iplist:
if numinline == 0:
outfd.write( '\t\t' )
outfd.write("'%s' "%ip)
numinline += 1
if numinline == numperline:
outfd.write( "\\\n" )
numinline = 0
if numinline > 0:
outfd.write( "\n" )
elif __output_style == 'rfc1918':
for ip in iplist:
outfd.write("%s\t\tlogdrop\t\t# Reserved\n"%ip)
if __name__ == '__main__':
main()