From: Tomek Mrugalski Date: Fri, 26 Sep 2014 13:40:42 +0000 (+0200) Subject: [3546] Pkt class added. X-Git-Tag: trac3489_base~2^2~14 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d7f6665faaa8ed69e9e8f85bbaae87971149b10b;p=thirdparty%2Fkea.git [3546] Pkt class added. --- diff --git a/src/lib/dhcp/Makefile.am b/src/lib/dhcp/Makefile.am index 14347bbc24..ce5090f09e 100644 --- a/src/lib/dhcp/Makefile.am +++ b/src/lib/dhcp/Makefile.am @@ -43,6 +43,7 @@ libkea_dhcp___la_SOURCES += option_definition.cc option_definition.h libkea_dhcp___la_SOURCES += option_space.cc option_space.h libkea_dhcp___la_SOURCES += option_string.cc option_string.h libkea_dhcp___la_SOURCES += protocol_util.cc protocol_util.h +libkea_dhcp___la_SOURCES += pkt.cc pkt.h libkea_dhcp___la_SOURCES += pkt6.cc pkt6.h libkea_dhcp___la_SOURCES += pkt4.cc pkt4.h libkea_dhcp___la_SOURCES += pkt_filter.h pkt_filter.cc diff --git a/src/lib/dhcp/pkt.h b/src/lib/dhcp/pkt.h new file mode 100644 index 0000000000..b95f93f50a --- /dev/null +++ b/src/lib/dhcp/pkt.h @@ -0,0 +1,240 @@ +// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#ifndef PKT_H +#define PKT_H + +#include +#include +#include +#include + +#include + +namespace isc { + +namespace dhcp { + +/// @brief Base class for DHCPv4 (Pkt4) and DHCPv6 (Pkt6) classes +/// +/// This is a base class that holds all common information (e.g. source and +/// destination ports) and operations (e.g. add, get, delete options). +/// This class is purely virtual. Please instantiate Pkt4, Pkt6 or any +/// other derived classes. +class Pkt { +protected: +Pkt(uint32_t transid, const isc::asiolink::IOAddress& local_addr, + const isc::asiolink::IOAddress& remote_addr, uint16_t local_port, + uint16_t remote_port) + :transid_(transid), + iface_(""), + ifindex_(-1), + local_addr_(local_addr), + remote_addr_(remote_addr), + local_port_(local_port), + remote_port_(remote_port), + buffer_out_(0) + { + } + + 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) + :transid_(0), + iface_(""), + ifindex_(-1), + local_addr_(local_addr), + remote_addr_(remote_addr), + local_port_(local_port), + remote_port_(remote_port), + buffer_out_(0) + { + data_.resize(len); + memcpy(&data_[0], buf, len); + } + +public: + + virtual void pack() = 0; + //virtual bool unpack() = 0; + + /// @brief Returns reference to output buffer. + /// + /// Returned buffer will contain reasonable data only for + /// output (TX) packet and after pack() was called. This buffer + /// is only valid till Pkt{4,6} object is valid. + /// + /// 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 + /// + /// @return reference to output buffer + isc::util::OutputBuffer& getBuffer() { return (buffer_out_); }; + + /// Adds an option to this packet. + /// + /// Sadly, we need to have 2 versions of that method. One that + /// accepts duplicates (DHCPv6) and one that does not (DHCPv4) + /// + /// @param opt option to be added. + virtual void addOption(const OptionPtr& opt); + + /// Attempts to delete first suboption of requested type + /// + /// @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); + + virtual std::string toText() = 0; + + /// Returns packet type + /// + /// For DHCPv6, this is a straightforward operation (read packet field), but + /// for DHCPv4 it requires finding appropriate option (that may or may not + /// be present). + virtual size_t len() = 0; + + /// Returns message type (e.g. 1 = SOLICIT) + /// + /// @return message type + virtual uint8_t getType() const = 0; + + /// Sets message type (e.g. 1 = SOLICIT) + /// + /// @param type message type to be set + virtual void setType(uint8_t type) = 0; + + /// @brief Sets transaction-id value + /// + /// @param transid transaction-id to be set. + void setTransid(uint32_t transid) { transid_ = transid; } + + /// Returns value of transaction-id field + /// + /// @return transaction-id + uint32_t getTransid() const { return (transid_); }; + + /// @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 should be used to operate on this field. + ClientClasses classes_; + + /// @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 packet to a specified class + /// + /// A packet can be added to the same class repeatedly. Any additional + /// attempts to add to a class the packet already belongs to, will be + /// ignored silently. + /// + /// @note It is a matter of naming convention. Conceptually, the server + /// processes a stream of packets, with some packets belonging to given + /// classes. From that perspective, this method adds a packet to specifed + /// class. Implementation wise, it looks the opposite - the class name + /// is added to the packet. Perhaps the most appropriate name for this + /// method would be associateWithClass()? But that seems overly long, + /// so I decided to stick with addClass(). + /// + /// @param client_class name of the class to be added + void addClass(const isc::dhcp::ClientClass& client_class); + + /// 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 clasess' + /// behavior must be taken into consideration before making + /// changes to this member such as access scope restriction or + /// data format change etc. + OptionBuffer data_; + + virtual ~Pkt() { } + +protected: + + /// 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 + /// + /// interface index (each network interface has assigned unique ifindex + /// it is functional equivalent of name, but sometimes more useful, e.g. + /// when using crazy systems that allow spaces in interface names + /// e.g. windows + int ifindex_; + + /// local address (dst if receiving packet, src if sending packet) + isc::asiolink::IOAddress local_addr_; + + /// remote address (src if receiving packet, dst if sending packet) + isc::asiolink::IOAddress remote_addr_; + + /// local TDP or UDP port + uint16_t local_port_; + + /// remote TCP or UDP port + uint16_t remote_port_; + + /// 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 clasess' + /// 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_; + + /// 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 clasess' + /// behavior must be taken into consideration before making + /// changes to this member such as access scope restriction or + /// data format change etc. + /// + /// @warning This public member is accessed by derived + /// classes directly. One of such derived classes is + /// @ref perfdhcp::PerfPkt4. The impact on derived clasess' + /// behavior must be taken into consideration before making + /// changes to this member such as access scope restriction or + /// data format change etc. This field is also public, because + /// it may be modified by callouts (which are written in C++ now, + /// but we expect to also have them in Python, so any accesibility + /// methods would overly complicate things here and degrade + /// performance). + isc::util::OutputBuffer buffer_out_; + + /// packet timestamp + boost::posix_time::ptime timestamp_; + + /// A callback to be called to unpack options from the packet. + UnpackOptionsCallback callback_; +}; + +}; // namespace isc::dhcp +}; // namespace isc + +#endif diff --git a/src/lib/dhcp/pkt4.cc b/src/lib/dhcp/pkt4.cc index d844d3ce01..868c0102d3 100644 --- a/src/lib/dhcp/pkt4.cc +++ b/src/lib/dhcp/pkt4.cc @@ -33,17 +33,11 @@ namespace dhcp { const IOAddress DEFAULT_ADDRESS("0.0.0.0"); Pkt4::Pkt4(uint8_t msg_type, uint32_t transid) - :buffer_out_(DHCPV4_PKT_HDR_LEN), - local_addr_(DEFAULT_ADDRESS), - remote_addr_(DEFAULT_ADDRESS), - iface_(""), - ifindex_(0), - local_port_(DHCP4_SERVER_PORT), - remote_port_(DHCP4_CLIENT_PORT), + :Pkt(transid, DEFAULT_ADDRESS, DEFAULT_ADDRESS, DHCP4_SERVER_PORT, + DHCP4_CLIENT_PORT), op_(DHCPTypeToBootpType(msg_type)), hwaddr_(new HWAddr()), hops_(0), - transid_(transid), secs_(0), flags_(0), ciaddr_(DEFAULT_ADDRESS), @@ -51,6 +45,7 @@ Pkt4::Pkt4(uint8_t msg_type, uint32_t transid) siaddr_(DEFAULT_ADDRESS), giaddr_(DEFAULT_ADDRESS) { + // buffer_out_.resize(DHCPV4_PKT_HDR_LEN); memset(sname_, 0, MAX_SNAME_LEN); memset(file_, 0, MAX_FILE_LEN); @@ -58,17 +53,11 @@ Pkt4::Pkt4(uint8_t msg_type, uint32_t transid) } Pkt4::Pkt4(const uint8_t* data, size_t len) - :buffer_out_(0), // not used, this is RX packet - local_addr_(DEFAULT_ADDRESS), - remote_addr_(DEFAULT_ADDRESS), - iface_(""), - ifindex_(0), - local_port_(DHCP4_SERVER_PORT), - remote_port_(DHCP4_CLIENT_PORT), + :Pkt(data, len, DEFAULT_ADDRESS, DEFAULT_ADDRESS, DHCP4_SERVER_PORT, + DHCP4_CLIENT_PORT), op_(BOOTREQUEST), hwaddr_(new HWAddr()), hops_(0), - transid_(0), secs_(0), flags_(0), ciaddr_(DEFAULT_ADDRESS), @@ -76,6 +65,7 @@ Pkt4::Pkt4(const uint8_t* data, size_t len) siaddr_(DEFAULT_ADDRESS), giaddr_(DEFAULT_ADDRESS) { + if (len < DHCPV4_PKT_HDR_LEN) { isc_throw(OutOfRange, "Truncated DHCPv4 packet (len=" << len << ") received, at least " << DHCPV4_PKT_HDR_LEN @@ -163,7 +153,7 @@ Pkt4::pack() { } } -void +bool Pkt4::unpack() { // input buffer (used during message reception) @@ -232,6 +222,8 @@ Pkt4::unpack() { // @todo check will need to be called separately, so hooks can be called // after the packet is parsed, but before its content is verified check(); + + return (true); } void Pkt4::check() { @@ -433,7 +425,7 @@ Pkt4::getHlen() const { } void -Pkt4::addOption(boost::shared_ptr