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 xdef to_long_ipv4(ip):ip = ip.split('.')if len(ip) != 4:raise ValueError, "bad address"b = 0Lfor n in ip:b *= 256b += int(n)return bdef to_long_ipv6(ip):if 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"b = []doublecolon = Falsefor n in ip.split(':'):if n == '': # double-colonif doublecolon:raise ValueError, "bad address"doublecolon = Trueb.append(None)continueif n.find('.') >= 0: # IPv4n = n.split('.')if len(n) != 4:raise ValueError, "bad address"for i in n:b.append(int(i))continuen = ('0'*(4-len(n))) + nb.append(int(n[:2],16))b.append(int(n[2:],16))bb = 0Lfor n in b:if n is None:for i in xrange(17-len(b)):bb *= 256continuebb *= 256bb += nreturn bbipv4addrmask = 65535L*256*256*256*256class IP_List:def __init__(self):self.ipv4list = [] # starts of rangesself.ipv4dict = {} # start: end of rangesself.ipv6list = [] # "self.ipv6dict = {} # "def __nonzero__(self):return bool(self.ipv4list or self.ipv6list)def append(self, ip_beg, ip_end = None):if ip_end is None:ip_end = ip_begelse:assert ip_beg <= ip_endif ip_beg.find(':') < 0: # IPv4ip_beg = to_long_ipv4(ip_beg)ip_end = to_long_ipv4(ip_end)l = self.ipv4listd = self.ipv4dictelse:ip_beg = to_long_ipv6(ip_beg)ip_end = to_long_ipv6(ip_end)bb = ip_beg % (256*256*256*256)if bb == ipv4addrmask:ip_beg -= bbip_end -= bbl = self.ipv4listd = self.ipv4dictelse:l = self.ipv6listd = self.ipv6dictpos = bisect(l,ip_beg)-1done = pos < 0while not done:p = poswhile p < len(l):range_beg = l[p]if range_beg > ip_end+1:done = Truebreakrange_end = d[range_beg]if range_end < ip_beg-1:p += 1if p == len(l):done = Truebreakcontinue# if neither of the above conditions is true, the ranges overlapip_beg = min(ip_beg, range_beg)ip_end = max(ip_end, range_end)del l[p]del d[range_beg]breakinsort(l,ip_beg)d[ip_beg] = ip_enddef includes(self, ip):if not (self.ipv4list or self.ipv6list):return Falseif ip.find(':') < 0: # IPv4ip = to_long_ipv4(ip)l = self.ipv4listd = self.ipv4dictelse:ip = to_long_ipv6(ip)bb = ip % (256*256*256*256)if bb == ipv4addrmask:ip -= bbl = self.ipv4listd = self.ipv4dictelse:l = self.ipv6listd = self.ipv6dictfor ip_beg in l[bisect(l,ip)-1:]:if ip == ip_beg:return Trueip_end = d[ip_beg]if ip > ip_beg and ip <= ip_end:return Truereturn False# reads a list from a file in the format 'whatever:whatever:ip-ip'# (not IPv6 compatible at all)def read_rangelist(self, file):f = open(file, 'r')while True:line = f.readline()if not line:breakline = line.strip()if not line or line[0] == '#':continueline = line.split(':')[-1]try:ip1,ip2 = line.split('-')except:ip1 = lineip2 = linetry:self.append(ip1.strip(),ip2.strip())except:print '*** WARNING *** could not parse IP range: '+linef.close()def is_ipv4(ip):return ip.find(':') < 0def is_valid_ip(ip):try:if is_ipv4(ip):a = ip.split('.')assert len(a) == 4for i in a:chr(int(i))return Trueto_long_ipv6(ip)return Trueexcept:return False