diff --git a/include/bootp.h b/include/bootp.h index 4230771..5772316 100644 --- a/include/bootp.h +++ b/include/bootp.h @@ -133,14 +133,14 @@ namespace Tins { /** \brief Getter for the vend field. * \return The vend field for this BootP PDU. */ - uint8_t *vend() { return _bootp.vend; } + uint8_t *vend() { return _vend; } /** \brief Getter for the vend field. */ uint32_t vend_size() const { return _vend_size; } /** \brief Getter for the header size. - * \return Returns the ARP header size. + * \return Returns the BOOTP header size. * \sa PDU::header_size */ uint32_t header_size() const; @@ -221,6 +221,8 @@ namespace Tins { * \param size The size of the new vend field. */ void vend(uint8_t *new_vend, uint32_t size); + protected: + void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); private: /** * Struct that represents the Bootp datagram. @@ -242,7 +244,6 @@ namespace Tins { uint8_t file[128]; } __attribute__((__packed__)); - void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); bootphdr _bootp; uint8_t *_vend; diff --git a/include/dhcp.h b/include/dhcp.h new file mode 100644 index 0000000..314470e --- /dev/null +++ b/include/dhcp.h @@ -0,0 +1,184 @@ +/* + * libtins is a net packet wrapper library for crafting and + * interpreting sniffed packets. + * + * Copyright (C) 2011 Nasel + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __DHCP_H +#define __DHCP_H + + +#include +#include "bootp.h" + + +namespace Tins { + + /** \brief Class that represents the DHCP PDU. + * + * The end option is added automatically at the end of the option list. + */ + class DHCP : public BootP { + public: + /** \brief DHCP flags. + */ + enum Flags { + DHCPDISCOVER = 1, + DHCPOFFER = 2, + DHCPREQUEST = 3, + DHCPDECLINE = 4, + DHCPACK = 5, + DHCPNAK = 6, + DHCPRELEASE = 7, + DHCPINFORM = 8 + }; + + /** \brief DHCP options enum. + */ + enum Options { + PAD, + SUBNET_MASK, + TIME_OFFSET, + ROUTERS, + TIME_SERVERS, + NAME_SERVERS, + DOMAIN_NAME_SERVERS, + LOG_SERVERS, + COOKIE_SERVERS, + LPR_SERVERS, + IMPRESS_SERVERS, + RESOURCE_LOCATION_SERVERS, + HOST_NAME, + BOOT_SIZE, + MERIT_DUMP, + DOMAIN_NAME, + SWAP_SERVER, + ROOT_PATH, + EXTENSIONS_PATH, + IP_FORWARDING, + NON_LOCAL_SOURCE_ROUTING, + POLICY_FILTER, + MAX_DGRAM_REASSEMBLY, + DEFAULT_IP_TTL, + PATH_MTU_AGING_TIMEOUT, + PATH_MTU_PLATEAU_TABLE, + INTERFACE_MTU, + ALL_SUBNETS_LOCAL, + BROADCAST_ADDRESS, + PERFORM_MASK_DISCOVERY, + MASK_SUPPLIER, + ROUTER_DISCOVERY, + ROUTER_SOLICITATION_ADDRESS, + STATIC_ROUTES, + TRAILER_ENCAPSULATION, + ARP_CACHE_TIMEOUT, + IEEE802_3_ENCAPSULATION, + DEFAULT_TCP_TTL, + TCP_KEEPALIVE_INTERVAL, + TCP_KEEPALIVE_GARBAGE, + NIS_DOMAIN, + NIS_SERVERS, + NTP_SERVERS, + VENDOR_ENCAPSULATED_OPTIONS, + NETBIOS_NAME_SERVERS, + NETBIOS_DD_SERVER, + NETBIOS_NODE_TYPE, + NETBIOS_SCOPE, + FONT_SERVERS, + X_DISPLAY_MANAGER, + DHCP_REQUESTED_ADDRESS, + DHCP_LEASE_TIME, + DHCP_OPTION_OVERLOAD, + DHCP_MESSAGE_TYPE, + DHCP_SERVER_IDENTIFIER, + DHCP_PARAMETER_REQUEST_LIST, + DHCP_MESSAGE, + DHCP_MAX_MESSAGE_SIZE, + DHCP_RENEWAL_TIME, + DHCP_REBINDING_TIME, + VENDOR_CLASS_IDENTIFIER, + DHCP_CLIENT_IDENTIFIER, + NWIP_DOMAIN_NAME, + NWIP_SUBOPTIONS, + USER_CLASS = 77, + FQDN = 81, + DHCP_AGENT_OPTIONS = 82, + SUBNET_SELECTION = 118, + AUTHENTICATE = 210, + END = 255 + }; + + /** \brief DHCP options struct. + */ + struct DHCPOption { + uint8_t option, length; + uint8_t *value; + + DHCPOption(uint8_t opt, uint8_t len, uint8_t *val); + }; + + /** \brief Creates an instance of DHCP. + * + * This sets the hwtype and hlen fields to match the ethernet + * type and length. + */ + DHCP(); + + /** \brief Adds a new option to this DHCP PDU. + * + * This copies the value buffer. Adding options may fail if + * there's not enough size to hold a new option. + * \param opt The option identifier. + * \param len The length of the value field. + * \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); + + /** \brief Adds a type option the the option list. + * \param type The type of this DHCP PDU. + */ + void add_type_option(Flags type); + + /** \brief Getter for the options list. + * \return The option list. + */ + const std::list options() const { return _options; } + + /** + * \brief Getter for the PDU's type. + * \sa PDU::pdu_type + */ + PDUType pdu_type() const { return PDU::UDP; } + + /** \brief Getter for the header size. + * \return Returns the BOOTP header size. + * \sa PDU::header_size + */ + uint32_t header_size() const; + private: + static const uint32_t MAX_DHCP_SIZE; + + void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); + + std::list _options; + uint32_t _size; + }; +}; + +#endif diff --git a/include/pdu.h b/include/pdu.h index 3743fa6..48420f0 100644 --- a/include/pdu.h +++ b/include/pdu.h @@ -56,7 +56,8 @@ namespace Tins { ARP, TCP, UDP, - ICMP + ICMP, + DHCP }; /** \brief PDU constructor diff --git a/include/udp.h b/include/udp.h index d4de486..477f582 100644 --- a/include/udp.h +++ b/include/udp.h @@ -41,7 +41,7 @@ namespace Tins { * \param dport Destination port. * \param sport Source port. * */ - UDP(uint16_t sport = 0, uint16_t dport = 0); + UDP(uint16_t dport = 0, uint16_t sport = 0, PDU *child = 0); /** \brief Returns the destination port @@ -63,6 +63,12 @@ namespace Tins { * \param new_sport The new source port. */ void sport(uint16_t new_sport); + + /** \brief Getter for the length field. + * \param new_len The new length field. + * \return The length field. + */ + void length(uint16_t new_len); /** \brief Set the payload. * @@ -88,7 +94,6 @@ namespace Tins { * \sa PDU::pdu_type */ PDUType pdu_type() const { return PDU::UDP; } - private: struct udphdr { uint16_t sport; diff --git a/src/bootp.cpp b/src/bootp.cpp index 8fd512e..ed6a0a6 100644 --- a/src/bootp.cpp +++ b/src/bootp.cpp @@ -4,16 +4,18 @@ #include "utils.h" -Tins::BootP::BootP() : PDU(255) { +Tins::BootP::BootP() : PDU(255), _vend_size(64) { _vend = new uint8_t[64]; + std::memset(&_bootp, 0, sizeof(bootphdr)); + std::memset(_vend, 0, 64); } Tins::BootP::~BootP() { - delete[] vend; + delete[] _vend; } uint32_t Tins::BootP::header_size() const { - return sizeof(bootphdr); + return sizeof(bootphdr) + _vend_size; } void Tins::BootP::opcode(uint8_t new_opcode) { @@ -61,7 +63,7 @@ void Tins::BootP::giaddr(uint32_t new_giaddr) { } void Tins::BootP::chaddr(uint8_t *new_chaddr) { - std::memcpy(_bootp.chaddr, new_chaddr, sizeof(_bootp.chaddr)); + std::memcpy(_bootp.chaddr, new_chaddr, _bootp.hlen); } void Tins::BootP::sname(uint8_t *new_sname) { @@ -80,6 +82,7 @@ void Tins::BootP::vend(uint8_t *new_vend, uint32_t size) { } void Tins::BootP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { - assert(total_sz >= sizeof(bootphdr)); + assert(total_sz >= sizeof(bootphdr) + _vend_size); std::memcpy(buffer, &_bootp, sizeof(bootphdr)); + std::memcpy(buffer + sizeof(bootphdr), _vend, _vend_size); } diff --git a/src/dhcp.cpp b/src/dhcp.cpp new file mode 100644 index 0000000..546442a --- /dev/null +++ b/src/dhcp.cpp @@ -0,0 +1,52 @@ +#include +#include +#include //borrame +#include "utils.h" +#include "dhcp.h" + +const uint32_t Tins::DHCP::MAX_DHCP_SIZE = 312; + +/* Magic cookie: uint32_t. + * end of options: 1 byte. */ +Tins::DHCP::DHCP() : _size(sizeof(uint32_t) + 1) { + opcode(BOOTREQUEST); + htype(1); //ethernet + hlen(6); +} + +Tins::DHCP::DHCPOption::DHCPOption(uint8_t opt, uint8_t len, 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) { + uint32_t opt_size = len + (sizeof(uint8_t) << 1); + if(_size + opt_size > MAX_DHCP_SIZE) + return false; + _options.push_back(DHCPOption((uint8_t)opt, len, val)); + _size += opt_size; + return true; +} + +void Tins::DHCP::add_type_option(Flags type) { + add_option(DHCP_MESSAGE_TYPE, 1, (uint8_t*)&type); +} + +uint32_t Tins::DHCP::header_size() const { + return BootP::header_size() - vend_size() + _size; +} + +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); + *((uint32_t*)result) = Utils::net_to_host_l(0x63825363); + for(std::list::const_iterator it = _options.begin(); it != _options.end(); ++it) { + *(ptr++) = it->option; + *(ptr++) = it->length; + std::memcpy(ptr++, it->value, it->length); + } + result[_size-1] = END; + vend(result, _size); + BootP::write_serialization(buffer, total_sz, parent); +} + diff --git a/src/pdu.cpp b/src/pdu.cpp index b31c305..cadae31 100644 --- a/src/pdu.cpp +++ b/src/pdu.cpp @@ -20,6 +20,7 @@ */ #include +#include //borrame #include "utils.h" #include "pdu.h" #include "rawpdu.h" diff --git a/src/udp.cpp b/src/udp.cpp index 196cd5d..417eabd 100644 --- a/src/udp.cpp +++ b/src/udp.cpp @@ -29,24 +29,27 @@ #include "ip.h" #include "rawpdu.h" -Tins::UDP::UDP(uint16_t sport, uint16_t dport) : PDU(IPPROTO_UDP) { - _udp.sport = sport; - _udp.dport = dport; +Tins::UDP::UDP(uint16_t dport, uint16_t sport, PDU *child) : PDU(IPPROTO_UDP, child) { + this->dport(dport); + this->sport(sport); _udp.check = 0; _udp.len = 0; } void Tins::UDP::payload(uint8_t *new_payload, uint32_t new_payload_size) { inner_pdu(new RawPDU(new_payload, new_payload_size)); - _udp.len = Utils::net_to_host_s(sizeof(udphdr) + new_payload_size); } void Tins::UDP::dport(uint16_t new_dport) { - _udp.dport = new_dport; + _udp.dport = Utils::net_to_host_s(new_dport); } void Tins::UDP::sport(uint16_t new_sport) { - _udp.sport = new_sport; + _udp.sport = Utils::net_to_host_s(new_sport); +} + +void Tins::UDP::length(uint16_t new_len) { + _udp.len = Utils::net_to_host_s(new_len); } uint32_t Tins::UDP::header_size() const { @@ -56,6 +59,8 @@ uint32_t Tins::UDP::header_size() const { void Tins::UDP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { assert(total_sz >= sizeof(udphdr)); const Tins::IP *ip_packet = dynamic_cast(parent); + if(inner_pdu()) + length(sizeof(udphdr) + inner_pdu()->size()); 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));