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