| 43 | | |
|---|
| 44 | | ############################################################################# |
|---|
| 45 | | ## Constants ## |
|---|
| 46 | | ############################################################################# |
|---|
| 47 | | |
|---|
| 48 | | ETH_P_IPV6 = 0x86dd |
|---|
| 49 | | OPENBSD=sys.platform.startswith("openbsd") |
|---|
| 50 | | FREEBSD=sys.platform.startswith("freebsd") |
|---|
| 51 | | NETBSD = sys.platform.startswith("netbsd") |
|---|
| 52 | | DARWIN=sys.platform.startswith("darwin") |
|---|
| 53 | | WINDOWS = sys.platform.startswith("win") |
|---|
| 54 | | |
|---|
| 55 | | |
|---|
| 56 | | # From net/ipv6.h on Linux (+ Additions) |
|---|
| 57 | | IPV6_ADDR_UNICAST = 0x01 |
|---|
| 58 | | IPV6_ADDR_MULTICAST = 0x02 |
|---|
| 59 | | IPV6_ADDR_CAST_MASK = 0x0F |
|---|
| 60 | | IPV6_ADDR_LOOPBACK = 0x10 |
|---|
| 61 | | IPV6_ADDR_GLOBAL = 0x00 |
|---|
| 62 | | IPV6_ADDR_LINKLOCAL = 0x20 |
|---|
| 63 | | IPV6_ADDR_SITELOCAL = 0x40 # deprecated since Sept. 2004 by RFC 3879 |
|---|
| 64 | | IPV6_ADDR_SCOPE_MASK = 0xF0 |
|---|
| 65 | | #IPV6_ADDR_COMPATv4 = 0x80 # deprecated; i.e. ::/96 |
|---|
| 66 | | #IPV6_ADDR_MAPPED = 0x1000 # i.e.; ::ffff:0.0.0.0/96 |
|---|
| 67 | | IPV6_ADDR_6TO4 = 0x0100 # Added to have more specific info (should be 0x0101 ?) |
|---|
| 68 | | IPV6_ADDR_UNSPECIFIED = 0x10000 |
|---|
| 376 | | def get_if_raw_addr6(iff): |
|---|
| 377 | | """ |
|---|
| 378 | | Returns the main global unicast address associated with provided |
|---|
| 379 | | interface, in network format. If no global address is found, None |
|---|
| 380 | | is returned. |
|---|
| 381 | | """ |
|---|
| 382 | | r = filter(lambda x: x[2] == iff and x[1] == IPV6_ADDR_GLOBAL, in6_getifaddr()) |
|---|
| 383 | | if len(r) == 0: |
|---|
| 384 | | return None |
|---|
| 385 | | else: |
|---|
| 386 | | r = r[0][0] |
|---|
| 387 | | return inet_pton(socket.AF_INET6, r) |
|---|
| 388 | | |
|---|
| 389 | | if LINUX: |
|---|
| 390 | | |
|---|
| 391 | | def in6_getifaddr(): |
|---|
| 392 | | """ |
|---|
| 393 | | Returns a list of 3-tuples of the form (addr, scope, iface) where |
|---|
| 394 | | 'addr' is the address of scope 'scope' associated to the interface |
|---|
| 395 | | 'ifcace'. |
|---|
| 396 | | |
|---|
| 397 | | This is the list of all addresses of all interfaces available on |
|---|
| 398 | | the system. |
|---|
| 399 | | """ |
|---|
| 400 | | ret = [] |
|---|
| 401 | | try: |
|---|
| 402 | | f = open("/proc/net/if_inet6","r") |
|---|
| 403 | | except IOError, err: |
|---|
| 404 | | return ret |
|---|
| 405 | | l = f.readlines() |
|---|
| 406 | | for i in l: |
|---|
| 407 | | # addr, index, plen, scope, flags, ifname |
|---|
| 408 | | tmp = i.split() |
|---|
| 409 | | addr = struct.unpack('4s4s4s4s4s4s4s4s', tmp[0]) |
|---|
| 410 | | addr = in6_ptop(':'.join(addr)) |
|---|
| 411 | | ret.append((addr, int(tmp[3], 16), tmp[5])) # (addr, scope, iface) |
|---|
| 412 | | return ret |
|---|
| 413 | | |
|---|
| 414 | | def read_routes6(): |
|---|
| 415 | | try: |
|---|
| 416 | | f = open("/proc/net/ipv6_route","r") |
|---|
| 417 | | except IOError, err: |
|---|
| 418 | | return [] |
|---|
| 419 | | # 1. destination network |
|---|
| 420 | | # 2. destination prefix length |
|---|
| 421 | | # 3. source network displayed |
|---|
| 422 | | # 4. source prefix length |
|---|
| 423 | | # 5. next hop |
|---|
| 424 | | # 6. metric |
|---|
| 425 | | # 7. reference counter (?!?) |
|---|
| 426 | | # 8. use counter (?!?) |
|---|
| 427 | | # 9. flags |
|---|
| 428 | | # 10. device name |
|---|
| 429 | | routes = [] |
|---|
| 430 | | def proc2r(p): |
|---|
| 431 | | ret = struct.unpack('4s4s4s4s4s4s4s4s', p) |
|---|
| 432 | | ret = ':'.join(ret) |
|---|
| 433 | | return in6_ptop(ret) |
|---|
| 434 | | |
|---|
| 435 | | lifaddr = in6_getifaddr() |
|---|
| 436 | | for l in f.readlines(): |
|---|
| 437 | | d,dp,s,sp,nh,m,rc,us,fl,dev = l.split() |
|---|
| 438 | | fl = int(fl, 16) |
|---|
| 439 | | |
|---|
| 440 | | if fl & RTF_UP == 0: |
|---|
| 441 | | continue |
|---|
| 442 | | if fl & RTF_REJECT: |
|---|
| 443 | | continue |
|---|
| 444 | | |
|---|
| 445 | | d = proc2r(d) ; dp = int(dp, 16) |
|---|
| 446 | | s = proc2r(s) ; sp = int(sp, 16) |
|---|
| 447 | | nh = proc2r(nh) |
|---|
| 448 | | |
|---|
| 449 | | cset = [] # candidate set (possible source addresses) |
|---|
| 450 | | if dev == LOOPBACK_NAME: |
|---|
| 451 | | if d == '::': |
|---|
| 452 | | continue |
|---|
| 453 | | cset = ['::1'] |
|---|
| 454 | | else: |
|---|
| 455 | | devaddrs = filter(lambda x: x[2] == dev, lifaddr) |
|---|
| 456 | | cset = construct_source_candidate_set(d, dp, devaddrs) |
|---|
| 457 | | |
|---|
| 458 | | if len(cset) != 0: |
|---|
| 459 | | routes.append((d, dp, nh, dev, cset)) |
|---|
| 460 | | f.close() |
|---|
| 461 | | return routes |
|---|
| 462 | | |
|---|
| 463 | | elif WINDOWS: |
|---|
| 464 | | def in6_getifaddr(): |
|---|
| 465 | | """ |
|---|
| 466 | | Returns a list of 3-tuples of the form (addr, scope, iface) where |
|---|
| 467 | | 'addr' is the address of scope 'scope' associated to the interface |
|---|
| 468 | | 'ifcace'. |
|---|
| 469 | | |
|---|
| 470 | | This is the list of all addresses of all interfaces available on |
|---|
| 471 | | the system. |
|---|
| 472 | | """ |
|---|
| 473 | | ret = [] |
|---|
| 474 | | # Just some dummy values for now |
|---|
| 475 | | xx = "::1" |
|---|
| 476 | | scope = 128 |
|---|
| 477 | | ifname = LOOPBACK_NAME |
|---|
| 478 | | ret.append(xx, scope, ifname) |
|---|
| 479 | | return ret |
|---|
| 480 | | |
|---|
| 481 | | def read_routes6(): |
|---|
| 482 | | routes = [] |
|---|
| 483 | | # Just some dummy values for now |
|---|
| 484 | | d = '::' |
|---|
| 485 | | dp = 0 |
|---|
| 486 | | nh = '::' |
|---|
| 487 | | dev = LOOPBACK_NAME |
|---|
| 488 | | cset = ['::1'] |
|---|
| 489 | | routes.append((d, dp, nh, dev, cset)) |
|---|
| 490 | | return routes |
|---|
| 491 | | |
|---|
| 492 | | else: |
|---|
| 493 | | def in6_getifaddr(): |
|---|
| 494 | | """ |
|---|
| 495 | | Returns a list of 3-tuples of the form (addr, scope, iface) where |
|---|
| 496 | | 'addr' is the address of scope 'scope' associated to the interface |
|---|
| 497 | | 'ifcace'. |
|---|
| 498 | | |
|---|
| 499 | | This is the list of all addresses of all interfaces available on |
|---|
| 500 | | the system. |
|---|
| 501 | | """ |
|---|
| 502 | | |
|---|
| 503 | | ret = [] |
|---|
| 504 | | i = dnet.intf() |
|---|
| 505 | | for int in i: |
|---|
| 506 | | ifname = int['name'] |
|---|
| 507 | | v6 = [] |
|---|
| 508 | | if int.has_key('alias_addrs'): |
|---|
| 509 | | v6 = int['alias_addrs'] |
|---|
| 510 | | for a in v6: |
|---|
| 511 | | if a.type != dnet.ADDR_TYPE_IP6: |
|---|
| 512 | | continue |
|---|
| 513 | | |
|---|
| 514 | | xx = str(a).split('/')[0] |
|---|
| 515 | | addr = in6_ptop(xx) |
|---|
| 516 | | |
|---|
| 517 | | scope = in6_getscope(addr) |
|---|
| 518 | | |
|---|
| 519 | | ret.append((xx, scope, ifname)) |
|---|
| 520 | | return ret |
|---|
| 521 | | |
|---|
| 522 | | def read_routes6(): |
|---|
| 523 | | f = os.popen("netstat -rn -f inet6") |
|---|
| 524 | | ok = -1 |
|---|
| 525 | | routes = [] |
|---|
| 526 | | lifaddr = in6_getifaddr() |
|---|
| 527 | | for l in f.readlines(): |
|---|
| 528 | | if not l: |
|---|
| 529 | | break |
|---|
| 530 | | l = l.strip() |
|---|
| 531 | | if ok < 0: |
|---|
| 532 | | ok = l.find('Destination') |
|---|
| 533 | | continue |
|---|
| 534 | | # gv 12/12/06: under debugging |
|---|
| 535 | | if NETBSD or OPENBSD: |
|---|
| 536 | | d,nh,fl,_,_,_,dev = l.split()[:7] |
|---|
| 537 | | else: # FREEBSD or DARWIN |
|---|
| 538 | | d,nh,fl,dev = l.split()[:4] |
|---|
| 539 | | if filter(lambda x: x[2] == dev, lifaddr) == []: |
|---|
| 540 | | continue |
|---|
| 541 | | if 'L' in fl: # drop MAC addresses |
|---|
| 542 | | continue |
|---|
| 543 | | |
|---|
| 544 | | if 'link' in nh: |
|---|
| 545 | | nh = '::' |
|---|
| 546 | | |
|---|
| 547 | | cset = [] # candidate set (possible source addresses) |
|---|
| 548 | | dp = 128 |
|---|
| 549 | | if d == 'default': |
|---|
| 550 | | d = '::' |
|---|
| 551 | | dp = 0 |
|---|
| 552 | | if '/' in d: |
|---|
| 553 | | d,dp = d.split("/") |
|---|
| 554 | | dp = int(dp) |
|---|
| 555 | | if '%' in d: |
|---|
| 556 | | d,dev = d.split('%') |
|---|
| 557 | | if '%' in nh: |
|---|
| 558 | | nh,dev = nh.split('%') |
|---|
| 559 | | if LOOPBACK_NAME in dev: |
|---|
| 560 | | cset = ['::1'] |
|---|
| 561 | | nh = '::' |
|---|
| 562 | | else: |
|---|
| 563 | | devaddrs = filter(lambda x: x[2] == dev, lifaddr) |
|---|
| 564 | | cset = construct_source_candidate_set(d, dp, devaddrs) |
|---|
| 565 | | |
|---|
| 566 | | if len(cset) != 0: |
|---|
| 567 | | routes.append((d, dp, nh, dev, cset)) |
|---|
| 568 | | |
|---|
| 569 | | f.close() |
|---|
| 570 | | return routes |
|---|