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:
120
include/ip.h
120
include/ip.h
@@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
81
src/ip.cpp
81
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<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
133
tests/src/ip.cpp
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user