Commit d7f6665f authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[3546] Pkt class added.

parent 4f942fc1
......@@ -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
......
// 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 <asiolink/io_address.h>
#include <util/buffer.h>
#include <dhcp/option.h>
#include <dhcp/classify.h>
#include <boost/date_time/posix_time/posix_time.hpp>
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
......@@ -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<Option> opt) {
Pkt4::addOption(const OptionPtr& opt) {
// Check for uniqueness (DHCPv4 options must be unique)
if (getOption(opt->getType())) {
isc_throw(BadValue, "Option " << opt->getType()
......@@ -485,17 +477,6 @@ Pkt4::isRelayed() const {
"hops != 0)");
}
bool Pkt4::inClass(const isc::dhcp::ClientClass& client_class) {
return (classes_.find(client_class) != classes_.end());
}
void
Pkt4::addClass(const isc::dhcp::ClientClass& client_class) {
if (classes_.find(client_class) == classes_.end()) {
classes_.insert(client_class);
}
}
} // end of namespace isc::dhcp
} // end of namespace isc
......@@ -21,8 +21,8 @@
#include <dhcp/option.h>
#include <dhcp/hwaddr.h>
#include <dhcp/classify.h>
#include <dhcp/pkt.h>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
......@@ -35,7 +35,7 @@ namespace isc {
namespace dhcp {
class Pkt4 {
class Pkt4 : public Pkt {
public:
/// length of the CHADDR field in DHCPv4 message
......@@ -88,7 +88,8 @@ public:
/// be stored in options_ container.
///
/// Method with throw exception if packet parsing fails.
void unpack();
/// @return true if unpack was successful
bool unpack();
/// @brief performs sanity check on a packet.
///
......@@ -216,16 +217,6 @@ public:
void
setGiaddr(const isc::asiolink::IOAddress& giaddr) { giaddr_ = giaddr; };
/// @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 Returns DHCP message type (e.g. 1 = DHCPDISCOVER).
///
/// @return message type
......@@ -304,33 +295,19 @@ public:
/// @return hardware address structure
HWAddrPtr getHWAddr() const { return (hwaddr_); }
/// @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 Pkt4 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_); };
/// @brief Add an option.
///
/// Throws BadValue if option with that type is already present.
///
/// @param opt option to be added
void
addOption(boost::shared_ptr<Option> opt);
virtual void
addOption(const OptionPtr& opt);
/// @brief Returns an option of specified type.
///
/// @return returns option of requested type (or NULL)
/// if no such option is present
boost::shared_ptr<Option>
OptionPtr
getOption(uint8_t opt_type) const;
/// @brief Deletes specified option
......@@ -520,20 +497,6 @@ public:
/// @throw isc::Unexpected if timestamp update failed
void updateTimestamp();
/// Output buffer (used during message transmission)
///
/// @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_;
/// @brief That's the data of input buffer used in RX packet.
///
/// @note Note that InputBuffer does not store the data itself, but just
......@@ -552,36 +515,6 @@ public:
/// performance).
std::vector<uint8_t> data_;
/// @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);
/// @brief Classes this packet belongs to.
///
/// This field is public, so the code outside of Pkt4 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_;
private:
......@@ -616,28 +549,6 @@ protected:
// remote HW address (src if receiving packet, dst if sending packet)
HWAddrPtr remote_hwaddr_;
/// 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_;
/// name of the network interface the packet was received/to be sent over
std::string iface_;
/// @brief 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. MS Windows)
uint32_t ifindex_;
/// local UDP port
uint16_t local_port_;
/// remote UDP port
uint16_t remote_port_;
/// @brief message operation code
///
/// Note: This is legacy BOOTP field. There's no need to manipulate it
......@@ -656,9 +567,6 @@ protected:
/// Number of relay agents traversed
uint8_t hops_;
/// DHCPv4 transaction-id (32 bits, not 24 bits as in DHCPv6)
uint32_t transid_;
/// elapsed (number of seconds since beginning of transmission)
uint16_t secs_;
......@@ -685,16 +593,6 @@ protected:
// end of real DHCPv4 fields
/// collection of options present in this message
///
/// @warning This protected member is accessed by derived
/// classes directly. One of such derived classes is
/// @ref perfdhcp::PerfPkt4. 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_;
/// packet timestamp
boost::posix_time::ptime timestamp_;
......
......@@ -27,41 +27,26 @@ using namespace isc::asiolink;
namespace isc {
namespace dhcp {
const IOAddress DEFAULT_ADDRESS6("::");
Pkt6::RelayInfo::RelayInfo()
:msg_type_(0), hop_count_(0), linkaddr_("::"), peeraddr_("::"), relay_msg_len_(0) {
:msg_type_(0), hop_count_(0), linkaddr_("::"), peeraddr_("::"),
relay_msg_len_(0) {
// interface_id_, subscriber_id_, remote_id_ initialized to NULL
// echo_options_ initialized to empty collection
}
Pkt6::Pkt6(const uint8_t* buf, uint32_t buf_len, DHCPv6Proto proto /* = UDP */) :
proto_(proto),
msg_type_(0),
transid_(rand()%0xffffff),
iface_(""),
ifindex_(-1),
local_addr_("::"),
remote_addr_("::"),
local_port_(0),
remote_port_(0),
buffer_out_(0) {
data_.resize(buf_len);
memcpy(&data_[0], buf, buf_len);
Pkt6::Pkt6(const uint8_t* buf, uint32_t buf_len, DHCPv6Proto proto /* = UDP */)
:Pkt(buf, buf_len, DEFAULT_ADDRESS6, DEFAULT_ADDRESS6, 0, 0),
proto_(proto), msg_type_(0) {
}
Pkt6::Pkt6(uint8_t msg_type, uint32_t transid, DHCPv6Proto proto /*= UDP*/) :
proto_(proto),
msg_type_(msg_type),
transid_(transid),
iface_(""),
ifindex_(-1),
local_addr_("::"),
remote_addr_("::"),
local_port_(0),
remote_port_(0),
buffer_out_(0) {
Pkt6::Pkt6(uint8_t msg_type, uint32_t transid, DHCPv6Proto proto /*= UDP*/)
:Pkt(transid, DEFAULT_ADDRESS6, DEFAULT_ADDRESS6, 0, 0), proto_(proto),
msg_type_(msg_type) {
}
uint16_t Pkt6::len() {
size_t Pkt6::len() {
if (relay_info_.empty()) {
return (directLen());
} else {
......@@ -488,21 +473,6 @@ Pkt6::getOptions(uint16_t opt_type) {
return (found);
}
void
Pkt6::addOption(const OptionPtr& opt) {
options_.insert(pair<int, boost::shared_ptr<Option> >(opt->getType(), opt));
}
bool
Pkt6::delOption(uint16_t type) {
isc::dhcp::OptionCollection::iterator x = options_.find(type);
if (x!=options_.end()) {
options_.erase(x);
return (true); // delete successful
}
return (false); // can't find option to be deleted
}
void Pkt6::repack() {
buffer_out_.writeData(&data_[0], data_.size());
}
......@@ -586,17 +556,5 @@ void Pkt6::copyRelayInfo(const Pkt6Ptr& question) {
}
}
bool
Pkt6::inClass(const std::string& client_class) {
return (classes_.find(client_class) != classes_.end());
}
void
Pkt6::addClass(const std::string& client_class) {
if (classes_.find(client_class) == classes_.end()) {
classes_.insert(client_class);
}
}
} // end of isc::dhcp namespace
} // end of isc namespace
......@@ -17,7 +17,7 @@
#include <asiolink/io_address.h>
#include <dhcp/option.h>
#include <dhcp/classify.h>
#include <dhcp/pkt.h>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/shared_array.hpp>
......@@ -35,7 +35,7 @@ namespace dhcp {