CIDR splitting functionality moved from filter to IPAddr;

meantime commit: code review, simplification, pythonization, etc. + test cases extended
pull/1414/head
sebres 2016-05-10 21:46:04 +02:00
parent 1b21f21c22
commit d65e37e93d
3 changed files with 48 additions and 29 deletions

View File

@ -343,19 +343,11 @@ class Filter(JailThread):
# An empty string is always false # An empty string is always false
if ipstr == "": if ipstr == "":
return return
s = ipstr.split('/', 1)
# IP address without CIDR mask
if len(s) == 1:
s.insert(1, -1) # <0 means no CIDR
elif "." in s[1]: # 255.255.255.0 style mask
s[1] = IPAddr.masktoplen(s[1])
s[1] = long(s[1])
# Create IP address object # Create IP address object
ip = IPAddr(s[0], s[1]) ip = IPAddr(ipstr)
# log and append to ignore list # log and append to ignore list
logSys.debug("Add %r to ignore list (%r, %r)", ip, s[0], s[1]) logSys.debug("Add %r to ignore list (%r)", ip, ipstr)
self.__ignoreIpList.append(ip) self.__ignoreIpList.append(ip)
def delIgnoreIP(self, ip): def delIgnoreIP(self, ip):

View File

@ -150,8 +150,20 @@ class IPAddr(object):
IPAddr.CACHE_OBJ.set(args, ip) IPAddr.CACHE_OBJ.set(args, ip)
return ip return ip
# object methods @staticmethod
def __init(self, ipstring, cidr=-1): def __wrap_ipstr(ipstr):
if "/" not in ipstr:
return ipstr, -1
s = ipstr.split('/', 1)
# IP address without CIDR mask
if len(s) > 2:
raise ValueError("invalid ipstr %r, too many plen representation" % (ipstr,))
if "." in s[1]: # 255.255.255.0 style mask
s[1] = IPAddr.masktoplen(s[1])
s[1] = long(s[1])
return s
def __init(self, ipstr, cidr=-1):
""" initialize IP object by converting IP address string """ initialize IP object by converting IP address string
to binary to integer to binary to integer
""" """
@ -160,9 +172,13 @@ class IPAddr(object):
self._plen = 0 self._plen = 0
self._maskplen = None self._maskplen = None
self._raw = "" self._raw = ""
if cidr == -1:
ipstr, cidr = self.__wrap_ipstr(ipstr)
for family in [socket.AF_INET, socket.AF_INET6]: for family in [socket.AF_INET, socket.AF_INET6]:
try: try:
binary = socket.inet_pton(family, ipstring) binary = socket.inet_pton(family, ipstr)
self._family = family self._family = family
break break
except socket.error: except socket.error:
@ -200,18 +216,13 @@ class IPAddr(object):
# string couldn't be converted neither to a IPv4 nor # string couldn't be converted neither to a IPv4 nor
# to a IPv6 address - retain raw input for later use # to a IPv6 address - retain raw input for later use
# (e.g. DNS resolution) # (e.g. DNS resolution)
self._raw = ipstring self._raw = ipstr
def __repr__(self): def __repr__(self):
if self.isIPv4 and self.plen < 32:
return "%s/%d" % (self.ntoa, self.plen)
elif self.isIPv6 and self.plen < 128:
return "%s/%d" % (self.ntoa, self.plen)
else:
return self.ntoa return self.ntoa
def __str__(self): def __str__(self):
return self.__repr__() return self.ntoa
@property @property
def addr(self): def addr(self):
@ -280,10 +291,10 @@ class IPAddr(object):
def hexdump(self): def hexdump(self):
"""Hex representation of the IP address (for debug purposes) """Hex representation of the IP address (for debug purposes)
""" """
if self.family == socket.AF_INET: if self._family == socket.AF_INET:
return "%08x" % self.addr return "%08x" % self._addr
elif self.family == socket.AF_INET6: elif self._family == socket.AF_INET6:
return "%032x" % self.addr return "%032x" % self._addr
else: else:
return "" return ""
@ -293,18 +304,23 @@ class IPAddr(object):
""" represent IP object as text like the deprecated """ represent IP object as text like the deprecated
C pendant inet.ntoa but address family independent C pendant inet.ntoa but address family independent
""" """
add = ''
if self.isIPv4: if self.isIPv4:
# convert network to host byte order # convert network to host byte order
binary = struct.pack("!L", self._addr) binary = struct.pack("!L", self._addr)
if self._plen and self._plen < 32:
add = "/%d" % self._plen
elif self.isIPv6: elif self.isIPv6:
# convert network to host byte order # convert network to host byte order
hi = self.addr >> 64 hi = self._addr >> 64
lo = self.addr & 0xFFFFFFFFFFFFFFFFL lo = self._addr & 0xFFFFFFFFFFFFFFFFL
binary = struct.pack("!QQ", hi, lo) binary = struct.pack("!QQ", hi, lo)
if self._plen and self._plen < 128:
add = "/%d" % self._plen
else: else:
return self._raw return self._raw
return socket.inet_ntop(self.family, binary) return socket.inet_ntop(self._family, binary) + add
def getPTR(self, suffix=""): def getPTR(self, suffix=""):
""" return the DNS PTR string of the provided IP address object """ return the DNS PTR string of the provided IP address object

View File

@ -1446,6 +1446,17 @@ class DNSUtilsNetworkTests(unittest.TestCase):
# compare with string direct: # compare with string direct:
self.assertEqual(d, d2) self.assertEqual(d, d2)
def testIPAddr_CIDR(self):
self.assertEqual(str(IPAddr('93.184.0.1', 24)), '93.184.0.0/24')
self.assertEqual(str(IPAddr('192.168.1.0/255.255.255.128')), '192.168.1.0/25')
self.assertEqual(IPAddr('93.184.0.1', 24).ntoa, '93.184.0.0/24')
self.assertEqual(IPAddr('192.168.1.0/255.255.255.128').ntoa, '192.168.1.0/25')
self.assertEqual(str(IPAddr('2606:2800:220:1:248:1893:25c8::', 120)), '2606:2800:220:1:248:1893:25c8:0/120')
self.assertEqual(IPAddr('2606:2800:220:1:248:1893:25c8::', 120).ntoa, '2606:2800:220:1:248:1893:25c8:0/120')
self.assertEqual(str(IPAddr('2606:2800:220:1:248:1893:25c8:0/120')), '2606:2800:220:1:248:1893:25c8:0/120')
self.assertEqual(IPAddr('2606:2800:220:1:248:1893:25c8:0/120').ntoa, '2606:2800:220:1:248:1893:25c8:0/120')
def testIPAddr_CompareDNS(self): def testIPAddr_CompareDNS(self):
ips = IPAddr('example.com') ips = IPAddr('example.com')
self.assertTrue(IPAddr("93.184.216.34").isInNet(ips)) self.assertTrue(IPAddr("93.184.216.34").isInNet(ips))