diff options
author | 2016-03-21 16:03:47 +0200 | |
---|---|---|
committer | 2016-03-21 16:03:47 +0200 | |
commit | b89efa188810bf95a9d245e69e2961b5721c3b0f (patch) | |
tree | 454273ac6c4ae972ebb8a2c86b893296970b4fa9 /scripts/external_libs/scapy-python3-0.18/scapy/layers/dhcp6.py | |
parent | f72c6df9d2e9998ae1f3529d729ab7930b35785a (diff) |
scapy python 2/3
Diffstat (limited to 'scripts/external_libs/scapy-python3-0.18/scapy/layers/dhcp6.py')
-rw-r--r-- | scripts/external_libs/scapy-python3-0.18/scapy/layers/dhcp6.py | 1718 |
1 files changed, 0 insertions, 1718 deletions
diff --git a/scripts/external_libs/scapy-python3-0.18/scapy/layers/dhcp6.py b/scripts/external_libs/scapy-python3-0.18/scapy/layers/dhcp6.py deleted file mode 100644 index a11a4149..00000000 --- a/scripts/external_libs/scapy-python3-0.18/scapy/layers/dhcp6.py +++ /dev/null @@ -1,1718 +0,0 @@ -## This file is part of Scapy -## See http://www.secdev.org/projects/scapy for more informations -## Copyright (C) Philippe Biondi <phil@secdev.org> -## This program is published under a GPLv2 license - -## Copyright (C) 2005 Guillaume Valadon <guedou@hongo.wide.ad.jp> -## Arnaud Ebalard <arnaud.ebalard@eads.net> - -""" -DHCPv6: Dynamic Host Configuration Protocol for IPv6. [RFC 3315] -""" - -import socket -from scapy.packet import * -from scapy.fields import * -from scapy.utils6 import * -from scapy.layers.inet6 import * -from scapy.ansmachine import AnsweringMachine - -############################################################################# -# Helpers ## -############################################################################# - -def get_cls(name, fallback_cls): - return globals().get(name, fallback_cls) - - -############################################################################# -############################################################################# -### DHCPv6 ### -############################################################################# -############################################################################# - -All_DHCP_Relay_Agents_and_Servers = "ff02::1:2" -All_DHCP_Servers = "ff05::1:3" # Site-Local scope : deprecated by 3879 - -dhcp6opts = { 1: "CLIENTID", - 2: "SERVERID", - 3: "IA_NA", - 4: "IA_TA", - 5: "IAADDR", - 6: "ORO", - 7: "PREFERENCE", - 8: "ELAPSED_TIME", - 9: "RELAY_MSG", - 11: "AUTH", - 12: "UNICAST", - 13: "STATUS_CODE", - 14: "RAPID_COMMIT", - 15: "USER_CLASS", - 16: "VENDOR_CLASS", - 17: "VENDOR_OPTS", - 18: "INTERFACE_ID", - 19: "RECONF_MSG", - 20: "RECONF_ACCEPT", - 21: "SIP Servers Domain Name List", #RFC3319 - 22: "SIP Servers IPv6 Address List", #RFC3319 - 23: "DNS Recursive Name Server Option", #RFC3646 - 24: "Domain Search List option", #RFC3646 - 25: "OPTION_IA_PD", #RFC3633 - 26: "OPTION_IAPREFIX", #RFC3633 - 27: "OPTION_NIS_SERVERS", #RFC3898 - 28: "OPTION_NISP_SERVERS", #RFC3898 - 29: "OPTION_NIS_DOMAIN_NAME", #RFC3898 - 30: "OPTION_NISP_DOMAIN_NAME", #RFC3898 - 31: "OPTION_SNTP_SERVERS", #RFC4075 - 32: "OPTION_INFORMATION_REFRESH_TIME", #RFC4242 - 33: "OPTION_BCMCS_SERVER_D", #RFC4280 - 34: "OPTION_BCMCS_SERVER_A", #RFC4280 - 36: "OPTION_GEOCONF_CIVIC", #RFC-ietf-geopriv-dhcp-civil-09.txt - 37: "OPTION_REMOTE_ID", #RFC4649 - 38: "OPTION_SUBSCRIBER_ID", #RFC4580 - 39: "OPTION_CLIENT_FQDN" } #RFC4704 - -dhcp6opts_by_code = { 1: "DHCP6OptClientId", - 2: "DHCP6OptServerId", - 3: "DHCP6OptIA_NA", - 4: "DHCP6OptIA_TA", - 5: "DHCP6OptIAAddress", - 6: "DHCP6OptOptReq", - 7: "DHCP6OptPref", - 8: "DHCP6OptElapsedTime", - 9: "DHCP6OptRelayMsg", - 11: "DHCP6OptAuth", - 12: "DHCP6OptServerUnicast", - 13: "DHCP6OptStatusCode", - 14: "DHCP6OptRapidCommit", - 15: "DHCP6OptUserClass", - 16: "DHCP6OptVendorClass", - 17: "DHCP6OptVendorSpecificInfo", - 18: "DHCP6OptIfaceId", - 19: "DHCP6OptReconfMsg", - 20: "DHCP6OptReconfAccept", - 21: "DHCP6OptSIPDomains", #RFC3319 - 22: "DHCP6OptSIPServers", #RFC3319 - 23: "DHCP6OptDNSServers", #RFC3646 - 24: "DHCP6OptDNSDomains", #RFC3646 - 25: "DHCP6OptIA_PD", #RFC3633 - 26: "DHCP6OptIAPrefix", #RFC3633 - 27: "DHCP6OptNISServers", #RFC3898 - 28: "DHCP6OptNISPServers", #RFC3898 - 29: "DHCP6OptNISDomain", #RFC3898 - 30: "DHCP6OptNISPDomain", #RFC3898 - 31: "DHCP6OptSNTPServers", #RFC4075 - 32: "DHCP6OptInfoRefreshTime", #RFC4242 - 33: "DHCP6OptBCMCSDomains", #RFC4280 - 34: "DHCP6OptBCMCSServers", #RFC4280 - #36: "DHCP6OptGeoConf", #RFC-ietf-geopriv-dhcp-civil-09.txt - 37: "DHCP6OptRemoteID", #RFC4649 - 38: "DHCP6OptSubscriberID", #RFC4580 - 39: "DHCP6OptClientFQDN", #RFC4704 - #40: "DHCP6OptPANAAgent", #RFC-ietf-dhc-paa-option-05.txt - #41: "DHCP6OptNewPOSIXTimeZone, #RFC4833 - #42: "DHCP6OptNewTZDBTimeZone, #RFC4833 - 43: "DHCP6OptRelayAgentERO" #RFC4994 - #44: "DHCP6OptLQQuery", #RFC5007 - #45: "DHCP6OptLQClientData", #RFC5007 - #46: "DHCP6OptLQClientTime", #RFC5007 - #47: "DHCP6OptLQRelayData", #RFC5007 - #48: "DHCP6OptLQClientLink", #RFC5007 -} - - -# sect 5.3 RFC 3315 : DHCP6 Messages types -dhcp6types = { 1:"SOLICIT", - 2:"ADVERTISE", - 3:"REQUEST", - 4:"CONFIRM", - 5:"RENEW", - 6:"REBIND", - 7:"REPLY", - 8:"RELEASE", - 9:"DECLINE", - 10:"RECONFIGURE", - 11:"INFORMATION-REQUEST", - 12:"RELAY-FORW", - 13:"RELAY-REPL" } - - -##################################################################### -### DHCPv6 DUID related stuff ### -##################################################################### - -duidtypes = { 1: "Link-layer address plus time", - 2: "Vendor-assigned unique ID based on Enterprise Number", - 3: "Link-layer Address" } - -# DUID hardware types - RFC 826 - Extracted from -# http://www.iana.org/assignments/arp-parameters on 31/10/06 -# We should add the length of every kind of address. -duidhwtypes = { 0: "NET/ROM pseudo", # Not referenced by IANA - 1: "Ethernet (10Mb)", - 2: "Experimental Ethernet (3Mb)", - 3: "Amateur Radio AX.25", - 4: "Proteon ProNET Token Ring", - 5: "Chaos", - 6: "IEEE 802 Networks", - 7: "ARCNET", - 8: "Hyperchannel", - 9: "Lanstar", - 10: "Autonet Short Address", - 11: "LocalTalk", - 12: "LocalNet (IBM PCNet or SYTEK LocalNET)", - 13: "Ultra link", - 14: "SMDS", - 15: "Frame Relay", - 16: "Asynchronous Transmission Mode (ATM)", - 17: "HDLC", - 18: "Fibre Channel", - 19: "Asynchronous Transmission Mode (ATM)", - 20: "Serial Line", - 21: "Asynchronous Transmission Mode (ATM)", - 22: "MIL-STD-188-220", - 23: "Metricom", - 24: "IEEE 1394.1995", - 25: "MAPOS", - 26: "Twinaxial", - 27: "EUI-64", - 28: "HIPARP", - 29: "IP and ARP over ISO 7816-3", - 30: "ARPSec", - 31: "IPsec tunnel", - 32: "InfiniBand (TM)", - 33: "TIA-102 Project 25 Common Air Interface (CAI)" } - -class UTCTimeField(IntField): - epoch = (2000, 1, 1, 0, 0, 0, 5, 1, 0) # required Epoch - def i2repr(self, pkt, x): - x = self.i2h(pkt, x) - from time import gmtime, strftime, mktime - delta = mktime(self.epoch) - mktime(gmtime(0)) - x = x + delta - t = strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime(x)) - return "%s (%d)" % (t, x) - -class _LLAddrField(MACField): - pass - -# XXX We only support Ethernet addresses at the moment. _LLAddrField -# will be modified when needed. Ask us. --arno -class DUID_LLT(Packet): # sect 9.2 RFC 3315 - name = "DUID - Link-layer address plus time" - fields_desc = [ ShortEnumField("type", 1, duidtypes), - XShortEnumField("hwtype", 1, duidhwtypes), - UTCTimeField("timeval", 0), # i.e. 01 Jan 2000 - _LLAddrField("lladdr", ETHER_ANY) ] - -# In fact, IANA enterprise-numbers file available at -# http//www.iana.org/asignments/enterprise-numbers) -# is simply huge (more than 2Mo and 600Ko in bz2). I'll -# add only most common vendors, and encountered values. -# -- arno -iana_enterprise_num = { 9: "ciscoSystems", - 35: "Nortel Networks", - 43: "3Com", - 311: "Microsoft", - 2636: "Juniper Networks, Inc.", - 4526: "Netgear", - 5771: "Cisco Systems, Inc.", - 5842: "Cisco Systems", - 16885: "Nortel Networks" } - -class DUID_EN(Packet): # sect 9.3 RFC 3315 - name = "DUID - Assigned by Vendor Based on Enterprise Number" - fields_desc = [ ShortEnumField("type", 2, duidtypes), - IntEnumField("enterprisenum", 311, iana_enterprise_num), - StrField("id",b"") ] - -class DUID_LL(Packet): # sect 9.4 RFC 3315 - name = "DUID - Based on Link-layer Address" - fields_desc = [ ShortEnumField("type", 3, duidtypes), - XShortEnumField("hwtype", 1, duidhwtypes), - _LLAddrField("lladdr", ETHER_ANY) ] - -duid_cls = { 1: "DUID_LLT", - 2: "DUID_EN", - 3: "DUID_LL"} - -##################################################################### -### DHCPv6 Options classes ### -##################################################################### - -class _DHCP6OptGuessPayload(Packet): - def guess_payload_class(self, payload): - cls = conf.raw_layer - if len(payload) > 2 : - opt = struct.unpack("!H", payload[:2])[0] - cls = get_cls(dhcp6opts_by_code.get(opt, "DHCP6OptUnknown"), DHCP6OptUnknown) - return cls - -class DHCP6OptUnknown(_DHCP6OptGuessPayload): # A generic DHCPv6 Option - name = "Unknown DHCPv6 OPtion" - fields_desc = [ ShortEnumField("optcode", 0, dhcp6opts), - FieldLenField("optlen", None, length_of="data", fmt="!H"), - StrLenField("data", b"", - length_from = lambda pkt: pkt.optlen)] - -class _DUIDField(PacketField): - holds_packets=1 - def __init__(self, name, default, length_from=None): - StrField.__init__(self, name, default) - self.length_from = length_from - - def i2m(self, pkt, i): - return bytes(i) - - def m2i(self, pkt, x): - cls = conf.raw_layer - if len(x) > 4: - o = struct.unpack("!H", x[:2])[0] - cls = get_cls(duid_cls.get(o, conf.raw_layer), conf.raw_layer) - return cls(x) - - def getfield(self, pkt, s): - l = self.length_from(pkt) - return s[l:], self.m2i(pkt,s[:l]) - - -class DHCP6OptClientId(_DHCP6OptGuessPayload): # RFC sect 22.2 - name = "DHCP6 Client Identifier Option" - fields_desc = [ ShortEnumField("optcode", 1, dhcp6opts), - FieldLenField("optlen", None, length_of="duid", fmt="!H"), - _DUIDField("duid", "", - length_from = lambda pkt: pkt.optlen) ] - - -class DHCP6OptServerId(DHCP6OptClientId): # RFC sect 22.3 - name = "DHCP6 Server Identifier Option" - optcode = 2 - -# Should be encapsulated in the option field of IA_NA or IA_TA options -# Can only appear at that location. -# TODO : last field IAaddr-options is not defined in the reference document -class DHCP6OptIAAddress(_DHCP6OptGuessPayload): # RFC sect 22.6 - name = "DHCP6 IA Address Option (IA_TA or IA_NA suboption)" - fields_desc = [ ShortEnumField("optcode", 5, dhcp6opts), - FieldLenField("optlen", None, length_of="iaaddropts", - fmt="!H", adjust = lambda pkt,x: x+24), - IP6Field("addr", "::"), - IntField("preflft", 0), - IntField("validlft", 0), - XIntField("iaid", None), - StrLenField("iaaddropts", b"", - length_from = lambda pkt: pkt.optlen - 24) ] - def guess_payload_class(self, payload): - return conf.padding_layer - -class _IANAOptField(PacketListField): - def i2len(self, pkt, z): - if z is None or z == []: - return 0 - return sum(map(lambda x: len(bytes(x)) ,z)) - - def getfield(self, pkt, s): - l = self.length_from(pkt) - lst = [] - remain, payl = s[:l], s[l:] - while len(remain)>0: - p = self.m2i(pkt,remain) - if conf.padding_layer in p: - pad = p[conf.padding_layer] - remain = pad.load - del(pad.underlayer.payload) - else: - remain = "" - lst.append(p) - return payl,lst - -class DHCP6OptIA_NA(_DHCP6OptGuessPayload): # RFC sect 22.4 - name = "DHCP6 Identity Association for Non-temporary Addresses Option" - fields_desc = [ ShortEnumField("optcode", 3, dhcp6opts), - FieldLenField("optlen", None, length_of="ianaopts", - fmt="!H", adjust = lambda pkt,x: x+12), - XIntField("iaid", None), - IntField("T1", None), - IntField("T2", None), - _IANAOptField("ianaopts", [], DHCP6OptIAAddress, - length_from = lambda pkt: pkt.optlen-12) ] - -class _IATAOptField(_IANAOptField): - pass - -class DHCP6OptIA_TA(_DHCP6OptGuessPayload): # RFC sect 22.5 - name = "DHCP6 Identity Association for Temporary Addresses Option" - fields_desc = [ ShortEnumField("optcode", 4, dhcp6opts), - FieldLenField("optlen", None, length_of="iataopts", - fmt="!H", adjust = lambda pkt,x: x+4), - XIntField("iaid", None), - _IATAOptField("iataopts", [], DHCP6OptIAAddress, - length_from = lambda pkt: pkt.optlen-4) ] - - -#### DHCPv6 Option Request Option ################################### - -class _OptReqListField(StrLenField): - islist = 1 - def i2h(self, pkt, x): - if x is None: - return [] - return x - - def i2len(self, pkt, x): - return 2*len(x) - - def any2i(self, pkt, x): - return x - - def i2repr(self, pkt, x): - s = [] - for y in self.i2h(pkt, x): - if y in dhcp6opts: - s.append(dhcp6opts[y]) - else: - s.append("%d" % y) - return "[%s]" % ", ".join(s) - - def m2i(self, pkt, x): - r = [] - while len(x) != 0: - if len(x)<2: - warning("Odd length for requested option field. Rejecting last byte") - return r - r.append(struct.unpack("!H", x[:2])[0]) - x = x[2:] - return r - - def i2m(self, pkt, x): - return b"".join(map(lambda y: struct.pack("!H", y), x)) - -# A client may include an ORO in a solicit, Request, Renew, Rebind, -# Confirm or Information-request -class DHCP6OptOptReq(_DHCP6OptGuessPayload): # RFC sect 22.7 - name = "DHCP6 Option Request Option" - fields_desc = [ ShortEnumField("optcode", 6, dhcp6opts), - FieldLenField("optlen", None, length_of="reqopts", fmt="!H"), - _OptReqListField("reqopts", [23, 24], - length_from = lambda pkt: pkt.optlen) ] - - -#### DHCPv6 Preference Option ####################################### - -# emise par un serveur pour affecter le choix fait par le client. Dans -# les messages Advertise, a priori -class DHCP6OptPref(_DHCP6OptGuessPayload): # RFC sect 22.8 - name = "DHCP6 Preference Option" - fields_desc = [ ShortEnumField("optcode", 7, dhcp6opts), - ShortField("optlen", 1 ), - ByteField("prefval",255) ] - - -#### DHCPv6 Elapsed Time Option ##################################### - -class _ElapsedTimeField(ShortField): - def i2repr(self, pkt, x): - if x == 0xffff: - return "infinity (0xffff)" - return "%.2f sec" % (self.i2h(pkt, x)/100.) - -class DHCP6OptElapsedTime(_DHCP6OptGuessPayload):# RFC sect 22.9 - name = "DHCP6 Elapsed Time Option" - fields_desc = [ ShortEnumField("optcode", 8, dhcp6opts), - ShortField("optlen", 2), - _ElapsedTimeField("elapsedtime", 0) ] - - -#### DHCPv6 Relay Message Option #################################### - -# Relayed message is seen as a payload. -class DHCP6OptRelayMsg(_DHCP6OptGuessPayload):# RFC sect 22.10 - name = "DHCP6 Relay Message Option" - fields_desc = [ ShortEnumField("optcode", 9, dhcp6opts), - ShortField("optlen", None ) ] - def post_build(self, p, pay): - if self.optlen is None: - l = len(pay) - p = p[:2]+struct.pack("!H", l) - return p + pay - - -#### DHCPv6 Authentication Option ################################### - -# The following fields are set in an Authentication option for the -# Reconfigure Key Authentication Protocol: -# -# protocol 3 -# -# algorithm 1 -# -# RDM 0 -# -# The format of the Authentication information for the Reconfigure Key -# Authentication Protocol is: -# -# 0 1 2 3 -# 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 -# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -# | Type | Value (128 bits) | -# +-+-+-+-+-+-+-+-+ | -# . . -# . . -# . +-+-+-+-+-+-+-+-+ -# | | -# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -# -# Type Type of data in Value field carried in this option: -# -# 1 Reconfigure Key value (used in Reply message). -# -# 2 HMAC-MD5 digest of the message (used in Reconfigure -# message). -# -# Value Data as defined by field. - - -# TODO : Decoding only at the moment -class DHCP6OptAuth(_DHCP6OptGuessPayload): # RFC sect 22.11 - name = "DHCP6 Option - Authentication" - fields_desc = [ ShortEnumField("optcode", 11, dhcp6opts), - FieldLenField("optlen", None, length_of="authinfo", - adjust = lambda pkt,x: x+11), - ByteField("proto", 3), # TODO : XXX - ByteField("alg", 1), # TODO : XXX - ByteField("rdm", 0), # TODO : XXX - StrFixedLenField("replay", b"A"*8, 8), # TODO: XXX - StrLenField("authinfo", b"", - length_from = lambda pkt: pkt.optlen - 11) ] - -#### DHCPv6 Server Unicast Option ################################### - -class _SrvAddrField(IP6Field): - def i2h(self, pkt, x): - if x is None: - return "::" - return x - - def i2m(self, pkt, x): - return inet_pton(socket.AF_INET6, self.i2h(pkt,x)) - -class DHCP6OptServerUnicast(_DHCP6OptGuessPayload):# RFC sect 22.12 - name = "DHCP6 Server Unicast Option" - fields_desc = [ ShortEnumField("optcode", 12, dhcp6opts), - ShortField("optlen", 16 ), - _SrvAddrField("srvaddr",None) ] - - -#### DHCPv6 Status Code Option ###################################### - -dhcp6statuscodes = { 0:"Success", # sect 24.4 - 1:"UnspecFail", - 2:"NoAddrsAvail", - 3:"NoBinding", - 4:"NotOnLink", - 5:"UseMulticast", - 6:"NoPrefixAvail"} # From RFC3633 - -class DHCP6OptStatusCode(_DHCP6OptGuessPayload):# RFC sect 22.13 - name = "DHCP6 Status Code Option" - fields_desc = [ ShortEnumField("optcode", 13, dhcp6opts), - FieldLenField("optlen", None, length_of="statusmsg", - fmt="!H", adjust = lambda pkt,x:x+2), - ShortEnumField("statuscode",None,dhcp6statuscodes), - StrLenField("statusmsg", b"", - length_from = lambda pkt: pkt.optlen-2) ] - - -#### DHCPv6 Rapid Commit Option ##################################### - -class DHCP6OptRapidCommit(_DHCP6OptGuessPayload): # RFC sect 22.14 - name = "DHCP6 Rapid Commit Option" - fields_desc = [ ShortEnumField("optcode", 14, dhcp6opts), - ShortField("optlen", 0)] - - -#### DHCPv6 User Class Option ####################################### - -class _UserClassDataField(PacketListField): - def i2len(self, pkt, z): - if z is None or z == []: - return 0 - return sum(map(lambda x: len(bytes(x)) ,z)) - - def getfield(self, pkt, s): - l = self.length_from(pkt) - lst = [] - remain, payl = s[:l], s[l:] - while len(remain)>0: - p = self.m2i(pkt,remain) - if conf.padding_layer in p: - pad = p[conf.padding_layer] - remain = pad.load - del(pad.underlayer.payload) - else: - remain = b"" - lst.append(p) - return payl,lst - - -class USER_CLASS_DATA(Packet): - name = "user class data" - fields_desc = [ FieldLenField("len", None, length_of="data"), - StrLenField("data", b"", - length_from = lambda pkt: pkt.len) ] - def guess_payload_class(self, payload): - return conf.padding_layer - -class DHCP6OptUserClass(_DHCP6OptGuessPayload):# RFC sect 22.15 - name = "DHCP6 User Class Option" - fields_desc = [ ShortEnumField("optcode", 15, dhcp6opts), - FieldLenField("optlen", None, fmt="!H", - length_of="userclassdata"), - _UserClassDataField("userclassdata", [], USER_CLASS_DATA, - length_from = lambda pkt: pkt.optlen) ] - - -#### DHCPv6 Vendor Class Option ##################################### - -class _VendorClassDataField(_UserClassDataField): - pass - -class VENDOR_CLASS_DATA(USER_CLASS_DATA): - name = "vendor class data" - -class DHCP6OptVendorClass(_DHCP6OptGuessPayload):# RFC sect 22.16 - name = "DHCP6 Vendor Class Option" - fields_desc = [ ShortEnumField("optcode", 16, dhcp6opts), - FieldLenField("optlen", None, length_of="vcdata", fmt="!H", - adjust = lambda pkt,x: x+4), - IntEnumField("enterprisenum",None , iana_enterprise_num ), - _VendorClassDataField("vcdata", [], VENDOR_CLASS_DATA, - length_from = lambda pkt: pkt.optlen-4) ] - -#### DHCPv6 Vendor-Specific Information Option ###################### - -class VENDOR_SPECIFIC_OPTION(_DHCP6OptGuessPayload): - name = "vendor specific option data" - fields_desc = [ ShortField("optcode", None), - FieldLenField("optlen", None, length_of="optdata"), - StrLenField("optdata", b"", - length_from = lambda pkt: pkt.optlen) ] - def guess_payload_class(self, payload): - return conf.padding_layer - -# The third one that will be used for nothing interesting -class DHCP6OptVendorSpecificInfo(_DHCP6OptGuessPayload):# RFC sect 22.17 - name = "DHCP6 Vendor-specific Information Option" - fields_desc = [ ShortEnumField("optcode", 17, dhcp6opts), - FieldLenField("optlen", None, length_of="vso", fmt="!H", - adjust = lambda pkt,x: x+4), - IntEnumField("enterprisenum",None , iana_enterprise_num), - _VendorClassDataField("vso", [], VENDOR_SPECIFIC_OPTION, - length_from = lambda pkt: pkt.optlen-4) ] - -#### DHCPv6 Interface-ID Option ##################################### - -# Repasser sur cette option a la fin. Elle a pas l'air d'etre des -# masses critique. -class DHCP6OptIfaceId(_DHCP6OptGuessPayload):# RFC sect 22.18 - name = "DHCP6 Interface-Id Option" - fields_desc = [ ShortEnumField("optcode", 18, dhcp6opts), - FieldLenField("optlen", None, fmt="!H", - length_of="ifaceid"), - StrLenField("ifaceid", b"", - length_from = lambda pkt: pkt.optlen) ] - - -#### DHCPv6 Reconfigure Message Option ############################## - -# A server includes a Reconfigure Message option in a Reconfigure -# message to indicate to the client whether the client responds with a -# renew message or an Informatiion-request message. -class DHCP6OptReconfMsg(_DHCP6OptGuessPayload): # RFC sect 22.19 - name = "DHCP6 Reconfigure Message Option" - fields_desc = [ ShortEnumField("optcode", 19, dhcp6opts), - ShortField("optlen", 1 ), - ByteEnumField("msgtype", 11, { 5:"Renew Message", - 11:"Information Request"}) ] - - -#### DHCPv6 Reconfigure Accept Option ############################### - -# A client uses the Reconfigure Accept option to announce to the -# server whether the client is willing to accept Recoonfigure -# messages, and a server uses this option to tell the client whether -# or not to accept Reconfigure messages. The default behavior in the -# absence of this option, means unwillingness to accept reconfigure -# messages, or instruction not to accept Reconfigure messages, for the -# client and server messages, respectively. -class DHCP6OptReconfAccept(_DHCP6OptGuessPayload): # RFC sect 22.20 - name = "DHCP6 Reconfigure Accept Option" - fields_desc = [ ShortEnumField("optcode", 20, dhcp6opts), - ShortField("optlen", 0)] - -# As required in Sect 8. of RFC 3315, Domain Names must be encoded as -# described in section 3.1 of RFC 1035 -# XXX Label should be at most 63 octets in length : we do not enforce it -# Total length of domain should be 255 : we do not enforce it either -class DomainNameListField(StrLenField): - islist = 1 - - def i2len(self, pkt, x): - return len(self.i2m(pkt, x)) - - def m2i(self, pkt, x): - res = [] - while x: - cur = [] - #while x and x[0] != b'\x00': - while x and x[0] != 0: - l = (x[0]) - cur.append(x[1:l+1]) - x = x[l+1:] - res.append(b".".join(cur)) - if x and x[0] == 0: - x = x[1:] - return res - - def i2m(self, pkt, x): - def conditionalTrailingDot(z): - if z and z[-1] == 0: - return z - return z+b'\x00' - res = b"" - x = [ i.encode('ascii') for i in x if type(i) is str ] - tmp = map(lambda y: map((lambda z: chr(len(z)).encode('ascii')+z), y.split(b'.')), x) - return b"".join(map(lambda x: conditionalTrailingDot(b"".join(x)), tmp)) - -class DHCP6OptSIPDomains(_DHCP6OptGuessPayload): #RFC3319 - name = "DHCP6 Option - SIP Servers Domain Name List" - fields_desc = [ ShortEnumField("optcode", 21, dhcp6opts), - FieldLenField("optlen", None, length_of="sipdomains"), - DomainNameListField("sipdomains", [], - length_from = lambda pkt: pkt.optlen) ] - -class DHCP6OptSIPServers(_DHCP6OptGuessPayload): #RFC3319 - name = "DHCP6 Option - SIP Servers IPv6 Address List" - fields_desc = [ ShortEnumField("optcode", 22, dhcp6opts), - FieldLenField("optlen", None, length_of="sipservers"), - IP6ListField("sipservers", [], - length_from = lambda pkt: pkt.optlen) ] - -class DHCP6OptDNSServers(_DHCP6OptGuessPayload): #RFC3646 - name = "DHCP6 Option - DNS Recursive Name Server" - fields_desc = [ ShortEnumField("optcode", 23, dhcp6opts), - FieldLenField("optlen", None, length_of="dnsservers"), - IP6ListField("dnsservers", [], - length_from = lambda pkt: pkt.optlen) ] - -class DHCP6OptDNSDomains(_DHCP6OptGuessPayload): #RFC3646 - name = "DHCP6 Option - Domain Search List option" - fields_desc = [ ShortEnumField("optcode", 24, dhcp6opts), - FieldLenField("optlen", None, length_of="dnsdomains"), - DomainNameListField("dnsdomains", [], - length_from = lambda pkt: pkt.optlen) ] - -# TODO: Implement iaprefopts correctly when provided with more -# information about it. -class DHCP6OptIAPrefix(_DHCP6OptGuessPayload): #RFC3633 - name = "DHCP6 Option - IA_PD Prefix option" - fields_desc = [ ShortEnumField("optcode", 26, dhcp6opts), - FieldLenField("optlen", None, length_of="iaprefopts", - adjust = lambda pkt,x: x+26), - IntField("preflft", 0), - IntField("validlft", 0), - ByteField("plen", 48), # TODO: Challenge that default value - IP6Field("prefix", "2001:db8::"), # At least, global and won't hurt - StrLenField("iaprefopts", b"", - length_from = lambda pkt: pkt.optlen-26) ] - -class DHCP6OptIA_PD(_DHCP6OptGuessPayload): #RFC3633 - name = "DHCP6 Option - Identity Association for Prefix Delegation" - fields_desc = [ ShortEnumField("optcode", 25, dhcp6opts), - FieldLenField("optlen", None, length_of="iapdopt", - adjust = lambda pkt,x: x+12), - IntField("iaid", 0), - IntField("T1", 0), - IntField("T2", 0), - PacketListField("iapdopt", [], DHCP6OptIAPrefix, - length_from = lambda pkt: pkt.optlen-12) ] - -class DHCP6OptNISServers(_DHCP6OptGuessPayload): #RFC3898 - name = "DHCP6 Option - NIS Servers" - fields_desc = [ ShortEnumField("optcode", 27, dhcp6opts), - FieldLenField("optlen", None, length_of="nisservers"), - IP6ListField("nisservers", [], - length_from = lambda pkt: pkt.optlen) ] - -class DHCP6OptNISPServers(_DHCP6OptGuessPayload): #RFC3898 - name = "DHCP6 Option - NIS+ Servers" - fields_desc = [ ShortEnumField("optcode", 28, dhcp6opts), - FieldLenField("optlen", None, length_of="nispservers"), - IP6ListField("nispservers", [], - length_from = lambda pkt: pkt.optlen) ] - -class DomainNameField(StrLenField): - def getfield(self, pkt, s): - l = self.length_from(pkt) - return s[l:], self.m2i(pkt,s[:l]) - - def i2len(self, pkt, x): - return len(self.i2m(pkt, x)) - - def m2i(self, pkt, x): - cur = [] - while x: - l = (x[0]) - cur.append(x[1:1+l]) - x = x[l+1:] - ret_str = b".".join(cur) - return ret_str - - def i2m(self, pkt, x): - if not x: - return b"" - tmp = b"".join(map(lambda z: chr(len(z)).encode('ascii')+z, x.split(b'.'))) - return tmp - -class DHCP6OptNISDomain(_DHCP6OptGuessPayload): #RFC3898 - name = "DHCP6 Option - NIS Domain Name" - fields_desc = [ ShortEnumField("optcode", 29, dhcp6opts), - FieldLenField("optlen", None, length_of="nisdomain"), - DomainNameField("nisdomain", "", - length_from = lambda pkt: pkt.optlen) ] - -class DHCP6OptNISPDomain(_DHCP6OptGuessPayload): #RFC3898 - name = "DHCP6 Option - NIS+ Domain Name" - fields_desc = [ ShortEnumField("optcode", 30, dhcp6opts), - FieldLenField("optlen", None, length_of="nispdomain"), - DomainNameField("nispdomain", "", - length_from= lambda pkt: pkt.optlen) ] - -class DHCP6OptSNTPServers(_DHCP6OptGuessPayload): #RFC4075 - name = "DHCP6 option - SNTP Servers" - fields_desc = [ ShortEnumField("optcode", 31, dhcp6opts), - FieldLenField("optlen", None, length_of="sntpservers"), - IP6ListField("sntpservers", [], - length_from = lambda pkt: pkt.optlen) ] - -IRT_DEFAULT=86400 -IRT_MINIMUM=600 -class DHCP6OptInfoRefreshTime(_DHCP6OptGuessPayload): #RFC4242 - name = "DHCP6 Option - Information Refresh Time" - fields_desc = [ ShortEnumField("optcode", 32, dhcp6opts), - ShortField("optlen", 4), - IntField("reftime", IRT_DEFAULT)] # One day - -class DHCP6OptBCMCSDomains(_DHCP6OptGuessPayload): #RFC4280 - name = "DHCP6 Option - BCMCS Domain Name List" - fields_desc = [ ShortEnumField("optcode", 33, dhcp6opts), - FieldLenField("optlen", None, length_of="bcmcsdomains"), - DomainNameListField("bcmcsdomains", [], - length_from = lambda pkt: pkt.optlen) ] - -class DHCP6OptBCMCSServers(_DHCP6OptGuessPayload): #RFC4280 - name = "DHCP6 Option - BCMCS Addresses List" - fields_desc = [ ShortEnumField("optcode", 34, dhcp6opts), - FieldLenField("optlen", None, length_of="bcmcsservers"), - IP6ListField("bcmcsservers", [], - length_from= lambda pkt: pkt.optlen) ] - -# TODO : Does Nothing at the moment -class DHCP6OptGeoConf(_DHCP6OptGuessPayload): #RFC-ietf-geopriv-dhcp-civil-09.txt - name = "" - fields_desc = [ ShortEnumField("optcode", 36, dhcp6opts), - FieldLenField("optlen", None, length_of="optdata"), - StrLenField("optdata", "", - length_from = lambda pkt: pkt.optlen) ] - -# TODO: see if we encounter opaque values from vendor devices -class DHCP6OptRemoteID(_DHCP6OptGuessPayload): #RFC4649 - name = "DHCP6 Option - Relay Agent Remote-ID" - fields_desc = [ ShortEnumField("optcode", 37, dhcp6opts), - FieldLenField("optlen", None, length_of="remoteid", - adjust = lambda pkt,x: x+4), - IntEnumField("enterprisenum", None, iana_enterprise_num), - StrLenField("remoteid", b"", - length_from = lambda pkt: pkt.optlen-4) ] - -# TODO : 'subscriberid' default value should be at least 1 byte long -class DHCP6OptSubscriberID(_DHCP6OptGuessPayload): #RFC4580 - name = "DHCP6 Option - Subscriber ID" - fields_desc = [ ShortEnumField("optcode", 38, dhcp6opts), - FieldLenField("optlen", None, length_of="subscriberid"), - StrLenField("subscriberid", b"", - length_from = lambda pkt: pkt.optlen) ] - -# TODO : "The data in the Domain Name field MUST be encoded -# as described in Section 8 of [5]" -class DHCP6OptClientFQDN(_DHCP6OptGuessPayload): #RFC4704 - name = "DHCP6 Option - Client FQDN" - fields_desc = [ ShortEnumField("optcode", 39, dhcp6opts), - FieldLenField("optlen", None, length_of="fqdn", - adjust = lambda pkt,x: x+1), - BitField("res", 0, 5), - FlagsField("flags", 0, 3, "SON" ), - DomainNameField("fqdn", "", - length_from = lambda pkt: pkt.optlen-1) ] - -class DHCP6OptRelayAgentERO(_DHCP6OptGuessPayload): # RFC4994 - name = "DHCP6 Option - RelayRequest Option" - fields_desc = [ ShortEnumField("optcode", 43, dhcp6opts), - FieldLenField("optlen", None, length_of="reqopts", fmt="!H"), - _OptReqListField("reqopts", [23, 24], - length_from = lambda pkt: pkt.optlen) ] - -##################################################################### -### DHCPv6 messages ### -##################################################################### - -# Some state parameters of the protocols that should probably be -# useful to have in the configuration (and keep up-to-date) -DHCP6RelayAgentUnicastAddr="" -DHCP6RelayHopCount="" -DHCP6ServerUnicastAddr="" -DHCP6ClientUnicastAddr="" -DHCP6ClientIA_TA="" -DHCP6ClientIA_NA="" -DHCP6ClientIAID="" -T1="" # Voir 2462 -T2="" # Voir 2462 -DHCP6ServerDUID="" -DHCP6CurrentTransactionID="" # devrait etre utilise pour matcher une -# reponse et mis a jour en mode client par une valeur aleatoire pour -# laquelle on attend un retour de la part d'un serveur. -DHCP6PrefVal="" # la valeur de preference a utiliser dans -# les options preference - -# Emitted by : -# - server : ADVERTISE, REPLY, RECONFIGURE, RELAY-REPL (vers relay) -# - client : SOLICIT, REQUEST, CONFIRM, RENEW, REBIND, RELEASE, DECLINE, -# INFORMATION REQUEST -# - relay : RELAY-FORW (toward server) - -class _DHCP6GuessPayload(Packet): - def guess_payload_class(self, payload): - if len(payload) > 1 : - print((payload[0])) - return get_cls(dhcp6opts.get(ord(payload[0]),"DHCP6OptUnknown"), conf.raw_layer) - return conf.raw_layer - -##################################################################### -## DHCPv6 messages sent between Clients and Servers (types 1 to 11) -# Comme specifie en section 15.1 de la RFC 3315, les valeurs de -# transaction id sont selectionnees de maniere aleatoire par le client -# a chaque emission et doivent matcher dans les reponses faites par -# les clients -class DHCP6(_DHCP6OptGuessPayload): - name = "DHCPv6 Generic Message)" - fields_desc = [ ByteEnumField("msgtype",None,dhcp6types), - X3BytesField("trid",0x000000) ] - overload_fields = { UDP: {"sport": 546, "dport": 547} } - - def hashret(self): - return struct.pack("!I", self.trid)[1:4] - -##################################################################### -# Solicit Message : sect 17.1.1 RFC3315 -# - sent by client -# - must include a client identifier option -# - the client may include IA options for any IAs to which it wants the -# server to assign address -# - The client use IA_NA options to request the assignment of -# non-temporary addresses and uses IA_TA options to request the -# assignment of temporary addresses -# - The client should include an Option Request option to indicate the -# options the client is interested in receiving (eventually -# including hints) -# - The client includes a Reconfigure Accept option if is willing to -# accept Reconfigure messages from the server. -# Le cas du send and reply est assez particulier car suivant la -# presence d'une option rapid commit dans le solicit, l'attente -# s'arrete au premier message de reponse recu ou alors apres un -# timeout. De la meme maniere, si un message Advertise arrive avec une -# valeur de preference de 255, il arrete l'attente et envoie une -# Request. -# - The client announces its intention to use DHCP authentication by -# including an Authentication option in its solicit message. The -# server selects a key for the client based on the client's DUID. The -# client and server use that key to authenticate all DHCP messages -# exchanged during the session - -class DHCP6_Solicit(DHCP6): - name = "DHCPv6 Solicit Message" - msgtype = 1 - overload_fields = { UDP: {"sport": 546, "dport": 547} } - -##################################################################### -# Advertise Message -# - sent by server -# - Includes a server identifier option -# - Includes a client identifier option -# - the client identifier option must match the client's DUID -# - transaction ID must match - -class DHCP6_Advertise(DHCP6): - name = "DHCPv6 Advertise Message" - msgtype = 2 - overload_fields = { UDP: {"sport": 547, "dport": 546} } - - def answers(self, other): - return (isinstance(other,DHCP6_Solicit) and - other.msgtype == 1 and - self.trid == other.trid) - -##################################################################### -# Request Message -# - sent by clients -# - includes a server identifier option -# - the content of Server Identifier option must match server's DUID -# - includes a client identifier option -# - must include an ORO Option (even with hints) p40 -# - can includes a reconfigure Accept option indicating whether or -# not the client is willing to accept Reconfigure messages from -# the server (p40) -# - When the server receives a Request message via unicast from a -# client to which the server has not sent a unicast option, the server -# discards the Request message and responds with a Reply message -# containinig Status Code option with the value UseMulticast, a Server -# Identifier Option containing the server's DUID, the client -# Identifier option from the client message and no other option. - -class DHCP6_Request(DHCP6): - name = "DHCPv6 Request Message" - msgtype = 3 - -##################################################################### -# Confirm Message -# - sent by clients -# - must include a clien identifier option -# - When the server receives a Confirm Message, the server determines -# whether the addresses in the Confirm message are appropriate for the -# link to which the client is attached. cf p50 - -class DHCP6_Confirm(DHCP6): - name = "DHCPv6 Confirm Message" - msgtype = 4 - -##################################################################### -# Renew Message -# - sent by clients -# - must include a server identifier option -# - content of server identifier option must match the server's identifier -# - must include a client identifier option -# - the clients includes any IA assigned to the interface that may -# have moved to a new link, along with the addresses associated with -# those IAs in its confirm messages -# - When the server receives a Renew message that contains an IA -# option from a client, it locates the client's binding and verifies -# that the information in the IA from the client matches the -# information for that client. If the server cannot find a client -# entry for the IA the server returns the IA containing no addresses -# with a status code option est to NoBinding in the Reply message. cf -# p51 pour le reste. - -class DHCP6_Renew(DHCP6): - name = "DHCPv6 Renew Message" - msgtype = 5 - -##################################################################### -# Rebind Message -# - sent by clients -# - must include a client identifier option -# cf p52 - -class DHCP6_Rebind(DHCP6): - name = "DHCPv6 Rebind Message" - msgtype = 6 - -##################################################################### -# Reply Message -# - sent by servers -# - the message must include a server identifier option -# - transaction-id field must match the value of original message -# The server includes a Rapid Commit option in the Reply message to -# indicate that the reply is in response to a solicit message -# - if the client receives a reply message with a Status code option -# with the value UseMulticast, the client records the receipt of the -# message and sends subsequent messages to the server through the -# interface on which the message was received using multicast. The -# client resends the original message using multicast -# - When the client receives a NotOnLink status from the server in -# response to a Confirm message, the client performs DHCP server -# solicitation as described in section 17 and client-initiated -# configuration as descrribed in section 18 (RFC 3315) -# - when the client receives a NotOnLink status from the server in -# response to a Request, the client can either re-issue the Request -# without specifying any addresses or restart the DHCP server -# discovery process. -# - the server must include a server identifier option containing the -# server's DUID in the Reply message - -class DHCP6_Reply(DHCP6): - name = "DHCPv6 Reply Message" - msgtype = 7 - - overload_fields = { UDP: {"sport": 547, "dport": 546} } - - def answers(self, other): - - types = (DHCP6_InfoRequest, DHCP6_Confirm, DHCP6_Rebind, DHCP6_Decline, DHCP6_Request, DHCP6_Release, DHCP6_Renew) - - return (isinstance(other, types) and - self.trid == other.trid) - -##################################################################### -# Release Message -# - sent by clients -# - must include a server identifier option -# cf p53 - -class DHCP6_Release(DHCP6): - name = "DHCPv6 Release Message" - msgtype = 8 - -##################################################################### -# Decline Message -# - sent by clients -# - must include a client identifier option -# - Server identifier option must match server identifier -# - The addresses to be declined must be included in the IAs. Any -# addresses for the IAs the client wishes to continue to use should -# not be in added to the IAs. -# - cf p54 - -class DHCP6_Decline(DHCP6): - name = "DHCPv6 Decline Message" - msgtype = 9 - -##################################################################### -# Reconfigure Message -# - sent by servers -# - must be unicast to the client -# - must include a server identifier option -# - must include a client identifier option that contains the client DUID -# - must contain a Reconfigure Message Option and the message type -# must be a valid value -# - the server sets the transaction-id to 0 -# - The server must use DHCP Authentication in the Reconfigure -# message. Autant dire que ca va pas etre le type de message qu'on va -# voir le plus souvent. - -class DHCP6_Reconf(DHCP6): - name = "DHCPv6 Reconfigure Message" - msgtype = 10 - overload_fields = { UDP: { "sport": 547, "dport": 546 } } - - -##################################################################### -# Information-Request Message -# - sent by clients when needs configuration information but no -# addresses. -# - client should include a client identifier option to identify -# itself. If it doesn't the server is not able to return client -# specific options or the server can choose to not respond to the -# message at all. The client must include a client identifier option -# if the message will be authenticated. -# - client must include an ORO of option she's interested in receiving -# (can include hints) - -class DHCP6_InfoRequest(DHCP6): - name = "DHCPv6 Information Request Message" - msgtype = 11 - -##################################################################### -# sent between Relay Agents and Servers -# -# Normalement, doit inclure une option "Relay Message Option" -# peut en inclure d'autres. -# voir section 7.1 de la 3315 - -# Relay-Forward Message -# - sent by relay agents to servers -# If the relay agent relays messages to the All_DHCP_Servers multicast -# address or other multicast addresses, it sets the Hop Limit field to -# 32. - -class DHCP6_RelayForward(_DHCP6GuessPayload,Packet): - name = "DHCPv6 Relay Forward Message (Relay Agent/Server Message)" - fields_desc = [ ByteEnumField("msgtype", 12, dhcp6types), - ByteField("hopcount", None), - IP6Field("linkaddr", "::"), - IP6Field("peeraddr", "::") ] - def hashret(self): # we filter on peer address field - return inet_pton(socket.AF_INET6, self.peeraddr) - -##################################################################### -# sent between Relay Agents and Servers -# Normalement, doit inclure une option "Relay Message Option" -# peut en inclure d'autres. -# Les valeurs des champs hop-count, link-addr et peer-addr -# sont copiees du messsage Forward associe. POur le suivi de session. -# Pour le moment, comme decrit dans le commentaire, le hashret -# se limite au contenu du champ peer address. -# Voir section 7.2 de la 3315. - -# Relay-Reply Message -# - sent by servers to relay agents -# - if the solicit message was received in a Relay-Forward message, -# the server constructs a relay-reply message with the Advertise -# message in the payload of a relay-message. cf page 37/101. Envoie de -# ce message en unicast au relay-agent. utilisation de l'adresse ip -# presente en ip source du paquet recu - -class DHCP6_RelayReply(DHCP6_RelayForward): - name = "DHCPv6 Relay Reply Message (Relay Agent/Server Message)" - msgtype = 13 - def hashret(self): # We filter on peer address field. - return inet_pton(socket.AF_INET6, self.peeraddr) - def answers(self, other): - return (isinstance(other, DHCP6_RelayForward) and - self.hopcount == other.hopcount and - self.linkaddr == other.linkaddr and - self.peeraddr == other.peeraddr ) - - -dhcp6_cls_by_type = { 1: "DHCP6_Solicit", - 2: "DHCP6_Advertise", - 3: "DHCP6_Request", - 4: "DHCP6_Confirm", - 5: "DHCP6_Renew", - 6: "DHCP6_Rebind", - 7: "DHCP6_Reply", - 8: "DHCP6_Release", - 9: "DHCP6_Decline", - 10: "DHCP6_Reconf", - 11: "DHCP6_InfoRequest", - 12: "DHCP6_RelayForward", - 13: "DHCP6_RelayReply" } - -def _dhcp6_dispatcher(x, *args, **kargs): - cls = conf.raw_layer - if len(x) >= 2: - cls = get_cls(dhcp6_cls_by_type.get((x[0]), "Raw"), conf.raw_layer) - return cls(x, *args, **kargs) - -bind_bottom_up(UDP, _dhcp6_dispatcher, { "dport": 547 } ) -bind_bottom_up(UDP, _dhcp6_dispatcher, { "dport": 546 } ) - - - -class DHCPv6_am(AnsweringMachine): - function_name = "dhcp6d" - filter = "udp and port 546 and port 547" - send_function = staticmethod(send) - def usage(self): - msg = """ -dhcp6d( dns="2001:500::1035", domain="localdomain, local", duid=None) - iface=conf.iface6, advpref=255, sntpservers=None, - sipdomains=None, sipservers=None, - nisdomain=None, nisservers=None, - nispdomain=None, nispservers=None, - bcmcsdomain=None, bcmcsservers=None) - - debug : When set, additional debugging information is printed. - - duid : some DUID class (DUID_LLT, DUID_LL or DUID_EN). If none - is provided a DUID_LLT is constructed based on the MAC - address of the sending interface and launch time of dhcp6d - answering machine. - - iface : the interface to listen/reply on if you do not want to use - conf.iface6. - - advpref : Value in [0,255] given to Advertise preference field. - By default, 255 is used. Be aware that this specific - value makes clients stops waiting for further Advertise - messages from other servers. - - dns : list of recursive DNS servers addresses (as a string or list). - By default, it is set empty and the associated DHCP6OptDNSServers - option is inactive. See RFC 3646 for details. - domain : a list of DNS search domain (as a string or list). By default, - it is empty and the associated DHCP6OptDomains option is inactive. - See RFC 3646 for details. - - sntpservers : a list of SNTP servers IPv6 addresses. By default, - it is empty and the associated DHCP6OptSNTPServers option - is inactive. - - sipdomains : a list of SIP domains. By default, it is empty and the - associated DHCP6OptSIPDomains option is inactive. See RFC 3319 - for details. - sipservers : a list of SIP servers IPv6 addresses. By default, it is - empty and the associated DHCP6OptSIPDomains option is inactive. - See RFC 3319 for details. - - nisdomain : a list of NIS domains. By default, it is empty and the - associated DHCP6OptNISDomains option is inactive. See RFC 3898 - for details. See RFC 3646 for details. - nisservers : a list of NIS servers IPv6 addresses. By default, it is - empty and the associated DHCP6OptNISServers option is inactive. - See RFC 3646 for details. - - nispdomain : a list of NIS+ domains. By default, it is empty and the - associated DHCP6OptNISPDomains option is inactive. See RFC 3898 - for details. - nispservers : a list of NIS+ servers IPv6 addresses. By default, it is - empty and the associated DHCP6OptNISServers option is inactive. - See RFC 3898 for details. - - bcmcsdomain : a list of BCMCS domains. By default, it is empty and the - associated DHCP6OptBCMCSDomains option is inactive. See RFC 4280 - for details. - bcmcsservers : a list of BCMCS servers IPv6 addresses. By default, it is - empty and the associated DHCP6OptBCMCSServers option is inactive. - See RFC 4280 for details. - - If you have a need for others, just ask ... or provide a patch.""" - print(msg) - - def parse_options(self, dns="2001:500::1035", domain="localdomain, local", - startip="2001:db8::1", endip="2001:db8::20", duid=None, - sntpservers=None, sipdomains=None, sipservers=None, - nisdomain=None, nisservers=None, nispdomain=None, - nispservers=None, bcmcsservers=None, bcmcsdomains=None, - iface=None, debug=0, advpref=255): - def norm_list(val, param_name): - if val is None: - return None - if type(val) is list: - return val - elif type(val) is str: - l = val.split(',') - return map(lambda x: x.strip(), l) - else: - print("Bad '%s' parameter provided." % param_name) - self.usage() - return -1 - - if iface is None: - iface = conf.iface6 - - self.debug = debug - - # Dictionary of provided DHCPv6 options, keyed by option type - self.dhcpv6_options={} - - for o in [(dns, "dns", 23, lambda x: DHCP6OptDNSServers(dnsservers=x)), - (domain, "domain", 24, lambda x: DHCP6OptDNSDomains(dnsdomains=x)), - (sntpservers, "sntpservers", 31, lambda x: DHCP6OptSNTPServers(sntpservers=x)), - (sipservers, "sipservers", 22, lambda x: DHCP6OptSIPServers(sipservers=x)), - (sipdomains, "sipdomains", 21, lambda x: DHCP6OptSIPDomains(sipdomains=x)), - (nisservers, "nisservers", 27, lambda x: DHCP6OptNISServers(nisservers=x)), - (nisdomain, "nisdomain", 29, lambda x: DHCP6OptNISDomain(nisdomain=(x+[""])[0])), - (nispservers, "nispservers", 28, lambda x: DHCP6OptNISPServers(nispservers=x)), - (nispdomain, "nispdomain", 30, lambda x: DHCP6OptNISPDomain(nispdomain=(x+[""])[0])), - (bcmcsservers, "bcmcsservers", 33, lambda x: DHCP6OptBCMCSServers(bcmcsservers=x)), - (bcmcsdomains, "bcmcsdomains", 34, lambda x: DHCP6OptBCMCSDomains(bcmcsdomains=x))]: - - opt = norm_list(o[0], o[1]) - if opt == -1: # Usage() was triggered - return False - elif opt is None: # We won't return that option - pass - else: - self.dhcpv6_options[o[2]] = o[3](opt) - - if self.debug: - print("\n[+] List of active DHCPv6 options:") - opts = self.dhcpv6_options.keys() - opts.sort() - for i in opts: - print(" %d: %s" % (i, repr(self.dhcpv6_options[i]))) - - # Preference value used in Advertise. - self.advpref = advpref - - # IP Pool - self.startip = startip - self.endip = endip - # XXX TODO Check IPs are in same subnet - - #### - # The interface we are listening/replying on - self.iface = iface - - #### - # Generate a server DUID - if duid is not None: - self.duid = duid - else: - # Timeval - from time import gmtime, strftime, mktime - epoch = (2000, 1, 1, 0, 0, 0, 5, 1, 0) - delta = mktime(epoch) - mktime(gmtime(0)) - timeval = time.time() - delta - - # Mac Address - rawmac = get_if_raw_hwaddr(iface) - mac = ":".join(map(lambda x: "%.02x" % x, rawmac)) - - self.duid = DUID_LLT(timeval = timeval, lladdr = mac) - - if self.debug: - print("\n[+] Our server DUID:" ) - self.duid.show(label_lvl=" "*4) - - #### - # Find the source address we will use - #l = filter(lambda x: x[2] == iface and in6_islladdr(x[0]), in6_getifaddr()) - l = [ x for x in in6_getifaddr() if x[2] == iface and in6_islladdr(x[0]) ] - if not l: - warning("Unable to get a Link-Local address") - return - - self.src_addr = l[0][0] - - #### - # Our leases - self.leases = {} - - - if self.debug: - print("\n[+] Starting DHCPv6 service on %s:" % self.iface ) - - def is_request(self, p): - if not IPv6 in p: - return False - - src = p[IPv6].src - dst = p[IPv6].dst - - p = p[IPv6].payload - if not isinstance(p, UDP) or p.sport != 546 or p.dport != 547 : - return False - - p = p.payload - if not isinstance(p, DHCP6): - return False - - # Message we considered client messages : - # Solicit (1), Request (3), Confirm (4), Renew (5), Rebind (6) - # Decline (9), Release (8), Information-request (11), - if not (p.msgtype in [1, 3, 4, 5, 6, 8, 9, 11]): - return False - - # Message validation following section 15 of RFC 3315 - - if ((p.msgtype == 1) or # Solicit - (p.msgtype == 6) or # Rebind - (p.msgtype == 4)): # Confirm - if ((not DHCP6OptClientId in p) or - DHCP6OptServerId in p): - return False - - if (p.msgtype == 6 or # Rebind - p.msgtype == 4): # Confirm - # XXX We do not reply to Confirm or Rebind as we - # XXX do not support address assignment - return False - - elif (p.msgtype == 3 or # Request - p.msgtype == 5 or # Renew - p.msgtype == 8): # Release - - # Both options must be present - if ((not DHCP6OptServerId in p) or - (not DHCP6OptClientId in p)): - return False - # provided server DUID must match ours - duid = p[DHCP6OptServerId].duid - if (type(duid) != type(self.duid)): - return False - if bytes(duid) != bytes(self.duid): - return False - - if (p.msgtype == 5 or # Renew - p.msgtype == 8): # Release - # XXX We do not reply to Renew or Release as we - # XXX do not support address assignment - return False - - elif p.msgtype == 9: # Decline - # XXX We should check if we are tracking that client - if not self.debug: - return False - - bo = Color.bold - g = Color.green + bo - b = Color.blue + bo - n = Color.normal - r = Color.red - - vendor = in6_addrtovendor(src) - if (vendor and vendor != "UNKNOWN"): - vendor = " [" + b + vendor + n + "]" - else: - vendor = "" - src = bo + src + n - - it = p - addrs = [] - while it: - l = [] - if isinstance(it, DHCP6OptIA_NA): - l = it.ianaopts - elif isinstance(it, DHCP6OptIA_TA): - l = it.iataopts - - #opsaddr = filter(lambda x: isinstance(x, DHCP6OptIAAddress),l) - opsaddr = [ x for x in l if isinstance(x, DHCP6OptIAAddress) ] - a=map(lambda x: x.addr, opsaddr) - addrs += a - it = it.payload - - addrs = map(lambda x: bo + x + n, addrs) - if debug: - msg = r + "[DEBUG]" + n + " Received " + g + "Decline" + n - msg += " from " + bo + src + vendor + " for " - msg += ", ".join(addrs)+ n - print(msg) - - # See sect 18.1.7 - - # Sent by a client to warn us she has determined - # one or more addresses assigned to her is already - # used on the link. - # We should simply log that fact. No messaged should - # be sent in return. - - # - Message must include a Server identifier option - # - the content of the Server identifier option must - # match the server's identifier - # - the message must include a Client Identifier option - return False - - elif p.msgtype == 11: # Information-Request - if DHCP6OptServerId in p: - duid = p[DHCP6OptServerId].duid - if (type(duid) != type(self.duid)): - return False - if bytes(duid) != bytes(self.duid): - return False - if ((DHCP6OptIA_NA in p) or - (DHCP6OptIA_TA in p) or - (DHCP6OptIA_PD in p)): - return False - else: - return False - - return True - - def print_reply(self, req, reply): - def norm(s): - if s.startswith("DHCPv6 "): - s = s[7:] - if s.endswith(" Message"): - s = s[:-8] - return s - - if reply is None: - return - - bo = Color.bold - g = Color.green + bo - b = Color.blue + bo - n = Color.normal - reqtype = g + norm(req.getlayer(UDP).payload.name) + n - reqsrc = req.getlayer(IPv6).src - vendor = in6_addrtovendor(reqsrc) - if (vendor and vendor != "UNKNOWN"): - vendor = " [" + b + vendor + n + "]" - else: - vendor = "" - reqsrc = bo + reqsrc + n - reptype = g + norm(reply.getlayer(UDP).payload.name) + n - - print("Sent %s answering to %s from %s%s" % (reptype, reqtype, reqsrc, vendor)) - - def make_reply(self, req): - req_mac_src = req.src - req_mac_dst = req.dst - - p = req[IPv6] - req_src = p.src - req_dst = p.dst - - p = p.payload.payload - - msgtype = p.msgtype - trid = p.trid - - if msgtype == 1: # SOLICIT (See Sect 17.1 and 17.2 of RFC 3315) - - # XXX We don't support address or prefix assignment - # XXX We also do not support relay function --arno - - client_duid = p[DHCP6OptClientId].duid - resp = IPv6(src=self.src_addr, dst=req_src) - resp /= UDP(sport=547, dport=546) - - if p.haslayer(DHCP6OptRapidCommit): - # construct a Reply packet - resp /= DHCP6_Reply(trid=trid) - resp /= DHCP6OptRapidCommit() # See 17.1.2 - resp /= DHCP6OptServerId(duid = self.duid) - resp /= DHCP6OptClientId(duid = client_duid) - - else: # No Rapid Commit in the packet. Reply with an Advertise - - if (p.haslayer(DHCP6OptIA_NA) or - p.haslayer(DHCP6OptIA_TA)): - # XXX We don't assign addresses at the moment - msg = "Scapy6 dhcp6d does not support address assignment" - resp /= DHCP6_Advertise(trid = trid) - resp /= DHCP6OptStatusCode(statuscode=2, statusmsg=msg) - resp /= DHCP6OptServerId(duid = self.duid) - resp /= DHCP6OptClientId(duid = client_duid) - - elif p.haslayer(DHCP6OptIA_PD): - # XXX We don't assign prefixes at the moment - msg = "Scapy6 dhcp6d does not support prefix assignment" - resp /= DHCP6_Advertise(trid = trid) - resp /= DHCP6OptStatusCode(statuscode=6, statusmsg=msg) - resp /= DHCP6OptServerId(duid = self.duid) - resp /= DHCP6OptClientId(duid = client_duid) - - else: # Usual case, no request for prefixes or addresse - resp /= DHCP6_Advertise(trid = trid) - resp /= DHCP6OptPref(prefval = self.advpref) - resp /= DHCP6OptServerId(duid = self.duid) - resp /= DHCP6OptClientId(duid = client_duid) - resp /= DHCP6OptReconfAccept() - - # See which options should be included - reqopts = [] - if p.haslayer(DHCP6OptOptReq): # add only asked ones - reqopts = p[DHCP6OptOptReq].reqopts - for o in self.dhcpv6_options.keys(): - if o in reqopts: - resp /= self.dhcpv6_options[o] - else: # advertise everything we have available - for o in self.dhcpv6_options.keys(): - resp /= self.dhcpv6_options[o] - - return resp - - elif msgtype == 3: #REQUEST (INFO-REQUEST is further below) - client_duid = p[DHCP6OptClientId].duid - resp = IPv6(src=self.src_addr, dst=req_src) - resp /= UDP(sport=547, dport=546) - resp /= DHCP6_Solicit(trid=trid) - resp /= DHCP6OptServerId(duid = self.duid) - resp /= DHCP6OptClientId(duid = client_duid) - - # See which options should be included - reqopts = [] - if p.haslayer(DHCP6OptOptReq): # add only asked ones - reqopts = p[DHCP6OptOptReq].reqopts - for o in self.dhcpv6_options.keys(): - if o in reqopts: - resp /= self.dhcpv6_options[o] - else: - # advertise everything we have available. - # Should not happen has clients MUST include - # and ORO in requests (sec 18.1.1) -- arno - for o in self.dhcpv6_options.keys(): - resp /= self.dhcpv6_options[o] - - return resp - - elif msgtype == 4: # CONFIRM - # see Sect 18.1.2 - - # Client want to check if addresses it was assigned - # are still appropriate - - # Server must discard any Confirm messages that - # do not include a Client Identifier option OR - # THAT DO INCLUDE a Server Identifier Option - - # XXX we must discard the SOLICIT if it is received with - # a unicast destination address - - pass - - elif msgtype == 5: # RENEW - # see Sect 18.1.3 - - # Clients want to extend lifetime of assigned addresses - # and update configuration parameters. This message is sent - # specifically to the server that provided her the info - - # - Received message must include a Server Identifier - # option. - # - the content of server identifier option must match - # the server's identifier. - # - the message must include a Client identifier option - - pass - - elif msgtype == 6: # REBIND - # see Sect 18.1.4 - - # Same purpose as the Renew message but sent to any - # available server after he received no response - # to its previous Renew message. - - - # - Message must include a Client Identifier Option - # - Message can't include a Server identifier option - - # XXX we must discard the SOLICIT if it is received with - # a unicast destination address - - pass - - elif msgtype == 8: # RELEASE - # See section 18.1.6 - - # Message is sent to the server to indicate that - # she will no longer use the addresses that was assigned - # We should parse the message and verify our dictionary - # to log that fact. - - - # - The message must include a server identifier option - # - The content of the Server Identifier option must - # match the server's identifier - # - the message must include a Client Identifier option - - pass - - elif msgtype == 9: # DECLINE - # See section 18.1.7 - pass - - elif msgtype == 11: # INFO-REQUEST - client_duid = None - if not p.haslayer(DHCP6OptClientId): - if self.debug: - warning("Received Info Request message without Client Id option") - else: - client_duid = p[DHCP6OptClientId].duid - - resp = IPv6(src=self.src_addr, dst=req_src) - resp /= UDP(sport=547, dport=546) - resp /= DHCP6_Reply(trid=trid) - resp /= DHCP6OptServerId(duid = self.duid) - - if client_duid: - resp /= DHCP6OptClientId(duid = client_duid) - - # Stack requested options if available - reqopts = [] - if p.haslayer(DHCP6OptOptReq): - reqopts = p[DHCP6OptOptReq].reqopts - for o in self.dhcpv6_options.keys(): - resp /= self.dhcpv6_options[o] - - return resp - - else: - # what else ? - pass - - # - We won't support reemission - # - We won't support relay role, nor relay forwarded messages - # at the beginning |