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

Added DHCPv6 client/server id options' getters/setters.

This commit is contained in:
Matias Fontanini
2013-01-28 16:23:47 -03:00
parent 5ee0ebb264
commit 0945e0b29e
4 changed files with 307 additions and 2 deletions

View File

@@ -352,6 +352,88 @@ public:
: enterprise_number(enterprise_number),
vendor_class_data(vendor_class_data) { }
};
/**
* The type used to represent DUIDs Based on Link-layer Address Plus
* Time.
*/
struct duid_llt {
static const uint16_t duid_id = 1;
typedef std::vector<uint8_t> lladdress_type;
uint16_t hw_type;
uint32_t time;
lladdress_type lladdress;
duid_llt(uint16_t hw_type = 0, uint32_t time = 0,
const lladdress_type &lladdress = lladdress_type())
: hw_type(hw_type), time(time), lladdress(lladdress) {}
PDU::serialization_type serialize() const;
static duid_llt from_bytes(const uint8_t *buffer, uint32_t total_sz);
};
/**
* The type used to represent DUIDs Based on Enterprise Number
*/
struct duid_en {
static const uint16_t duid_id = 2;
typedef std::vector<uint8_t> identifier_type;
uint32_t enterprise_number;
identifier_type identifier;
duid_en(uint32_t enterprise_number = 0,
const identifier_type &identifier = identifier_type())
: enterprise_number(enterprise_number), identifier(identifier) {}
PDU::serialization_type serialize() const;
static duid_en from_bytes(const uint8_t *buffer, uint32_t total_sz);
};
/**
* The type used to represent DUIDs Based on Link-layer Address.
*/
struct duid_ll {
static const uint16_t duid_id = 3;
typedef std::vector<uint8_t> lladdress_type;
uint16_t hw_type;
lladdress_type lladdress;
duid_ll(uint16_t hw_type = 0,
const lladdress_type &lladdress = lladdress_type())
: hw_type(hw_type), lladdress(lladdress) {}
PDU::serialization_type serialize() const;
static duid_ll from_bytes(const uint8_t *buffer, uint32_t total_sz);
};
/**
* Type type used to represent DUIDs. This will be stored as the
* value for the Client/Server Identifier options.
*/
struct duid_type {
typedef PDU::serialization_type data_type;
uint16_t id;
data_type data;
duid_type(uint16_t id = 0, const data_type &data = data_type())
: id(id), data(data) {}
duid_type(const duid_llt &identifier)
: id(duid_llt::duid_id), data(identifier.serialize()) {}
duid_type(const duid_en &identifier)
: id(duid_en::duid_id), data(identifier.serialize()) {}
duid_type(const duid_ll &identifier)
: id(duid_en::duid_id), data(identifier.serialize()) {}
};
/**
* The type used to store the Option Request option.
@@ -599,6 +681,22 @@ public:
*/
bool has_reconfigure_accept() const;
/**
* \brief Getter for the Client Identifier option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
duid_type client_id() const;
/**
* \brief Getter for the Server Identifier option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
duid_type server_id() const;
// Option setters
/**
@@ -718,6 +816,20 @@ public:
*/
void reconfigure_accept();
/**
* \brief Setter for the Client Identifier option.
*
* \param value The new Client Identifier option data.
*/
void client_id(const duid_type &value);
/**
* \brief Setter for the Server Identifier option.
*
* \param value The new Server Identifier option data.
*/
void server_id(const duid_type &value);
// Other stuff
/**

View File

@@ -332,6 +332,32 @@ bool DHCPv6::has_reconfigure_accept() const {
return search_option(RECONF_ACCEPT);
}
DHCPv6::duid_type DHCPv6::client_id() const {
const dhcpv6_option *opt = safe_search_option<std::less>(
CLIENTID, sizeof(uint16_t) + 1
);
return duid_type(
Endian::be_to_host(*(const uint16_t*)opt->data_ptr()),
serialization_type(
opt->data_ptr() + sizeof(uint16_t),
opt->data_ptr() + opt->data_size()
)
);
}
DHCPv6::duid_type DHCPv6::server_id() const {
const dhcpv6_option *opt = safe_search_option<std::less>(
SERVERID, sizeof(uint16_t) + 1
);
return duid_type(
Endian::be_to_host(*(const uint16_t*)opt->data_ptr()),
serialization_type(
opt->data_ptr() + sizeof(uint16_t),
opt->data_ptr() + opt->data_size()
)
);
}
// ********************************************************************
// Option setters
// ********************************************************************
@@ -512,4 +538,109 @@ void DHCPv6::reconfigure_msg(uint8_t value) {
void DHCPv6::reconfigure_accept() {
add_option(RECONF_ACCEPT);
}
// DUIDs
DHCPv6::duid_llt DHCPv6::duid_llt::from_bytes(const uint8_t *buffer, uint32_t total_sz)
{
// at least one byte for lladdress
if(total_sz < sizeof(uint16_t) + sizeof(uint32_t) + 1)
throw std::runtime_error("Not enough size for a DUID_LLT identifier");
duid_llt output;
output.hw_type = Endian::be_to_host(*(const uint16_t*)buffer);
buffer += sizeof(uint16_t);
output.time = Endian::be_to_host(*(const uint32_t*)buffer);
buffer += sizeof(uint32_t);
total_sz -= sizeof(uint16_t) + sizeof(uint32_t);
output.lladdress.assign(buffer, buffer + total_sz);
return output;
}
PDU::serialization_type DHCPv6::duid_llt::serialize() const {
serialization_type output(sizeof(uint16_t) + sizeof(uint32_t) + lladdress.size());
*(uint16_t*)&output[0] = Endian::host_to_be(hw_type);
*(uint32_t*)&output[sizeof(uint16_t)] = Endian::host_to_be(time);
std::copy(
lladdress.begin(),
lladdress.end(),
output.begin() + sizeof(uint16_t) + sizeof(uint32_t)
);
return output;
}
DHCPv6::duid_en DHCPv6::duid_en::from_bytes(const uint8_t *buffer, uint32_t total_sz)
{
// at least one byte for identifier
if(total_sz < sizeof(uint32_t) + 1)
throw std::runtime_error("Not enough size for a DUID_en identifier");
duid_en output;
output.enterprise_number = Endian::be_to_host(*(const uint32_t*)buffer);
buffer += sizeof(uint32_t);
total_sz -= sizeof(uint32_t);
output.identifier.assign(buffer, buffer + total_sz);
return output;
}
PDU::serialization_type DHCPv6::duid_en::serialize() const {
serialization_type output(sizeof(uint32_t) + identifier.size());
*(uint32_t*)&output[0] = Endian::host_to_be(enterprise_number);
std::copy(
identifier.begin(),
identifier.end(),
output.begin() + sizeof(uint32_t)
);
return output;
}
DHCPv6::duid_ll DHCPv6::duid_ll::from_bytes(const uint8_t *buffer, uint32_t total_sz)
{
// at least one byte for lladdress
if(total_sz < sizeof(uint16_t) + 1)
throw std::runtime_error("Not enough size for a DUID_en identifier");
duid_ll output;
output.hw_type = Endian::be_to_host(*(const uint16_t*)buffer);
buffer += sizeof(uint16_t);
total_sz -= sizeof(uint16_t);
output.lladdress.assign(buffer, buffer + total_sz);
return output;
}
PDU::serialization_type DHCPv6::duid_ll::serialize() const {
serialization_type output(sizeof(uint16_t) + lladdress.size());
*(uint16_t*)&output[0] = Endian::host_to_be(hw_type);
std::copy(
lladdress.begin(),
lladdress.end(),
output.begin() + sizeof(uint16_t)
);
return output;
}
void DHCPv6::client_id(const duid_type &value) {
serialization_type buffer(sizeof(uint16_t) + value.data.size());
*(uint16_t*)&buffer[0] = Endian::host_to_be(value.id);
std::copy(
value.data.begin(),
value.data.end(),
buffer.begin() + sizeof(uint16_t)
);
add_option(
dhcpv6_option(CLIENTID, buffer.begin(), buffer.end())
);
}
void DHCPv6::server_id(const duid_type &value) {
serialization_type buffer(sizeof(uint16_t) + value.data.size());
*(uint16_t*)&buffer[0] = Endian::host_to_be(value.id);
std::copy(
value.data.begin(),
value.data.end(),
buffer.begin() + sizeof(uint16_t)
);
add_option(
dhcpv6_option(SERVERID, buffer.begin(), buffer.end())
);
}
} // namespace Tins

View File

@@ -44,8 +44,8 @@
#include "llc.h"
#include "rawpdu.h"
#if defined(BSD) && !defined(PF_LLC)
// compilation fix, check if it works xD
#if !defined(PF_LLC)
// compilation fix, nasty but at least works on BSD
#define PF_LLC 26
#endif

View File

@@ -275,3 +275,65 @@ TEST_F(DHCPv6Test, ReconfigureAccept) {
dhcp.reconfigure_accept();
EXPECT_EQ(true, dhcp.has_reconfigure_accept());
}
TEST_F(DHCPv6Test, Client_Server_ID_DUIDLL) {
DHCPv6 dhcp;
DHCPv6::duid_ll data, output;
DHCPv6::duid_type tmp, tmp2;
data.hw_type = 0x5f;
data.lladdress.push_back(78);
data.lladdress.push_back(66);
data.lladdress.push_back(209);
dhcp.client_id(data);
tmp = dhcp.client_id();
output = DHCPv6::duid_ll::from_bytes(&tmp.data[0], tmp.data.size());
EXPECT_EQ(data.hw_type, output.hw_type);
EXPECT_EQ(data.lladdress, output.lladdress);
dhcp.server_id(data);
tmp2 = dhcp.server_id();
EXPECT_EQ(tmp.id, tmp2.id);
EXPECT_EQ(tmp.data, tmp2.data);
}
TEST_F(DHCPv6Test, Client_Server_ID_DUIDLLT) {
DHCPv6 dhcp;
DHCPv6::duid_llt data, output;
DHCPv6::duid_type tmp, tmp2;
data.hw_type = 0x5f;
data.time = 0x92837af;
data.lladdress.push_back(78);
data.lladdress.push_back(66);
data.lladdress.push_back(209);
dhcp.client_id(data);
tmp = dhcp.client_id();
output = DHCPv6::duid_llt::from_bytes(&tmp.data[0], tmp.data.size());
EXPECT_EQ(data.hw_type, output.hw_type);
EXPECT_EQ(data.time, output.time);
EXPECT_EQ(data.lladdress, output.lladdress);
dhcp.server_id(data);
tmp2 = dhcp.server_id();
EXPECT_EQ(tmp.id, tmp2.id);
EXPECT_EQ(tmp.data, tmp2.data);
}
TEST_F(DHCPv6Test, Client_Server_ID_DUIDEN) {
DHCPv6 dhcp;
DHCPv6::duid_en data, output;
DHCPv6::duid_type tmp, tmp2;
data.enterprise_number = 0x5faa23da;
data.identifier.push_back(78);
data.identifier.push_back(66);
data.identifier.push_back(209);
dhcp.client_id(data);
tmp = dhcp.client_id();
output = DHCPv6::duid_en::from_bytes(&tmp.data[0], tmp.data.size());
EXPECT_EQ(data.enterprise_number, output.enterprise_number);
EXPECT_EQ(data.identifier, output.identifier);
dhcp.server_id(data);
tmp2 = dhcp.server_id();
EXPECT_EQ(tmp.id, tmp2.id);
EXPECT_EQ(tmp.data, tmp2.data);
}