Changeset 923:9174613795d6

Show
Ignore:
Timestamp:
09/12/08 17:57:20 (4 months ago)
Author:
Phil <phil@secdev.org>
Message:

Split DHCP6

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • scapy/config.py

    r921 r923  
    316316    load_layers = ["l2", "inet", "dhcp", "dns", "dot11", "gprs", "hsrp", "inet6", "ir", "isakmp", "l2tp", 
    317317                   "mgcp", "mobileip", "netbios", "netflow", "ntp", "ppp", "radius", "rip", "rtp", 
    318                    "sebek", "skinny", "smb", "snmp", "tftp", "x509", "bluetooth"
     318                   "sebek", "skinny", "smb", "snmp", "tftp", "x509", "bluetooth", "dhcp6"
    319319     
    320320 
  • scapy/layers/inet6.py

    r922 r923  
    22802280    return cls 
    22812281 
    2282 ############################################################################# 
    2283 ############################################################################# 
    2284 ###                                DHCPv6                                 ### 
    2285 ############################################################################# 
    2286 ############################################################################# 
    2287  
    2288 All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"  
    2289 All_DHCP_Servers = "ff05::1:3"  # Site-Local scope : deprecated by 3879 
    2290  
    2291 dhcp6opts = { 1: "CLIENTID",   
    2292               2: "SERVERID", 
    2293               3: "IA_NA", 
    2294               4: "IA_TA", 
    2295               5: "IAADDR", 
    2296               6: "ORO", 
    2297               7: "PREFERENCE", 
    2298               8: "ELAPSED_TIME", 
    2299               9: "RELAY_MSG", 
    2300              11: "AUTH", 
    2301              12: "UNICAST", 
    2302              13: "STATUS_CODE", 
    2303              14: "RAPID_COMMIT", 
    2304              15: "USER_CLASS", 
    2305              16: "VENDOR_CLASS", 
    2306              17: "VENDOR_OPTS", 
    2307              18: "INTERFACE_ID", 
    2308              19: "RECONF_MSG", 
    2309              20: "RECONF_ACCEPT", 
    2310              21: "SIP Servers Domain Name List",     #RFC3319 
    2311              22: "SIP Servers IPv6 Address List",    #RFC3319 
    2312              23: "DNS Recursive Name Server Option", #RFC3646 
    2313              24: "Domain Search List option",        #RFC3646 
    2314              25: "OPTION_IA_PD",                     #RFC3633 
    2315              26: "OPTION_IAPREFIX",                  #RFC3633 
    2316              27: "OPTION_NIS_SERVERS",               #RFC3898 
    2317              28: "OPTION_NISP_SERVERS",              #RFC3898 
    2318              29: "OPTION_NIS_DOMAIN_NAME",           #RFC3898 
    2319              30: "OPTION_NISP_DOMAIN_NAME",          #RFC3898 
    2320              31: "OPTION_SNTP_SERVERS",              #RFC4075 
    2321              32: "OPTION_INFORMATION_REFRESH_TIME",  #RFC4242 
    2322              33: "OPTION_BCMCS_SERVER_D",            #RFC4280          
    2323              34: "OPTION_BCMCS_SERVER_A",            #RFC4280 
    2324              36: "OPTION_GEOCONF_CIVIC",             #RFC-ietf-geopriv-dhcp-civil-09.txt 
    2325              37: "OPTION_REMOTE_ID",                 #RFC4649 
    2326              38: "OPTION_SUBSCRIBER_ID",             #RFC4580 
    2327              39: "OPTION_CLIENT_FQDN" }              #RFC4704 
    2328  
    2329 dhcp6opts_by_code = {  1: "DHCP6OptClientId",  
    2330                        2: "DHCP6OptServerId", 
    2331                        3: "DHCP6OptIA_NA", 
    2332                        4: "DHCP6OptIA_TA", 
    2333                        5: "DHCP6OptIAAddress", 
    2334                        6: "DHCP6OptOptReq", 
    2335                        7: "DHCP6OptPref", 
    2336                        8: "DHCP6OptElapsedTime", 
    2337                        9: "DHCP6OptRelayMsg", 
    2338                        11: "DHCP6OptAuth", 
    2339                        12: "DHCP6OptServerUnicast", 
    2340                        13: "DHCP6OptStatusCode", 
    2341                        14: "DHCP6OptRapidCommit", 
    2342                        15: "DHCP6OptUserClass", 
    2343                        16: "DHCP6OptVendorClass", 
    2344                        17: "DHCP6OptVendorSpecificInfo", 
    2345                        18: "DHCP6OptIfaceId", 
    2346                        19: "DHCP6OptReconfMsg", 
    2347                        20: "DHCP6OptReconfAccept", 
    2348                        21: "DHCP6OptSIPDomains",          #RFC3319 
    2349                        22: "DHCP6OptSIPServers",          #RFC3319 
    2350                        23: "DHCP6OptDNSServers",          #RFC3646 
    2351                        24: "DHCP6OptDNSDomains",          #RFC3646 
    2352                        25: "DHCP6OptIA_PD",               #RFC3633 
    2353                        26: "DHCP6OptIAPrefix",            #RFC3633 
    2354                        27: "DHCP6OptNISServers",          #RFC3898 
    2355                        28: "DHCP6OptNISPServers",         #RFC3898 
    2356                        29: "DHCP6OptNISDomain",           #RFC3898 
    2357                        30: "DHCP6OptNISPDomain",          #RFC3898 
    2358                        31: "DHCP6OptSNTPServers",         #RFC4075 
    2359                        32: "DHCP6OptInfoRefreshTime",     #RFC4242 
    2360                        33: "DHCP6OptBCMCSDomains",        #RFC4280          
    2361                        34: "DHCP6OptBCMCSServers",        #RFC4280 
    2362                        #36: "DHCP6OptGeoConf",            #RFC-ietf-geopriv-dhcp-civil-09.txt 
    2363                        37: "DHCP6OptRemoteID",            #RFC4649 
    2364                        38: "DHCP6OptSubscriberID",        #RFC4580 
    2365                        39: "DHCP6OptClientFQDN",          #RFC4704 
    2366                        #40: "DHCP6OptPANAAgent",          #RFC-ietf-dhc-paa-option-05.txt 
    2367                        #41: "DHCP6OptNewPOSIXTimeZone,    #RFC4833 
    2368                        #42: "DHCP6OptNewTZDBTimeZone,     #RFC4833 
    2369                        43: "DHCP6OptRelayAgentERO"        #RFC4994 
    2370                        #44: "DHCP6OptLQQuery",            #RFC5007 
    2371                        #45: "DHCP6OptLQClientData",       #RFC5007 
    2372                        #46: "DHCP6OptLQClientTime",       #RFC5007 
    2373                        #47: "DHCP6OptLQRelayData",        #RFC5007 
    2374                        #48: "DHCP6OptLQClientLink",       #RFC5007 
    2375 } 
    2376  
    2377  
    2378 # sect 5.3 RFC 3315 : DHCP6 Messages types 
    2379 dhcp6types = {   1:"SOLICIT", 
    2380                  2:"ADVERTISE", 
    2381                  3:"REQUEST", 
    2382                  4:"CONFIRM", 
    2383                  5:"RENEW", 
    2384                  6:"REBIND", 
    2385                  7:"REPLY", 
    2386                  8:"RELEASE", 
    2387                  9:"DECLINE", 
    2388                 10:"RECONFIGURE", 
    2389                 11:"INFORMATION-REQUEST", 
    2390                 12:"RELAY-FORW", 
    2391                 13:"RELAY-REPL" } 
    2392  
    2393  
    2394 ##################################################################### 
    2395 ###                  DHCPv6 DUID related stuff                    ### 
    2396 ##################################################################### 
    2397  
    2398 duidtypes = { 1: "Link-layer address plus time",  
    2399               2: "Vendor-assigned unique ID based on Enterprise Number", 
    2400               3: "Link-layer Address" } 
    2401  
    2402 # DUID hardware types - RFC 826 - Extracted from  
    2403 # http://www.iana.org/assignments/arp-parameters on 31/10/06 
    2404 # We should add the length of every kind of address. 
    2405 duidhwtypes = {  0: "NET/ROM pseudo", # Not referenced by IANA 
    2406                  1: "Ethernet (10Mb)", 
    2407                  2: "Experimental Ethernet (3Mb)", 
    2408                  3: "Amateur Radio AX.25", 
    2409                  4: "Proteon ProNET Token Ring", 
    2410                  5: "Chaos", 
    2411                  6: "IEEE 802 Networks", 
    2412                  7: "ARCNET", 
    2413                  8: "Hyperchannel", 
    2414                  9: "Lanstar", 
    2415                 10: "Autonet Short Address", 
    2416                 11: "LocalTalk", 
    2417                 12: "LocalNet (IBM PCNet or SYTEK LocalNET)", 
    2418                 13: "Ultra link", 
    2419                 14: "SMDS", 
    2420                 15: "Frame Relay", 
    2421                 16: "Asynchronous Transmission Mode (ATM)", 
    2422                 17: "HDLC", 
    2423                 18: "Fibre Channel", 
    2424                 19: "Asynchronous Transmission Mode (ATM)", 
    2425                 20: "Serial Line", 
    2426                 21: "Asynchronous Transmission Mode (ATM)", 
    2427                 22: "MIL-STD-188-220", 
    2428                 23: "Metricom", 
    2429                 24: "IEEE 1394.1995", 
    2430                 25: "MAPOS", 
    2431                 26: "Twinaxial", 
    2432                 27: "EUI-64", 
    2433                 28: "HIPARP", 
    2434                 29: "IP and ARP over ISO 7816-3", 
    2435                 30: "ARPSec", 
    2436                 31: "IPsec tunnel", 
    2437                 32: "InfiniBand (TM)", 
    2438                 33: "TIA-102 Project 25 Common Air Interface (CAI)" } 
    2439  
    2440 class UTCTimeField(IntField): 
    2441     epoch = (2000, 1, 1, 0, 0, 0, 5, 1, 0) # required Epoch 
    2442     def i2repr(self, pkt, x): 
    2443         x = self.i2h(pkt, x) 
    2444         from time import gmtime, strftime, mktime 
    2445         delta = mktime(self.epoch) - mktime(gmtime(0)) 
    2446         x = x + delta 
    2447         t = strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime(x)) 
    2448         return "%s (%d)" % (t, x) 
    2449  
    2450 class _LLAddrField(MACField): 
    2451     pass 
    2452  
    2453 # XXX We only support Ethernet addresses at the moment. _LLAddrField  
    2454 #     will be modified when needed. Ask us. --arno 
    2455 class DUID_LLT(Packet):  # sect 9.2 RFC 3315 
    2456     name = "DUID - Link-layer address plus time" 
    2457     fields_desc = [ ShortEnumField("type", 1, duidtypes), 
    2458                     XShortEnumField("hwtype", 1, duidhwtypes),  
    2459                     UTCTimeField("timeval", 0), # i.e. 01 Jan 2000 
    2460                     _LLAddrField("lladdr", ETHER_ANY) ] 
    2461  
    2462 # In fact, IANA enterprise-numbers file available at  
    2463 # http//www.iana.org/asignments/enterprise-numbers) 
    2464 # is simply huge (more than 2Mo and 600Ko in bz2). I'll 
    2465 # add only most common vendors, and encountered values. 
    2466 # -- arno 
    2467 iana_enterprise_num = {    9: "ciscoSystems", 
    2468                           35: "Nortel Networks", 
    2469                           43: "3Com", 
    2470                          311: "Microsoft", 
    2471                         2636: "Juniper Networks, Inc.", 
    2472                         4526: "Netgear", 
    2473                         5771: "Cisco Systems, Inc.", 
    2474                         5842: "Cisco Systems", 
    2475                        16885: "Nortel Networks" } 
    2476  
    2477 class DUID_EN(Packet):  # sect 9.3 RFC 3315 
    2478     name = "DUID - Assigned by Vendor Based on Enterprise Number" 
    2479     fields_desc = [ ShortEnumField("type", 2, duidtypes), 
    2480                     IntEnumField("enterprisenum", 311, iana_enterprise_num), 
    2481                     StrField("id","") ]  
    2482  
    2483 class DUID_LL(Packet):  # sect 9.4 RFC 3315 
    2484     name = "DUID - Based on Link-layer Address" 
    2485     fields_desc = [ ShortEnumField("type", 3, duidtypes), 
    2486                     XShortEnumField("hwtype", 1, duidhwtypes),  
    2487                     _LLAddrField("lladdr", ETHER_ANY) ] 
    2488  
    2489 duid_cls = { 1: "DUID_LLT", 
    2490              2: "DUID_EN", 
    2491              3: "DUID_LL"} 
    2492  
    2493 ##################################################################### 
    2494 ###                   DHCPv6 Options classes                      ### 
    2495 ##################################################################### 
    2496  
    2497 class _DHCP6OptGuessPayload(Packet): 
    2498     def guess_payload_class(self, payload): 
    2499         cls = Raw 
    2500         if len(payload) > 2 : 
    2501             opt = struct.unpack("!H", payload[:2])[0] 
    2502             cls = get_cls(dhcp6opts_by_code.get(opt, "DHCP6OptUnknown"), DHCP6OptUnknown) 
    2503         return cls 
    2504  
    2505 class DHCP6OptUnknown(_DHCP6OptGuessPayload): # A generic DHCPv6 Option 
    2506     name = "Unknown DHCPv6 OPtion" 
    2507     fields_desc = [ ShortEnumField("optcode", 0, dhcp6opts),  
    2508                     FieldLenField("optlen", None, length_of="data", fmt="!H"), 
    2509                     StrLenField("data", "", 
    2510                                 length_from = lambda pkt: pkt.optlen)] 
    2511  
    2512 class _DUIDField(PacketField): 
    2513     holds_packets=1 
    2514     def __init__(self, name, default, length_from=None): 
    2515         StrField.__init__(self, name, default) 
    2516         self.length_from = length_from 
    2517  
    2518     def i2m(self, pkt, i): 
    2519         return str(i) 
    2520  
    2521     def m2i(self, pkt, x): 
    2522         cls = Raw  
    2523         if len(x) > 4: 
    2524             o = struct.unpack("!H", x[:2])[0] 
    2525             cls = get_cls(duid_cls.get(o, Raw), "Raw") 
    2526         return cls(x) 
    2527  
    2528     def getfield(self, pkt, s): 
    2529         l = self.length_from(pkt) 
    2530         return s[l:], self.m2i(pkt,s[:l]) 
    2531   
    2532  
    2533 class DHCP6OptClientId(_DHCP6OptGuessPayload):     # RFC sect 22.2 
    2534     name = "DHCP6 Client Identifier Option" 
    2535     fields_desc = [ ShortEnumField("optcode", 1, dhcp6opts),  
    2536                     FieldLenField("optlen", None, length_of="duid", fmt="!H"), 
    2537                     _DUIDField("duid", "", 
    2538                                length_from = lambda pkt: pkt.optlen) ] 
    2539  
    2540  
    2541 class DHCP6OptServerId(DHCP6OptClientId):     # RFC sect 22.3 
    2542     name = "DHCP6 Server Identifier Option" 
    2543     __metaclass__ = NewDefaultValues 
    2544     optcode = 2 
    2545  
    2546 # Should be encapsulated in the option field of IA_NA or IA_TA options 
    2547 # Can only appear at that location. 
    2548 # TODO : last field IAaddr-options is not defined in the reference document 
    2549 class DHCP6OptIAAddress(_DHCP6OptGuessPayload):    # RFC sect 22.6 
    2550     name = "DHCP6 IA Address Option (IA_TA or IA_NA suboption)" 
    2551     fields_desc = [ ShortEnumField("optcode", 5, dhcp6opts),  
    2552                     FieldLenField("optlen", None, length_of="iaaddropts", 
    2553                                   fmt="!H", adjust = lambda pkt,x: x+24), 
    2554                     IP6Field("addr", "::"), 
    2555                     IntField("preflft", 0), 
    2556                     IntField("validlft", 0), 
    2557                     XIntField("iaid", None), 
    2558                     StrLenField("iaaddropts", "", 
    2559                                 length_from  = lambda pkt: pkt.optlen - 24) ] 
    2560     def guess_payload_class(self, payload): 
    2561         return Padding 
    2562  
    2563 class _IANAOptField(PacketListField): 
    2564     def i2len(self, pkt, z): 
    2565         if z is None or z == []: 
    2566             return 0 
    2567         return sum(map(lambda x: len(str(x)) ,z)) 
    2568  
    2569     def getfield(self, pkt, s): 
    2570         l = self.length_from(pkt) 
    2571         lst = [] 
    2572         remain, payl = s[:l], s[l:] 
    2573         while len(remain)>0: 
    2574             p = self.m2i(pkt,remain) 
    2575             if Padding in p: 
    2576                 pad = p[Padding] 
    2577                 remain = pad.load 
    2578                 del(pad.underlayer.payload) 
    2579             else: 
    2580                 remain = "" 
    2581             lst.append(p) 
    2582         return payl,lst 
    2583  
    2584 class DHCP6OptIA_NA(_DHCP6OptGuessPayload):         # RFC sect 22.4 
    2585     name = "DHCP6 Identity Association for Non-temporary Addresses Option" 
    2586     fields_desc = [ ShortEnumField("optcode", 3, dhcp6opts),  
    2587                     FieldLenField("optlen", None, length_of="ianaopts", 
    2588                                   fmt="!H", adjust = lambda pkt,x: x+12), 
    2589                     XIntField("iaid", None), 
    2590                     IntField("T1", None), 
    2591                     IntField("T2", None), 
    2592                     _IANAOptField("ianaopts", [], DHCP6OptIAAddress, 
    2593                                   length_from = lambda pkt: pkt.optlen-12) ] 
    2594  
    2595 class _IATAOptField(_IANAOptField): 
    2596     pass 
    2597  
    2598 class DHCP6OptIA_TA(_DHCP6OptGuessPayload):         # RFC sect 22.5 
    2599     name = "DHCP6 Identity Association for Temporary Addresses Option" 
    2600     fields_desc = [ ShortEnumField("optcode", 4, dhcp6opts),  
    2601                     FieldLenField("optlen", None, length_of="iataopts", 
    2602                                   fmt="!H", adjust = lambda pkt,x: x+4), 
    2603                     XIntField("iaid", None), 
    2604                     _IATAOptField("iataopts", [], DHCP6OptIAAddress, 
    2605                                   length_from = lambda pkt: pkt.optlen-4) ] 
    2606  
    2607  
    2608 #### DHCPv6 Option Request Option ################################### 
    2609  
    2610 class _OptReqListField(StrLenField): 
    2611     islist = 1 
    2612     def i2h(self, pkt, x): 
    2613         if x is None: 
    2614             return [] 
    2615         return x 
    2616  
    2617     def i2len(self, pkt, x): 
    2618         return 2*len(x) 
    2619  
    2620     def any2i(self, pkt, x): 
    2621         return x 
    2622  
    2623     def i2repr(self, pkt, x): 
    2624         s = [] 
    2625         for y in self.i2h(pkt, x): 
    2626             if dhcp6opts.has_key(y): 
    2627                 s.append(dhcp6opts[y]) 
    2628             else: 
    2629                 s.append("%d" % y) 
    2630         return "[%s]" % ", ".join(s)  
    2631  
    2632     def m2i(self, pkt, x): 
    2633         r = [] 
    2634         while len(x) != 0: 
    2635             if len(x)<2: 
    2636                 warning("Odd length for requested option field. Rejecting last byte") 
    2637                 return r 
    2638             r.append(struct.unpack("!H", x[:2])[0]) 
    2639             x = x[2:] 
    2640         return r 
    2641      
    2642     def i2m(self, pkt, x): 
    2643         return "".join(map(lambda y: struct.pack("!H", y), x)) 
    2644  
    2645 # A client may include an ORO in a solicit, Request, Renew, Rebind, 
    2646 # Confirm or Information-request 
    2647 class DHCP6OptOptReq(_DHCP6OptGuessPayload):       # RFC sect 22.7 
    2648     name = "DHCP6 Option Request Option" 
    2649     fields_desc = [ ShortEnumField("optcode", 6, dhcp6opts), 
    2650                     FieldLenField("optlen", None, length_of="reqopts", fmt="!H"), 
    2651                     _OptReqListField("reqopts", [23, 24], 
    2652                                      length_from = lambda pkt: pkt.optlen) ] 
    2653  
    2654  
    2655 #### DHCPv6 Preference Option ####################################### 
    2656  
    2657 # emise par un serveur pour affecter le choix fait par le client. Dans 
    2658 # les messages Advertise, a priori 
    2659 class DHCP6OptPref(_DHCP6OptGuessPayload):       # RFC sect 22.8 
    2660     name = "DHCP6 Preference Option" 
    2661     fields_desc = [ ShortEnumField("optcode", 7, dhcp6opts),  
    2662                     ShortField("optlen", 1 ), 
    2663                     ByteField("prefval",255) ] 
    2664  
    2665  
    2666 #### DHCPv6 Elapsed Time Option ##################################### 
    2667  
    2668 class _ElapsedTimeField(ShortField): 
    2669     def i2repr(self, pkt, x): 
    2670         if x == 0xffff: 
    2671             return "infinity (0xffff)" 
    2672         return "%.2f sec" % (self.i2h(pkt, x)/100.) 
    2673  
    2674 class DHCP6OptElapsedTime(_DHCP6OptGuessPayload):# RFC sect 22.9 
    2675     name = "DHCP6 Elapsed Time Option" 
    2676     fields_desc = [ ShortEnumField("optcode", 8, dhcp6opts),  
    2677                     ShortField("optlen", 2), 
    2678                     _ElapsedTimeField("elapsedtime", 0) ] 
    2679  
    2680  
    2681 #### DHCPv6 Relay Message Option #################################### 
    2682  
    2683 # Relayed message is seen as a payload. 
    2684 class DHCP6OptRelayMsg(_DHCP6OptGuessPayload):# RFC sect 22.10 
    2685     name = "DHCP6 Relay Message Option" 
    2686     fields_desc = [ ShortEnumField("optcode", 9, dhcp6opts),  
    2687                     ShortField("optlen", None ) ] 
    2688     def post_build(self, p, pay): 
    2689         if self.optlen is None: 
    2690             l = len(pay)  
    2691             p = p[:2]+struct.pack("!H", l) 
    2692         return p + pay 
    2693  
    2694  
    2695 #### DHCPv6 Authentication Option ################################### 
    2696  
    2697 #    The following fields are set in an Authentication option for the 
    2698 #    Reconfigure Key Authentication Protocol: 
    2699 # 
    2700 #       protocol    3 
    2701 # 
    2702 #       algorithm   1 
    2703 # 
    2704 #       RDM         0 
    2705 # 
    2706 #    The format of the Authentication information for the Reconfigure Key 
    2707 #    Authentication Protocol is: 
    2708 # 
    2709 #      0                   1                   2                   3 
    2710 #      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
    2711 #     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
    2712 #     |     Type      |                 Value (128 bits)              | 
    2713 #     +-+-+-+-+-+-+-+-+                                               | 
    2714 #     .                                                               . 
    2715 #     .                                                               . 
    2716 #     .                                               +-+-+-+-+-+-+-+-+ 
    2717 #     |                                               | 
    2718 #     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
    2719 # 
    2720 #       Type    Type of data in Value field carried in this option: 
    2721 # 
    2722 #                  1   Reconfigure Key value (used in Reply message). 
    2723 # 
    2724 #                  2   HMAC-MD5 digest of the message (used in Reconfigure 
    2725 #                      message). 
    2726 # 
    2727 #       Value   Data as defined by field. 
    2728  
    2729  
    2730 # TODO : Decoding only at the moment 
    2731 class DHCP6OptAuth(_DHCP6OptGuessPayload):    # RFC sect 22.11 
    2732     name = "DHCP6 Option - Authentication" 
    2733     fields_desc = [ ShortEnumField("optcode", 11, dhcp6opts),  
    2734                     FieldLenField("optlen", None, length_of="authinfo", 
    2735                                   adjust = lambda pkt,x: x+11), 
    2736                     ByteField("proto", 3), # TODO : XXX 
    2737                     ByteField("alg", 1), # TODO : XXX 
    2738                     ByteField("rdm", 0), # TODO : XXX 
    2739                     StrFixedLenField("replay", "A"*8, 8), # TODO: XXX 
    2740                     StrLenField("authinfo", "", 
    2741                                 length_from = lambda pkt: pkt.optlen - 11) ] 
    2742  
    2743 #### DHCPv6 Server Unicast Option ################################### 
    2744  
    2745 class _SrvAddrField(IP6Field): 
    2746     def i2h(self, pkt, x): 
    2747         if x is None: 
    2748             return "::" 
    2749         return x 
    2750      
    2751     def i2m(self, pkt, x): 
    2752         return inet_pton(socket.AF_INET6, self.i2h(pkt,x)) 
    2753  
    2754 class DHCP6OptServerUnicast(_DHCP6OptGuessPayload):# RFC sect 22.12 
    2755     name = "DHCP6 Server Unicast Option" 
    2756     fields_desc = [ ShortEnumField("optcode", 12, dhcp6opts),  
    2757                     ShortField("optlen", 16 ), 
    2758                     _SrvAddrField("srvaddr",None) ] 
    2759  
    2760  
    2761 #### DHCPv6 Status Code Option ###################################### 
    2762  
    2763 dhcp6statuscodes = { 0:"Success",      # sect 24.4 
    2764                      1:"UnspecFail", 
    2765                      2:"NoAddrsAvail", 
    2766                      3:"NoBinding", 
    2767                      4:"NotOnLink", 
    2768                      5:"UseMulticast", 
    2769                      6:"NoPrefixAvail"} # From RFC3633 
    2770  
    2771 class DHCP6OptStatusCode(_DHCP6OptGuessPayload):# RFC sect 22.13 
    2772     name = "DHCP6 Status Code Option" 
    2773     fields_desc = [ ShortEnumField("optcode", 13, dhcp6opts),  
    2774                     FieldLenField("optlen", None, length_of="statusmsg", 
    2775                                   fmt="!H", adjust = lambda pkt,x:x+2), 
    2776                     ShortEnumField("statuscode",None,dhcp6statuscodes), 
    2777                     StrLenField("statusmsg", "", 
    2778                                 length_from = lambda pkt: pkt.optlen-2) ] 
    2779  
    2780  
    2781 #### DHCPv6 Rapid Commit Option ##################################### 
    2782  
    2783 class DHCP6OptRapidCommit(_DHCP6OptGuessPayload):   # RFC sect 22.14 
    2784     name = "DHCP6 Rapid Commit Option" 
    2785     fields_desc = [ ShortEnumField("optcode", 14, dhcp6opts), 
    2786                     ShortField("optlen", 0)] 
    2787  
    2788  
    2789 #### DHCPv6 User Class Option ####################################### 
    2790  
    2791 class _UserClassDataField(PacketListField): 
    2792     def i2len(self, pkt, z): 
    2793         if z is None or z == []: 
    2794             return 0 
    2795         return sum(map(lambda x: len(str(x)) ,z)) 
    2796  
    2797     def getfield(self, pkt, s): 
    2798         l = self.length_from(pkt) 
    2799         lst = [] 
    2800         remain, payl = s[:l], s[l:] 
    2801         while len(remain)>0: 
    2802             p = self.m2i(pkt,remain) 
    2803             if Padding in p: 
    2804                 pad = p[Padding] 
    2805                 remain = pad.load 
    2806                 del(pad.underlayer.payload) 
    2807             else: 
    2808                 remain = "" 
    2809             lst.append(p) 
    2810         return payl,lst 
    2811  
    2812  
    2813 class USER_CLASS_DATA(Packet): 
    2814     name = "user class data" 
    2815     fields_desc = [ FieldLenField("len", None, length_of="data"), 
    2816                     StrLenField("data", "", 
    2817                                 length_from = lambda pkt: pkt.len) ] 
    2818     def guess_payload_class(self, payload): 
    2819         return Padding 
    2820  
    2821 class DHCP6OptUserClass(_DHCP6OptGuessPayload):# RFC sect 22.15 
    2822     name = "DHCP6 User Class Option" 
    2823     fields_desc = [ ShortEnumField("optcode", 15, dhcp6opts),  
    2824                     FieldLenField("optlen", None, fmt="!H", 
    2825                                   length_of="userclassdata"), 
    2826                     _UserClassDataField("userclassdata", [], USER_CLASS_DATA, 
    2827                                         length_from = lambda pkt: pkt.optlen) ] 
    2828  
    2829  
    2830 #### DHCPv6 Vendor Class Option ##################################### 
    2831  
    2832 class _VendorClassDataField(_UserClassDataField): 
    2833     pass 
    2834  
    2835 class VENDOR_CLASS_DATA(USER_CLASS_DATA): 
    2836     name = "vendor class data" 
    2837  
    2838 class DHCP6OptVendorClass(_DHCP6OptGuessPayload):# RFC sect 22.16 
    2839     name = "DHCP6 Vendor Class Option" 
    2840     fields_desc = [ ShortEnumField("optcode", 16, dhcp6opts),  
    2841                     FieldLenField("optlen", None, length_of="vcdata", fmt="!H", 
    2842                                   adjust = lambda pkt,x: x+4), 
    2843                     IntEnumField("enterprisenum",None , iana_enterprise_num ), 
    2844                     _VendorClassDataField("vcdata", [], VENDOR_CLASS_DATA, 
    2845                                           length_from = lambda pkt: pkt.optlen-4) ] 
    2846  
    2847 #### DHCPv6 Vendor-Specific Information Option ###################### 
    2848  
    2849 class VENDOR_SPECIFIC_OPTION(_DHCP6OptGuessPayload): 
    2850     name = "vendor specific option data" 
    2851     fields_desc = [ ShortField("optcode", None), 
    2852                     FieldLenField("optlen", None, length_of="optdata"), 
    2853                     StrLenField("optdata", "", 
    2854                                 length_from = lambda pkt: pkt.optlen) ] 
    2855     def guess_payload_class(self, payload): 
    2856         return Padding 
    2857  
    2858 # The third one that will be used for nothing interesting 
    2859 class DHCP6OptVendorSpecificInfo(_DHCP6OptGuessPayload):# RFC sect 22.17 
    2860     name = "DHCP6 Vendor-specific Information Option" 
    2861     fields_desc = [ ShortEnumField("optcode", 17, dhcp6opts),  
    2862                     FieldLenField("optlen", None, length_of="vso", fmt="!H", 
    2863                                   adjust = lambda pkt,x: x+4), 
    2864                     IntEnumField("enterprisenum",None , iana_enterprise_num), 
    2865                     _VendorClassDataField("vso", [], VENDOR_SPECIFIC_OPTION, 
    2866                                           length_from = lambda pkt: pkt.optlen-4) ] 
    2867  
    2868 #### DHCPv6 Interface-ID Option ##################################### 
    2869  
    2870 # Repasser sur cette option a la fin. Elle a pas l'air d'etre des 
    2871 # masses critique. 
    2872 class DHCP6OptIfaceId(_DHCP6OptGuessPayload):# RFC sect 22.18 
    2873     name = "DHCP6 Interface-Id Option" 
    2874     fields_desc = [ ShortEnumField("optcode", 18, dhcp6opts), 
    2875                     FieldLenField("optlen", None, fmt="!H", 
    2876                                   length_of="ifaceid"), 
    2877                     StrLenField("ifaceid", "", 
    2878                                 length_from = lambda pkt: pkt.optlen) ] 
    2879  
    2880  
    2881 #### DHCPv6 Reconfigure Message Option ############################## 
    2882  
    2883 # A server includes a Reconfigure Message option in a Reconfigure 
    2884 # message to indicate to the client whether the client responds with a 
    2885 # renew message or an Informatiion-request message. 
    2886 class DHCP6OptReconfMsg(_DHCP6OptGuessPayload):       # RFC sect 22.19 
    2887     name = "DHCP6 Reconfigure Message Option" 
    2888     fields_desc = [ ShortEnumField("optcode", 19, dhcp6opts),  
    2889                     ShortField("optlen", 1 ), 
    2890                     ByteEnumField("msgtype", 11, {  5:"Renew Message",  
    2891                                                    11:"Information Request"}) ] 
    2892  
    2893  
    2894 #### DHCPv6 Reconfigure Accept Option ############################### 
    2895  
    2896 # A client uses the Reconfigure Accept option to announce to the 
    2897 # server whether the client is willing to accept Recoonfigure 
    2898 # messages, and a server uses this option to tell the client whether 
    2899 # or not to accept Reconfigure messages. The default behavior in the 
    2900 # absence of this option, means unwillingness to accept reconfigure 
    2901 # messages, or instruction not to accept Reconfigure messages, for the 
    2902 # client and server messages, respectively. 
    2903 class DHCP6OptReconfAccept(_DHCP6OptGuessPayload):   # RFC sect 22.20 
    2904     name = "DHCP6 Reconfigure Accept Option" 
    2905     fields_desc = [ ShortEnumField("optcode", 20, dhcp6opts), 
    2906                     ShortField("optlen", 0)] 
    2907  
    2908 # As required in Sect 8. of RFC 3315, Domain Names must be encoded as  
    2909 # described in section 3.1 of RFC 1035 
    2910 # XXX Label should be at most 63 octets in length : we do not enforce it 
    2911 #     Total length of domain should be 255 : we do not enforce it either 
    2912 class DomainNameListField(StrLenField): 
    2913     islist = 1 
    2914  
    2915     def i2len(self, pkt, x): 
    2916         return len(self.i2m(pkt, x)) 
    2917  
    2918     def m2i(self, pkt, x): 
    2919         res = [] 
    2920         while x: 
    2921             cur = [] 
    2922             while x and x[0] != '\x00': 
    2923                 l = ord(x[0]) 
    2924                 cur.append(x[1:l+1]) 
    2925                 x = x[l+1:] 
    2926             res.append(".".join(cur)) 
    2927             if x and x[0] == '\x00': 
    2928                 x = x[1:] 
    2929         return res 
    2930  
    2931     def i2m(self, pkt, x): 
    2932         def conditionalTrailingDot(z): 
    2933             if z and z[-1] == '\x00': 
    2934                 return z 
    2935             return z+'\x00' 
    2936         res = "" 
    2937         tmp = map(lambda y: map((lambda z: chr(len(z))+z), y.split('.')), x) 
    2938         return "".join(map(lambda x: conditionalTrailingDot("".join(x)), tmp)) 
    2939  
    2940 class DHCP6OptSIPDomains(_DHCP6OptGuessPayload):       #RFC3319 
    2941     name = "DHCP6 Option - SIP Servers Domain Name List" 
    2942     fields_desc = [ ShortEnumField("optcode", 21, dhcp6opts), 
    2943                     FieldLenField("optlen", None, length_of="sipdomains"), 
    2944                     DomainNameListField("sipdomains", [], 
    2945                                         length_from = lambda pkt: pkt.optlen) ] 
    2946  
    2947 class DHCP6OptSIPServers(_DHCP6OptGuessPayload):          #RFC3319 
    2948     name = "DHCP6 Option - SIP Servers IPv6 Address List" 
    2949     fields_desc = [ ShortEnumField("optcode", 22, dhcp6opts), 
    2950                     FieldLenField("optlen", None, length_of="sipservers"), 
    2951                     IP6ListField("sipservers", [],  
    2952                                  length_from = lambda pkt: pkt.optlen) ] 
    2953  
    2954 class DHCP6OptDNSServers(_DHCP6OptGuessPayload):          #RFC3646 
    2955     name = "DHCP6 Option - DNS Recursive Name Server" 
    2956     fields_desc = [ ShortEnumField("optcode", 23, dhcp6opts), 
    2957                     FieldLenField("optlen", None, length_of="dnsservers"), 
    2958                     IP6ListField("dnsservers", [], 
    2959                                  length_from = lambda pkt: pkt.optlen) ] 
    2960  
    2961 class DHCP6OptDNSDomains(_DHCP6OptGuessPayload): #RFC3646 
    2962     name = "DHCP6 Option - Domain Search List option" 
    2963     fields_desc = [ ShortEnumField("optcode", 24, dhcp6opts), 
    2964                     FieldLenField("optlen", None, length_of="dnsdomains"), 
    2965                     DomainNameListField("dnsdomains", [], 
    2966                                         length_from = lambda pkt: pkt.optlen) ] 
    2967  
    2968 # TODO: Implement iaprefopts correctly when provided with more  
    2969 #       information about it. 
    2970 class DHCP6OptIAPrefix(_DHCP6OptGuessPayload):                    #RFC3633 
    2971     name = "DHCP6 Option - IA_PD Prefix option" 
    2972     fields_desc = [ ShortEnumField("optcode", 26, dhcp6opts), 
    2973                     FieldLenField("optlen", None, length_of="iaprefopts", 
    2974                                   adjust = lambda pkt,x: x+26), 
    2975                     IntField("preflft", 0), 
    2976                     IntField("validlft", 0), 
    2977                     ByteField("plen", 48),  # TODO: Challenge that default value 
    2978                     IP6Field("prefix", "2001:db8::"), # At least, global and won't hurt 
    2979                     StrLenField("iaprefopts", "", 
    2980                                 length_from = lambda pkt: pkt.optlen-26) ] 
    2981  
    2982 class DHCP6OptIA_PD(_DHCP6OptGuessPayload):                       #RFC3633 
    2983     name = "DHCP6 Option - Identity Association for Prefix Delegation" 
    2984     fields_desc = [ ShortEnumField("optcode", 25, dhcp6opts), 
    2985                     FieldLenField("optlen", None, length_of="iapdopt", 
    2986                                   adjust = lambda pkt,x: x+12), 
    2987                     IntField("iaid", 0), 
    2988                     IntField("T1", 0), 
    2989                     IntField("T2", 0), 
    2990                     PacketListField("iapdopt", [], DHCP6OptIAPrefix, 
    2991                                     length_from = lambda pkt: pkt.optlen-12) ] 
    2992  
    2993 class DHCP6OptNISServers(_DHCP6OptGuessPayload):                 #RFC3898 
    2994     name = "DHCP6 Option - NIS Servers" 
    2995     fields_desc = [ ShortEnumField("optcode", 27, dhcp6opts), 
    2996                     FieldLenField("optlen", None, length_of="nisservers"), 
    2997                     IP6ListField("nisservers", [], 
    2998                                  length_from = lambda pkt: pkt.optlen) ] 
    2999  
    3000 class DHCP6OptNISPServers(_DHCP6OptGuessPayload):                #RFC3898 
    3001     name = "DHCP6 Option - NIS+ Servers" 
    3002     fields_desc = [ ShortEnumField("optcode", 28, dhcp6opts), 
    3003                     FieldLenField("optlen", None, length_of="nispservers"), 
    3004                     IP6ListField("nispservers", [], 
    3005                                  length_from = lambda pkt: pkt.optlen) ] 
    3006  
    3007 class DomainNameField(StrLenField): 
    3008     def getfield(self, pkt, s): 
    3009         l = self.length_from(pkt) 
    3010         return s[l:], self.m2i(pkt,s[:l]) 
    3011  
    3012     def i2len(self, pkt, x): 
    3013         return len(self.i2m(pkt, x)) 
    3014  
    3015     def m2i(self, pkt, x): 
    3016         save = x 
    3017         cur = [] 
    3018         while x and x[0] != '\x00': 
    3019             l = ord(x[0]) 
    3020             cur.append(x[1:1+l]) 
    3021             x = x[l+1:] 
    3022         if x[0] != '\x00': 
    3023             print "Found weird domain: '%s'. Keeping %s" % (save, x) 
    3024         return ".".join(cur) 
    3025  
    3026     def i2m(self, pkt, x): 
    3027         def conditionalTrailingDot(z): 
    3028             if (z and z[-1] == '\x00'): 
    3029                 return z 
    3030             return z+'\x00' 
    3031         if not x: 
    3032             return "" 
    3033         tmp = "".join(map(lambda z: chr(len(z))+z, x.split('.'))) 
    3034         return conditionalTrailingDot(tmp) 
    3035  
    3036 class DHCP6OptNISDomain(_DHCP6OptGuessPayload):             #RFC3898 
    3037     name = "DHCP6 Option - NIS Domain Name" 
    3038     fields_desc = [ ShortEnumField("optcode", 29, dhcp6opts), 
    3039                     FieldLenField("optlen", None, length_of="nisdomain"), 
    3040                     DomainNameField("nisdomain", "", 
    3041                                     length_from = lambda pkt: pkt.optlen) ] 
    3042  
    3043 class DHCP6OptNISPDomain(_DHCP6OptGuessPayload):            #RFC3898 
    3044     name = "DHCP6 Option - NIS+ Domain Name" 
    3045     fields_desc = [ ShortEnumField("optcode", 30, dhcp6opts), 
    3046                     FieldLenField("optlen", None, length_of="nispdomain"), 
    3047                     DomainNameField("nispdomain", "", 
    3048                                     length_from= lambda pkt: pkt.optlen) ] 
    3049  
    3050 class DHCP6OptSNTPServers(_DHCP6OptGuessPayload):                #RFC4075 
    3051     name = "DHCP6 option - SNTP Servers" 
    3052     fields_desc = [ ShortEnumField("optcode", 31, dhcp6opts), 
    3053                     FieldLenField("optlen", None, length_of="sntpservers"), 
    3054                     IP6ListField("sntpservers", [], 
    3055                                  length_from = lambda pkt: pkt.optlen) ] 
    3056  
    3057 IRT_DEFAULT=86400 
    3058 IRT_MINIMUM=600 
    3059 class DHCP6OptInfoRefreshTime(_DHCP6OptGuessPayload):    #RFC4242 
    3060     name = "DHCP6 Option - Information Refresh Time" 
    3061     fields_desc = [ ShortEnumField("optcode", 32, dhcp6opts), 
    3062                     ShortField("optlen", 4), 
    3063                     IntField("reftime", IRT_DEFAULT)] # One day 
    3064  
    3065 class DHCP6OptBCMCSDomains(_DHCP6OptGuessPayload):              #RFC4280          
    3066     name = "DHCP6 Option - BCMCS Domain Name List" 
    3067     fields_desc = [ ShortEnumField("optcode", 33, dhcp6opts), 
    3068                     FieldLenField("optlen", None, length_of="bcmcsdomains"), 
    3069                     DomainNameListField("bcmcsdomains", [], 
    3070                                         length_from = lambda pkt: pkt.optlen) ] 
    3071  
    3072 class DHCP6OptBCMCSServers(_DHCP6OptGuessPayload):              #RFC4280 
    3073     name = "DHCP6 Option - BCMCS Addresses List" 
    3074     fields_desc = [ ShortEnumField("optcode", 34, dhcp6opts), 
    3075                     FieldLenField("optlen", None, length_of="bcmcsservers"), 
    3076                     IP6ListField("bcmcsservers", [], 
    3077                                  length_from= lambda pkt: pkt.optlen) ] 
    3078  
    3079 # TODO : Does Nothing at the moment 
    3080 class DHCP6OptGeoConf(_DHCP6OptGuessPayload):               #RFC-ietf-geopriv-dhcp-civil-09.txt 
    3081     name = "" 
    3082     fields_desc = [ ShortEnumField("optcode", 36, dhcp6opts), 
    3083                     FieldLenField("optlen", None, length_of="optdata"), 
    3084                     StrLenField("optdata", "", 
    3085                                 length_from = lambda pkt: pkt.optlen) ] 
    3086  
    3087 # TODO: see if we encounter opaque values from vendor devices 
    3088 class DHCP6OptRemoteID(_DHCP6OptGuessPayload):                   #RFC4649 
    3089     name = "DHCP6 Option - Relay Agent Remote-ID" 
    3090     fields_desc = [ ShortEnumField("optcode", 37, dhcp6opts), 
    3091                     FieldLenField("optlen", None, length_of="remoteid", 
    3092                                   adjust = lambda pkt,x: x+4), 
    3093                     IntEnumField("enterprisenum", None, iana_enterprise_num), 
    3094                     StrLenField("remoteid", "", 
    3095                                 length_from = lambda pkt: pkt.optlen-4) ] 
    3096  
    3097 # TODO : 'subscriberid' default value should be at least 1 byte long 
    3098 class DHCP6OptSubscriberID(_DHCP6OptGuessPayload):               #RFC4580 
    3099     name = "DHCP6 Option - Subscriber ID" 
    3100     fields_desc = [ ShortEnumField("optcode", 38, dhcp6opts), 
    3101                     FieldLenField("optlen", None, length_of="subscriberid"), 
    3102                     StrLenField("subscriberid", "", 
    3103                                 length_from = lambda pkt: pkt.optlen) ] 
    3104  
    3105 # TODO :  "The data in the Domain Name field MUST be encoded 
    3106 #          as described in Section 8 of [5]" 
    3107 class DHCP6OptClientFQDN(_DHCP6OptGuessPayload):                 #RFC4704 
    3108     name = "DHCP6 Option - Client FQDN" 
    3109     fields_desc = [ ShortEnumField("optcode", 39, dhcp6opts), 
    3110                     FieldLenField("optlen", None, length_of="fqdn", 
    3111                                   adjust = lambda pkt,x: x+1), 
    3112                     BitField("res", 0, 5), 
    3113                     FlagsField("flags", 0, 3, "SON" ), 
    3114                     DomainNameField("fqdn", "", 
    3115                                     length_from = lambda pkt: pkt.optlen-1) ] 
    3116  
    3117 class DHCP6OptRelayAgentERO(_DHCP6OptGuessPayload):       # RFC4994 
    3118     name = "DHCP6 Option - RelayRequest Option" 
    3119     fields_desc = [ ShortEnumField("optcode", 43, dhcp6opts), 
    3120                     FieldLenField("optlen", None, length_of="reqopts", fmt="!H"), 
    3121                     _OptReqListField("reqopts", [23, 24], 
    3122                                      length_from = lambda pkt: pkt.optlen) ] 
    3123&