1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 02:35:57 +01:00

Added IPTest. Fixed some IP bugs.

This commit is contained in:
Matias Fontanini
2011-09-24 22:59:58 -03:00
parent 8a84910d9d
commit 8f74ddbc30
3 changed files with 253 additions and 81 deletions

View File

@@ -27,7 +27,7 @@
#endif
#include <string>
#include <utility>
#include <vector>
#include <list>
#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<IpOption> _ip_options;
std::list<IPOption> _ip_options;
uint32_t _options_size, _padded_options_size;
};
};

View File

@@ -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<IpOption>::iterator it = this->_ip_options.begin(); it != this->_ip_options.end(); it++) {
for (list<IPOption>::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<IPOption>::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<IPOption>::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<IpOption>::const_iterator it = other->_ip_options.begin(); it != other->_ip_options.end(); ++it) {
IpOption new_opt;
for(list<IPOption>::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);

133
tests/src/ip.cpp Normal file
View File

@@ -0,0 +1,133 @@
#include <gtest/gtest.h>
#include <cstring>
#include <string>
#include <stdint.h>
#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);
}