Blame | Last modification | View Log | Download
# Written by John Hoffman# see LICENSE.txt for license informationfrom bisect import bisect, insorttry:Trueexcept:True = 1False = 0bool = lambda x: not not xhexbinmap = {'0': '0000','1': '0001','2': '0010','3': '0011','4': '0100','5': '0101','6': '0110','7': '0111','8': '1000','9': '1001','a': '1010','b': '1011','c': '1100','d': '1101','e': '1110','f': '1111','x': '0000',}chrbinmap = {}for n in xrange(256):b = []nn = nfor i in xrange(8):if nn & 0x80:b.append('1')else:b.append('0')nn <<= 1chrbinmap[n] = ''.join(b)def to_bitfield_ipv4(ip):ip = ip.split('.')if len(ip) != 4:raise ValueError, "bad address"b = []for i in ip:b.append(chrbinmap[int(i)])return ''.join(b)def to_bitfield_ipv6(ip):b = ''doublecolon = Falseif ip == '':raise ValueError, "bad address"if ip == '::': # boundary handlingip = ''elif ip[:2] == '::':ip = ip[1:]elif ip[0] == ':':raise ValueError, "bad address"elif ip[-2:] == '::':ip = ip[:-1]elif ip[-1] == ':':raise ValueError, "bad address"for n in ip.split(':'):if n == '': # double-colonif doublecolon:raise ValueError, "bad address"doublecolon = Trueb += ':'continueif n.find('.') >= 0: # IPv4n = to_bitfield_ipv4(n)b += n + '0'*(32-len(n))continuen = ('x'*(4-len(n))) + nfor i in n:b += hexbinmap[i]if doublecolon:pos = b.find(':')b = b[:pos]+('0'*(129-len(b)))+b[pos+1:]if len(b) != 128: # always check sizeraise ValueError, "bad address"return bipv4addrmask = to_bitfield_ipv6('::ffff:0:0')[:96]class IP_List:def __init__(self):self.ipv4list = []self.ipv6list = []def __nonzero__(self):return bool(self.ipv4list or self.ipv6list)def append(self, ip, depth = 256):if ip.find(':') < 0: # IPv4insort(self.ipv4list,to_bitfield_ipv4(ip)[:depth])else:b = to_bitfield_ipv6(ip)if b.startswith(ipv4addrmask):insort(self.ipv4list,b[96:][:depth-96])else:insort(self.ipv6list,b[:depth])def includes(self, ip):if not (self.ipv4list or self.ipv6list):return Falseif ip.find(':') < 0: # IPv4b = to_bitfield_ipv4(ip)else:b = to_bitfield_ipv6(ip)if b.startswith(ipv4addrmask):b = b[96:]if len(b) > 32:l = self.ipv6listelse:l = self.ipv4listfor map in l[bisect(l,b)-1:]:if b.startswith(map):return Trueif map > b:return Falsereturn Falsedef read_fieldlist(self, file): # reads a list from a file in the format 'ip/len <whatever>'f = open(file, 'r')while True:line = f.readline()if not line:breakline = line.strip().expandtabs()if not line or line[0] == '#':continuetry:line, garbage = line.split(' ',1)except:passtry:line, garbage = line.split('#',1)except:passtry:ip, depth = line.split('/')except:ip = linedepth = Nonetry:if depth is not None:depth = int(depth)self.append(ip,depth)except:print '*** WARNING *** could not parse IP range: '+linef.close()def set_intranet_addresses(self):self.append('127.0.0.1',8)self.append('10.0.0.0',8)self.append('172.16.0.0',12)self.append('192.168.0.0',16)self.append('169.254.0.0',16)self.append('::1')self.append('fe80::',16)self.append('fec0::',16)def set_ipv4_addresses(self):self.append('::ffff:0:0',96)def ipv6_to_ipv4(ip):ip = to_bitfield_ipv6(ip)if not ip.startswith(ipv4addrmask):raise ValueError, "not convertible to IPv4"ip = ip[-32:]x = ''for i in range(4):x += str(int(ip[:8],2))if i < 3:x += '.'ip = ip[8:]return xdef to_ipv4(ip):if is_ipv4(ip):_valid_ipv4(ip)return ipreturn ipv6_to_ipv4(ip)def is_ipv4(ip):return ip.find(':') < 0def _valid_ipv4(ip):ip = ip.split('.')if len(ip) != 4:raise ValueErrorfor i in ip:chr(int(i))def is_valid_ip(ip):try:if not ip:return Falseif is_ipv4(ip):_valid_ipv4(ip)return Trueto_bitfield_ipv6(ip)return Trueexcept:return False