"""
Implementation of Subscriber-ID option as specified in :rfc:`4580`.
"""
from struct import pack
from typing import Union
from dhcpkit.ipv6.messages import RelayForwardMessage, RelayReplyMessage
from dhcpkit.ipv6.options import Option
OPTION_SUBSCRIBER_ID = 38
[docs]class SubscriberIdOption(Option):
"""
:rfc:`4580#section-2`
The subscriber-id information allows the service provider to assign/
activate subscriber-specific actions; e.g., assignment of specific IP
addresses, prefixes, DNS configuration, trigger accounting, etc.
This option is de-coupled from the access network's physical
structure, so a subscriber that moves from one access-point to
another, for example, would not require reconfiguration at the
service provider's DHCPv6 servers.
The subscriber-id information is only intended for use within a
single administrative domain and is only exchanged between the relay
agents and DHCPv6 servers within that domain. Therefore, the format
and encoding of the data in the option is not standardized, and this
specification does not establish any semantic requirements on the
data. This specification only defines the option for conveying this
information from relay agents to DHCPv6 servers.
However, as the DHCPv4 Subscriber-ID suboption [3] specifies Network
Virtual Terminal (NVT) American Standard Code for Information
Interchange (ASCII) [4] encoded data, in environments where both
DHCPv4 [5] and DHCPv6 are being used, it may be beneficial to use
that encoding.
The format of the DHCPv6 Relay Agent Subscriber-ID option is shown
below:
.. code-block:: none
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| OPTION_SUBSCRIBER_ID | option-len |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
. .
. subscriber-id .
. .
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
option-code
OPTION_SUBSCRIBER_ID (38)
option-len
length, in octets, of the subscriber-id field.
The minimum length is 1 octet.
subscriber-id
The subscriber's identity.
"""
option_type = OPTION_SUBSCRIBER_ID
def __init__(self, subscriber_id: bytes = b''):
self.subscriber_id = subscriber_id
"""The subscriber-id as bytes"""
[docs] def validate(self):
"""
Validate that the contents of this object conform to protocol specs.
"""
if not isinstance(self.subscriber_id, bytes):
raise ValueError("Subscriber-ID must be sequence of bytes")
if len(self.subscriber_id) > (2 ** 16 - 1):
raise ValueError("Subscriber-ID cannot be longer than {} bytes".format(2 ** 16 - 1))
[docs] def load_from(self, buffer: bytes, offset: int = 0, length: int = None) -> int:
"""
Load the internal state of this object from the given buffer. The buffer may contain more data after the
structured element is parsed. This data is ignored.
:param buffer: The buffer to read data from
:param offset: The offset in the buffer where to start reading
:param length: The amount of data we are allowed to read from the buffer
:return: The number of bytes used from the buffer
"""
my_offset, option_len = self.parse_option_header(buffer, offset, length)
self.subscriber_id = buffer[offset + my_offset:offset + my_offset + option_len]
my_offset += option_len
return my_offset
[docs] def save(self) -> Union[bytes, bytearray]:
"""
Save the internal state of this object as a buffer.
:return: The buffer with the data from this element
"""
return pack('!HH', self.option_type, len(self.subscriber_id)) + self.subscriber_id
RelayForwardMessage.add_may_contain(SubscriberIdOption)
# The RFC says there is no requirement for servers to include this option in replies, but it is not forbidden
RelayReplyMessage.add_may_contain(SubscriberIdOption)