3030 'IpRangeList' ,
3131)
3232
33+
3334# sniff for python2.x / python3k compatibility "fixes'
3435try :
3536 basestring = basestring
@@ -49,10 +50,22 @@ def next(iterable):
4950except ImportError :
5051 # python <2.6 doesn't have abc classes to extend
5152 Sequence = object
52-
5353# end compatibility "fixes'
5454
55+
5556from . import ipv4
57+ from . import ipv6
58+
59+
60+ def _address2long (address ):
61+ """
62+ Convert an address string to a long.
63+ """
64+ parsed = ipv4 .ip2long (address )
65+ if parsed is None :
66+ parsed = ipv6 .ip2long (address )
67+ return parsed
68+ #end _addess2long
5669
5770
5871class IpRange (Sequence ):
@@ -71,6 +84,10 @@ class IpRange (Sequence):
7184 False
7285 >>> 2130706433 in r
7386 True
87+ >>> '::ffff:192.0.2.128' in r
88+ False
89+ >>> '::ffff:c000:0280' in r
90+ False
7491 >>> r = IpRange('127/24')
7592 >>> print(r)
7693 ('127.0.0.0', '127.0.0.255')
@@ -86,6 +103,21 @@ class IpRange (Sequence):
86103 >>> r = IpRange('127/255.255.255.0')
87104 >>> print(r)
88105 ('127.0.0.0', '127.0.0.255')
106+ >>> r = IpRange('::ffff:0000:0000', '::ffff:ffff:ffff')
107+ >>> '::ffff:192.0.2.128' in r
108+ True
109+ >>> '::ffff:c000:0280' in r
110+ True
111+ >>> 281473902969472 in r
112+ True
113+ >>> '192.168.2.128' in r
114+ False
115+ >>> 2130706433 in r
116+ False
117+ >>> r = IpRange('::ffff:ffff:0000/120')
118+ >>> for ip in r:
119+ ... print(ip) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
120+ ::ffff:ffff:0 ... ::ffff:ffff:6d ... ::ffff:ffff:ff
89121
90122
91123 :param start: Ip address in dotted quad format, CIDR notation, subnet
@@ -108,6 +140,10 @@ def __init__(self, start, end=None):
108140 # CIDR notation range
109141 start , end = ipv4 .cidr2block (start )
110142
143+ elif ipv6 .validate_cidr (start ):
144+ # CIDR notation range
145+ start , end = ipv6 .cidr2block (start )
146+
111147 elif ipv4 .validate_subnet (start ):
112148 # Netmask notation range
113149 start , end = ipv4 .subnet2block (start )
@@ -116,11 +152,15 @@ def __init__(self, start, end=None):
116152 # degenerate range
117153 end = start
118154
119- start = ipv4 . ip2long (start )
120- end = ipv4 . ip2long (end )
155+ start = _address2long (start )
156+ end = _address2long (end )
121157 self .startIp = min (start , end )
122158 self .endIp = max (start , end )
123159 self ._len = self .endIp - self .startIp + 1
160+
161+ self ._ipver = ipv4
162+ if self .endIp > ipv4 .MAX_IP :
163+ self ._ipver = ipv6
124164 #end __init__
125165
126166 def __repr__ (self ):
@@ -133,7 +173,8 @@ def __repr__(self):
133173 "IpRange('127.0.0.0', '127.0.0.255')"
134174 """
135175 return "IpRange(%r, %r)" % (
136- ipv4 .long2ip (self .startIp ), ipv4 .long2ip (self .endIp ))
176+ self ._ipver .long2ip (self .startIp ),
177+ self ._ipver .long2ip (self .endIp ))
137178 #end __repr__
138179
139180 def __str__ (self ):
@@ -146,7 +187,8 @@ def __str__(self):
146187 "('127.0.0.0', '127.0.0.255')"
147188 """
148189 return (
149- ipv4 .long2ip (self .startIp ), ipv4 .long2ip (self .endIp )).__repr__ ()
190+ self ._ipver .long2ip (self .startIp ),
191+ self ._ipver .long2ip (self .endIp )).__repr__ ()
150192 #end __str__
151193
152194 def __eq__ (self , other ):
@@ -195,10 +237,10 @@ def __hash__(self):
195237
196238 def _cast (self , item ):
197239 if isinstance (item , basestring ):
198- item = ipv4 . ip2long (item )
199- if type (item ) not in [type (1 ), type (ipv4 .MAX_IP )]:
240+ item = _address2long (item )
241+ if type (item ) not in [type (1 ), type (ipv4 .MAX_IP ), type ( ipv6 . MAX_IP ) ]:
200242 raise TypeError (
201- "expected dotted-quad ip address or 32 -bit integer" )
243+ "expected ip address, 32-bit integer or 128 -bit integer" )
202244 return item
203245 #end _cast
204246
@@ -226,7 +268,7 @@ def index(self, item):
226268 offset = item - self .startIp
227269 if offset >= 0 and offset < self ._len :
228270 return offset
229- raise ValueError ('%s is not in range' % ipv4 .long2ip (item ))
271+ raise ValueError ('%s is not in range' % self . _ipver .long2ip (item ))
230272 #end index
231273
232274 def count (self , item ):
@@ -249,7 +291,7 @@ def __contains__(self, item):
249291 >>> 'invalid' in r
250292 Traceback (most recent call last):
251293 ...
252- TypeError: expected dotted-quad ip address or 32 -bit integer
294+ TypeError: expected ip address, 32-bit integer or 128 -bit integer
253295
254296
255297 :param item: Dotted-quad ip address.
@@ -307,15 +349,15 @@ def __getitem__(self, index):
307349 if stop > self ._len :
308350 raise IndexError ('stop index out of range' )
309351 return IpRange (
310- ipv4 .long2ip (self .startIp + start ),
311- ipv4 .long2ip (self .startIp + stop - 1 ))
352+ self . _ipver .long2ip (self .startIp + start ),
353+ self . _ipver .long2ip (self .startIp + stop - 1 ))
312354
313355 else :
314356 if index < 0 :
315357 index = self ._len + index
316358 if index < 0 or index >= self ._len :
317359 raise IndexError ('index out of range' )
318- return ipv4 .long2ip (self .startIp + index )
360+ return self . _ipver .long2ip (self .startIp + index )
319361 #end __getitem__
320362
321363 def __iter__ (self ):
@@ -335,7 +377,7 @@ def __iter__(self):
335377 """
336378 i = self .startIp
337379 while i <= self .endIp :
338- yield ipv4 .long2ip (i )
380+ yield self . _ipver .long2ip (i )
339381 i += 1
340382 #end __iter__
341383#end class IpRange
@@ -345,29 +387,12 @@ class IpRangeList (object):
345387 """
346388 List of IpRange objects.
347389
348- Converts a list of dotted quad ip address and/or CIDR addresses into a
349- list of IpRange objects. This list can perform ``in`` and ``not in`` tests
350- and iterate all of the addresses in the range.
351-
352- This can be used to convert django's conf.settings.INTERNAL_IPS list into
353- a smart object which allows CIDR notation.
354-
355-
356- >>> INTERNAL_IPS = IpRangeList(
357- ... '127.0.0.1','10/8',('192.168.0.1','192.168.255.255'))
358- >>> '127.0.0.1' in INTERNAL_IPS
359- True
360- >>> '10.10.10.10' in INTERNAL_IPS
361- True
362- >>> '192.168.192.168' in INTERNAL_IPS
363- True
364- >>> '172.16.0.1' in INTERNAL_IPS
365- False
366-
390+ Converts a list of ip address and/or CIDR addresses into a list of IpRange
391+ objects. This list can perform ``in`` and ``not in`` tests and iterate all
392+ of the addresses in the range.
367393
368- :param \*args: List of ip addresses in dotted quad format or CIDR
369- notation and/or ``(start, end)`` tuples of ip addresses in dotted quad
370- format.
394+ :param \*args: List of ip addresses or CIDR notation and/or
395+ ``(start, end)`` tuples of ip addresses.
371396 :type \*args: list of str and/or tuple
372397 """
373398 def __init__ (self , * args ):
@@ -420,7 +445,7 @@ def __contains__(self, item):
420445 >>> 'invalid' in r
421446 Traceback (most recent call last):
422447 ...
423- TypeError: expected dotted-quad ip address or 32 -bit integer
448+ TypeError: expected ip address, 32-bit integer or 128 -bit integer
424449
425450
426451 :param item: Dotted-quad ip address.
0 commit comments