source: publico/il.spdo/trunk/Paste-1.7.5.1-py2.6.egg/paste/util/ip4.py @ 5327

Última Alteração nesse arquivo desde 5327 foi 5327, incluída por fabianosantos, 8 anos atrás

Import inicial.

File size: 9.1 KB
Linha 
1# -*- coding: iso-8859-15 -*-
2"""IP4 address range set implementation.
3
4Implements an IPv4-range type.
5
6Copyright (C) 2006, Heiko Wundram.
7Released under the MIT-license.
8"""
9
10# Version information
11# -------------------
12
13__author__ = "Heiko Wundram <me@modelnine.org>"
14__version__ = "0.2"
15__revision__ = "3"
16__date__ = "2006-01-20"
17
18
19# Imports
20# -------
21
22import intset
23import socket
24
25
26# IP4Range class
27# --------------
28
29class IP4Range(intset.IntSet):
30    """IP4 address range class with efficient storage of address ranges.
31    Supports all set operations."""
32
33    _MINIP4 = 0
34    _MAXIP4 = (1<<32) - 1
35    _UNITYTRANS = "".join([chr(n) for n in range(256)])
36    _IPREMOVE = "0123456789."
37
38    def __init__(self,*args):
39        """Initialize an ip4range class. The constructor accepts an unlimited
40        number of arguments that may either be tuples in the form (start,stop),
41        integers, longs or strings, where start and stop in a tuple may
42        also be of the form integer, long or string.
43
44        Passing an integer or long means passing an IPv4-address that's already
45        been converted to integer notation, whereas passing a string specifies
46        an address where this conversion still has to be done. A string
47        address may be in the following formats:
48
49        - 1.2.3.4    - a plain address, interpreted as a single address
50        - 1.2.3      - a set of addresses, interpreted as 1.2.3.0-1.2.3.255
51        - localhost  - hostname to look up, interpreted as single address
52        - 1.2.3<->5  - a set of addresses, interpreted as 1.2.3.0-1.2.5.255
53        - 1.2.0.0/16 - a set of addresses, interpreted as 1.2.0.0-1.2.255.255
54
55        Only the first three notations are valid if you use a string address in
56        a tuple, whereby notation 2 is interpreted as 1.2.3.0 if specified as
57        lower bound and 1.2.3.255 if specified as upper bound, not as a range
58        of addresses.
59
60        Specifying a range is done with the <-> operator. This is necessary
61        because '-' might be present in a hostname. '<->' shouldn't be, ever.
62        """
63
64        # Special case copy constructor.
65        if len(args) == 1 and isinstance(args[0],IP4Range):
66            super(IP4Range,self).__init__(args[0])
67            return
68
69        # Convert arguments to tuple syntax.
70        args = list(args)
71        for i in range(len(args)):
72            argval = args[i]
73            if isinstance(argval,str):
74                if "<->" in argval:
75                    # Type 4 address.
76                    args[i] = self._parseRange(*argval.split("<->",1))
77                    continue
78                elif "/" in argval:
79                    # Type 5 address.
80                    args[i] = self._parseMask(*argval.split("/",1))
81                else:
82                    # Type 1, 2 or 3.
83                    args[i] = self._parseAddrRange(argval)
84            elif isinstance(argval,tuple):
85                if len(tuple) <> 2:
86                    raise ValueError("Tuple is of invalid length.")
87                addr1, addr2 = argval
88                if isinstance(addr1,str):
89                    addr1 = self._parseAddrRange(addr1)[0]
90                elif not isinstance(addr1,(int,long)):
91                    raise TypeError("Invalid argument.")
92                if isinstance(addr2,str):
93                    addr2 = self._parseAddrRange(addr2)[1]
94                elif not isinstance(addr2,(int,long)):
95                    raise TypeError("Invalid argument.")
96                args[i] = (addr1,addr2)
97            elif not isinstance(argval,(int,long)):
98                raise TypeError("Invalid argument.")
99
100        # Initialize the integer set.
101        super(IP4Range,self).__init__(min=self._MINIP4,max=self._MAXIP4,*args)
102
103    # Parsing functions
104    # -----------------
105
106    def _parseRange(self,addr1,addr2):
107        naddr1, naddr1len = _parseAddr(addr1)
108        naddr2, naddr2len = _parseAddr(addr2)
109        if naddr2len < naddr1len:
110            naddr2 += naddr1&(((1<<((naddr1len-naddr2len)*8))-1)<<
111                              (naddr2len*8))
112            naddr2len = naddr1len
113        elif naddr2len > naddr1len:
114            raise ValueError("Range has more dots than address.")
115        naddr1 <<= (4-naddr1len)*8
116        naddr2 <<= (4-naddr2len)*8
117        naddr2 += (1<<((4-naddr2len)*8))-1
118        return (naddr1,naddr2)
119
120    def _parseMask(self,addr,mask):
121        naddr, naddrlen = _parseAddr(addr)
122        naddr <<= (4-naddrlen)*8
123        try:
124            if not mask:
125                masklen = 0
126            else:
127                masklen = int(mask)
128            if not 0 <= masklen <= 32:
129                raise ValueError
130        except ValueError:
131            try:
132                mask = _parseAddr(mask,False)
133            except ValueError:
134                raise ValueError("Mask isn't parseable.")
135            remaining = 0
136            masklen = 0
137            if not mask:
138                masklen = 0
139            else:
140                while not (mask&1):
141                    remaining += 1
142                while (mask&1):
143                    mask >>= 1
144                    masklen += 1
145                if remaining+masklen <> 32:
146                    raise ValueError("Mask isn't a proper host mask.")
147        naddr1 = naddr & (((1<<masklen)-1)<<(32-masklen))
148        naddr2 = naddr1 + (1<<(32-masklen)) - 1
149        return (naddr1,naddr2)
150
151    def _parseAddrRange(self,addr):
152        naddr, naddrlen = _parseAddr(addr)
153        naddr1 = naddr<<((4-naddrlen)*8)
154        naddr2 = ( (naddr<<((4-naddrlen)*8)) +
155                   (1<<((4-naddrlen)*8)) - 1 )
156        return (naddr1,naddr2)
157
158    # Utility functions
159    # -----------------
160
161    def _int2ip(self,num):
162        rv = []
163        for i in range(4):
164            rv.append(str(num&255))
165            num >>= 8
166        return ".".join(reversed(rv))
167
168    # Iterating
169    # ---------
170
171    def iteraddresses(self):
172        """Returns an iterator which iterates over ips in this iprange. An
173        IP is returned in string form (e.g. '1.2.3.4')."""
174
175        for v in super(IP4Range,self).__iter__():
176            yield self._int2ip(v)
177
178    def iterranges(self):
179        """Returns an iterator which iterates over ip-ip ranges which build
180        this iprange if combined. An ip-ip pair is returned in string form
181        (e.g. '1.2.3.4-2.3.4.5')."""
182
183        for r in self._ranges:
184            if r[1]-r[0] == 1:
185                yield self._int2ip(r[0])
186            else:
187                yield '%s-%s' % (self._int2ip(r[0]),self._int2ip(r[1]-1))
188
189    def itermasks(self):
190        """Returns an iterator which iterates over ip/mask pairs which build
191        this iprange if combined. An IP/Mask pair is returned in string form
192        (e.g. '1.2.3.0/24')."""
193
194        for r in self._ranges:
195            for v in self._itermasks(r):
196                yield v
197
198    def _itermasks(self,r):
199        ranges = [r]
200        while ranges:
201            cur = ranges.pop()
202            curmask = 0
203            while True:
204                curmasklen = 1<<(32-curmask)
205                start = (cur[0]+curmasklen-1)&(((1<<curmask)-1)<<(32-curmask))
206                if start >= cur[0] and start+curmasklen <= cur[1]:
207                    break
208                else:
209                    curmask += 1
210            yield "%s/%s" % (self._int2ip(start),curmask)
211            if cur[0] < start:
212                ranges.append((cur[0],start))
213            if cur[1] > start+curmasklen:
214                ranges.append((start+curmasklen,cur[1]))
215
216    __iter__ = iteraddresses
217
218    # Printing
219    # --------
220
221    def __repr__(self):
222        """Returns a string which can be used to reconstruct this iprange."""
223
224        rv = []
225        for start, stop in self._ranges:
226            if stop-start == 1:
227                rv.append("%r" % (self._int2ip(start),))
228            else:
229                rv.append("(%r,%r)" % (self._int2ip(start),
230                                       self._int2ip(stop-1)))
231        return "%s(%s)" % (self.__class__.__name__,",".join(rv))
232
233def _parseAddr(addr,lookup=True):
234    if lookup and addr.translate(IP4Range._UNITYTRANS, IP4Range._IPREMOVE):
235        try:
236            addr = socket.gethostbyname(addr)
237        except socket.error:
238            raise ValueError("Invalid Hostname as argument.")
239    naddr = 0
240    for naddrpos, part in enumerate(addr.split(".")):
241        if naddrpos >= 4:
242            raise ValueError("Address contains more than four parts.")
243        try:
244            if not part:
245                part = 0
246            else:
247                part = int(part)
248            if not 0 <= part < 256:
249                raise ValueError
250        except ValueError:
251            raise ValueError("Address part out of range.")
252        naddr <<= 8
253        naddr += part
254    return naddr, naddrpos+1
255
256def ip2int(addr, lookup=True):
257    return _parseAddr(addr, lookup=lookup)[0]
258
259if __name__ == "__main__":
260    # Little test script.
261    x = IP4Range("172.22.162.250/24")
262    y = IP4Range("172.22.162.250","172.22.163.250","172.22.163.253<->255")
263    print x
264    for val in x.itermasks():
265        print val
266    for val in y.itermasks():
267        print val
268    for val in (x|y).itermasks():
269        print val
270    for val in (x^y).iterranges():
271        print val
272    for val in x:
273        print val
Note: Veja TracBrowser para ajuda no uso do navegador do trac.
 

The contents and data of this website are published under license:
Creative Commons 4.0 Brasil - Atribuir Fonte - Compartilhar Igual.