DHCPv6
The system provides a Python object alc.dhcpv6 to inspect and modify DHCPv6 packets.
The alc.dhcpv6 object
Attributes
The object exposes the header fields as attributes on the object. Depending on the message-type (client-server or relay), different attributes are supported. Trying to fetch an attribute from a different message-type raises an AttributeError.
| Attribute | Field | Access | Type | 
|---|---|---|---|
| pkt_len | total length, in bytes, of the original DHCPv6-layer | ro | int | 
| msg_type | msg-type | ro | bytes | 
| transaction_id | transaction-id | ro | bytes | 
| Attribute | Field | Access | Type | 
|---|---|---|---|
| pkt_len | total length, in bytes, of the original DHCPv6-layer | ro | int | 
| msg_type | msg-type | ro | bytes | 
| hop_count | hop-count | rw | bytes | 
| link_addr | link-address | rw | bytes | 
| peer_addr | peer-address | rw | bytes | 
Methods
- alc.Dhcp6.drop()
- Drops the packet. 
- alc.Dhcp6.getOptionList()
- Returns a tuple of option-codes that are present in the top-level packet. - The order of the elements is the same as they appear in the packet. 
- If there are multiple instances of the same option, the option-code also appears multiple times in the tuple. 
 - # for a c/s packet with options # Elapsed Time/Client Identifier/IANA/FQDN/Vendor Class/Option Request print(alc.dhcpv6.getOptionList()) # (8, 1, 3, 39, 16, 6) 
- alc.Dhcp6.get(op_code, /)
- Returns a tuple of all values of options with the specified option-code. The values are returned as the exact bytestrings as they appear in the packet. - If the specified option does not exist, the result is an empty tuple: () 
- If a specific instance has zero length or no values, the corresponding bytestring in the result tuple is an empty bytestring: b”” 
 - param int option_code
- option-code to fetch 
- rtype
- tuple of bytestrings 
 - # For a packet with status-code option (code=0, msg="Address Assigned"): print(alc.dhcpv6.get(13)) # (b‘\x00\x00Address Assigned’,) 
- alc.Dhcp6.set(op_code, value, /)
- Deletes existing options of the specified code and inserts new options with the specified code and value. Multiple values can be specified in a tuple, in which case an option is added for each item in the tuple. - param int option_code
- option-code to set 
- param bytes|tuple(bytes) value
- value of the option; the length is computed from this value 
 - # To insert an address lease time option(51) with value 60: alc.dhcpv6.set(51, b'\x00\x00\x00\x3c') 
- alc.Dhcp6.clear(op_code, /)
- Remove all options with specified option-code. - Parameters
- option_code (int) – option-code to clear 
 
- alc.Dhcp6.set_iana(opdl, /)
- Sets the IA_NA(3) option as an OPDL data structure. - Parameters
- value (OPDL) – IA_NA option to be set 
 
- alc.Dhcp6.set_iata(opdl, /)
- Sets the IA_TA(3) option as an OPDL data structure. - Parameters
- value (OPDL) – IA_TA option to be set 
 
- alc.Dhcp6.set_iapd(opdl, /)
- Sets the IA_PD(3) option as an OPDL data structure. - Parameters
- value (OPDL) – IA_PD option to be set 
 
- alc.Dhcp6.get_vendoropts()
- Retrieves the vendor_opts(17) option as an OPDL data structure. - Return type
 
- alc.Dhcp6.set_vendoropts(opdl, /)
- Sets the vendor_opts(17) option as an OPDL data structure. - Parameters
- value (OPDL) – vendor specific option to set 
 
- alc.Dhcp6.get_relaymsg()
- Returns the embedded relay-message. - Return type
- alc.Dhcpv6
- Raises
- RuntimeError – when invoked on a client-server message 
 - Note - The embedded packet returned from - alc.Dhcpv6.get_relaymsg()can also be modified in-place. However, these changes do not automatically propagate to the outer packet. This occurs only when the- alc.Dhcpv6.set_relaymsg()method is called on the outer packet with the modified embedded packet as the argument.
- alc.Dhcp6.set_relaymsg(msg, /)
- Replaces the current relay-message option with the specified message. - Parameters
- msg (alc.Dhcpv6) – DHCPv6 message to set as the relay-message 
- Raises
- RuntimeError – when invoked on a client-server message 
 
Option Datastructure List (OPDL)
The OPDL is a nested data structure which represents the value of some DHCPv6 options.
- An OPDL is a list where each element represents an instance of that option (referred to as an OPD). The elements are ordered as they appear in the packet. 
- An OPD is a list where each element represents one field in the option. The elements are ordered as they appear in the packet. 
- There are two types of fields in the OPD: - The first fields (if any) are bytestrings and correspond to fixed fields. The number and meaning are specific to the option. 
- The last field is a dictionary which contains the sub-options, where - the keys are the sub-option codes 
- the values are themselves an OPDL if the sub-options are supported, or a bytestring of the whole sub-option if not supported. 
- if there are no sub-options, the dictionary is empty. 
 
 
In summary:
- OPDL := [OPD, OPD, …] 
- OPD := [field, field, …, sub-options] 
- field := bytestring 
- sub-options := {sub-opt-code: sub-opt-value, …} 
- sub-opt-code := int 
- sub-opt-value := bytestring or OPDL 
| Option | Fields | Sub-options | 
|---|---|---|
| IA-NA(3) | [IAID, T1, T2] | IAADDR(5), Status Code(13) | 
| IA-TA(4) | [IAID] | IA Address(5), Status Code(13) | 
| IA-PD(25) | [IAID, T1, T2] | IA Prefix(26), Status Code(13) | 
| Vendor Options(17) | [enterprise-number] | |
| IA Address(5) | [ipv6addr, preferred-lifetime, valid-lifetime] | Status Code(13) | 
| Status Code(13) | [status-code, status-message] | |
| IA Prefix(26) | [preferred-lifetime, valid-lifetime, prefix-length, ipv6-prefix] | Status Code(13) | 
Note
The OPDL data structures that have been extracted from a alc.Dhcpv6 packet can be modified in-place.
However, these changes do not automatically propagate to packet options.
This occurs only when the corresponding alc.Dhcpv6.set_xxx() method is called with the modified OPDL as the argument.
Example 1: Extract address from IA_NA option
With an IA_NA option as in the following:
Identity Association for Non-temporary Address
  Option: Identity Association for the Non-temporary Address (3)
  Length: 40
  Value:  0ff0def10002a30000043800000500182001055860450047...
  IAID:   0ff0def1
  T1:     172800
  T2:     276480
  IA Address: 2001:558:6045:47:45cc:d9f2:5727:eae0
    Option:             IA Address (5)
    Length:             24
    Value:              200105586045004745ccd9f25727eae00005460000054600
    IPv6 address:       2001:558:6045:47:45cc:d9f2:5727:eae0
    Preferred lifetime: 345600
    Valid lifetime:     345600
The following extracts the address from the IA_NA option:
opdl = alc.dhcpv6.get_iana()
# opdl: [[b'\x0f\xf0\xde\xf1', b'\x00\x02\xa3\x00', b'\x00\x048\x00', {5: [[b" \x01\x05X`E\x00GE\xcc\xd9\xf2W'\xea\xe0", b'\x00\x05F\x00', b'\x00\x05F\x00', {}]]}]]
addresses = [hexlify(sub_opd[0]) for opd in opdl for sub_opd in opd[3][5]]
# addresses: [b'200105586045004745ccd9f25727eae0']
Example 2: Extract information from IA_PD option
With an IA_PD option as in the following:
Identity Association for Prefix Delegation
  Option: Identity Association for Prefix Delegation (25)
  Length:  41
  Value:  000000010000070800000b40001a001900000e1000015180...
  IAID:  00000001
  T1:  1800
  T2:  2880
  IA  Prefix
    Option: IA Prefix (26)
    Length:  25
    Value:  00000e10000151803820010db80002000000000000000000...
    Preferred lifetime: 3600
    Valid lifetime: 86400
    Prefix length: 56
    Prefix address: 2001:db8:2::
The following code extracts the IAID, T1, and T2:
opdl = alc.dhcpv6.get_iapd()
# opdl: [[b'\x00\x00\x00\x01', b'\x00\x00\x07\x08', b'\x00\x00\x0b@', {26: [[b'\x00\x00\x0e\x10', b'\x00\x01Q\x80', b'8', b' \x01\r\xb8\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', {}]]}]]
iaid,t1,t2 = (int.from_bytes(x, 'big') for x in opdl[0][0:3])
# iaid,t1,t2 = (1, 1800, 2880)
Example 3: Extract Enterprise ID from Vendor Option
With a Vendor Option as in the following:
Vendor-specific Information
  Option: Vendor-specific Information (17)
  Length:  40
  Value:  0000197f0001000969612d6e615f3030310002000969612d...
  Enterprise ID: Panthera Networks, Inc. (6527)
  option
    option code: 1
    option length: 9
    option-data
  option
    option code: 2
    option length: 9
    option-data
  option
    option code: 3
    option length: 1
    option-data
  option
    option code: 4
    option length: 1
    option-data
The following code extracts the vendor ID:
opdl = alc.dhcpv6.get_vendoropts()
# opdl: [[b'\x00\x00\x19\x7f', {4: [b'@'], 1: [b'ia-na_001'], 2: [b'ia-pd_001'], 3: [b'8']}]]
vendor = int.from_bytes(opdl[0][0], 'big')
# vendor: 6527
Example 4: Change T1 of IA_NA option in relayed message
embed_dhcpv6_packet = alc.dhcpv6.get_relaymsg()
iana_list = embed_dhcpv6_packet.get_iana()
iana_list[0][1] = b'\x00\x00\x04\xb0' # change T1 to 1200
embed_dhcpv6_packet.set_iana(iana_list) #update the IA_NA of the embedded packet
alc.dhcpv6.set_relaymsg(embed_dhcpv6_packet) #update the Relay Message option
Example 5: Change T1 of IA_NA option in double relayed message
embed_lv1_packet = alc.dhcpv6.get_relaymsg()
embed_lv2_packet = embed_lv1_packet.get_relaymsg()
iana_list = embed_dhcpv6_packet.get_iana()
iana_list[0][1] = b'\x00\x00\x04\xb0' # change T1 to 1200
embed_lv2_packet.set_iana(iana_list)
embed_lv1_packet.set_relaymsg(embed_lv2_packet)
alc.dhcpv6.set_relaymsg(embed_lv1_packet)