mirror of
https://gitlab.com/shorewall/code.git
synced 2024-11-15 04:04:10 +01:00
207 lines
6.0 KiB
Python
207 lines
6.0 KiB
Python
|
#!/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()
|