Skip to content

Commit 33f2a44

Browse files
committed
Add basic ipv6 functions.
- ipv6.validate_ip - ipv6.ip2long - Add ipv6 to doctest runner
1 parent 8ca9080 commit 33f2a44

2 files changed

Lines changed: 135 additions & 1 deletion

File tree

src/iptools/ipv6.py

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Copyright (c) 2008-2013, Bryan Davis
5+
# All rights reserved.
6+
#
7+
# Redistribution and use in source and binary forms, with or without
8+
# modification, are permitted provided that the following conditions are met:
9+
# - Redistributions of source code must retain the above copyright notice,
10+
# this list of conditions and the following disclaimer.
11+
# - Redistributions in binary form must reproduce the above copyright
12+
# notice, this list of conditions and the following disclaimer in the
13+
# documentation and/or other materials provided with the distribution.
14+
#
15+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25+
# POSSIBILITY OF SUCH DAMAGE.
26+
27+
import re
28+
_HEX_RE = re.compile(r'^([0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}$')
29+
30+
def validate_ip (s):
31+
"""Validate a hexidecimal IPv6 ip address.
32+
33+
34+
>>> validate_ip('::')
35+
True
36+
>>> validate_ip('::1')
37+
True
38+
>>> validate_ip('2001:db8:85a3::8a2e:370:7334')
39+
True
40+
>>> validate_ip('2001:db8:85a3:0:0:8a2e:370:7334')
41+
True
42+
>>> validate_ip('2001:0db8:85a3:0000:0000:8a2e:0370:7334')
43+
True
44+
>>> validate_ip('2001:db8::1:0:0:1')
45+
True
46+
>>> validate_ip('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff')
47+
True
48+
>>> validate_ip('::ff::ff')
49+
False
50+
>>> validate_ip('::fffff')
51+
False
52+
>>> validate_ip(None) #doctest: +IGNORE_EXCEPTION_DETAIL
53+
Traceback (most recent call last):
54+
...
55+
TypeError: expected string or buffer
56+
57+
58+
:param s: String to validate as a hexidecimal IPv6 ip address.
59+
:type s: str
60+
:returns: ``True`` if a valid hexidecimal IPv6 ip address, ``False`` otherwise.
61+
:raises: TypeError
62+
"""
63+
if _HEX_RE.match(s):
64+
return len(s.split('::')) <= 2
65+
return False
66+
#end validate_ip
67+
68+
def ip2long (ip):
69+
"""Convert a hexidecimal IPv6 address to a network byte order 128-bit
70+
integer.
71+
72+
73+
>>> ip2long('::') == 0
74+
True
75+
>>> ip2long('::1') == 1
76+
True
77+
>>> expect = 0x20010db885a3000000008a2e03707334
78+
>>> ip2long('2001:db8:85a3::8a2e:370:7334') == expect
79+
True
80+
>>> ip2long('2001:db8:85a3:0:0:8a2e:370:7334') == expect
81+
True
82+
>>> ip2long('2001:0db8:85a3:0000:0000:8a2e:0370:7334') == expect
83+
True
84+
>>> expect = 0x20010db8000000000001000000000001
85+
>>> ip2long('2001:db8::1:0:0:1') == expect
86+
True
87+
>>> expect = 0xffffffffffffffffffffffffffffffff
88+
>>> ip2long('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff') == expect
89+
True
90+
>>> ip2long('ff::ff::ff') == None
91+
True
92+
93+
94+
:param ip: Hexidecimal IPv6 address
95+
:type ip: str
96+
:returns: Network byte order 128-bit integer or ``None`` if ip is invalid.
97+
"""
98+
if not validate_ip(ip):
99+
return None
100+
101+
halves = ip.split('::')
102+
hextets = halves[0].split(':')
103+
if len(halves) == 2:
104+
h2 = halves[1].split(':')
105+
for z in xrange(8 - (len(hextets) + len(h2))):
106+
hextets.append('0')
107+
for h in h2:
108+
hextets.append(h)
109+
#end if
110+
111+
lngip = 0
112+
for h in hextets:
113+
if '' == h:
114+
h = '0'
115+
lngip = (lngip << 16) | int(h, 16)
116+
return lngip
117+
#end ip2long
118+
119+
120+
def _test ():
121+
import doctest
122+
failure, nbtest = doctest.testmod()
123+
if failure:
124+
import sys
125+
sys.exit(1)
126+
#end _test
127+
128+
if __name__ == '__main__':
129+
_test()
130+
131+
# vim: set sw=4 ts=4 sts=4 et :

src/iptools/test_iptools.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,12 @@
3131
import doctest
3232
import unittest
3333
import iptools
34+
from iptools import ipv6
3435

3536
def additional_tests(): # for setup.py
36-
return doctest.DocTestSuite(iptools)
37+
tests = doctest.DocTestSuite(iptools)
38+
tests.addTests(doctest.DocTestSuite(ipv6))
39+
return tests
3740

3841
def main():
3942
result = unittest.TextTestRunner().run(additional_tests())

0 commit comments

Comments
 (0)