%PDF- %PDF-
| Direktori : /proc/thread-self/root/backups/router/usr/local/include/kea/dhcp/ |
| Current File : //proc/thread-self/root/backups/router/usr/local/include/kea/dhcp/pkt.h |
// Copyright (C) 2014-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef PKT_H
#define PKT_H
#include <asiolink/io_address.h>
#include <util/buffer.h>
#include <dhcp/option.h>
#include <dhcp/hwaddr.h>
#include <dhcp/classify.h>
#include <hooks/callout_handle_associate.h>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/shared_ptr.hpp>
#include <limits>
#include <utility>
namespace isc {
namespace dhcp {
/// @brief A value used to signal that the interface index was not set.
/// That means that more than UNSET_IFINDEX interfaces are not supported.
/// That's fine, since it would have overflowed with UNSET_IFINDEX + 1 anyway.
constexpr unsigned int UNSET_IFINDEX = std::numeric_limits<unsigned int>::max();
/// @brief RAII object enabling copying options retrieved from the
/// packet.
///
/// This object enables copying retrieved options from a packet within
/// a scope in which this object exists. When the object goes out of scope
/// copying options is disabled. This is applicable in cases when the
/// server is going to invoke a callout (hook library) where copying options
/// must be enabled by default. When the callouts return copying options
/// should be disabled. The use of RAII object eliminates the need for
/// explicitly re-disabling options copying and is safer in case of
/// exceptions thrown by callouts and a presence of multiple exit points.
///
/// @tparam PktType Type of the packet, e.g. Pkt4, Pkt6, Pkt4o6.
template<typename PktType>
class ScopedEnableOptionsCopy {
public:
/// @brief Pointer to an encapsulated packet.
typedef boost::shared_ptr<PktType> PktTypePtr;
/// @brief Constructor.
///
/// Enables options copying on a packet(s).
///
/// @param pkt1 Pointer to first packet.
/// @param pkt2 Optional pointer to the second packet.
ScopedEnableOptionsCopy(const PktTypePtr& pkt1,
const PktTypePtr& pkt2 = PktTypePtr())
: pkts_(pkt1, pkt2) {
if (pkt1) {
pkt1->setCopyRetrievedOptions(true);
}
if (pkt2) {
pkt2->setCopyRetrievedOptions(true);
}
}
/// @brief Destructor.
///
/// Disables options copying on a packets.
~ScopedEnableOptionsCopy() {
if (pkts_.first) {
pkts_.first->setCopyRetrievedOptions(false);
}
if (pkts_.second) {
pkts_.second->setCopyRetrievedOptions(false);
}
}
private:
/// @brief Holds a pair of pointers of the packets.
std::pair<PktTypePtr, PktTypePtr> pkts_;
};
/// @brief Describes an event during the life cycle of a packet.
class PktEvent {
public:
/// @brief Event that marks when a packet is placed in the socket buffer
/// by the kernel.
static const std::string SOCKET_RECEIVED;
/// @brief Event that marks when a packet is read from the socket buffer
/// by application.
static const std::string BUFFER_READ;
/// @brief Event that marks when a packet is been written to the socket
/// by application.
static const std::string RESPONSE_SENT;
/// @brief Constructor.
///
/// @param label string identifying the event.
/// @param timestamp time at which the event occurred.
PktEvent(const std::string& label, boost::posix_time::ptime timestamp)
: label_(label), timestamp_(timestamp) {
}
/// @brief Destructor.
~PktEvent() = default;
/// @brief Fetch the current UTC system time, microsecond precision.
///
/// @return ptime containing the microsecond system time.
static boost::posix_time::ptime now() {
return (boost::posix_time::microsec_clock::universal_time());
}
/// @brief Fetch an empty timestamp, used for logic comparisons
///
/// @return an unset ptime.
static boost::posix_time::ptime& EMPTY_TIME() {
static boost::posix_time::ptime empty_time;
return (empty_time);
}
/// @brief Fetches the minimum timestamp
///
/// @return the minimum timestamp
static boost::posix_time::ptime& MIN_TIME() {
static auto min_time = boost::posix_time::ptime(boost::posix_time::min_date_time);
return (min_time);
}
/// @brief Fetches the maximum timestamp
///
/// @return the maximum timestamp
static boost::posix_time::ptime& MAX_TIME() {
static auto max_time = boost::posix_time::ptime(boost::posix_time::max_date_time);
return (max_time);
}
/// @brief Label identifying this event.
std::string label_;
/// @brief Timestamp at which the event occurred.
boost::posix_time::ptime timestamp_;
};
/// @brief Base class for classes representing DHCP messages.
///
/// This is a base class that holds common information (e.g. source
/// and destination ports) and operations (e.g. add, get, delete options)
/// for derived classes representing both DHCPv4 and DHCPv6 messages.
/// The @c Pkt4 and @c Pkt6 classes derive from it.
///
/// @note This is abstract class. Please instantiate derived classes
/// such as @c Pkt4 or @c Pkt6.
class Pkt : public hooks::CalloutHandleAssociate {
protected:
/// @brief Constructor.
///
/// This constructor is typically used for transmitted messages as it
/// creates an empty (no options) packet. The constructor is protected,
/// so only derived classes can call it. Pkt class cannot be instantiated
/// anyway, because it is an abstract class.
///
/// @param transid transaction-id
/// @param local_addr local IPv4 or IPv6 address
/// @param remote_addr remote IPv4 or IPv6 address
/// @param local_port local UDP (one day also TCP) port
/// @param remote_port remote UDP (one day also TCP) port
Pkt(uint32_t transid, const isc::asiolink::IOAddress& local_addr,
const isc::asiolink::IOAddress& remote_addr, uint16_t local_port,
uint16_t remote_port);
/// @brief Constructor.
///
/// This constructor is typically used for received messages as it takes
/// a buffer that's going to be parsed as one of arguments. The constructor
/// is protected, so only derived classes can call it. Pkt class cannot be
/// instantiated anyway, because it is an abstract class.
///
/// @param buf pointer to a buffer that contains on-wire data
/// @param len length of the pointer specified in buf
/// @param local_addr local IPv4 or IPv6 address
/// @param remote_addr remote IPv4 or IPv6 address
/// @param local_port local UDP (one day also TCP) port
/// @param remote_port remote UDP (one day also TCP) port
Pkt(const uint8_t* buf, uint32_t len,
const isc::asiolink::IOAddress& local_addr,
const isc::asiolink::IOAddress& remote_addr, uint16_t local_port,
uint16_t remote_port);
public:
/// @brief Prepares on-wire format of DHCP (either v4 or v6) packet.
///
/// Prepares on-wire format of message and all its options.
/// A caller must ensure that options are stored in options_ field
/// prior to calling this method.
///
/// Output buffer will be stored in buffer_out_.
/// The buffer_out_ should be cleared before writing to the buffer
/// in the derived classes.
///
/// @note This is a pure virtual method and must be implemented in
/// the derived classes. The @c Pkt4 and @c Pkt6 class have respective
/// implementations of this method.
///
/// @throw InvalidOperation if packing fails
virtual void pack() = 0;
/// @brief Parses on-wire form of DHCP (either v4 or v6) packet.
///
/// Parses received packet, stored in on-wire format in data_.
///
/// Will create a collection of option objects that will
/// be stored in options_ container.
///
/// @note This is a pure virtual method and must be implemented in
/// the derived classes. The @c Pkt4 and @c Pkt6 class have respective
/// implementations of this method.
///
/// Method will throw exception if packet parsing fails.
///
/// @throw tbd
virtual void unpack() = 0;
/// @brief Returns reference to output buffer.
///
/// Returned buffer will contain reasonable data only for
/// output (TX) packet and after pack() was called.
///
/// RX packet or TX packet before pack() will return buffer with
/// zero length. This buffer is returned as non-const, so hooks
/// framework (and user's callouts) can modify them if needed
///
/// @note This buffer is only valid till object that returned it exists.
///
/// @return reference to output buffer
isc::util::OutputBuffer& getBuffer() {
return (buffer_out_);
}
/// @brief Adds an option to this packet.
///
/// Derived classes may provide more specialized implementations.
/// In particular @c Pkt4 provides one that checks if option is
/// unique.
///
/// @param opt option to be added.
virtual void addOption(const OptionPtr& opt);
/// @brief Attempts to delete first suboption of requested type.
///
/// If there are several options of the same type present, only
/// the first option will be deleted.
///
/// @param type Type of option to be deleted.
///
/// @return true if option was deleted, false if no such option existed
bool delOption(uint16_t type);
/// @brief Returns text representation primary packet identifiers
///
/// This method is intended to be used to provide as a consistent way to
/// identify packets within log statements. Derivations should supply
/// there own implementation.
///
/// @return string with text representation
virtual std::string getLabel() const {
isc_throw(NotImplemented, "Pkt::getLabel()");
}
/// @brief Returns text representation of the packet.
///
/// This function is useful mainly for debugging.
///
/// @note This is a pure virtual method and must be implemented in
/// the derived classes. The @c Pkt4 and @c Pkt6 class have respective
/// implementations of this method.
///
/// @return string with text representation
virtual std::string toText() const = 0;
/// @brief Returns packet size in binary format.
///
/// Returns size of the packet in on-wire format or size needed to store
/// it in on-wire format.
///
/// @note This is a pure virtual method and must be implemented in
/// the derived classes. The @c Pkt4 and @c Pkt6 class have respective
/// implementations of this method.
///
/// @return packet size in bytes
virtual size_t len() = 0;
/// @brief Returns message type (e.g. 1 = SOLICIT).
///
/// @note This is a pure virtual method and must be implemented in
/// the derived classes. The @c Pkt4 and @c Pkt6 class have respective
/// implementations of this method.
///
/// @return message type
virtual uint8_t getType() const = 0;
/// @brief Sets message type (e.g. 1 = SOLICIT).
///
/// @note This is a pure virtual method and must be implemented in
/// the derived classes. The @c Pkt4 and @c Pkt6 class have respective
/// implementations of this method.
///
/// @param type message type to be set
virtual void setType(uint8_t type) = 0;
/// @brief Returns name of the DHCP message.
///
/// For all unsupported messages the derived classes must return
/// "UNKNOWN".
///
/// @return Pointer to "const" string containing DHCP message name.
/// The implementations in the derived classes should statically
/// allocate returned strings and the caller must not release the
/// returned pointer.
virtual const char* getName() const = 0;
/// @brief Sets transaction-id value.
///
/// @param transid transaction-id to be set.
void setTransid(uint32_t transid) {
transid_ = transid;
}
/// @brief Returns value of transaction-id field.
///
/// @return transaction-id
uint32_t getTransid() const {
return (transid_);
}
/// @brief Checks whether a client belongs to a given class.
///
/// @param client_class name of the class
/// @return true if belongs
bool inClass(const isc::dhcp::ClientClass& client_class);
/// @brief Adds a specified class to the packet.
///
/// A class can be added to the same packet repeatedly. Any additional
/// attempts to add to a packet the class already added, will be
/// ignored silently.
///
/// @param client_class name of the class to be added
/// @param required the class is marked for required evaluation
void addClass(const isc::dhcp::ClientClass& client_class,
bool required = false);
/// @brief Adds a specified subclass to the packet.
///
/// A subclass can be added to the same packet repeatedly. Any additional
/// attempts to add to a packet the subclass already added, will be
/// ignored silently.
///
/// @param class_def name of the class definition to be added
/// @param subclass name of the subclass to be added
void addSubClass(const isc::dhcp::ClientClass& class_def,
const isc::dhcp::ClientClass& subclass);
/// @brief Returns the class set
///
/// @note This should be used only to iterate over the class set.
/// @param required return classes or required to be evaluated classes.
/// @return if required is false (the default) the classes the
/// packet belongs to else the classes which are required to be
/// evaluated.
const ClientClasses& getClasses(bool required = false) const {
return (!required ? classes_ : required_classes_);
}
/// @brief Returns the class set including template classes associated with
/// subclasses
///
/// @note This should be used only to iterate over the class set.
/// @note SubClasses are always last.
/// @return if required is false (the default) the classes the
/// packet belongs to else the classes which are required to be
/// evaluated.
const SubClassRelationContainer& getSubClassesRelations() const {
return (subclasses_);
}
/// @brief Unparsed data (in received packets).
///
/// @warning This public member is accessed by derived
/// classes directly. One of such derived classes is
/// @ref perfdhcp::PerfPkt6. The impact on derived classes'
/// behavior must be taken into consideration before making
/// changes to this member such as access scope restriction or
/// data format change etc.
OptionBuffer data_;
protected:
/// @brief Returns the first option of specified type without copying.
///
/// This method is internally used by the @ref Pkt class and derived
/// classes to retrieve a pointer to the specified option. This
/// method doesn't copy the option before returning it to the
/// caller.
///
/// @param type Option type.
///
/// @return Pointer to the option of specified type or NULL pointer
/// if such option is not present.
OptionPtr getNonCopiedOption(const uint16_t type) const;
/// @brief Returns all option instances of specified type without
/// copying.
///
/// This is a variant of @ref getOptions method, which returns a collection
/// of options without copying them. This method should be only used by
/// the @ref Pkt6 class and derived classes. Any external callers should
/// use @ref getOptions which copies option instances before returning them
/// when the @ref Pkt::copy_retrieved_options_ flag is set to true.
///
/// @param opt_type Option code.
///
/// @return Collection of options found.
OptionCollection getNonCopiedOptions(const uint16_t opt_type) const;
public:
/// @brief Clones all options so that they can be safely modified.
///
/// @return A container with option clones.
OptionCollection cloneOptions();
/// @brief Returns the first option of specified type.
///
/// Returns the first option of specified type. Note that in DHCPv6 several
/// instances of the same option are allowed (and frequently used).
///
/// The options will be only returned after unpack() is called.
///
/// @param type option type we are looking for
///
/// @return pointer to found option (or NULL)
OptionPtr getOption(const uint16_t type);
/// @brief Returns all instances of specified type.
///
/// Returns all instances of options of the specified type. DHCPv6 protocol
/// allows (and uses frequently) multiple instances.
///
/// @param type option type we are looking for
/// @return instance of option collection with requested options
isc::dhcp::OptionCollection getOptions(const uint16_t type);
/// @brief Controls whether the option retrieved by the @ref Pkt::getOption
/// should be copied before being returned.
///
/// Setting this value to true enables the mechanism of copying options
/// retrieved from the packet to prevent accidental modifications of
/// options that shouldn't be modified. The typical use case for this
/// mechanism is to prevent hook library from modifying instance of
/// an option within the packet that would also affect the value for
/// this option within the Kea configuration structures.
///
/// Kea doesn't copy option instances which it stores in the packet.
/// It merely copy pointers into the packets. Thus, any modification
/// to an option would change the value of this option in the
/// Kea configuration. To prevent this, option copying should be
/// enabled prior to passing the pointer to a packet to a hook library.
///
/// Not only does this method cause the server to copy
/// an option, but the copied option also replaces the original
/// option within the packet. The option can be then freely modified
/// and the modifications will only affect the instance of this
/// option within the packet but not within the server configuration.
///
/// @param copy Indicates if the options should be copied when
/// retrieved (if true), or not copied (if false).
virtual void setCopyRetrievedOptions(const bool copy) {
copy_retrieved_options_ = copy;
}
/// @brief Returns whether the copying of retrieved options is enabled.
///
/// Also see @ref setCopyRetrievedOptions.
///
/// @return true if retrieved options are copied.
bool isCopyRetrievedOptions() const {
return (copy_retrieved_options_);
}
/// @brief Update packet timestamp.
///
/// Updates packet timestamp. This method is invoked
/// by interface manager just before sending or
/// just after receiving it.
/// @throw isc::Unexpected if timestamp update failed
void updateTimestamp();
/// @brief Returns packet timestamp.
///
/// Returns packet timestamp value updated when
/// packet is received or send.
///
/// @return packet timestamp.
const boost::posix_time::ptime& getTimestamp() const {
return timestamp_;
}
/// @brief Set socket receive timestamp.
///
/// Sets the socket receive timestamp to an arbitrary value.
void setTimestamp(boost::posix_time::ptime& timestamp) {
timestamp_ = timestamp;
}
/// @brief Adds an event to the end of the event stack.
///
/// @param label string identifying the event
/// @param timestamp time at which the event occurred. It is expected
/// to be in UTC/microseconds. Defaults to the current time.
void addPktEvent(const std::string& label,
const boost::posix_time::ptime& timestamp = PktEvent::now());
/// @brief Adds an event to the end of the event stack with the timestamp
/// specified as a struct timeval.
///
/// @param label string identifying the event
/// @param timestamp time at which the event occurred. It is expected
/// to be in UTC/microseconds.
void addPktEvent(const std::string& label, const struct timeval& timestamp);
/// @brief Updates (or adds) an event in the event stack.
///
/// Updates the timestamp of the event described by label if it exists in
/// the stack, otherwise it adds the event to the end of the stack. This
/// is intended to be used for testing.
///
/// @param label string identifying the event
/// @param timestamp time at which the event occurred. It is expected
/// to be in UTC/microseconds.
void setPktEvent(const std::string& label,
const boost::posix_time::ptime& timestamp = PktEvent::now());
/// @brief Discards contents of the packet event stack.
///
/// This is provided primarily for test purposes.
void clearPktEvents();
/// @brief Fetches the timestamp for a given event in the stack.
///
/// @param label string identifying the event
/// @return timestamp of the event (UTC/microseconds)
boost::posix_time::ptime getPktEventTime(const std::string& label) const;
/// @brief Fetches the current event stack contents.
///
/// @return reference to the list of events.
const std::list<PktEvent>& getPktEvents() {
return (events_);
}
/// @brief Creates a dump of the stack contents to a string for logging.
///
/// @param verbose when true the dump is more verbose, includes durations
/// between events and spans multiple lines. Defaults to false.
std::string dumpPktEvents(bool verbose = false) const;
/// @brief Copies content of input buffer to output buffer.
///
/// This is mostly a diagnostic function. It is being used for sending
/// received packet. Received packet is stored in data_, but
/// transmitted data is stored in buffer_out_. If we want to send packet
/// that we just received, a copy between those two buffers is necessary.
void repack();
/// @brief Sets remote IP address.
///
/// @param remote specifies remote address
void setRemoteAddr(const isc::asiolink::IOAddress& remote) {
remote_addr_ = remote;
}
/// @brief Returns remote IP address.
///
/// @return remote address
const isc::asiolink::IOAddress& getRemoteAddr() const {
return (remote_addr_);
}
/// @brief Sets local IP address.
///
/// @param local specifies local address
void setLocalAddr(const isc::asiolink::IOAddress& local) {
local_addr_ = local;
}
/// @brief Returns local IP address.
///
/// @return local address
const isc::asiolink::IOAddress& getLocalAddr() const {
return (local_addr_);
}
/// @brief Sets local UDP (and soon TCP) port.
///
/// This sets a local port, i.e. destination port for recently received
/// packet or a source port for to be transmitted packet.
///
/// @param local specifies local port
void setLocalPort(uint16_t local) {
local_port_ = local;
}
/// @brief Returns local UDP (and soon TCP) port.
///
/// This sets a local port, i.e. destination port for recently received
/// packet or a source port for to be transmitted packet.
///
/// @return local port
uint16_t getLocalPort() const {
return (local_port_);
}
/// @brief Sets remote UDP (and soon TCP) port.
///
/// This sets a remote port, i.e. source port for recently received
/// packet or a destination port for to be transmitted packet.
///
/// @param remote specifies remote port
void setRemotePort(uint16_t remote) {
remote_port_ = remote;
}
/// @brief Returns remote port.
///
/// @return remote port
uint16_t getRemotePort() const {
return (remote_port_);
}
/// @brief Sets interface index.
///
/// @param ifindex specifies interface index.
void setIndex(const unsigned int ifindex) {
ifindex_ = ifindex;
}
/// @brief Resets interface index to negative value.
void resetIndex() {
ifindex_ = UNSET_IFINDEX;
}
/// @brief Returns interface index.
///
/// @return interface index
int getIndex() const {
return (ifindex_);
}
/// @brief Checks if interface index has been set.
///
/// @return true if interface index set, false otherwise.
bool indexSet() const {
return (ifindex_ != UNSET_IFINDEX);
}
/// @brief Returns interface name.
///
/// Returns interface name over which packet was received or is
/// going to be transmitted.
///
/// @return interface name
std::string getIface() const {
return (iface_);
}
/// @brief Sets interface name.
///
/// Sets interface name over which packet was received or is
/// going to be transmitted.
///
/// @param iface The interface name
void setIface(const std::string& iface) {
iface_ = iface;
}
/// @brief Sets remote hardware address.
///
/// Sets hardware address (MAC) from an existing HWAddr structure.
/// The remote address is a destination address for outgoing
/// packet and source address for incoming packet. When this
/// is an outgoing packet, this address will be used to
/// construct the link layer header.
///
/// @param hw_addr structure representing HW address.
///
/// @throw BadValue if addr is null
void setRemoteHWAddr(const HWAddrPtr& hw_addr);
/// @brief Sets remote hardware address.
///
/// Sets the destination hardware (MAC) address for the outgoing packet
/// or source HW address for the incoming packet. When this
/// is an outgoing packet this address will be used to construct
/// the link layer header.
///
/// @note mac_addr must be a buffer of at least hlen bytes.
///
/// In a typical case, hlen field would be redundant, as it could
/// be extracted from mac_addr.size(). However, the difference is
/// when running on exotic hardware, like Infiniband, that had
/// MAC addresses 20 bytes long. In that case, hlen is set to zero
/// in DHCPv4.
///
/// @param htype hardware type (will be sent in htype field)
/// @param hlen hardware length (will be sent in hlen field)
/// @param hw_addr pointer to hardware address
void setRemoteHWAddr(const uint8_t htype, const uint8_t hlen,
const std::vector<uint8_t>& hw_addr);
/// @brief Returns the remote HW address obtained from raw sockets.
///
/// @return remote HW address.
HWAddrPtr getRemoteHWAddr() const {
return (remote_hwaddr_);
}
/// @brief Returns MAC address.
///
/// The difference between this method and getRemoteHWAddr() is that
/// getRemoteHWAddr() returns only what was obtained from raw sockets.
/// This method is more generic and can attempt to obtain MAC from
/// varied sources: raw sockets, client-id, link-local IPv6 address,
/// and various relay options.
///
/// @note Technically the proper term for this information is a link layer
/// address, but it is frequently referred to MAC or hardware address.
/// Since we're calling the feature "MAC addresses in DHCPv6", we decided
/// to keep the name of getMAC().
///
/// hw_addr_src takes a combination of bit values specified in
/// HWADDR_SOURCE_* constants.
///
/// @param hw_addr_src a bitmask that specifies hardware address source
HWAddrPtr getMAC(uint32_t hw_addr_src);
/// @brief Virtual destructor.
///
/// There is nothing to clean up here, but since there are virtual methods,
/// we define virtual destructor to ensure that derived classes will have
/// a virtual one, too.
virtual ~Pkt() {
}
/// @brief Classes this packet belongs to.
///
/// This field is public, so the code outside of Pkt4 or Pkt6 class can
/// iterate over existing classes. Having it public also solves the problem
/// of returned reference lifetime. It is preferred to use @ref inClass and
/// @ref addClass to operate on this field.
ClientClasses classes_;
/// @brief Classes which are required to be evaluated.
///
/// The comment on @ref classes_ applies here.
///
/// Before output option processing these classes will be evaluated
/// and if evaluation status is true added to the previous collection.
ClientClasses required_classes_;
/// @brief SubClasses this packet belongs to.
///
/// This field is public, so the code outside of Pkt4 or Pkt6 class can
/// iterate over existing classes. Having it public also solves the problem
/// of returned reference lifetime. It is preferred to use @ref inClass and
/// @ref addSubClass to operate on this field.
SubClassRelationContainer subclasses_;
/// @brief Collection of options present in this message.
///
/// @warning This public member is accessed by derived
/// classes directly. One of such derived classes is
/// @ref perfdhcp::PerfPkt6. The impact on derived classes'
/// behavior must be taken into consideration before making
/// changes to this member such as access scope restriction or
/// data format change etc.
isc::dhcp::OptionCollection options_;
protected:
/// @brief Attempts to obtain MAC address from source link-local
/// IPv6 address
///
/// This method is called from getMAC(HWADDR_SOURCE_IPV6_LINK_LOCAL)
/// and should not be called directly. It is not 100% reliable.
/// The source IPv6 address does not necessarily have to be link-local
/// (may be global or ULA) and even if it's link-local, it doesn't
/// necessarily be based on EUI-64. For example, Windows supports
/// RFC4941, which randomized IID part of the link-local address.
/// If this method fails, it will return NULL.
///
/// For direct message, it attempts to use remote_addr_ field. For relayed
/// message, it uses peer-addr of the first relay.
///
/// @note This is a pure virtual method and must be implemented in
/// the derived classes. The @c Pkt6 class have respective implementation.
/// This method is not applicable to DHCPv4.
///
/// @return hardware address (or NULL)
virtual HWAddrPtr getMACFromSrcLinkLocalAddr() = 0;
/// @brief Attempts to obtain MAC address from relay option
/// client-linklayer-addr
///
/// This method is called from getMAC(HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION)
/// and should not be called directly. It will extract the client's
/// MAC/Hardware address from option client_linklayer_addr (RFC6939)
/// inserted by the relay agent closest to the client.
/// If this method fails, it will return NULL.
///
/// @note This is a pure virtual method and must be implemented in
/// the derived classes. The @c Pkt6 class have respective implementation.
/// This method is not applicable to DHCPv4.
///
/// @return hardware address (or NULL)
virtual HWAddrPtr getMACFromIPv6RelayOpt() = 0;
/// @brief Attempts to obtain MAC address from DUID-LL or DUID-LLT.
///
/// This method is called from getMAC(HWADDR_SOURCE_DUID) and should not be
/// called directly. It will attempt to extract MAC address information
/// from DUID if its type is LLT or LL. If this method fails, it will
/// return NULL.
///
/// @note This is a pure virtual method and must be implemented in
/// the derived classes. The @c Pkt6 class have respective implementation.
/// This method is not applicable to DHCPv4.
///
/// @return hardware address (or NULL)
virtual HWAddrPtr getMACFromDUID() = 0;
/// @brief Attempts to obtain MAC address from remote-id relay option.
///
/// This method is called from getMAC(HWADDR_SOURCE_REMOTE_ID) and should not be
/// called directly. It will attempt to extract MAC address information
/// from remote-id option inserted by a relay agent closest to the client.
/// If this method fails, it will return NULL.
///
/// @note This is a pure virtual method and must be implemented in
/// the derived classes. The @c Pkt6 class have respective implementation.
/// This method is not applicable to DHCPv4.
///
/// @return hardware address (or NULL)
virtual HWAddrPtr getMACFromRemoteIdRelayOption() = 0;
/// @brief Attempts to convert IPv6 address into MAC.
///
/// Utility method that attempts to convert link-local IPv6 address to the
/// MAC address. That works only for link-local IPv6 addresses that are
/// based on EUI-64.
///
/// @note This method uses hardware type of the interface the packet was
/// received on. If you have multiple access technologies in your network
/// (e.g. client connected to WiFi that relayed the traffic to the server
/// over Ethernet), hardware type may be invalid.
///
/// @param addr IPv6 address to be converted
/// @return hardware address (or NULL)
HWAddrPtr
getMACFromIPv6(const isc::asiolink::IOAddress& addr);
/// @brief Attempts to extract MAC/Hardware address from DOCSIS options
/// inserted by the modem itself.
///
/// This is a generic mechanism for extracting hardware address from the
/// DOCSIS options.
///
/// @note This is a pure virtual method and must be implemented in
/// the derived classes. The @c Pkt6 class have respective implementation.
/// This method is currently not implemented in DHCPv4.
///
/// @return hardware address (if necessary DOCSIS suboptions are present)
virtual HWAddrPtr getMACFromDocsisModem() = 0;
/// @brief Attempts to extract MAC/Hardware address from DOCSIS options
/// inserted by the CMTS (the relay agent)
///
/// This is a generic mechanism for extracting hardware address from the
/// DOCSIS options.
///
/// @note This is a pure virtual method and must be implemented in
/// the derived classes. The @c Pkt6 class have respective implementation.
/// This method is currently not implemented in DHCPv4.
///
/// @return hardware address (if necessary DOCSIS suboptions are present)
virtual HWAddrPtr getMACFromDocsisCMTS() = 0;
/// Transaction-id (32 bits for v4, 24 bits for v6)
uint32_t transid_;
/// Name of the network interface the packet was received/to be sent over.
std::string iface_;
/// @brief Interface index.
///
/// Each network interface has assigned an unique ifindex.
/// It is a functional equivalent of a name, but sometimes more useful, e.g.
/// when using odd systems that allow spaces in interface names.
unsigned int ifindex_;
/// @brief Local IP (v4 or v6) address.
///
/// Specifies local IPv4 or IPv6 address. It is a destination address for
/// received packet, and a source address if it packet is being transmitted.
isc::asiolink::IOAddress local_addr_;
/// @brief Remote IP address.
///
/// Specifies local IPv4 or IPv6 address. It is source address for received
/// packet and a destination address for packet being transmitted.
isc::asiolink::IOAddress remote_addr_;
/// local TDP or UDP port
uint16_t local_port_;
/// remote TCP or UDP port
uint16_t remote_port_;
/// Output buffer (used during message transmission)
///
/// @warning This protected member is accessed by derived
/// classes directly. One of such derived classes is
/// @ref perfdhcp::PerfPkt6. The impact on derived classes'
/// behavior must be taken into consideration before making
/// changes to this member such as access scope restriction or
/// data format change etc.
isc::util::OutputBuffer buffer_out_;
/// @brief Indicates if a copy of the retrieved option should be
/// returned when @ref Pkt::getOption is called.
///
/// @see the documentation for @ref Pkt::setCopyRetrievedOptions.
bool copy_retrieved_options_;
/// packet timestamp
boost::posix_time::ptime timestamp_;
// remote HW address (src if receiving packet, dst if sending packet)
HWAddrPtr remote_hwaddr_;
private:
/// @brief Generic method that validates and sets HW address.
///
/// This is a generic method used by all modifiers of this class
/// which set class members representing HW address.
///
/// @param htype hardware type.
/// @param hlen hardware length.
/// @param hw_addr pointer to actual hardware address.
/// @param [out] storage pointer to a class member to be modified.
///
/// @throw isc::OutOfRange if invalid HW address specified.
virtual void setHWAddrMember(const uint8_t htype, const uint8_t hlen,
const std::vector<uint8_t>& hw_addr,
HWAddrPtr& storage);
/// @brief List of timestamped packet events.
std::list<PktEvent> events_;
};
/// @brief A pointer to either Pkt4 or Pkt6 packet
typedef boost::shared_ptr<isc::dhcp::Pkt> PktPtr;
/// @brief RAII object enabling duplication of the stored options and restoring
/// the original options on destructor.
///
/// This object enables duplication of the stored options and restoring the
/// original options on destructor. When the object goes out of scope, the
/// initial options are restored. This is applicable in cases when the server is
/// going to invoke a callout (hook library) where the list of options in the
/// packet will be modified. This can also be used to restore the initial
/// suboptions of an option when the suboptions are changed (e.g. when splitting
/// long options and suboptions). The use of RAII object eliminates the need for
/// explicitly copying and restoring the list of options and is safer in case of
/// exceptions thrown by callouts and a presence of multiple exit points.
class ScopedSubOptionsCopy {
public:
/// @brief Constructor.
///
/// Creates a copy of the initial options on an option.
///
/// @param opt Pointer to the option.
ScopedSubOptionsCopy(const OptionPtr& opt) : option_(opt) {
if (opt) {
options_ = opt->getMutableOptions();
}
}
/// @brief Destructor.
///
/// Restores the initial options on a packet.
~ScopedSubOptionsCopy() {
if (option_) {
option_->getMutableOptions() = options_;
}
}
private:
/// @brief Holds a pointer to the option.
OptionPtr option_;
/// @brief Holds the initial options.
OptionCollection options_;
};
/// @brief RAII object enabling duplication of the stored options and restoring
/// the original options on destructor.
///
/// This object enables duplication of the stored options and restoring the
/// original options on destructor. When the object goes out of scope, the
/// initial options are restored. This is applicable in cases when the server is
/// going to invoke a callout (hook library) where the list of options in the
/// packet will be modified. The use of RAII object eliminates the need for
/// explicitly copying and restoring the list of options and is safer in case of
/// exceptions thrown by callouts and a presence of multiple exit points.
///
/// @tparam PktType Type of the packet, e.g. Pkt4, Pkt6, Pkt4o6.
template<typename PktType>
class ScopedPktOptionsCopy {
public:
/// @brief Constructor.
///
/// Creates a copy of the initial options on a packet.
///
/// @param pkt Pointer to the packet.
ScopedPktOptionsCopy(PktType& pkt) : pkt_(pkt), options_(pkt.options_) {
pkt_.options_ = pkt_.cloneOptions();
}
/// @brief Destructor.
///
/// Restores the initial options on a packet.
~ScopedPktOptionsCopy() {
pkt_.options_ = options_;
}
private:
/// @brief Holds a reference to the packet.
PktType& pkt_;
/// @brief Holds the initial options.
OptionCollection options_;
};
} // end of namespace isc::dhcp
} // end of namespace isc
#endif