root/scapy/utils6.py

Revision 933:1bb5abec6545, 23.2 kB (checked in by Phil <phil@secdev.org>, 3 months ago)

Fixed namespace problem for LOOPBACK_NAME in utils6.py

Line 
1 ## This file is part of Scapy
2 ## See http://www.secdev.org/projects/scapy for more informations
3 ## Copyright (C) Philippe Biondi <phil@secdev.org>
4 ## This program is published under a GPLv2 license
5
6 ## Copyright (C) 2005  Guillaume Valadon <guedou@hongo.wide.ad.jp>
7 ##                     Arnaud Ebalard <arnaud.ebalard@eads.net>
8
9
10 from config import conf
11 from data import *
12 from utils import *
13
14
15 def construct_source_candidate_set(addr, plen, laddr, loname):
16     """
17     Given all addresses assigned to a specific interface ('laddr' parameter),
18     this function returns the "candidate set" associated with 'addr/plen'.
19     
20     Basically, the function filters all interface addresses to keep only those
21     that have the same scope as provided prefix.
22     
23     This is on this list of addresses that the source selection mechanism
24     will then be performed to select the best source address associated
25     with some specific destination that uses this prefix.
26     """
27
28     cset = []
29     if in6_isgladdr(addr):
30         cset = filter(lambda x: x[1] == IPV6_ADDR_GLOBAL, laddr)
31     elif in6_islladdr(addr):
32         cset = filter(lambda x: x[1] == IPV6_ADDR_LINKLOCAL, laddr)
33     elif in6_issladdr(addr):
34         cset = filter(lambda x: x[1] == IPV6_ADDR_SITELOCAL, laddr)
35     elif in6_ismaddr(addr):
36         if in6_ismnladdr(addr):
37             cset = [('::1', 16, loname)]
38         elif in6_ismgladdr(addr):
39             cset = filter(lambda x: x[1] == IPV6_ADDR_GLOBAL, laddr)
40         elif in6_ismlladdr(addr):
41             cset = filter(lambda x: x[1] == IPV6_ADDR_LINKLOCAL, laddr)
42         elif in6_ismsladdr(addr):
43             cset = filter(lambda x: x[1] == IPV6_ADDR_SITELOCAL, laddr)
44     elif addr == '::' and plen == 0:
45         cset = filter(lambda x: x[1] == IPV6_ADDR_GLOBAL, laddr)
46     cset = map(lambda x: x[0], cset)
47     return cset           
48
49 def get_source_addr_from_candidate_set(dst, candidate_set):
50     """
51     This function implement a limited version of source address selection
52     algorithm defined in section 5 of RFC 3484. The format is very different
53     from that described in the document because it operates on a set
54     of candidate source address for some specific route.
55     
56     Rationale behind the implementation is to be able to make the right
57     choice for a 6to4 destination when both a 6to4 address and a IPv6 native
58     address are available for that interface.
59     """
60    
61     if len(candidate_set) == 0:
62         # Should not happen
63         return None
64    
65     if in6_isaddr6to4(dst):
66         tmp = filter(lambda x: in6_isaddr6to4(x), candidate_set)
67         if len(tmp) != 0:
68             return tmp[0]
69
70     return candidate_set[0]
71
72
73 def find_ifaddr2(addr, plen, laddr):
74     dstAddrType = in6_getAddrType(addr)
75    
76     if dstAddrType == IPV6_ADDR_UNSPECIFIED: # Shouldn't happen as dst addr
77         return None
78
79     if dstAddrType == IPV6_ADDR_LOOPBACK:
80         return None
81
82     tmp = [[]] + map(lambda (x,y,z): (in6_getAddrType(x), x, y, z), laddr)
83     def filterSameScope(l, t):
84         if (t[0] & dstAddrType & IPV6_ADDR_SCOPE_MASK) == 0:
85             l.append(t)
86         return l
87     sameScope = reduce(filterSameScope, tmp)
88    
89     l =  len(sameScope)
90     if l == 1:  # Only one address for our scope
91         return sameScope[0][1]
92
93     elif l > 1: # Muliple addresses for our scope
94         stfAddr = filter(lambda x: x[0] & IPV6_ADDR_6TO4, sameScope)
95         nativeAddr = filter(lambda x: not (x[0] & IPV6_ADDR_6TO4), sameScope)
96
97         if not (dstAddrType & IPV6_ADDR_6TO4): # destination is not 6to4
98            if len(nativeAddr) != 0:
99                return nativeAddr[0][1]
100            return stfAddr[0][1]
101
102         else# Destination is 6to4, try to use source 6to4 addr if any
103             if len(stfAddr) != 0:
104                 return stfAddr[0][1]
105             return nativeAddr[0][1]
106     else:
107         return None
108
109 # Think before modify it : for instance, FE::1 does exist and is unicast
110 # there are many others like that.
111 # TODO : integrate Unique Local Addresses
112 def in6_getAddrType(addr):
113     naddr = inet_pton(socket.AF_INET6, addr)
114     paddr = inet_ntop(socket.AF_INET6, naddr) # normalize
115     addrType = 0
116     # _Assignable_ Global Unicast Address space
117     # is defined in RFC 3513 as those in 2000::/3
118     if ((struct.unpack("B", naddr[0])[0] & 0xE0) == 0x20):
119         addrType = (IPV6_ADDR_UNICAST | IPV6_ADDR_GLOBAL)
120         if naddr[:2] == ' \x02': # Mark 6to4 @
121             addrType |= IPV6_ADDR_6TO4
122     elif naddr[0] == '\xff': # multicast
123         addrScope = paddr[3]
124         if addrScope == '2':
125             addrType = (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_MULTICAST)
126         elif addrScope == 'e':
127             addrType = (IPV6_ADDR_GLOBAL | IPV6_ADDR_MULTICAST)
128         else:
129             addrType = (IPV6_ADDR_GLOBAL | IPV6_ADDR_MULTICAST)
130     elif ((naddr[0] == '\xfe') and ((int(paddr[2], 16) & 0xC) == 0x8)):
131         addrType = (IPV6_ADDR_UNICAST | IPV6_ADDR_LINKLOCAL)
132     elif paddr == "::1":
133         addrType = IPV6_ADDR_LOOPBACK
134     elif paddr == "::":
135         addrType = IPV6_ADDR_UNSPECIFIED
136     else:
137         # Everything else is global unicast (RFC 3513)
138         # Even old deprecated (RFC3879) Site-Local addresses
139         addrType = (IPV6_ADDR_GLOBAL | IPV6_ADDR_UNICAST)
140
141     return addrType
142
143 def in6_mactoifaceid(mac, ulbit=None):
144     """
145     Compute the interface ID in modified EUI-64 format associated
146     to the Ethernet address provided as input.
147     value taken by U/L bit in the interface identifier is basically
148     the reversed value of that in given MAC address it can be forced
149     to a specific value by using optional 'ulbit' parameter.
150     """
151     if len(mac) != 17: return None
152     m = "".join(mac.split(':'))
153     if len(m) != 12: return None
154     first = int(m[0:2], 16)
155     if ulbit is None or not (ulbit == 0 or ulbit == 1):
156         ulbit = [1,'-',0][first & 0x02]
157     ulbit *= 2
158     first = "%.02x" % ((first & 0xFD) | ulbit)
159     eui64 = first + m[2:4] + ":" + m[4:6] + "FF:FE" + m[6:8] + ":" + m[8:12]
160     return eui64.upper()
161
162 def in6_ifaceidtomac(ifaceid): # TODO: finish commenting function behavior
163     """
164     Extract the mac address from provided iface ID. Iface ID is provided
165     in printable format ("XXXX:XXFF:FEXX:XXXX", eventually compressed). None
166     is returned on error.
167     """
168     try:
169         ifaceid = inet_pton(socket.AF_INET6, "::"+ifaceid)[8:16]
170     except:
171         return None
172     if ifaceid[3:5] != '\xff\xfe':
173         return None
174     first = struct.unpack("B", ifaceid[:1])[0]
175     ulbit = 2*[1,'-',0][first & 0x02]
176     first = struct.pack("B", ((first & 0xFD) | ulbit))
177     oui = first + ifaceid[1:3]
178     end = ifaceid[5:]
179     l = map(lambda x: "%.02x" % struct.unpack("B", x)[0], list(oui+end))
180     return ":".join(l)
181
182 def in6_addrtomac(addr):
183     """
184     Extract the mac address from provided address. None is returned
185     on error.
186     """
187     mask = inet_pton(socket.AF_INET6, "::ffff:ffff:ffff:ffff")
188     x = in6_and(mask, inet_pton(socket.AF_INET6, addr))
189     ifaceid = inet_ntop(socket.AF_INET6, x)[2:]
190     return in6_ifaceidtomac(ifaceid)
191
192 def in6_addrtovendor(addr):
193     """
194     Extract the MAC address from a modified EUI-64 constructed IPv6
195     address provided and use the IANA oui.txt file to get the vendor.
196     The database used for the conversion is the one loaded by Scapy,
197     based on Wireshark (/usr/share/wireshark/wireshark/manuf)  None
198     is returned on error, "UNKNOWN" if the vendor is unknown.
199     """
200     mac = in6_addrtomac(addr)
201     if mac is None:
202         return None
203
204     res = conf.manufdb._get_manuf(mac)
205     if len(res) == 17 and res.count(':') != 5: # Mac address, i.e. unknown
206         res = "UNKNOWN"
207
208     return res
209
210 def in6_getLinkScopedMcastAddr(addr, grpid=None, scope=2):
211     """
212     Generate a Link-Scoped Multicast Address as described in RFC 4489.
213     Returned value is in printable notation.
214
215     'addr' parameter specifies the link-local address to use for generating
216     Link-scoped multicast address IID.
217     
218     By default, the function returns a ::/96 prefix (aka last 32 bits of
219     returned address are null). If a group id is provided through 'grpid'
220     parameter, last 32 bits of the address are set to that value (accepted
221     formats : '\x12\x34\x56\x78' or '12345678' or 0x12345678 or 305419896).
222
223     By default, generated address scope is Link-Local (2). That value can
224     be modified by passing a specific 'scope' value as an argument of the
225     function. RFC 4489 only authorizes scope values <= 2. Enforcement
226     is performed by the function (None will be returned).
227     
228     If no link-local address can be used to generate the Link-Scoped IPv6
229     Multicast address, or if another error occurs, None is returned.
230     """
231     if not scope in [0, 1, 2]:
232         return None   
233     try:
234         if not in6_islladdr(addr):
235             return None
236         addr = inet_pton(socket.AF_INET6, addr)
237     except:
238         warning("in6_getLinkScopedMcastPrefix(): Invalid address provided")
239         return None
240
241     iid = addr[8:]
242
243     if grpid is None:
244         grpid = '\x00\x00\x00\x00'
245     else:
246         if type(grpid) is str:
247             if len(grpid) == 8:
248                 try:
249                     grpid = int(grpid, 16) & 0xffffffff
250                 except:
251                     warning("in6_getLinkScopedMcastPrefix(): Invalid group id provided")
252                     return None
253             elif len(grpid) == 4:
254                 try:
255                     grpid = struct.unpack("!I", grpid)[0]
256                 except:
257                     warning("in6_getLinkScopedMcastPrefix(): Invalid group id provided")
258                     return None
259         grpid = struct.pack("!I", grpid)
260
261     flgscope = struct.pack("B", 0xff & ((0x3 << 4) | scope))
262     plen = '\xff'
263     res = '\x00'
264     a = '\xff' + flgscope + res + plen + iid + grpid
265
266     return inet_ntop(socket.AF_INET6, a)
267
268 def in6_get6to4Prefix(addr):
269     """
270     Returns the /48 6to4 prefix associated with provided IPv4 address
271     On error, None is returned. No check is performed on public/private
272     status of the address
273     """
274     try:
275         addr = inet_pton(socket.AF_INET, addr)
276         addr = inet_ntop(socket.AF_INET6, '\x20\x02'+addr+'\x00'*10)
277     except:
278         return None
279     return addr
280
281 def in6_6to4ExtractAddr(addr):
282     """
283     Extract IPv4 address embbeded in 6to4 address. Passed address must be
284     a 6to4 addrees. None is returned on error.
285     """
286     try:
287         addr = inet_pton(socket.AF_INET6, addr)
288     except:
289         return None
290     if addr[:2] != " \x02":
291         return None
292     return inet_ntop(socket.AF_INET, addr[2:6])
293    
294
295 def in6_getLocalUniquePrefix():
296     """
297     Returns a pseudo-randomly generated Local Unique prefix. Function
298     follows recommandation of Section 3.2.2 of RFC 4193 for prefix
299     generation.
300     """
301     # Extracted from RFC 1305 (NTP) :
302     # NTP timestamps are represented as a 64-bit unsigned fixed-point number,
303     # in seconds relative to 0h on 1 January 1900. The integer part is in the
304     # first 32 bits and the fraction part in the last 32 bits.
305
306     # epoch = (1900, 1, 1, 0, 0, 0, 5, 1, 0)
307     # x = time.time()
308     # from time import gmtime, strftime, gmtime, mktime
309     # delta = mktime(gmtime(0)) - mktime(self.epoch)
310     # x = x-delta
311
312     tod = time.time() # time of day. Will bother with epoch later
313     i = int(tod)
314     j = int((tod - i)*(2**32))
315     tod = struct.pack("!II", i,j)
316     # TODO: Add some check regarding system address gathering
317     rawmac = get_if_raw_hwaddr(conf.iface6)[1]
318     mac = ":".join(map(lambda x: "%.02x" % ord(x), list(rawmac)))
319     # construct modified EUI-64 ID
320     eui64 = inet_pton(socket.AF_INET6, '::' + in6_mactoifaceid(mac))[8:]
321     import sha
322     globalid = sha.new(tod+eui64).digest()[:5]
323     return inet_ntop(socket.AF_INET6, '\xfd' + globalid + '\x00'*10)
324
325 def in6_getRandomizedIfaceId(ifaceid, previous=None):
326     """
327     Implements the interface ID generation algorithm described in RFC 3041.
328     The function takes the Modified EUI-64 interface identifier generated
329     as described in RFC 4291 and an optional previous history value (the
330     first element of the output of this function). If no previous interface
331     identifier is provided, a random one is generated. The function returns
332     a tuple containing the randomized interface identifier and the history
333     value (for possible future use). Input and output values are provided in
334     a "printable" format as depicted below.
335     
336     ex:
337
338     >>> in6_getRandomizedIfaceId('20b:93ff:feeb:2d3')
339     ('4c61:76ff:f46a:a5f3', 'd006:d540:db11:b092')
340
341     >>> in6_getRandomizedIfaceId('20b:93ff:feeb:2d3',
342                                  previous='d006:d540:db11:b092')
343     ('fe97:46fe:9871:bd38', 'eeed:d79c:2e3f:62e')
344     """
345
346     s = ""
347     if previous is None:
348         d = "".join(map(chr, range(256)))
349         for i in range(8):
350             s += random.choice(d)
351         previous = s
352     s = inet_pton(socket.AF_INET6, "::"+ifaceid)[8:] + previous
353     import md5
354     s = md5.new(s).digest()
355     s1,s2 = s[:8],s[8:]
356     s1 = chr(ord(s1[0]) | 0x04) + s1[1:] 
357     s1 = inet_ntop(socket.AF_INET6, "\xff"*8 + s1)[20:]
358     s2 = inet_ntop(socket.AF_INET6, "\xff"*8 + s2)[20:]   
359     return (s1, s2)
360
361
362 _rfc1924map = [ '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E',
363                 'F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T',
364                 'U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i',
365                 'j','k','l','m','n','o','p','q','r','s','t','u','v','w','x',
366                 'y','z','!','#','$','%','&','(',')','*','+','-',';','<','=',
367                 '>','?','@','^','_','`','{','|','}','~' ]
368
369 def in6_ctop(addr):
370     """
371     Convert an IPv6 address in Compact Representation Notation
372     (RFC 1924) to printable representation ;-)
373     Returns None on error.
374     """
375     if len(addr) != 20 or not reduce(lambda x,y: x and y,
376                                      map(lambda x: x in _rfc1924map, addr)):
377         return None
378     i = 0
379     for c in addr:
380         j = _rfc1924map.index(c)
381         i = 85*i + j
382     res = []
383     for j in range(4):
384         res.append(struct.pack("!I", i%2**32))
385         i = i/(2**32)
386     res.reverse()
387     return inet_ntop(socket.AF_INET6, "".join(res))
388
389 def in6_ptoc(addr):
390     """
391     Converts an IPv6 address in printable representation to RFC
392     1924 Compact Representation ;-)
393     Returns None on error.
394     """   
395     try:
396         d=struct.unpack("!IIII", inet_pton(socket.AF_INET6, addr))
397     except:
398         return None
399     res = 0
400     m = [2**96, 2**64, 2**32, 1]
401     for i in range(4):
402         res += d[i]*m[i]
403     rem = res
404     res = []
405     while rem:
406         res.append(_rfc1924map[rem%85])
407         rem = rem/85
408     res.reverse()
409     return "".join(res)
410
411    
412 def in6_isaddr6to4(x):
413     """
414     Return True if provided address (in printable format) is a 6to4
415     address (being in 2002::/16).
416     """
417     x = inet_pton(socket.AF_INET6, x)
418     return x[:2] == ' \x02'
419
420 conf.teredoPrefix = "2001::" # old one was 3ffe:831f (it is a /32)
421 conf.teredoServerPort = 3544
422
423 def in6_isaddrTeredo(x):
424     """
425     Return True if provided address is a Teredo, meaning it is under
426     the /32 conf.teredoPrefix prefix value (by default, 2001::).
427     Otherwise, False is returned. Address must be passed in printable
428     format.
429     """
430     our = inet_pton(socket.AF_INET6, x)[0:4]
431     teredoPrefix = inet_pton(socket.AF_INET6, conf.teredoPrefix)[0:4]
432     return teredoPrefix == our
433
434 def teredoAddrExtractInfo(x):
435     """
436     Extract information from a Teredo address. Return value is
437     a 4-tuple made of IPv4 address of Teredo server, flag value (int),
438     mapped address (non obfuscated) and mapped port (non obfuscated).
439     No specific checks are performed on passed address.
440     """
441     addr = inet_pton(socket.AF_INET6, x)
442     server = inet_ntop(socket.AF_INET, addr[4:8])
443     flag = struct.unpack("!H",addr[8:10])[0]
444     mappedport = struct.unpack("!H",strxor(addr[10:12],'\xff'*2))[0]
445     mappedaddr = inet_ntop(socket.AF_INET, strxor(addr[12:16],'\xff'*4))
446     return server, flag, mappedaddr, mappedport
447
448 def in6_iseui64(x):
449     """
450     Return True if provided address has an interface identifier part
451     created in modified EUI-64 format (meaning it matches *::*:*ff:fe*:*).
452     Otherwise, False is returned. Address must be passed in printable
453     format.
454     """
455     eui64 = inet_pton(socket.AF_INET6, '::ff:fe00:0')
456     x = in6_and(inet_pton(socket.AF_INET6, x), eui64)
457     return x == eui64
458
459 def in6_isanycast(x): # RFC 2526
460     if in6_iseui64(x):
461         s = '::fdff:ffff:ffff:ff80'
462         x = in6_and(x, inet_pton(socket.AF_INET6, '::ffff:ffff:ffff:ff80'))
463         x = in6_and(x, inet_pton(socket.AF_INET6, s))
464         return x == inet_pton(socket.AF_INET6, s)
465     else:
466         # not EUI-64
467         #|              n bits             |    121-n bits    |   7 bits   |
468         #+---------------------------------+------------------+------------+
469         #|           subnet prefix         | 1111111...111111 | anycast ID |
470         #+---------------------------------+------------------+------------+
471         #                                  |   interface identifier field  |
472         warning('in6_isanycast(): TODO not EUI-64')
473         return 0
474
475 def _in6_bitops(a1, a2, operator=0):
476     a1 = struct.unpack('4I', a1)
477     a2 = struct.unpack('4I', a2)
478     fop = [ lambda x,y: x | y,
479             lambda x,y: x & y,
480             lambda x,y: x ^ y
481           ] 
482     ret = map(fop[operator%len(fop)], a1, a2)
483     t = ''.join(map(lambda x: struct.pack('I', x), ret))
484     return t
485
486 def in6_or(a1, a2):
487     """
488     Provides a bit to bit OR of provided addresses. They must be
489     passed in network format. Return value is also an IPv6 address
490     in network format.
491     """
492     return _in6_bitops(a1, a2, 0)
493
494 def in6_and(a1, a2):
495     """
496     Provides a bit to bit AND of provided addresses. They must be
497     passed in network format. Return value is also an IPv6 address
498     in network format.
499     """
500     return _in6_bitops(a1, a2, 1)
501
502 def in6_xor(a1, a2):
503     """
504     Provides a bit to bit XOR of provided addresses. They must be
505     passed in network format. Return value is also an IPv6 address
506     in network format.
507     """
508     return _in6_bitops(a1, a2, 2)
509
510 def in6_cidr2mask(m):
511     """
512     Return the mask (bitstring) associated with provided length
513     value. For instance if function is called on 48, return value is
514     '\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'.
515     
516     """
517     if m > 128 or m < 0:
518         raise Scapy_Exception("value provided to in6_cidr2mask outside [0, 128] domain (%d)" % m)
519
520     t = []
521     for i in xrange(0, 4):
522         t.append(max(0, 2**32  - 2**(32-min(32, m))))
523         m -= 32
524
525     return ''.join(map(lambda x: struct.pack('!I', x), t))
526
527 def in6_getnsma(a):
528     """
529     Return link-local solicited-node multicast address for given
530     address. Passed address must be provided in network format.
531     Returned value is also in network format.
532     """
533
534     r = in6_and(a, inet_pton(socket.AF_INET6, '::ff:ffff'))
535     r = in6_or(inet_pton(socket.AF_INET6, 'ff02::1:ff00:0'), r)
536     return r
537
538 def in6_getnsmac(a): # return multicast Ethernet address associated with multicast v6 destination
539     """
540     Return the multicast mac address associated with provided
541     IPv6 address. Passed address must be in network format.
542     """
543
544     a = struct.unpack('16B', a)[-4:]
545     mac = '33:33:'
546     mac += ':'.join(map(lambda x: '%.2x' %x, a))
547     return mac
548
549 def in6_getha(prefix):
550     """
551     Return the anycast address associated with all home agents on a given
552     subnet.
553     """
554     r = in6_and(inet_pton(socket.AF_INET6, prefix), in6_cidr2mask(64))
555     r = in6_or(r, inet_pton(socket.AF_INET6, '::fdff:ffff:ffff:fffe'))
556     return inet_ntop(socket.AF_INET6, r)
557
558 def in6_ptop(str):
559     """
560     Normalizes IPv6 addresses provided in printable format, returning the
561     same address in printable format. (2001:0db8:0:0::1 -> 2001:db8::1)
562     """
563     return inet_ntop(socket.AF_INET6, inet_pton(socket.AF_INET6, str))
564
565 def in6_isincluded(addr, prefix, plen):
566     """
567     Returns True when 'addr' belongs to prefix/plen. False otherwise.
568     """
569     temp = inet_pton(socket.AF_INET6, addr)
570     pref = in6_cidr2mask(plen)
571     zero = inet_pton(socket.AF_INET6, prefix)
572     return zero == in6_and(temp, pref)
573
574 def in6_isdocaddr(str):
575     """
576     Returns True if provided address in printable format belongs to
577     2001:db8::/32 address space reserved for documentation (as defined
578     in RFC 3849).
579     """
580     return in6_isincluded(str, '2001:db8::', 32)
581
582 def in6_islladdr(str):
583     """
584     Returns True if provided address in printable format belongs to
585     _allocated_ link-local unicast address space (fe80::/10)
586     """
587     return in6_isincluded(str, 'fe80::', 10)
588
589 def in6_issladdr(str):
590     """
591     Returns True if provided address in printable format belongs to
592     _allocated_ site-local address space (fec0::/10). This prefix has
593     been deprecated, address being now reserved by IANA. Function
594     will remain for historic reasons.
595     """
596     return in6_isincluded(str, 'fec0::', 10)
597
598 def in6_isuladdr(str):
599     """
600     Returns True if provided address in printable format belongs to
601     Unique local address space (fc00::/7).
602     """
603     return in6_isincluded(str, 'fc::', 7)
604
605 # TODO : we should see the status of Unique Local addresses against
606 #        global address space.
607 #        Up-to-date information is available through RFC 3587.
608 #        We should review function behavior based on its content.
609 def in6_isgladdr(str):
610     """
611     Returns True if provided address in printable format belongs to
612     _allocated_ global address space (2000::/3). Please note that,
613     Unique Local addresses (FC00::/7) are not part of global address
614     space, and won't match.
615     """
616     return in6_isincluded(str, '2000::', 3)
617
618 def in6_ismaddr(str):
619     """
620     Returns True if provided address in printable format belongs to
621     allocated Multicast address space (ff00::/8).
622     """
623     return in6_isincluded(str, 'ff00::', 8)
624
625 def in6_ismnladdr(str):
626     """
627     Returns True if address belongs to node-local multicast address
628     space (ff01::/16) as defined in RFC
629     """
630     return in6_isincluded(str, 'ff01::', 16)
631
632 def in6_ismgladdr(str):
633     """
634     Returns True if address belongs to global multicast address
635     space (ff0e::/16).
636     """
637     return in6_isincluded(str, 'ff0e::', 16)
638
639 def in6_ismlladdr(str):
640     """
641     Returns True if address balongs to link-local multicast address
642     space (ff02::/16)
643     """
644     return in6_isincluded(str, 'ff02::', 16)
645
646 def in6_ismsladdr(str):
647     """
648     Returns True if address belongs to site-local multicast address
649     space (ff05::/16). Site local address space has been deprecated.
650     Function remains for historic reasons.
651     """
652     return in6_isincluded(str, 'ff05::', 16)
653
654 def in6_isaddrllallnodes(str):
655     """
656     Returns True if address is the link-local all-nodes multicast
657     address (ff02::1).
658     """
659     return (inet_pton(socket.AF_INET6, "ff02::1") ==
660             inet_pton(socket.AF_INET6, str))
661
662 def in6_isaddrllallservers(str):
663     """
664     Returns True if address is the link-local all-servers multicast
665     address (ff02::2).
666     """
667     return (inet_pton(socket.AF_INET6, "ff02::2") ==
668             inet_pton(socket.AF_INET6, str))
669
670
671 def in6_getscope(addr):
672     """
673     Returns the scope of the address.
674     """
675     if in6_isgladdr(addr):
676         scope = IPV6_ADDR_GLOBAL
677     elif in6_islladdr(addr):
678         scope = IPV6_ADDR_LINKLOCAL
679     elif in6_issladdr(addr):
680         scope = IPV6_ADDR_SITELOCAL
681     elif in6_ismaddr(addr):
682         scope = IPV6_ADDR_MULTICAST
683     elif addr == '::1':
684         scope = IPV6_ADDR_LOOPBACK
685     else:
686         scope = -1
687     return scope
Note: See TracBrowser for help on using the browser.