/* * Copyright (c) 2016, 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 "dhcpv6.h" #include "exceptions.h" #include "memory_helpers.h" using std::find_if; using std::copy; using std::vector; using std::runtime_error; using std::memcpy; using std::equal; using Tins::Memory::InputMemoryStream; using Tins::Memory::OutputMemoryStream; namespace Tins { PDU::metadata DHCPv6::extract_metadata(const uint8_t* /*buffer*/, uint32_t total_sz) { if (TINS_UNLIKELY(total_sz < 2)) { throw malformed_packet(); } return metadata(total_sz, pdu_flag, PDU::UNKNOWN); } DHCPv6::DHCPv6() : header_data_(), options_size_() { } DHCPv6::DHCPv6(const uint8_t* buffer, uint32_t total_sz) : options_size_() { InputMemoryStream stream(buffer, total_sz); if (!stream) { throw malformed_packet(); } // Relay Agent/Server Messages const MessageType message_type = (MessageType)*stream.pointer(); bool is_relay_msg = (message_type == RELAY_FORWARD || message_type == RELAY_REPLY); uint32_t required_size = is_relay_msg ? 2 : 4; stream.read(&header_data_, required_size); if (is_relay_message()) { stream.read(link_addr_); stream.read(peer_addr_); } while (stream) { uint16_t opt = stream.read_be(); uint16_t data_size = stream.read_be(); if (!stream.can_read(data_size)) { throw malformed_packet(); } add_option(option(opt, stream.pointer(), stream.pointer() + data_size)); stream.skip(data_size); } } void DHCPv6::add_option(const option& opt) { options_.push_back(opt); options_size_ += opt.data_size() + sizeof(uint16_t) * 2; } bool DHCPv6::remove_option(OptionTypes type) { options_type::iterator iter = search_option_iterator(type); if (iter == options_.end()) { return false; } options_size_ -= iter->data_size() + sizeof(uint16_t) * 2; options_.erase(iter); return true; } const DHCPv6::option* DHCPv6::search_option(OptionTypes type) const { // Search for the iterator. If we found something, return it, otherwise return nullptr. options_type::const_iterator iter = search_option_iterator(type); return (iter != options_.end()) ? &*iter : 0; } DHCPv6::options_type::const_iterator DHCPv6::search_option_iterator(OptionTypes type) const { Internals::option_type_equality_comparator