/* * Copyright (c) 2017, Matias Fontanini * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include using std::string; using std::vector; using std::runtime_error; using Tins::Memory::InputMemoryStream; using Tins::Memory::OutputMemoryStream; namespace Tins { PDU::metadata DHCP::extract_metadata(const uint8_t* /*buffer*/, uint32_t total_sz) { if (TINS_UNLIKELY(total_sz < sizeof(bootp_header))) { throw malformed_packet(); } return metadata(total_sz, pdu_flag, PDU::UNKNOWN); } // Magic cookie: uint32_t. DHCP::DHCP() : size_(sizeof(uint32_t)) { opcode(BOOTREQUEST); htype(1); // ethernet hlen(6); // MAC address length } DHCP::DHCP(const uint8_t* buffer, uint32_t total_sz) : BootP(buffer, total_sz, 0), size_(sizeof(uint32_t)) { InputMemoryStream stream(buffer, total_sz); stream.skip(BootP::header_size() - vend().size()); const uint32_t magic_number = stream.read(); if (magic_number != Endian::host_to_be(0x63825363)) { throw malformed_packet(); } // While there's data left while (stream) { OptionTypes option_type; uint8_t option_length = 0; option_type = (OptionTypes)stream.read(); // We should only read the length if it's not END nor PAD if (option_type != END && option_type != PAD) { option_length = stream.read(); } // Make sure we can read the payload size if (!stream.can_read(option_length)) { throw malformed_packet(); } add_option(option(option_type, option_length, stream.pointer())); stream.skip(option_length); } } void DHCP::add_option(const option& opt) { internal_add_option(opt); options_.push_back(opt); } void DHCP::internal_add_option(const option& opt) { size_ += static_cast(opt.data_size() + (sizeof(uint8_t) << 1)); } bool DHCP::remove_option(OptionTypes type) { options_type::iterator iter = search_option_iterator(type); if (iter == options_.end()) { return false; } size_ -= static_cast(iter->data_size() + (sizeof(uint8_t) << 1)); options_.erase(iter); return true; } const DHCP::option* DHCP::search_option(OptionTypes opt) const { // Search for the iterator. If we found something, return it, otherwise return nullptr. options_type::const_iterator iter = search_option_iterator(opt); return (iter != options_.end()) ? &*iter : 0; } DHCP::options_type::const_iterator DHCP::search_option_iterator(OptionTypes opt) const { return Internals::find_option_const