diff --git a/include/ethernetII.h b/include/ethernetII.h index dd3e30b..2ed67b3 100644 --- a/include/ethernetII.h +++ b/include/ethernetII.h @@ -74,6 +74,16 @@ namespace Tins { */ EthernetII(const uint8_t *buffer, uint32_t total_sz); + /** + * \brief Copy constructor. + */ + EthernetII(const EthernetII &other); + + /** + * \brief Copy assignment operator. + */ + EthernetII &operator= (const EthernetII &other); + /* Getters */ /** * \brief Getter for the destination's mac address. @@ -176,6 +186,13 @@ namespace Tins { * \sa PDU::clone_packet */ PDU *clone_packet(const uint8_t *ptr, uint32_t total_sz); + + /** + * \brief Clones this PDU. + * + * \sa PDU::clone_pdu + */ + PDU *clone_pdu() const; private: /** * Struct that represents the Ethernet II header @@ -192,6 +209,7 @@ namespace Tins { */ EthernetII(const ethhdr *eth_ptr); + void copy_fields(const EthernetII *other); void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); diff --git a/include/ip.h b/include/ip.h index 5c0cb3b..b877622 100644 --- a/include/ip.h +++ b/include/ip.h @@ -76,6 +76,11 @@ namespace Tins { IPOPT_QS = 25 }; + /** + * \brief Default constructor. + */ + IP(); + /** * \brief Constructor for building the IP PDU taking strings as ip addresses. * @@ -86,7 +91,7 @@ namespace Tins { * \param ip_src string containing the source hostname(optional). * \param child pointer to a PDU which will be set as the inner_pdu for the packet being constructed(optional). */ - IP(const std::string &ip_dst = "", const std::string &ip_src = "", PDU *child = 0); + IP(const std::string &ip_dst, const std::string &ip_src = "", PDU *child = 0); /** * \brief Constructor for building the IP PDU taking integer as ip addresses. @@ -98,7 +103,12 @@ namespace Tins { * \param ip_src The source ip address(optional). * \param child pointer to a PDU which will be set as the inner_pdu for the packet being constructed(optional). */ - IP(uint32_t ip_dst = 0, uint32_t ip_src = 0, PDU *child = 0); + IP(uint32_t ip_dst, uint32_t ip_src = 0, PDU *child = 0); + + /** + * \brief Copy constructor. + */ + IP(const IP &other); /** * \brief Constructor which creates an IP object from a buffer and adds all identifiable @@ -116,6 +126,11 @@ namespace Tins { */ ~IP(); + /** + * \brief Copy assignment operator. + */ + IP &operator= (const IP &other); + /* Getters */ /** @@ -349,6 +364,13 @@ namespace Tins { * \sa PDU::clone_packet */ PDU *clone_packet(const uint8_t *ptr, uint32_t total_sz); + + /** + * \brief Clones this PDU. + * + * \sa PDU::clone_pdu + */ + PDU *clone_pdu() const; private: static const uint8_t DEFAULT_TTL; @@ -398,7 +420,8 @@ namespace Tins { * \param ptr The ip header pointer. */ IP(const iphdr *ptr); - + + void copy_fields(const IP *other); void init_ip_fields(); void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); diff --git a/include/pdu.h b/include/pdu.h index 03595d7..3ffccca 100644 --- a/include/pdu.h +++ b/include/pdu.h @@ -95,12 +95,15 @@ namespace Tins { */ uint32_t size() const; - /** \brief This PDU's type flag identifier. - * + /** + * \brief Getter for this PDU's type flag identifier. + * \return The type flag identifier. */ inline uint32_t flag() const { return _flag; } - /** \brief The child PDU. + /** + * \brief Getter for the inner PDU. + * \return The current inner PDU. Might be 0. */ inline PDU *inner_pdu() const { return _inner_pdu; } @@ -108,7 +111,8 @@ namespace Tins { */ void flag(uint32_t new_flag); - /** \brief Sets the child PDU. + /** + * \brief Sets the child PDU. * * \param next_pdu The new child PDU. * When setting a new inner_pdu, the instance takesownership of @@ -143,6 +147,28 @@ namespace Tins { return 0; } + /** + * \brief Clones this packet. + * + * This method clones this PDU and clones every inner PDU, + * therefore obtaining a clone of the whole inner PDU chain. + * The pointer returned must be deleted by the user. + * \return A pointer to a clone of this packet. + */ + PDU *clone_packet() const; + + /** + * \brief Clones this PDU. + * + * This method does not clone the inner PDUs. \sa PDU::clone_packet + * \return A pointer to a copy of this PDU. + */ + virtual PDU *clone_pdu() const { + /* Should be pure virtual. It's this way to avoid compiling issues. + * Once every pdu has implemented it, make it pure virtual. */ + return 0; + } + /** \brief Send the stack of PDUs through a PacketSender. * * This method will be called only for the PDU on the bottom of the stack, diff --git a/src/ethernetII.cpp b/src/ethernetII.cpp index 7fa793c..df11180 100644 --- a/src/ethernetII.cpp +++ b/src/ethernetII.cpp @@ -73,6 +73,15 @@ Tins::EthernetII::EthernetII(const uint8_t *buffer, uint32_t total_sz) : PDU(ETH inner_pdu(next); } +Tins::EthernetII::EthernetII(const EthernetII &other) : PDU(ETHERTYPE_IP) { + *this = other; +} + +Tins::EthernetII &Tins::EthernetII::operator= (const EthernetII &other) { + copy_fields(&other); + return *this; +} + Tins::EthernetII::EthernetII(const ethhdr *eth_ptr) : PDU(ETHERTYPE_IP) { memcpy(&_eth, eth_ptr, sizeof(ethhdr)); } @@ -176,3 +185,14 @@ Tins::PDU *Tins::EthernetII::clone_packet(const uint8_t *ptr, uint32_t total_sz) cloned->inner_pdu(child); return cloned; } + +void Tins::EthernetII::copy_fields(const EthernetII *other) { + memcpy(&_eth, &other->_eth, sizeof(_eth)); + _iface_index = other->_iface_index; +} + +Tins::PDU *Tins::EthernetII::clone_pdu() const { + EthernetII *new_pdu = new EthernetII(_iface_index); + new_pdu->copy_fields(this); + return new_pdu; +} diff --git a/src/ip.cpp b/src/ip.cpp index 1ba0834..c85aa69 100644 --- a/src/ip.cpp +++ b/src/ip.cpp @@ -46,6 +46,21 @@ Tins::IP::IP(const string &ip_dst, const string &ip_src, PDU *child) : PDU(IPPRO } +Tins::IP::IP(const IP &other) : PDU(IPPROTO_IP) { + *this = other; +} + +Tins::IP::IP() : PDU(IPPROTO_IP) { + init_ip_fields(); +} + +Tins::IP &Tins::IP::operator= (const IP &other) { + copy_fields(&other); + if(other.inner_pdu()) + inner_pdu(other.inner_pdu()->clone_packet()); + return *this; +} + Tins::IP::IP(const uint8_t *buffer, uint32_t total_sz) : PDU(IPPROTO_IP) { if(total_sz < sizeof(iphdr)) throw std::runtime_error("Not enough size for an IP header in the buffer."); @@ -330,3 +345,22 @@ Tins::PDU *Tins::IP::clone_packet(const uint8_t *ptr, uint32_t total_sz) { cloned->inner_pdu(child); return cloned; } + +void Tins::IP::copy_fields(const IP *other) { + memcpy(&_ip, &other->_ip, sizeof(_ip)); + for(vector::const_iterator it = other->_ip_options.begin(); it != other->_ip_options.end(); ++it) { + IpOption new_opt; + if(it->optional_data) { + new_opt.optional_data = new uint8_t[it->optional_data_size]; + memcpy(new_opt.optional_data, it->optional_data, it->optional_data_size); + } + new_opt.optional_data_size = it->optional_data_size; + _ip_options.push_back(new_opt); + } +} + +Tins::PDU *Tins::IP::clone_pdu() const { + IP *new_pdu = new IP(); + new_pdu->copy_fields(this); + return new_pdu; +} diff --git a/src/pdu.cpp b/src/pdu.cpp index 52960e0..090b33e 100644 --- a/src/pdu.cpp +++ b/src/pdu.cpp @@ -80,6 +80,19 @@ Tins::PDU *Tins::PDU::clone_inner_pdu(const uint8_t *ptr, uint32_t total_sz) { return child; } +Tins::PDU *Tins::PDU::clone_packet() const { + PDU *ret = clone_pdu(); + if(ret) { + PDU *ptr = 0, *last = ret; + while(last && last->inner_pdu()) { + ptr = last->inner_pdu()->clone_pdu(); + last->inner_pdu(ptr); + last = ptr; + } + } + return ret; +} + /* Static methods */ uint32_t Tins::PDU::do_checksum(uint8_t *start, uint8_t *end) { uint32_t checksum(0);