Ticket #1713: match-ipv6.patch
| File match-ipv6.patch, 6.7 kB (added by chrisz, 3 months ago) |
|---|
-
turbogears/identity/conditions.py
old new 1 1 import cherrypy 2 import socket3 import struct4 import threading5 2 import types 6 3 import turbogears 7 4 from turbogears.identity.exceptions import * 8 5 from turbogears.identity import * 9 6 from turbogears.decorator import weak_signature_decorator 7 from turbogears.util import match_ip 10 8 9 11 10 class Predicate(object): 12 11 ''' 13 12 Generic base class for testing true or false for a condition. … … 177 176 return "" 178 177 179 178 180 def _match_ip(cidr, ip):181 if not '/' in cidr:182 return cidr == ip183 184 else:185 try:186 b,m = cidr.split('/')187 shift = 32 - int(m)188 a1 = struct.unpack('!L', socket.inet_aton(b))[0] >> shift189 a2 = struct.unpack('!L', socket.inet_aton(ip))[0] >> shift190 return a1 == a2191 192 except:193 return False194 195 196 179 class from_host(Predicate, IdentityPredicateHelper): 197 180 ''' 198 181 Predicate for checking whether the visitor's host is an allowed host. … … 209 192 Match the visitor's host against the criteria. 210 193 ''' 211 194 ip = _remoteHost() 212 if _match_ip(self.host, ip):195 if match_ip(self.host, ip): 213 196 return True 214 197 215 198 self.append_error_message(errors) -
turbogears/tests/test_util.py
old new 90 90 == 'Chip & Chap' 91 91 assert util.fixentities('<"<©>">') \ 92 92 == '<"<©>">' 93 94 95 def test_match_ip(): 96 m = util.match_ip 97 assert m('1.2.3.4', '1.2.3.4') 98 assert not m('1.2.3.4', '1.2.3.5') 99 assert not m('4.3.2.1', '5.3.2.1') 100 assert m('1.2.3.4', '::ffff:102:304') 101 assert not m('1.2.3.4', '::102:304') 102 assert m('127.0.0.1', '::ffff:127.0.0.1') 103 assert m('127.0.0.1', '::ffff:7f00:0001') 104 assert m('::ffff:127.0.0.1', '127.0.0.1') 105 assert m('192.168.42.76/32', '192.168.42.76') 106 assert m('192.168.42.77/32', '192.168.42.77') 107 assert not m('192.168.42.76/32', '192.168.42.77') 108 assert not m('192.168.42.77/32', '192.168.42.76') 109 assert m('192.168.42.76/31', '192.168.42.76') 110 assert m('192.168.42.76/31', '192.168.42.77') 111 assert m('224.0.0.0/3', '224.1.2.3') 112 assert m('224.0.0.0/3', '255.255.255.255') 113 assert not m('224.0.0.0/3', '192.0.0.0') 114 assert not m('192.168.42.76/31', '192.168.42.73') 115 assert m('1:2:3::', '1:02:0003:0:0::0') 116 assert m('1:2:3::/48', '1:2:3:4::') 117 assert not m('1:2:3::/48', '1:2:4:::') 118 assert m('1:2:3::8', '1:2:3:0:0:0:0:8') 119 assert m('2001:0db8:85a3:08d3:1319:8a2e:0370:7334', 120 '2001:db8:85a3:8d3:1319:8a2e:3.112.115.52') 121 assert m('2001:db8:85a3:8d3:1300::/72', 122 '2001:0db8:85a3:08d3:1319:8a2e:0370:7334') 123 assert m('2001:db8:85a3:8d3:1300::/72', 124 '2001:0db8:85a3:08d3:1399:8a2e:0370:7334') 125 assert not m('2001:db8:85a3:8d3:1300::/72', 126 '2001:0db8:85a3:08d3:1219:8a2e:0370:7334') -
turbogears/util.py
old new 6 6 import logging 7 7 import warnings 8 8 import htmlentitydefs 9 import socket 10 import struct 9 11 from inspect import getargspec, getargvalues 10 12 from itertools import izip, islice, chain, imap 11 13 from operator import isSequenceType … … 539 541 return re.sub("&(\w+);?", repl, htmltext) 540 542 541 543 544 if hasattr(socket, 'inet_pton') and hasattr(socket, 'AF_INET6'): 545 546 def inet6_aton(addr): 547 """Convert IP6 standard hex notation to IP6 address.""" 548 return socket.inet_pton(socket.AF_INET6, addr) 549 550 else: # Windows etc. 551 552 import string 553 _inet6_chars = string.hexdigits + ':.' 554 555 def inet6_aton(addr): 556 """Convert IPv6 standard hex notation to IPv6 address. 557 558 Inspired by http://twistedmatrix.com/trac/. 559 560 """ 561 faulty = addr.lstrip(_inet6_chars) 562 if faulty: 563 raise ValueError("Illegal character '%c' in IPv6 address" % faulty[0]) 564 parts = addr.split(':') 565 elided = parts.count('') 566 extenso = '.' in parts[-1] and 7 or 8 567 if len(parts) > extenso or elided > 3: 568 raise ValueError("Syntactically invalid IPv6 address") 569 if elided == 3: 570 return '\x00' * 16 571 if elided: 572 zeros = ['0'] * (extenso - len(parts) + elided) 573 if addr.startswith('::'): 574 parts[:2] = zeros 575 elif addr.endswith('::'): 576 parts[-2:] = zeros 577 else: 578 idx = parts.index('') 579 parts[idx:idx+1] = zeros 580 if len(parts) != extenso: 581 raise ValueError("Syntactically invalid IPv6 address") 582 if extenso == 7: 583 ipv4 = parts.pop() 584 if ipv4.count('.') != 3: 585 raise ValueError("Syntactically invalid IPv6 address") 586 parts = [int(x, 16) for x in parts] 587 return struct.pack('!6H', *parts) + socket.inet_aton(ipv4) 588 else: 589 parts = [int(x, 16) for x in parts] 590 return struct.pack('!8H', *parts) 591 592 593 def inet_aton(addr): 594 """Convert IPv4 or IPv6 notation to IPv6 address.""" 595 if ':' in addr: 596 return inet6_aton(addr) 597 else: 598 return struct.pack('!QL', 0, 0xffff) + socket.inet_aton(addr) 599 600 601 def _inet_prefix(addr, masked): 602 """Remove the number of masked bits from the IPV6 address.""" 603 hi, lo = struct.unpack("!QQ", addr) 604 return (hi << 64 | lo) >> masked 605 606 607 def match_ip(cidr, ip): 608 """Check whether IP address matches CIDR IP address block.""" 609 if '/' in cidr: 610 cidr, prefix = cidr.split('/', 1) 611 masked = (':' in cidr and 128 or 32) - int(prefix) 612 else: 613 masked = None 614 cidr = inet_aton(cidr) 615 ip = inet_aton(ip) 616 if masked: 617 cidr = _inet_prefix(cidr, masked) 618 ip = _inet_prefix(ip, masked) 619 return ip == cidr 620 621 542 622 __all__ = ["Bunch", "DictObj", "DictWrapper", "Enum", "setlike", 543 623 "get_package_name", "get_model", "load_project_config", 544 624 "ensure_sequence", "has_arg", "to_kw", "from_kw", … … 548 628 "flatten_sequence", "load_class", "parse_http_accept_header", 549 629 "to_unicode", "to_utf8", "quote_cookie", "unquote_cookie", 550 630 "get_template_encoding_default", "find_precision", 551 "copy_if_mutable", " deprecated"]631 "copy_if_mutable", "match_ip", "deprecated"]