diff --git a/include/bootp.h b/include/bootp.h index 6e84329..4c07cc0 100644 --- a/include/bootp.h +++ b/include/bootp.h @@ -23,10 +23,9 @@ #define __BOOTP_H #include - #include - #include "pdu.h" +#include "utils.h" namespace Tins { @@ -104,17 +103,17 @@ namespace Tins { /** \brief Getter for the xid field. * \return The xid field for this BootP PDU. */ - uint32_t xid() const { return _bootp.xid; } + uint32_t xid() const { return Utils::net_to_host_l(_bootp.xid); } /** \brief Getter for the secs field. * \return The secs field for this BootP PDU. */ - uint16_t secs() const { return _bootp.secs; } + uint16_t secs() const { return Utils::net_to_host_s(_bootp.secs); } /** \brief Getter for the padding field. * \return The padding field for this BootP PDU. */ - uint16_t padding() const { return _bootp.padding; } + uint16_t padding() const { return Utils::net_to_host_s(_bootp.padding); } /** \brief Getter for the ciaddr field. * \return The ciaddr field for this BootP PDU. @@ -223,19 +222,20 @@ namespace Tins { void giaddr(uint32_t new_giaddr); /** \brief Setter for the chaddr field. + * The new_chaddr pointer must be at least BOOTP::hlen() bytes long. * \param new_chaddr The chaddr to be set. */ - void chaddr(uint8_t *new_chaddr); + void chaddr(const uint8_t *new_chaddr); /** \brief Setter for the sname field. * \param new_sname The sname to be set. */ - void sname(uint8_t *new_sname); + void sname(const uint8_t *new_sname); /** \brief Setter for the file field. * \param new_file The file to be set. */ - void file(uint8_t *new_file); + void file(const uint8_t *new_file); /** \brief Setter for the vend field. * \param new_vend The vend to be set. diff --git a/include/dhcp.h b/include/dhcp.h index 8e23ddf..bc347b4 100644 --- a/include/dhcp.h +++ b/include/dhcp.h @@ -41,14 +41,14 @@ namespace Tins { * \brief DHCP flags. */ enum Flags { - DHCPDISCOVER = 1, - DHCPOFFER = 2, - DHCPREQUEST = 3, - DHCPDECLINE = 4, - DHCPACK = 5, - DHCPNAK = 6, - DHCPRELEASE = 7, - DHCPINFORM = 8 + DISCOVER = 1, + OFFER = 2, + REQUEST = 3, + DECLINE = 4, + ACK = 5, + NAK = 6, + RELEASE = 7, + INFORM = 8 }; /** @@ -201,6 +201,13 @@ namespace Tins { * \return True if the option was added successfully. */ bool add_option(Options opt, uint8_t len, const uint8_t *val); + + /** + * \brief Searchs for an option that matchs the given flag. + * \param opt_flag The flag to be searched. + * \return A pointer to the option, or 0 if it was not found. + */ + const DHCPOption *search_option(Options opt) const; /** * \brief Adds a type option the the option list. @@ -209,6 +216,13 @@ namespace Tins { */ bool add_type_option(Flags type); + /** + * \brief Searchs for a type option. + * \param value A pointer in which the option's value will be stored. + * \return True if the option was found, false otherwise. + */ + bool search_type_option(uint8_t *value); + /** * \brief Adds a server identifier option. * \param ip The ip of the server. @@ -216,6 +230,13 @@ namespace Tins { */ bool add_server_identifier(uint32_t ip); + /** + * \brief Searchs for a server identifier option. + * \param value A pointer in which the option's value will be stored. + * \return True if the option was found, false otherwise. + */ + bool search_server_identifier(uint32_t *value); + /** * \brief Adds an IP address lease time option. * \param time The lease time. @@ -223,6 +244,13 @@ namespace Tins { */ bool add_lease_time(uint32_t time); + /** + * \brief Searchs for a lease time option. + * \param value A pointer in which the option's value will be stored. + * \return True if the option was found, false otherwise. + */ + bool search_lease_time(uint32_t *value); + /** * \brief Adds a subnet mask option. * \param mask The subnet mask. @@ -230,6 +258,13 @@ namespace Tins { */ bool add_subnet_mask(uint32_t mask); + /** + * \brief Searchs for a subnet mask option. + * \param value A pointer in which the option's value will be stored. + * \return True if the option was found, false otherwise. + */ + bool search_subnet_mask(uint32_t *value); + /** * \brief Adds a routers option. * \param routers A list of ip addresses in integer notation. @@ -237,12 +272,26 @@ namespace Tins { */ bool add_routers_option(const std::list &routers); + /** + * \brief Searchs for a routers option. + * \param routers A pointer in which the option's value will be stored. + * \return True if the option was found, false otherwise. + */ + bool search_routers_option(std::list *routers); + /** * \brief Adds a domain name servers option. * \param dns 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); + bool add_dns_option(const std::list &dns); + + /** + * \brief Searchs for a dns option. + * \param dns A pointer in which the option's value will be stored. + * \return True if the option was found, false otherwise. + */ + bool search_dns_option(std::list *dns); /** * \brief Adds a broadcast address option. @@ -251,6 +300,13 @@ namespace Tins { */ bool add_broadcast_option(uint32_t addr); + /** + * \brief Searchs for a broadcast option. + * \param value A pointer in which the option's value will be stored. + * \return True if the option was found, false otherwise. + */ + bool search_broadcast_option(uint32_t *value); + /** * \brief Adds a domain name option. * \param name The domain name. @@ -258,6 +314,13 @@ namespace Tins { */ bool add_domain_name(const std::string &name); + /** + * \brief Searchs for a domain name option. + * \param value A pointer in which the option's value will be stored. + * \return True if the option was found, false otherwise. + */ + bool search_domain_name(std::string *value); + /** \brief Getter for the options list. * \return The option list. */ @@ -288,6 +351,19 @@ namespace Tins { void copy_fields(const DHCP *other); void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); + template bool generic_search(Options opt, T *value) { + const DHCPOption *option = search_option(opt); + if(option && option->length == sizeof(T)) { + *value = *(T*)option->value; + return true; + } + return false; + } + + bool generic_search(Options opt, std::list *container); + + bool generic_search(Options opt, std::string *str); + uint8_t *serialize_list(const std::list &int_list, uint32_t &sz); std::list _options; diff --git a/src/bootp.cpp b/src/bootp.cpp index 8574927..aec5793 100644 --- a/src/bootp.cpp +++ b/src/bootp.cpp @@ -2,7 +2,6 @@ #include #include #include "bootp.h" -#include "utils.h" Tins::BootP::BootP() : PDU(255), _vend_size(64) { @@ -71,30 +70,30 @@ void Tins::BootP::padding(uint16_t new_padding) { } void Tins::BootP::ciaddr(uint32_t new_ciaddr) { - _bootp.ciaddr = Utils::net_to_host_l(new_ciaddr); + _bootp.ciaddr = new_ciaddr; } void Tins::BootP::yiaddr(uint32_t new_yiaddr) { - _bootp.yiaddr = Utils::net_to_host_l(new_yiaddr); + _bootp.yiaddr = new_yiaddr; } void Tins::BootP::siaddr(uint32_t new_siaddr) { - _bootp.siaddr = Utils::net_to_host_l(new_siaddr); + _bootp.siaddr = new_siaddr; } void Tins::BootP::giaddr(uint32_t new_giaddr) { - _bootp.giaddr = Utils::net_to_host_l(new_giaddr); + _bootp.giaddr = new_giaddr; } -void Tins::BootP::chaddr(uint8_t *new_chaddr) { +void Tins::BootP::chaddr(const uint8_t *new_chaddr) { std::memcpy(_bootp.chaddr, new_chaddr, _bootp.hlen); } -void Tins::BootP::sname(uint8_t *new_sname) { +void Tins::BootP::sname(const uint8_t *new_sname) { std::memcpy(_bootp.sname, new_sname, sizeof(_bootp.sname)); } -void Tins::BootP::file(uint8_t *new_file) { +void Tins::BootP::file(const uint8_t *new_file) { std::memcpy(_bootp.file, new_file, sizeof(_bootp.file)); } diff --git a/src/dhcp.cpp b/src/dhcp.cpp index 4abad7f..092d00d 100644 --- a/src/dhcp.cpp +++ b/src/dhcp.cpp @@ -24,6 +24,7 @@ #include #include "utils.h" #include "dhcp.h" +#include "ethernetII.h" const uint32_t Tins::DHCP::MAX_DHCP_SIZE = 312; @@ -34,18 +35,24 @@ using namespace std; Tins::DHCP::DHCP() : _size(sizeof(uint32_t) + 1) { opcode(BOOTREQUEST); htype(1); //ethernet - hlen(6); + hlen(EthernetII::ADDR_SIZE); } -Tins::DHCP::DHCP(const uint8_t *buffer, uint32_t total_sz) : BootP(buffer, total_sz, 0) { - buffer += BootP::header_size(); - total_sz -= BootP::header_size(); +Tins::DHCP::DHCP(const uint8_t *buffer, uint32_t total_sz) : BootP(buffer, total_sz, 0), _size(sizeof(uint32_t) + 1){ + buffer += BootP::header_size() - vend_size(); + total_sz -= BootP::header_size() - vend_size(); uint8_t args[2] = {0}; + if(total_sz < sizeof(uint32_t) || *(uint32_t*)buffer != Utils::net_to_host_l(0x63825363)) + throw std::runtime_error("Not enough size for a DHCP header in the buffer."); + buffer += sizeof(uint32_t); + total_sz -= sizeof(uint32_t); while(total_sz) { - for(unsigned i(0); i < 2 && args[0] != END && args[0] != PAD; ++i) { + for(unsigned i(0); i < 2; ++i) { args[i] = *(buffer++); total_sz--; - if(!total_sz) + if(args[0] == END || args[0] == PAD) + i = 2; + else if(!total_sz) throw std::runtime_error("Not enough size for a DHCP header in the buffer."); } // If the END-OF-OPTIONS was not found... @@ -98,21 +105,49 @@ bool Tins::DHCP::add_option(Options opt, uint8_t len, const uint8_t *val) { return true; } +const Tins::DHCP::DHCPOption *Tins::DHCP::search_option(Options opt) const{ + for(std::list::const_iterator it = _options.begin(); it != _options.end(); ++it) { + if(it->option == opt) + return &(*it); + } + return 0; +} + bool Tins::DHCP::add_type_option(Flags type) { - return add_option(DHCP_MESSAGE_TYPE, 1, (const uint8_t*)&type); + return add_option(DHCP_MESSAGE_TYPE, sizeof(uint8_t), (const uint8_t*)&type); +} + +bool Tins::DHCP::search_type_option(uint8_t *value) { + return generic_search(DHCP_MESSAGE_TYPE, value); } bool Tins::DHCP::add_server_identifier(uint32_t ip) { - return add_option(DHCP_SERVER_IDENTIFIER, 4, (const uint8_t*)&ip); + return add_option(DHCP_SERVER_IDENTIFIER, sizeof(uint32_t), (const uint8_t*)&ip); +} + +bool Tins::DHCP::search_server_identifier(uint32_t *value) { + return generic_search(DHCP_SERVER_IDENTIFIER, value); } bool Tins::DHCP::add_lease_time(uint32_t time) { time = Utils::net_to_host_l(time); - return add_option(DHCP_LEASE_TIME, 4, (const uint8_t*)&time); + return add_option(DHCP_LEASE_TIME, sizeof(uint32_t), (const uint8_t*)&time); +} + +bool Tins::DHCP::search_lease_time(uint32_t *value) { + if(generic_search(DHCP_LEASE_TIME, value)) { + *value = Utils::net_to_host_l(*value); + return true; + } + return false; } bool Tins::DHCP::add_subnet_mask(uint32_t mask) { - return add_option(SUBNET_MASK, 4, (const uint8_t*)&mask); + return add_option(SUBNET_MASK, sizeof(uint32_t), (const uint8_t*)&mask); +} + +bool Tins::DHCP::search_subnet_mask(uint32_t *value) { + return generic_search(SUBNET_MASK, value); } bool Tins::DHCP::add_routers_option(const list &routers) { @@ -123,7 +158,11 @@ bool Tins::DHCP::add_routers_option(const list &routers) { return ret; } -bool Tins::DHCP::add_dns_options(const list &dns) { +bool Tins::DHCP::search_routers_option(std::list *routers) { + return generic_search(ROUTERS, routers); +} + +bool Tins::DHCP::add_dns_option(const list &dns) { uint32_t size; uint8_t *buffer = serialize_list(dns, size); bool ret = add_option(DOMAIN_NAME_SERVERS, size, buffer); @@ -131,14 +170,26 @@ bool Tins::DHCP::add_dns_options(const list &dns) { return ret; } +bool Tins::DHCP::search_dns_option(std::list *dns) { + return generic_search(DOMAIN_NAME_SERVERS, dns); +} + bool Tins::DHCP::add_broadcast_option(uint32_t addr) { return add_option(BROADCAST_ADDRESS, 4, (uint8_t*)&addr); } +bool Tins::DHCP::search_broadcast_option(uint32_t *value) { + return generic_search(BROADCAST_ADDRESS, value); +} + bool Tins::DHCP::add_domain_name(const string &name) { return add_option(DOMAIN_NAME, name.size(), (const uint8_t*)name.c_str()); } +bool Tins::DHCP::search_domain_name(std::string *value) { + return generic_search(DOMAIN_NAME, value); +} + 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; @@ -187,3 +238,26 @@ Tins::PDU *Tins::DHCP::clone_pdu() const { new_pdu->copy_fields(this); return new_pdu; } + +bool Tins::DHCP::generic_search(Options opt, std::list *container) { + const DHCPOption *option = search_option(opt); + if(!option) + return false; + const uint32_t *ptr = (const uint32_t*)option->value; + uint32_t len = option->length; + if((len % sizeof(uint32_t)) != 0) + return false; + while(len) { + container->push_back(*(ptr++)); + len -= sizeof(uint32_t); + } + return true; +} + +bool Tins::DHCP::generic_search(Options opt, std::string *str) { + const DHCPOption *option = search_option(opt); + if(!option) + return false; + *str = string((const char*)option->value, option->length); + return true; +}