diff --git a/include/dhcp.h b/include/dhcp.h index 9cb830e..3294d57 100644 --- a/include/dhcp.h +++ b/include/dhcp.h @@ -24,6 +24,7 @@ #include +#include #include "bootp.h" @@ -133,7 +134,7 @@ namespace Tins { uint8_t option, length; uint8_t *value; - DHCPOption(uint8_t opt, uint8_t len, uint8_t *val); + DHCPOption(uint8_t opt, uint8_t len, const uint8_t *val); }; /** @@ -144,6 +145,13 @@ namespace Tins { */ DHCP(); + /** + * \brief DHCP destructor + * + * Releases the memory allocated for options. + */ + ~DHCP(); + /** * \brief Adds a new option to this DHCP PDU. * @@ -154,7 +162,7 @@ namespace Tins { * \param val The value of this option. * \return True if the option was added successfully. */ - bool add_option(Options opt, uint8_t len, uint8_t *val); + bool add_option(Options opt, uint8_t len, const uint8_t *val); /** * \brief Adds a type option the the option list. @@ -177,6 +185,41 @@ namespace Tins { */ bool add_lease_time(uint32_t time); + /** + * \brief Adds a subnet mask option. + * \param mask The subnet mask. + * \return True if the option was added successfully. \sa DHCP::add_option + */ + bool add_subnet_mask(uint32_t mask); + + /** + * \brief Adds a routers option. + * \param routers A list of ip addresses in integer notation. + * \return True if the option was added successfully. \sa DHCP::add_option + */ + bool add_routers_option(const std::list &routers); + + /** + * \brief Adds a domain name servers option. + * \param routers A list of ip addresses in integer notation. + * \return True if the option was added successfully. \sa DHCP::add_option + */ + bool add_dns_options(const std::list &dns); + + /** + * \brief Adds a broadcast address option. + * \param addr The broadcast address. + * \return True if the option was added successfully. \sa DHCP::add_option + */ + bool add_broadcast_option(uint32_t addr); + + /** + * \brief Adds a domain name option. + * \param name The domain name. + * \return True if the option was added successfully. \sa DHCP::add_option + */ + bool add_domain_name(const std::string &name); + /** \brief Getter for the options list. * \return The option list. */ @@ -199,6 +242,8 @@ namespace Tins { void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); + uint8_t *serialize_list(const std::list &int_list, uint32_t &sz); + std::list _options; uint32_t _size; }; diff --git a/src/dhcp.cpp b/src/dhcp.cpp index ee17352..fe6c4da 100644 --- a/src/dhcp.cpp +++ b/src/dhcp.cpp @@ -27,6 +27,8 @@ const uint32_t Tins::DHCP::MAX_DHCP_SIZE = 312; +using namespace std; + /* Magic cookie: uint32_t. * end of options: 1 byte. */ Tins::DHCP::DHCP() : _size(sizeof(uint32_t) + 1) { @@ -35,12 +37,19 @@ Tins::DHCP::DHCP() : _size(sizeof(uint32_t) + 1) { hlen(6); } -Tins::DHCP::DHCPOption::DHCPOption(uint8_t opt, uint8_t len, uint8_t *val) : option(opt), length(len) { +Tins::DHCP::~DHCP() { + while(_options.size()) { + delete[] _options.front().value; + _options.pop_front(); + } +} + +Tins::DHCP::DHCPOption::DHCPOption(uint8_t opt, uint8_t len, const uint8_t *val) : option(opt), length(len) { value = new uint8_t[len]; std::memcpy(value, val, len); } -bool Tins::DHCP::add_option(Options opt, uint8_t len, uint8_t *val) { +bool Tins::DHCP::add_option(Options opt, uint8_t len, const uint8_t *val) { uint32_t opt_size = len + (sizeof(uint8_t) << 1); if(_size + opt_size > MAX_DHCP_SIZE) return false; @@ -50,16 +59,53 @@ bool Tins::DHCP::add_option(Options opt, uint8_t len, uint8_t *val) { } bool Tins::DHCP::add_type_option(Flags type) { - return add_option(DHCP_MESSAGE_TYPE, 1, (uint8_t*)&type); + return add_option(DHCP_MESSAGE_TYPE, 1, (const uint8_t*)&type); } bool Tins::DHCP::add_server_identifier(uint32_t ip) { - return add_option(DHCP_SERVER_IDENTIFIER, 4, (uint8_t*)&ip); + return add_option(DHCP_SERVER_IDENTIFIER, 4, (const uint8_t*)&ip); } bool Tins::DHCP::add_lease_time(uint32_t time) { time = Utils::net_to_host_l(time); - return add_option(DHCP_LEASE_TIME, 4, (uint8_t*)&time); + return add_option(DHCP_LEASE_TIME, 4, (const uint8_t*)&time); +} + +bool Tins::DHCP::add_subnet_mask(uint32_t mask) { + return add_option(SUBNET_MASK, 4, (const uint8_t*)&mask); +} + +bool Tins::DHCP::add_routers_option(const list &routers) { + uint32_t size; + uint8_t *buffer = serialize_list(routers, size); + bool ret = add_option(ROUTERS, size, buffer); + delete[] buffer; + return ret; +} + +bool Tins::DHCP::add_dns_options(const list &dns) { + uint32_t size; + uint8_t *buffer = serialize_list(dns, size); + bool ret = add_option(DOMAIN_NAME_SERVERS, size, buffer); + delete[] buffer; + return ret; +} + +bool Tins::DHCP::add_broadcast_option(uint32_t addr) { + return add_option(BROADCAST_ADDRESS, 4, (uint8_t*)&addr); +} + +bool Tins::DHCP::add_domain_name(const string &name) { + return add_option(DOMAIN_NAME, name.size(), (const uint8_t*)name.c_str()); +} + +uint8_t *Tins::DHCP::serialize_list(const list &int_list, uint32_t &sz) { + uint8_t *buffer = new uint8_t[int_list.size() * sizeof(uint32_t)]; + uint32_t *ptr = (uint32_t*)buffer; + for(list::const_iterator it = int_list.begin(); it != int_list.end(); ++it) + *(ptr++) = *it; + sz = sizeof(uint32_t) * int_list.size(); + return buffer; } uint32_t Tins::DHCP::header_size() const { @@ -69,6 +115,7 @@ uint32_t Tins::DHCP::header_size() const { void Tins::DHCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { assert(total_sz >= header_size()); uint8_t *result = new uint8_t[_size], *ptr = result + sizeof(uint32_t); + // Magic cookie *((uint32_t*)result) = Utils::net_to_host_l(0x63825363); for(std::list::const_iterator it = _options.begin(); it != _options.end(); ++it) { *(ptr++) = it->option; @@ -76,6 +123,7 @@ void Tins::DHCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const P std::memcpy(ptr, it->value, it->length); ptr += it->length; } + // End of options result[_size-1] = END; vend(result, _size); BootP::write_serialization(buffer, total_sz, parent); diff --git a/src/udp.cpp b/src/udp.cpp index 417eabd..8199927 100644 --- a/src/udp.cpp +++ b/src/udp.cpp @@ -61,14 +61,14 @@ void Tins::UDP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PD const Tins::IP *ip_packet = dynamic_cast(parent); if(inner_pdu()) length(sizeof(udphdr) + inner_pdu()->size()); + std::memcpy(buffer, &_udp, sizeof(udphdr)); if(!_udp.check && ip_packet) { uint32_t checksum = PDU::pseudoheader_checksum(ip_packet->source_address(), ip_packet->dest_address(), size(), IPPROTO_UDP) + - PDU::do_checksum(buffer + sizeof(udphdr), buffer + total_sz) + PDU::do_checksum((uint8_t*)&_udp, ((uint8_t*)&_udp) + sizeof(udphdr)); + PDU::do_checksum(buffer, buffer + total_sz); while (checksum >> 16) checksum = (checksum & 0xffff)+(checksum >> 16); - _udp.check = Utils::net_to_host_s(~checksum); + ((udphdr*)buffer)->check = Utils::net_to_host_s(~checksum); } - std::memcpy(buffer, &_udp, sizeof(udphdr)); _udp.check = 0; }