From 8f74ddbc3062fb1be3c5d945819e52b1c0936754 Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Sat, 24 Sep 2011 22:59:58 -0300 Subject: [PATCH] Added IPTest. Fixed some IP bugs. --- include/ip.h | 120 ++++++++++++++++++++++++++---------------- src/ip.cpp | 81 ++++++++++++++++------------- tests/src/ip.cpp | 133 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 253 insertions(+), 81 deletions(-) create mode 100644 tests/src/ip.cpp diff --git a/include/ip.h b/include/ip.h index dea482f..010f044 100644 --- a/include/ip.h +++ b/include/ip.h @@ -27,7 +27,7 @@ #endif #include #include -#include +#include #include "pdu.h" #include "utils.h" @@ -35,6 +35,10 @@ namespace Tins { /** * \brief Class that represents an IP PDU. + * + * By default, IP PDUs are initialized, setting TTL to IP::DEFAULT_TTL, + * id field to 1 and version to 4. Taking this into account, users + * should set destination and source port and would be enough to send one. */ class IP : public PDU { public: @@ -57,32 +61,54 @@ namespace Tins { /** * \brief Enum indicating the option's id number. * - * Enum OptionNumber indicates the possible IP Options. + * Enum Option indicates the possible IP Options. */ - enum OptionNumber { - IPOPT_END = 0, - IPOPT_NOOP = 1, - IPOPT_SEC = 2, - IPOPT_LSSR = 3, - IPOPT_TIMESTAMP = 4, - IPOPT_EXTSEC = 5, - IPOPT_RR = 7, - IPOPT_SID = 8, - IPOPT_SSRR = 9, - IPOPT_MTUPROBE = 11, - IPOPT_MTUREPLY = 12, - IPOPT_EIP = 17, - IPOPT_TR = 18, - IPOPT_ADDEXT = 19, - IPOPT_RTRALT = 20, - IPOPT_SDB = 21, - IPOPT_DPS = 23, - IPOPT_UMP = 24, - IPOPT_QS = 25 + enum Option { + END = 0, + NOOP = 1, + SEC = 2, + LSSR = 3, + TIMESTAMP = 4, + EXTSEC = 5, + RR = 7, + SID = 8, + SSRR = 9, + MTUPROBE = 11, + MTUREPLY = 12, + EIP = 17, + TR = 18, + ADDEXT = 19, + RTRALT = 20, + SDB = 21, + DPS = 23, + UMP = 24, + QS = 25 }; + + /** + * \brief This class represents an IP option. + */ + struct IPOption { + struct { + #if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int number:5; + unsigned int op_class:2; + unsigned int copied:1; + #elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int copied:1; + unsigned int op_class:2; + unsigned int number:5; + #endif + } type; + uint8_t* optional_data; + uint32_t optional_data_size; + + uint8_t* write(uint8_t* buffer); + } __attribute__((__packed__)); /** * \brief Default constructor. + * Sets the source and destination port to 0. */ IP(); @@ -205,6 +231,11 @@ namespace Tins { * \return The destination address for this IP PDU. */ inline uint32_t dst_addr() const { return Utils::net_to_host_l(_ip.daddr); } + + /** \brief Getter for the version field. + * \return The version for this IP PDU. + */ + inline uint8_t version() const { return _ip.version; } /* Setters */ @@ -291,6 +322,14 @@ namespace Tins { * \param ip The ip address in integer notation. */ void dst_addr(uint32_t ip); + + /** + * \brief Setter for the version field. + * + * \param ver The version field to be set. + */ + void version(uint8_t ver); + /** * \brief Sets an IP option. @@ -301,17 +340,25 @@ namespace Tins { * \param data The data of this options. * \param data_size The data size. */ - void set_option(uint8_t copied, OptionClass op_class, OptionNumber number, uint8_t* data = 0, uint32_t data_size = 0); + void set_option(uint8_t copied, OptionClass op_class, Option number, const uint8_t* data = 0, uint32_t data_size = 0); + + /** + * \brief Searchs for an option that matchs the given flag. + * \param opt_class The option class to be searched. + * \param opt_number The option number to be searched. + * \return A pointer to the option, or 0 if it was not found. + */ + const IPOption *search_option(OptionClass opt_class, Option opt_number) const; /** * \brief Sets the End of List option. */ - void set_option_eol(); + void set_eol_option(); /** * \brief Sets the NOP option. */ - void set_option_noop(); + void set_noop_option(); /** * \brief Sets the security option. @@ -319,7 +366,7 @@ namespace Tins { * \param data The data for this option * \param data_len The length of the data. */ - void set_option_sec(uint8_t* data, uint32_t data_len); + void set_sec_option(const uint8_t* data, uint32_t data_len); /* Add more option setters */ /* Virtual methods */ @@ -401,32 +448,13 @@ namespace Tins { /*The options start here. */ } __attribute__((__packed__)); - struct IpOption { - struct { - #if __BYTE_ORDER == __LITTLE_ENDIAN - unsigned int number:5; - unsigned int op_class:2; - unsigned int copied:1; - #elif __BYTE_ORDER == __BIG_ENDIAN - unsigned int copied:1; - unsigned int op_class:2; - unsigned int number:5; - #endif - } type; - uint8_t* optional_data; - uint32_t optional_data_size; - - uint8_t* write(uint8_t* buffer); - - } __attribute__((__packed__)); - void copy_fields(const IP *other); void init_ip_fields(); void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); void cleanup(); iphdr _ip; - std::vector _ip_options; + std::list _ip_options; uint32_t _options_size, _padded_options_size; }; }; diff --git a/src/ip.cpp b/src/ip.cpp index 0a4fc93..a26a193 100644 --- a/src/ip.cpp +++ b/src/ip.cpp @@ -80,30 +80,30 @@ Tins::IP::IP(const uint8_t *buffer, uint32_t total_sz) : PDU(Constants::IP::PROT /* While the end of the options is not reached read an option */ try { while (total_sz && ptr_buffer < buffer && (*ptr_buffer != 0)) { - IpOption opt_to_add; + IPOption opt_to_add; opt_to_add.optional_data = 0; opt_to_add.optional_data_size = 0; memcpy(&opt_to_add.type, ptr_buffer, sizeof(uint8_t)); ptr_buffer++; switch (opt_to_add.type.number) { /* Multibyte options with length as second byte */ - case IPOPT_SEC: - case IPOPT_LSSR: - case IPOPT_TIMESTAMP: - case IPOPT_EXTSEC: - case IPOPT_RR: - case IPOPT_SID: - case IPOPT_SSRR: - case IPOPT_MTUPROBE: - case IPOPT_MTUREPLY: - case IPOPT_EIP: - case IPOPT_TR: - case IPOPT_ADDEXT: - case IPOPT_RTRALT: - case IPOPT_SDB: - case IPOPT_DPS: - case IPOPT_UMP: - case IPOPT_QS: + case SEC: + case LSSR: + case TIMESTAMP: + case EXTSEC: + case RR: + case SID: + case SSRR: + case MTUPROBE: + case MTUREPLY: + case EIP: + case TR: + case ADDEXT: + case RTRALT: + case SDB: + case DPS: + case UMP: + case QS: if(!total_sz || *ptr_buffer == 0) throw std::runtime_error(msg); opt_to_add.optional_data_size = *ptr_buffer - 1; @@ -155,7 +155,7 @@ Tins::IP::~IP() { } void Tins::IP::cleanup() { - for (vector::iterator it = this->_ip_options.begin(); it != this->_ip_options.end(); it++) { + for (list::iterator it = _ip_options.begin(); it != _ip_options.end(); it++) { delete[] it->optional_data; } } @@ -216,28 +216,31 @@ void Tins::IP::dst_addr(uint32_t ip) { } void Tins::IP::head_len(uint8_t new_head_len) { - this->_ip.ihl = new_head_len; + _ip.ihl = new_head_len; } -void Tins::IP::set_option_eol() { - this->set_option(0, IP::CONTROL, IP::IPOPT_END); +void Tins::IP::version(uint8_t ver) { + _ip.version = ver; } -void Tins::IP::set_option_noop() { - this->set_option(0, IP::CONTROL, IP::IPOPT_NOOP); +void Tins::IP::set_eol_option() { + this->set_option(0, IP::CONTROL, IP::END); } -void Tins::IP::set_option_sec(uint8_t* data, uint32_t data_len) { - assert(data_len == 10); - this->set_option(1, IP::CONTROL, IP::IPOPT_SEC, data, data_len); +void Tins::IP::set_noop_option() { + this->set_option(0, IP::CONTROL, IP::NOOP); +} + +void Tins::IP::set_sec_option(const uint8_t* data, uint32_t data_len) { + this->set_option(1, IP::CONTROL, IP::SEC, data, data_len); } void Tins::IP::set_option(uint8_t copied, OptionClass op_class, - OptionNumber number, - uint8_t* data, + Option number, + const uint8_t* data, uint32_t data_size) { - IpOption option; + IPOption option; option.type.copied = copied; option.type.op_class = op_class; option.type.number = number; @@ -254,7 +257,15 @@ void Tins::IP::set_option(uint8_t copied, _padded_options_size = padding? (_options_size - padding + 4) : _options_size; } -uint8_t* Tins::IP::IpOption::write(uint8_t* buffer) { +const Tins::IP::IPOption *Tins::IP::search_option(OptionClass opt_class, Option opt_number) const { + for(std::list::const_iterator it = _ip_options.begin(); it != _ip_options.end(); ++it) { + if(it->type.op_class == opt_class && it->type.number == opt_number) + return &(*it); + } + return 0; +} + +uint8_t* Tins::IP::IPOption::write(uint8_t* buffer) { memcpy(buffer, &type, 1); buffer += 1; if (optional_data) { @@ -312,8 +323,8 @@ void Tins::IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU memcpy(buffer, &_ip, sizeof(_ip)); uint8_t* ptr_buffer = buffer + sizeof(_ip); - for(uint32_t i = 0; i < _ip_options.size(); ++i) - ptr_buffer = _ip_options[i].write(ptr_buffer); + for(list::iterator it = _ip_options.begin(); it != _ip_options.end(); ++it) + ptr_buffer = it->write(ptr_buffer); memset(buffer + sizeof(_ip) + _options_size, 0, _padded_options_size - _options_size); @@ -356,8 +367,8 @@ Tins::PDU *Tins::IP::clone_packet(const uint8_t *ptr, uint32_t total_sz) { 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; + for(list::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); diff --git a/tests/src/ip.cpp b/tests/src/ip.cpp new file mode 100644 index 0000000..ae34d89 --- /dev/null +++ b/tests/src/ip.cpp @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include "ip.h" +#include "utils.h" + +using namespace std; +using namespace Tins; + +class IPTest : public testing::Test { +public: + static const uint8_t expected_packet[]; + + void test_equals(const IP &tcp1, const IP &tcp2); +}; + + +TEST_F(IPTest, DefaultConstructor) { + IP ip; + EXPECT_EQ(ip.dst_addr(), 0); + EXPECT_EQ(ip.src_addr(), 0); + EXPECT_EQ(ip.version(), 4); + EXPECT_EQ(ip.id(), 1); + EXPECT_EQ(ip.pdu_type(), PDU::IP); +} + +TEST_F(IPTest, IPIntConstructor) { + IP ip(0x23abcdef, 0xff1443ab); + EXPECT_EQ(ip.dst_addr(), 0x23abcdef); + EXPECT_EQ(ip.src_addr(), 0xff1443ab); + EXPECT_EQ(ip.version(), 4); + EXPECT_EQ(ip.id(), 1); +} + +TEST_F(IPTest, IPStringConstructor) { + string ip1 = "154.33.200.55", ip2 = "192.10.11.52"; + IP ip(ip1, ip2); + EXPECT_EQ(ip.dst_addr(), Utils::ip_to_int(ip1)); + EXPECT_EQ(ip.src_addr(), Utils::ip_to_int(ip2)); + EXPECT_EQ(ip.version(), 4); + EXPECT_EQ(ip.id(), 1); +} + +TEST_F(IPTest, HeadLen) { + IP ip; + ip.head_len(14); + EXPECT_EQ(ip.head_len(), 14); +} + +TEST_F(IPTest, TOS) { + IP ip; + ip.tos(0x7a); + EXPECT_EQ(ip.tos(), 0x7a); +} + +TEST_F(IPTest, TotLen) { + IP ip; + ip.tot_len(0x7f1a); + EXPECT_EQ(ip.tot_len(), 0x7f1a); +} + +TEST_F(IPTest, ID) { + IP ip; + ip.id(0x7f1a); + EXPECT_EQ(ip.id(), 0x7f1a); +} + +TEST_F(IPTest, FragOffset) { + IP ip; + ip.frag_off(0x7f1a); + EXPECT_EQ(ip.frag_off(), 0x7f1a); +} + +TEST_F(IPTest, TTL) { + IP ip; + ip.ttl(0x7f); + EXPECT_EQ(ip.ttl(), 0x7f); +} + +TEST_F(IPTest, Protocol) { + IP ip; + ip.protocol(0x7f); + EXPECT_EQ(ip.protocol(), 0x7f); +} + +TEST_F(IPTest, Check) { + IP ip; + ip.check(0x7f1a); + EXPECT_EQ(ip.check(), 0x7f1a); +} + +TEST_F(IPTest, SrcIPString) { + IP ip; + string string_ip("192.155.32.10"); + ip.src_addr(string_ip); + EXPECT_EQ(ip.src_addr(), Utils::ip_to_int(string_ip)); +} + +TEST_F(IPTest, DstIPString) { + IP ip; + string string_ip("192.155.32.10"); + ip.dst_addr(string_ip); + EXPECT_EQ(ip.dst_addr(), Utils::ip_to_int(string_ip)); +} + +TEST_F(IPTest, SrcIPInt) { + IP ip; + ip.src_addr(0x7f137ab3); + EXPECT_EQ(ip.src_addr(), 0x7f137ab3); +} + +TEST_F(IPTest, DstIPInt) { + IP ip; + ip.dst_addr(0x7f137ab3); + EXPECT_EQ(ip.dst_addr(), 0x7f137ab3); +} + +TEST_F(IPTest, Version) { + IP ip; + ip.version(0xb); + EXPECT_EQ(ip.version(), 0xb); +} + +TEST_F(IPTest, SecOption) { + IP ip; + const uint8_t data[] = { 0x15, 0x17, 0x94, 0x66, 0xff }; + ip.set_sec_option(data, sizeof(data)); + const IP::IPOption *option; + ASSERT_TRUE((option = ip.search_option(IP::CONTROL, IP::SEC))); + ASSERT_EQ(option->optional_data_size, sizeof(data)); + EXPECT_TRUE(memcmp(option->optional_data, data, sizeof(data)) == 0); +}