From 443803caf0d34a3d8870023772e9137c2e68a706 Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Sat, 24 Nov 2012 18:50:21 -0300 Subject: [PATCH] Added ICMPv6 class. It's working. Option getters/setters are missing. --- configure | 2 +- configure.ac | 2 +- depends.d | 24 +- include/icmpv6.h | 509 +++++++++++++++++++++++++++++++++++++++++++ include/ipv6.h | 5 +- include/pdu.h | 3 +- include/tins.h | 1 + src/icmpv6.cpp | 197 +++++++++++++++++ src/ipv6.cpp | 6 +- tests/configure | 139 +++++++----- tests/configure.ac | 2 +- tests/depends.d | 59 ++++- tests/src/icmpv6.cpp | 180 +++++++++++++++ tests/src/ipv6.cpp | 29 +-- 14 files changed, 1067 insertions(+), 91 deletions(-) create mode 100644 include/icmpv6.h create mode 100644 src/icmpv6.cpp create mode 100644 tests/src/icmpv6.cpp diff --git a/configure b/configure index 611e432..ab79daa 100755 --- a/configure +++ b/configure @@ -2516,7 +2516,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -n "$debug" then - CFLAGS="-DDEBUG -g" + CFLAGS="-DTINS_DEBUG -g" else CFLAGS="-O3" fi diff --git a/configure.ac b/configure.ac index 64812db..67673cf 100644 --- a/configure.ac +++ b/configure.ac @@ -5,7 +5,7 @@ AC_LANG(C++) if test -n "$debug" then - CFLAGS="-DDEBUG -g" + CFLAGS="-DTINS_DEBUG -g" else CFLAGS="-O3" fi diff --git a/depends.d b/depends.d index a32f070..249f76c 100644 --- a/depends.d +++ b/depends.d @@ -223,6 +223,16 @@ include/ip_address.h: include/ipv6_address.h: include/hw_address.h: +src/icmpv6.o: src/icmpv6.cpp include/icmpv6.h include/pdu.h \ + include/endianness.h include/small_uint.h + +include/icmpv6.h: + +include/pdu.h: + +include/endianness.h: + +include/small_uint.h: src/ieee802_3.o: src/ieee802_3.cpp include/ieee802_3.h include/pdu.h \ include/endianness.h include/hw_address.h include/network_interface.h \ include/ip_address.h include/packet_sender.h include/llc.h @@ -472,8 +482,8 @@ include/eapol.h: src/sniffer.o: src/sniffer.cpp include/sniffer.h include/pdu.h \ include/ethernetII.h include/endianness.h include/hw_address.h \ include/network_interface.h include/ip_address.h include/radiotap.h \ - include/packet.h include/timestamp.h include/loopback.h include/dot11.h \ - include/small_uint.h include/pdu_option.h + include/packet.h include/timestamp.h include/cxxstd.h include/loopback.h \ + include/dot11.h include/small_uint.h include/pdu_option.h include/sniffer.h: @@ -495,6 +505,8 @@ include/packet.h: include/timestamp.h: +include/cxxstd.h: + include/loopback.h: include/dot11.h: @@ -537,7 +549,7 @@ src/tcp_stream.o: src/tcp_stream.cpp include/rawpdu.h include/pdu.h \ include/tcp_stream.h include/sniffer.h include/ethernetII.h \ include/endianness.h include/hw_address.h include/network_interface.h \ include/ip_address.h include/radiotap.h include/packet.h \ - include/timestamp.h include/loopback.h include/dot11.h \ + include/timestamp.h include/cxxstd.h include/loopback.h include/dot11.h \ include/small_uint.h include/pdu_option.h include/tcp.h include/utils.h \ include/ipv6_address.h include/ip.h @@ -565,6 +577,8 @@ include/packet.h: include/timestamp.h: +include/cxxstd.h: + include/loopback.h: include/dot11.h: @@ -612,7 +626,7 @@ src/utils.o: src/utils.cpp include/utils.h include/ip_address.h \ include/ipv6_address.h include/hw_address.h include/pdu.h include/arp.h \ include/pdu.h include/endianness.h include/ethernetII.h \ include/network_interface.h include/endianness.h \ - include/network_interface.h include/packet_sender.h + include/network_interface.h include/packet_sender.h include/cxxstd.h include/utils.h: @@ -639,3 +653,5 @@ include/endianness.h: include/network_interface.h: include/packet_sender.h: + +include/cxxstd.h: diff --git a/include/icmpv6.h b/include/icmpv6.h new file mode 100644 index 0000000..558986a --- /dev/null +++ b/include/icmpv6.h @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2012, Nasel + * 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. + * + */ + +#ifndef TINS_ICMPV6_H +#define TINS_ICMPV6_H + +#include +#include "pdu.h" +#include "ipv6_address.h" +#include "pdu_option.h" +#include "endianness.h" +#include "small_uint.h" + +namespace Tins { +/** + * Represents an ICMPv6 PDU. + */ +class ICMPv6 : public PDU { +public: + /** + * \brief This PDU's flag. + */ + static const PDU::PDUType pdu_flag = PDU::ICMPv6; + + /** + * The types of ICMPv6 messages + */ + enum Types { + DEST_UNREACHABLE = 1, + PACKET_TOOBIG = 2, + TIME_EXCEEDED = 3, + PARAM_PROBLEM = 4, + ECHO_REQUEST = 128, + ECHO_REPLY = 129, + MGM_QUERY = 130, + MGM_REPORT = 131, + MGM_REDUCTION = 132, + ROUTER_SOLICIT = 133, + ROUTER_ADVERT = 134, + NEIGHBOUR_SOLICIT = 135, + NEIGHBOUR_ADVERT = 136, + REDIRECT = 137, + ROUTER_RENUMBER = 137, + NI_QUERY = 139, + NI_REPLY = 140, + MLD2_REPORT = 143, + DHAAD_REQUEST = 144, + DHAAD_REPLY = 145, + MOBILE_PREFIX_SOL = 146, + MOBILE_PREFIX_ADV = 147 + }; + + /** + * The types of ICMPv6 options. + */ + enum Options { + SOURCE_ADDRESS = 1, + TARGET_ADDRESS, + PREFIX_INFO, + REDIRECT_HEADER, + MTU, + NBMA_SHORT_LIMIT, + ADVERT_INTERVAL, + HOME_AGENT_INFO, + S_ADDRESS_LIST, + T_ADDRESS_LIST, + CGA, + RSA_SIGN, + TIMESTAMP, + NONCE, + TRUST_ANCHOR, + CERTIFICATE, + IP_PREFIX, + NEW_ROUTER_PREFIX, + LINK_ADDRESS, + NEIGHBOUR_ADVERT_ACK, + MAP = 23, + ROUTE_INFO, + RECURSIVE_DNS_SERV, + RA_FLAGS_EXT, + HANDOVER_KEY_REQ, + HANDOVER_KEY_REPLY, + HANDOVER_ASSIST_INFO, + MOBILE_NODE_ID, + DNS_SEARCH_LIST, + PROXY_SIGNATURE, + ADDRESS_REG, + SIXLOWPAN_CONTEXT, + AUTHORITATIVE_BORDER_ROUTER, + CARD_REQUEST = 138, + CARD_REPLY + }; + + /** + * The type used to store addresses. + */ + typedef IPv6Address address_type; + + /** + * The type used to represent ICMPv6 options. + */ + typedef PDUOption icmpv6_option; + + /** + * The type used to store options. + */ + typedef std::list options_type; + + /** + * \brief Constructs an ICMPv6 object. + * + * The type of the constructed object will be an echo request, unless + * you provide another one in the tp parameter. + * + * \param tp The message type of this ICMPv6 object. + */ + ICMPv6(Types tp = ECHO_REQUEST); + + /** + * \brief Constructor which creates an ICMP object from a buffer and + * adds all identifiable PDUs found in the buffer as children of this one. + * + * \param buffer The buffer from which this PDU will be constructed. + * \param total_sz The total size of the buffer. + */ + ICMPv6(const uint8_t *buffer, uint32_t total_sz); + + // Getters + + /** + * \brief Getter for the type field. + * \return The stored type field value. + */ + Types type() const { + return static_cast(_header.type); + } + + /** + * \brief Getter for the code field. + * \return The stored code field value. + */ + uint8_t code() const { + return _header.code; + } + + /** + * \brief Getter for the cksum field. + * \return The stored cksum field value. + */ + uint16_t checksum() const { + return Endian::be_to_host(_header.cksum); + } + + /** + * \brief Getter for the identifier field. + * \return The stored identifier field value. + */ + uint16_t identifier() const { + return Endian::be_to_host(_header.u_echo.identifier); + } + + /** + * \brief Getter for the sequence field. + * \return The stored sequence field value. + */ + uint16_t sequence() const { + return Endian::be_to_host(_header.u_echo.sequence); + } + + /** + * \brief Getter for the override field. + * \return The stored override field value. + */ + small_uint<1> override() const { + return _header.u_nd_advt.override; + } + + /** + * \brief Getter for the solicited field. + * \return The stored solicited field value. + */ + small_uint<1> solicited() const { + return _header.u_nd_advt.solicited; + } + + /** + * \brief Getter for the router field. + * \return The stored router field value. + */ + small_uint<1> router() const { + return _header.u_nd_advt.router; + } + + /** + * \brief Getter for the hop_limit field. + * \return The stored hop_limit field value. + */ + uint8_t hop_limit() const { + return _header.u_nd_ra.hop_limit; + } + + /** + * \brief Getter for the router_pref field. + * \return The stored router_pref field value. + */ + small_uint<2> router_pref() const { + return _header.u_nd_ra.router_pref; + } + + /** + * \brief Getter for the home_agent field. + * \return The stored home_agent field value. + */ + small_uint<1> home_agent() const { + return _header.u_nd_ra.home_agent; + } + + /** + * \brief Getter for the other field. + * \return The stored other field value. + */ + small_uint<1> other() const { + return _header.u_nd_ra.other; + } + + /** + * \brief Getter for the managed field. + * \return The stored managed field value. + */ + small_uint<1> managed() const { + return _header.u_nd_ra.managed; + } + + /** + * \brief Getter for the router_lifetime field. + * \return The stored router_lifetime field value. + */ + uint16_t router_lifetime() const { + return Endian::be_to_host(_header.u_nd_ra.router_lifetime); + } + + /** + * \brief Getter for the reachable_time field. + * \return The stored reachable_time field value. + */ + uint32_t reachable_time() const { + return Endian::be_to_host(reach_time); + } + + /** + * \brief Getter for the retransmit_timer field. + * \return The stored retransmit_timer field value. + */ + uint32_t retransmit_timer() const { + return Endian::be_to_host(retrans_timer); + } + + /** + * \brief Getter for the target address field. + * \return The stored target address field value. + */ + const address_type &target_addr() const { + return _target_address; + } + + // Setters + + /** + * \brief Setter for the type field. + * \param new_type The new type field value. + */ + void type(Types new_type); + + /** + * \brief Setter for the code field. + * \param new_code The new code field value. + */ + void code(uint8_t new_code); + + /** + * \brief Setter for the cksum field. + * \param new_cksum The new cksum field value. + */ + void checksum(uint16_t new_cksum); + + /** + * \brief Setter for the identifier field. + * \param new_identifier The new identifier field value. + */ + void identifier(uint16_t new_identifier); + + /** + * \brief Setter for the sequence field. + * \param new_sequence The new sequence field value. + */ + void sequence(uint16_t new_sequence); + + /** + * \brief Setter for the override field. + * \param new_override The new override field value. + */ + void override(small_uint<1> new_override); + + /** + * \brief Setter for the solicited field. + * \param new_solicited The new solicited field value. + */ + void solicited(small_uint<1> new_solicited); + + /** + * \brief Setter for the router field. + * \param new_router The new router field value. + */ + void router(small_uint<1> new_router); + + /** + * \brief Setter for the hop_limit field. + * \param new_hop_limit The new hop_limit field value. + */ + void hop_limit(uint8_t new_hop_limit); + + /** + * \brief Setter for the router_pref field. + * \param new_router_pref The new router_pref field value. + */ + void router_pref(small_uint<2> new_router_pref); + + /** + * \brief Setter for the home_agent field. + * \param new_home_agent The new home_agent field value. + */ + void home_agent(small_uint<1> new_home_agent); + + /** + * \brief Setter for the other field. + * \param new_other The new other field value. + */ + void other(small_uint<1> new_other); + + /** + * \brief Setter for the managed field. + * \param new_managed The new managed field value. + */ + void managed(small_uint<1> new_managed); + + /** + * \brief Setter for the router_lifetime field. + * \param new_router_lifetime The new router_lifetime field value. + */ + void router_lifetime(uint16_t new_router_lifetime); + + /** + * \brief Setter for the target address field. + * \param new_target_addr The new target address field value. + */ + void target_addr(const address_type &new_target_addr); + + /** + * \brief Setter for the reachable_time field. + * \param new_reachable_time The new reachable_time field value. + */ + void reachable_time(uint32_t new_reachable_time); + + /** + * \brief Setter for the retransmit_timer field. + * \param new_retrans_timer The new retrans_timer field value. + */ + void retransmit_timer(uint32_t new_retrans_timer); + + /** + * \brief Getter for the PDU's type. + * + * \sa PDU::pdu_type + */ + PDUType pdu_type() const { return pdu_flag; } + + /** + * \brief Checks whether this ICMPv6 object has a target_addr field. + * + * This depends on the type field. + */ + bool has_target_addr() const { + return type() == NEIGHBOUR_SOLICIT || + type() == NEIGHBOUR_ADVERT || + type() == REDIRECT; + } + + /** + * \brief Adds an ICMPv6 option. + * + * The option is added after the last option in the option + * fields. + * + * \param option The option to be added + */ + void add_option(const icmpv6_option &option); + + /** + * \brief Returns the header size. + * + * This metod overrides PDU::header_size. This size includes the + * payload and options size. \sa PDU::header_size + */ + uint32_t header_size() const; + + /** + * \brief Searchs for an option that matchs the given flag. + * + * If the header is not found, a null pointer is returned. + * Deleting the returned pointer will result in undefined + * behaviour. + * + * \param id The option identifier to be searched. + */ + const icmpv6_option *search_option(Options id) const; + + /** + * \sa PDU::clone + */ + ICMPv6 *clone() const { + return new ICMPv6(*this); + } +private: + struct icmp6hdr { + uint8_t type; + uint8_t code; + uint16_t cksum; + union { + struct { + uint16_t identifier; + uint16_t sequence; + } u_echo; + + struct { + #if TINS_IS_LITTLE_ENDIAN + uint32_t reserved:5, + override:1, + solicited:1, + router:1, + reserved2:24; + #else + uint32_t router:1, + solicited:1, + override:1, + reserved:29; + #endif + } u_nd_advt; + struct { + uint8_t hop_limit; + #if TINS_IS_LITTLE_ENDIAN + uint8_t reserved:3, + router_pref:2, + home_agent:1, + other:1, + managed:1; + #else + uint8_t managed:1, + other:1, + home_agent:1, + router_pref:2, + reserved:3; + #endif + uint16_t router_lifetime; + } u_nd_ra; + }; + } __attribute__((packed)); + + void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); + bool has_options() const; + uint8_t *write_option(const icmpv6_option &opt, uint8_t *buffer); + void parse_options(const uint8_t *&buffer, uint32_t &total_sz); + + + icmp6hdr _header; + address_type _target_address; + options_type _options; + uint32_t _options_size; + uint32_t reach_time, retrans_timer; +}; +} + + +#endif // TINS_ICMPV6_H diff --git a/include/ipv6.h b/include/ipv6.h index dbd5acd..1adef10 100644 --- a/include/ipv6.h +++ b/include/ipv6.h @@ -41,6 +41,9 @@ namespace Tins { class PacketSender; +/** + * Represents an IPv6 PDU. + */ class IPv6 : public PDU { public: /** @@ -280,7 +283,7 @@ public: * * \param id The header identifier to be searched. */ - const ipv6_ext_header *search_option(ExtensionHeader id) const; + const ipv6_ext_header *search_header(ExtensionHeader id) const; private: void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); void set_last_next_header(uint8_t value); diff --git a/include/pdu.h b/include/pdu.h index 7a34f91..93835e1 100644 --- a/include/pdu.h +++ b/include/pdu.h @@ -102,7 +102,8 @@ namespace Tins { RSNEAPOL, DNS, LOOPBACK, - IPv6 + IPv6, + ICMPv6 }; /** \brief PDU constructor diff --git a/include/tins.h b/include/tins.h index 85844d6..e596ff1 100644 --- a/include/tins.h +++ b/include/tins.h @@ -38,6 +38,7 @@ #include "ieee802_3.h" #include "llc.h" #include "icmp.h" +#include "icmpv6.h" #include "dot11.h" #include "ip.h" #include "ipv6.h" diff --git a/src/icmpv6.cpp b/src/icmpv6.cpp new file mode 100644 index 0000000..ea4f5a4 --- /dev/null +++ b/src/icmpv6.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2012, Nasel + * 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 "icmpv6.h" +#include "rawpdu.h" + +namespace Tins { + +ICMPv6::ICMPv6(Types tp) +: _options_size() +{ + std::memset(&_header, 0, sizeof(_header)); + type(tp); +} + +ICMPv6::ICMPv6(const uint8_t *buffer, uint32_t total_sz) +: _options_size() +{ + if(total_sz < sizeof(_header)) + throw std::runtime_error("Not enough size for an ICMPv6 header"); + std::memcpy(&_header, buffer, sizeof(_header)); + buffer += sizeof(_header); + total_sz -= sizeof(_header); + if(type() == NEIGHBOUR_SOLICIT || type() == NEIGHBOUR_ADVERT || type() == REDIRECT) { + if(total_sz < address_type::address_size) + throw std::runtime_error("Not enough size for the target address"); + target_addr(buffer); + buffer += address_type::address_size; + total_sz -= address_type::address_size; + } + if(type() == ROUTER_ADVERT) { + if(total_sz < sizeof(uint32_t) * 2) + throw std::runtime_error("Not enough size for router advert fields"); + const uint32_t *ptr_32 = (const uint32_t*)buffer; + reach_time = *ptr_32++; + retrans_timer = *ptr_32++; + + buffer += sizeof(uint32_t) * 2; + total_sz -= sizeof(uint32_t) * 2; + } + if(has_options()) + parse_options(buffer, total_sz); + if(total_sz > 0) + inner_pdu(new RawPDU(buffer, total_sz)); +} + +void ICMPv6::parse_options(const uint8_t *&buffer, uint32_t &total_sz) { + while(total_sz > 0) { + if(total_sz < 8 || (buffer[1] * 8) > total_sz) + throw std::runtime_error("Not enough size for options"); + // size(option) = option_size - identifier_size - length_identifier_size + add_option(icmpv6_option(buffer[0], buffer[1] * 8 - sizeof(uint8_t) * 2, buffer + 2)); + total_sz -= buffer[1] * 8; + buffer += buffer[1] * 8; + } +} + +void ICMPv6::type(Types new_type) { + _header.type = new_type; +} + +void ICMPv6::code(uint8_t new_code) { + _header.code = new_code; +} + +void ICMPv6::checksum(uint16_t new_cksum) { + _header.cksum = Endian::host_to_be(new_cksum); +} + +void ICMPv6::identifier(uint16_t new_identifier) { + _header.u_echo.identifier = Endian::host_to_be(new_identifier); +} + +void ICMPv6::sequence(uint16_t new_sequence) { + _header.u_echo.sequence = Endian::host_to_be(new_sequence); +} + +void ICMPv6::override(small_uint<1> new_override) { + _header.u_nd_advt.override = new_override; +} + +void ICMPv6::solicited(small_uint<1> new_solicited) { + _header.u_nd_advt.solicited = new_solicited; +} + +void ICMPv6::router(small_uint<1> new_router) { + _header.u_nd_advt.router = new_router; +} + +void ICMPv6::hop_limit(uint8_t new_hop_limit) { + _header.u_nd_ra.hop_limit = new_hop_limit; +} + +void ICMPv6::router_pref(small_uint<2> new_router_pref) { + _header.u_nd_ra.router_pref = new_router_pref; +} + +void ICMPv6::home_agent(small_uint<1> new_home_agent) { + _header.u_nd_ra.home_agent = new_home_agent; +} + +void ICMPv6::other(small_uint<1> new_other) { + _header.u_nd_ra.other = new_other; +} + +void ICMPv6::managed(small_uint<1> new_managed) { + _header.u_nd_ra.managed = new_managed; +} + +void ICMPv6::router_lifetime(uint16_t new_router_lifetime) { + _header.u_nd_ra.router_lifetime = Endian::host_to_be(new_router_lifetime); +} + +void ICMPv6::reachable_time(uint32_t new_reachable_time) { + reach_time = Endian::host_to_be(new_reachable_time); +} + +void ICMPv6::retransmit_timer(uint32_t new_retrans_timer) { + retrans_timer = Endian::host_to_be(new_retrans_timer); +} + +void ICMPv6::target_addr(const address_type &new_target_addr) { + _target_address = new_target_addr; +} + +uint32_t ICMPv6::header_size() const { + return sizeof(_header) + _options_size; +} + +void ICMPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { + #ifdef TINS_DEBUG + assert(total_sz >= header_size()); + #endif + std::memcpy(buffer, &_header, sizeof(_header)); + for(options_type::const_iterator it = _options.begin(); it != _options.end(); ++it) { + #ifdef TINS_DEBUG + assert(total_sz >= it->data_size() + sizeof(uint8_t) * 2); + total_sz -= it->data_size() + sizeof(uint8_t) * 2; + #endif + buffer = write_option(*it, buffer); + } +} + +// can i haz more? +bool ICMPv6::has_options() const { + return type() == NEIGHBOUR_SOLICIT || + type() == ROUTER_ADVERT; +} + +void ICMPv6::add_option(const icmpv6_option &option) { + _options.push_back(option); + _options_size += option.data_size() + sizeof(uint8_t) * 2; +} + +uint8_t *ICMPv6::write_option(const icmpv6_option &opt, uint8_t *buffer) { + *buffer++ = opt.option(); + *buffer++ = opt.data_size(); + return std::copy(opt.data_ptr(), opt.data_ptr() + opt.data_size(), buffer); +} + +const ICMPv6::icmpv6_option *ICMPv6::search_option(Options id) const { + for(options_type::const_iterator it = _options.begin(); it != _options.end(); ++it) { + if(it->option() == id) + return &*it; + } + return 0; +} +} + diff --git a/src/ipv6.cpp b/src/ipv6.cpp index f76ebd4..9b2da08 100644 --- a/src/ipv6.cpp +++ b/src/ipv6.cpp @@ -12,6 +12,7 @@ #include "tcp.h" #include "udp.h" #include "icmp.h" +#include "icmpv6.h" #include "rawpdu.h" namespace Tins { @@ -62,6 +63,9 @@ IPv6::IPv6(const uint8_t *buffer, uint32_t total_sz) case Constants::IP::PROTO_ICMP: inner_pdu(new Tins::ICMP(buffer, total_sz)); break; + case Constants::IP::PROTO_ICMPV6: + inner_pdu(new Tins::ICMPv6(buffer, total_sz)); + break; default: inner_pdu(new Tins::RawPDU(buffer, total_sz)); break; @@ -176,7 +180,7 @@ void IPv6::add_ext_header(const ipv6_ext_header &header) { headers_size += header.data_size() + sizeof(uint8_t) * 2; } -const IPv6::ipv6_ext_header *IPv6::search_option(ExtensionHeader id) const { +const IPv6::ipv6_ext_header *IPv6::search_header(ExtensionHeader id) const { uint8_t current_header = _header.next_header; headers_type::const_iterator it = ext_headers.begin(); while(it != ext_headers.end() && current_header != id) { diff --git a/tests/configure b/tests/configure index 349b368..2761978 100755 --- a/tests/configure +++ b/tests/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.67 for myconfig 0.1. +# Generated by GNU Autoconf 2.68 for myconfig 0.1. # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -89,6 +89,7 @@ fi IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. +as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -214,11 +215,18 @@ IFS=$as_save_IFS # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. + # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL - exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} + case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; + esac + exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : @@ -1059,7 +1067,7 @@ Try \`$0 --help' for more information" $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac @@ -1339,7 +1347,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF myconfig configure 0.1 -generated by GNU Autoconf 2.67 +generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation @@ -1385,7 +1393,7 @@ sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile @@ -1422,7 +1430,7 @@ sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_cpp @@ -1435,10 +1443,10 @@ fi ac_fn_cxx_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval "test \"\${$3+set}\"" = set; then : + if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 @@ -1501,7 +1509,7 @@ $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" @@ -1510,7 +1518,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_cxx_check_header_mongrel @@ -1551,7 +1559,7 @@ sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_run @@ -1565,7 +1573,7 @@ ac_fn_cxx_check_header_compile () as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -1583,7 +1591,7 @@ fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_cxx_check_header_compile @@ -1628,7 +1636,7 @@ fi # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_link @@ -1637,7 +1645,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by myconfig $as_me 0.1, which was -generated by GNU Autoconf 2.67. Invocation command line was +generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -1895,7 +1903,7 @@ $as_echo "$as_me: loading site script $ac_site_file" >&6;} || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi done @@ -2001,7 +2009,7 @@ if test -z "$CXX"; then set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CXX+set}" = set; then : +if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then @@ -2045,7 +2053,7 @@ do set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : +if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then @@ -2209,7 +2217,7 @@ sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C++ compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } @@ -2252,7 +2260,7 @@ else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 @@ -2311,7 +2319,7 @@ $as_echo "$ac_try_echo"; } >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C++ compiled programs. If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi fi fi @@ -2322,7 +2330,7 @@ rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } -if test "${ac_cv_objext+set}" = set; then : +if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2363,7 +2371,7 @@ sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi @@ -2373,7 +2381,7 @@ OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } -if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : +if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2410,7 +2418,7 @@ ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } -if test "${ac_cv_prog_cxx_g+set}" = set; then : +if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag @@ -2499,7 +2507,7 @@ ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ex ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -CFLAGS="-DDEBUG -g" +CFLAGS="-DTINS_DEBUG -g" ac_ext=cpp @@ -2510,7 +2518,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 $as_echo_n "checking how to run the C++ preprocessor... " >&6; } if test -z "$CXXCPP"; then - if test "${ac_cv_prog_CXXCPP+set}" = set; then : + if ${ac_cv_prog_CXXCPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CXXCPP needs to be expanded @@ -2626,7 +2634,7 @@ else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=cpp @@ -2638,7 +2646,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if test "${ac_cv_path_GREP+set}" = set; then : +if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then @@ -2701,7 +2709,7 @@ $as_echo "$ac_cv_path_GREP" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } -if test "${ac_cv_path_EGREP+set}" = set; then : +if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 @@ -2768,7 +2776,7 @@ $as_echo "$ac_cv_path_EGREP" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } -if test "${ac_cv_header_stdc+set}" = set; then : +if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2910,7 +2918,7 @@ done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_loop in -lpcap" >&5 $as_echo_n "checking for pcap_loop in -lpcap... " >&6; } -if test "${ac_cv_lib_pcap_pcap_loop+set}" = set; then : +if ${ac_cv_lib_pcap_pcap_loop+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -2944,7 +2952,7 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcap_pcap_loop" >&5 $as_echo "$ac_cv_lib_pcap_pcap_loop" >&6; } -if test "x$ac_cv_lib_pcap_pcap_loop" = x""yes; then : +if test "x$ac_cv_lib_pcap_pcap_loop" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPCAP 1 _ACEOF @@ -3023,10 +3031,21 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then - test "x$cache_file" != "x/dev/null" && + if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} - cat confcache >$cache_file + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} @@ -3094,7 +3113,7 @@ LTLIBOBJS=$ac_ltlibobjs -: ${CONFIG_STATUS=./config.status} +: "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" @@ -3195,6 +3214,7 @@ fi IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. +as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3502,7 +3522,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by myconfig $as_me 0.1, which was -generated by GNU Autoconf 2.67. Invocation command line was +generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -3555,7 +3575,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ myconfig config.status 0.1 -configured by $0, generated by GNU Autoconf 2.67, +configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" Copyright (C) 2010 Free Software Foundation, Inc. @@ -3666,7 +3686,7 @@ do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done @@ -3687,9 +3707,10 @@ fi # after its creation but before its name has been assigned to `$tmp'. $debug || { - tmp= + tmp= ac_tmp= trap 'exit_status=$? - { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } @@ -3697,12 +3718,13 @@ $debug || { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -n "$tmp" && test -d "$tmp" + test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. @@ -3724,7 +3746,7 @@ else ac_cs_awk_cr=$ac_cr fi -echo 'BEGIN {' >"$tmp/subs1.awk" && +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF @@ -3752,7 +3774,7 @@ done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h @@ -3800,7 +3822,7 @@ t delim rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK -cat >>"\$tmp/subs1.awk" <<_ACAWK && +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" @@ -3832,7 +3854,7 @@ if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat -fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF @@ -3872,7 +3894,7 @@ do esac case $ac_mode$ac_tag in :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac @@ -3891,7 +3913,7 @@ do for ac_f do case $ac_f in - -) ac_f="$tmp/stdin";; + -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. @@ -3900,7 +3922,7 @@ do [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" @@ -3926,8 +3948,8 @@ $as_echo "$as_me: creating $ac_file" >&6;} esac case $ac_tag in - *:-:* | *:-) cat >"$tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac @@ -4052,21 +4074,22 @@ s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} - rm -f "$tmp/stdin" + rm -f "$ac_tmp/stdin" case $ac_file in - -) cat "$tmp/out" && rm -f "$tmp/out";; - *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; diff --git a/tests/configure.ac b/tests/configure.ac index c023be9..26a49ea 100644 --- a/tests/configure.ac +++ b/tests/configure.ac @@ -3,7 +3,7 @@ AC_INIT(myconfig, 0.1) AC_PROG_CXX() AC_LANG(C++) -CFLAGS="-DDEBUG -g" +CFLAGS="-DTINS_DEBUG -g" AC_CHECK_HEADERS([pcap.h gtest/gtest.h]) AC_CHECK_LIB(pcap, pcap_loop, [], [AC_MSG_ERROR([pcap library is needed!])]) diff --git a/tests/depends.d b/tests/depends.d index 3444ac2..e52a630 100644 --- a/tests/depends.d +++ b/tests/depends.d @@ -113,6 +113,26 @@ src/icmp.o: src/icmp.cpp ../include/icmp.h ../include/pdu.h \ ../include/ipv6_address.h: +../include/hw_address.h: +src/icmpv6.o: src/icmpv6.cpp ../include/icmpv6.h ../include/pdu.h \ + ../include/endianness.h ../include/small_uint.h ../include/utils.h \ + ../include/ip_address.h ../include/ipv6_address.h \ + ../include/hw_address.h + +../include/icmpv6.h: + +../include/pdu.h: + +../include/endianness.h: + +../include/small_uint.h: + +../include/utils.h: + +../include/ip_address.h: + +../include/ipv6_address.h: + ../include/hw_address.h: src/ipaddress.o: src/ipaddress.cpp ../include/ip_address.h \ ../include/utils.h ../include/ip_address.h ../include/ipv6_address.h \ @@ -357,10 +377,10 @@ src/tcp_stream.o: src/tcp_stream.cpp ../include/tcp_stream.h \ ../include/endianness.h ../include/hw_address.h \ ../include/network_interface.h ../include/ip_address.h \ ../include/radiotap.h ../include/packet.h ../include/timestamp.h \ - ../include/loopback.h ../include/dot11.h ../include/small_uint.h \ - ../include/pdu_option.h ../include/tcp.h ../include/utils.h \ - ../include/ipv6_address.h ../include/ip.h ../include/tcp.h \ - ../include/utils.h + ../include/cxxstd.h ../include/loopback.h ../include/dot11.h \ + ../include/small_uint.h ../include/pdu_option.h ../include/tcp.h \ + ../include/utils.h ../include/ipv6_address.h ../include/ip.h \ + ../include/tcp.h ../include/utils.h ../include/tcp_stream.h: @@ -384,6 +404,8 @@ src/tcp_stream.o: src/tcp_stream.cpp ../include/tcp_stream.h \ ../include/timestamp.h: +../include/cxxstd.h: + ../include/loopback.h: ../include/dot11.h: @@ -1147,6 +1169,16 @@ include/tests/dot11.h: ../include/ipv6_address.h: ../include/hw_address.h: +../src/icmpv6.o: ../src/icmpv6.cpp ../include/icmpv6.h ../include/pdu.h \ + ../include/endianness.h ../include/small_uint.h + +../include/icmpv6.h: + +../include/pdu.h: + +../include/endianness.h: + +../include/small_uint.h: ../src/ieee802_3.o: ../src/ieee802_3.cpp ../include/ieee802_3.h \ ../include/pdu.h ../include/endianness.h ../include/hw_address.h \ ../include/network_interface.h ../include/ip_address.h \ @@ -1400,8 +1432,8 @@ include/tests/dot11.h: ../include/pdu.h ../include/ethernetII.h ../include/endianness.h \ ../include/hw_address.h ../include/network_interface.h \ ../include/ip_address.h ../include/radiotap.h ../include/packet.h \ - ../include/timestamp.h ../include/loopback.h ../include/dot11.h \ - ../include/small_uint.h ../include/pdu_option.h + ../include/timestamp.h ../include/cxxstd.h ../include/loopback.h \ + ../include/dot11.h ../include/small_uint.h ../include/pdu_option.h ../include/sniffer.h: @@ -1423,6 +1455,8 @@ include/tests/dot11.h: ../include/timestamp.h: +../include/cxxstd.h: + ../include/loopback.h: ../include/dot11.h: @@ -1466,9 +1500,9 @@ include/tests/dot11.h: ../include/ethernetII.h ../include/endianness.h ../include/hw_address.h \ ../include/network_interface.h ../include/ip_address.h \ ../include/radiotap.h ../include/packet.h ../include/timestamp.h \ - ../include/loopback.h ../include/dot11.h ../include/small_uint.h \ - ../include/pdu_option.h ../include/tcp.h ../include/utils.h \ - ../include/ipv6_address.h ../include/ip.h + ../include/cxxstd.h ../include/loopback.h ../include/dot11.h \ + ../include/small_uint.h ../include/pdu_option.h ../include/tcp.h \ + ../include/utils.h ../include/ipv6_address.h ../include/ip.h ../include/rawpdu.h: @@ -1494,6 +1528,8 @@ include/tests/dot11.h: ../include/timestamp.h: +../include/cxxstd.h: + ../include/loopback.h: ../include/dot11.h: @@ -1543,7 +1579,8 @@ include/tests/dot11.h: ../include/hw_address.h ../include/pdu.h ../include/arp.h \ ../include/pdu.h ../include/endianness.h ../include/ethernetII.h \ ../include/network_interface.h ../include/endianness.h \ - ../include/network_interface.h ../include/packet_sender.h + ../include/network_interface.h ../include/packet_sender.h \ + ../include/cxxstd.h ../include/utils.h: @@ -1570,3 +1607,5 @@ include/tests/dot11.h: ../include/network_interface.h: ../include/packet_sender.h: + +../include/cxxstd.h: diff --git a/tests/src/icmpv6.cpp b/tests/src/icmpv6.cpp new file mode 100644 index 0000000..8608065 --- /dev/null +++ b/tests/src/icmpv6.cpp @@ -0,0 +1,180 @@ +#include +#include +#include +#include +#include "icmpv6.h" +#include "utils.h" +#include "hw_address.h" + +using namespace Tins; + +class ICMPv6Test : public testing::Test { +public: + static const uint8_t expected_packet[]; + static const uint8_t expected_packet1[]; + + void test_equals(const ICMPv6 &icmp1, const ICMPv6 &icmp2); +}; + +const uint8_t ICMPv6Test::expected_packet[] = { + '\x88', '\x00', '\xdc', '\x15', '\xc0', '\x00', '\x00', '\x00', '?', + '\xfe', '\x05', '\x07', '\x00', '\x00', '\x00', '\x01', '\x02', '`', + '\x97', '\xff', '\xfe', '\x07', 'i', '\xea' +}; + +const uint8_t ICMPv6Test::expected_packet1[] = { + '\x86', '\x00', 'F', '%', '@', '\x00', '\x07', '\x08', '\x00', '\x00', + 'u', '0', '\x00', '\x00', '\x03', '\xe8', '\x01', '\x01', '\x00', '`', + '\x97', '\x07', 'i', '\xea', '\x05', '\x01', '\x00', '\x00', '\x00', + '\x00', '\x05', '\xdc', '\x03', '\x04', '@', '\xc0', '\x00', '6', + '\xee', '\x80', '\x00', '6', '\xee', '\x80', '\x00', '\x00', '\x00', + '\x00', '?', '\xfe', '\x05', '\x07', '\x00', '\x00', '\x00', '\x01', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00' +}; + +TEST_F(ICMPv6Test, Constructor) { + ICMPv6 icmp; + EXPECT_EQ(icmp.type(), ICMPv6::ECHO_REQUEST); + EXPECT_EQ(icmp.code(), 0); + EXPECT_EQ(icmp.checksum(), 0); + EXPECT_EQ(icmp.identifier(), 0); + EXPECT_EQ(icmp.sequence(), 0); + EXPECT_EQ(icmp.override(), 0); + EXPECT_EQ(icmp.solicited(), 0); + EXPECT_EQ(icmp.router(), 0); + EXPECT_EQ(icmp.hop_limit(), 0); + EXPECT_EQ(icmp.router_pref(), 0); + EXPECT_EQ(icmp.home_agent(), 0); + EXPECT_EQ(icmp.other(), 0); + EXPECT_EQ(icmp.managed(), 0); + EXPECT_EQ(icmp.router_lifetime(), 0); +} + +TEST_F(ICMPv6Test, ConstructorFromBuffer) { + ICMPv6 icmp(expected_packet, sizeof(expected_packet)); + EXPECT_EQ(icmp.type(), ICMPv6::NEIGHBOUR_ADVERT); + EXPECT_EQ(icmp.code(), 0); + EXPECT_EQ(icmp.checksum(), 0xdc15); + EXPECT_EQ(icmp.solicited(), 1); + EXPECT_EQ(icmp.router(), 1); + EXPECT_EQ(icmp.override(), 0); + EXPECT_EQ(icmp.target_addr(), "3ffe:507:0:1:260:97ff:fe07:69ea"); +} + +TEST_F(ICMPv6Test, ConstructorFromBuffer2) { + ICMPv6 icmp(expected_packet1, sizeof(expected_packet1)); + EXPECT_EQ(icmp.type(), ICMPv6::ROUTER_ADVERT); + EXPECT_EQ(icmp.code(), 0); + EXPECT_EQ(icmp.checksum(), 0x4625); + EXPECT_EQ(icmp.managed(), 0); + EXPECT_EQ(icmp.home_agent(), 0); + EXPECT_EQ(icmp.other(), 0); + EXPECT_EQ(icmp.router_pref(), 0); + EXPECT_EQ(icmp.router_lifetime(), 1800); + EXPECT_EQ(icmp.reachable_time(), 30000); + EXPECT_EQ(icmp.retransmit_timer(), 1000); + const ICMPv6::icmpv6_option *opt = icmp.search_option(ICMPv6::SOURCE_ADDRESS); + ASSERT_TRUE(opt); + EXPECT_EQ(opt->data_size(), 6); + EXPECT_EQ(HWAddress<6>(opt->data_ptr()), "00:60:97:07:69:ea"); + + opt = icmp.search_option(ICMPv6::MTU); + ASSERT_TRUE(opt); + EXPECT_EQ(opt->data_size(), 6); + + opt = icmp.search_option(ICMPv6::PREFIX_INFO); + ASSERT_TRUE(opt); + EXPECT_EQ(opt->data_size(), 30); +} + +TEST_F(ICMPv6Test, Type) { + ICMPv6 icmp; + icmp.type(ICMPv6::MLD2_REPORT); + EXPECT_EQ(icmp.type(), ICMPv6::MLD2_REPORT); +} + +TEST_F(ICMPv6Test, Code) { + ICMPv6 icmp; + icmp.code(0x7a); + EXPECT_EQ(icmp.code(), 0x7a); +} + +TEST_F(ICMPv6Test, Checksum) { + ICMPv6 icmp; + icmp.checksum(0x827f); + EXPECT_EQ(icmp.checksum(), 0x827f); +} + +TEST_F(ICMPv6Test, Identifier) { + ICMPv6 icmp; + icmp.identifier(0x827f); + EXPECT_EQ(icmp.identifier(), 0x827f); +} + +TEST_F(ICMPv6Test, Sequence) { + ICMPv6 icmp; + icmp.sequence(0x827f); + EXPECT_EQ(icmp.sequence(), 0x827f); +} + +TEST_F(ICMPv6Test, Override) { + ICMPv6 icmp; + icmp.override(1); + EXPECT_EQ(icmp.override(), 1); + icmp.override(0); + EXPECT_EQ(icmp.override(), 0); +} + +TEST_F(ICMPv6Test, Solicited) { + ICMPv6 icmp; + icmp.solicited(1); + EXPECT_EQ(icmp.solicited(), 1); + icmp.solicited(0); + EXPECT_EQ(icmp.solicited(), 0); +} + +TEST_F(ICMPv6Test, Router) { + ICMPv6 icmp; + icmp.router(1); + EXPECT_EQ(icmp.router(), 1); + icmp.router(0); + EXPECT_EQ(icmp.router(), 0); +} + +TEST_F(ICMPv6Test, RouterPref) { + ICMPv6 icmp; + icmp.router_pref(1); + EXPECT_EQ(icmp.router_pref(), 1); + icmp.router_pref(0); + EXPECT_EQ(icmp.router_pref(), 0); +} + +TEST_F(ICMPv6Test, HomeAgent) { + ICMPv6 icmp; + icmp.home_agent(1); + EXPECT_EQ(icmp.home_agent(), 1); + icmp.home_agent(0); + EXPECT_EQ(icmp.home_agent(), 0); +} + +TEST_F(ICMPv6Test, Other) { + ICMPv6 icmp; + icmp.other(1); + EXPECT_EQ(icmp.other(), 1); + icmp.other(0); + EXPECT_EQ(icmp.other(), 0); +} + +TEST_F(ICMPv6Test, Managed) { + ICMPv6 icmp; + icmp.managed(1); + EXPECT_EQ(icmp.managed(), 1); + icmp.managed(0); + EXPECT_EQ(icmp.managed(), 0); +} + +TEST_F(ICMPv6Test, RTLifetime) { + ICMPv6 icmp; + icmp.router_lifetime(0x827f); + EXPECT_EQ(icmp.router_lifetime(), 0x827f); +} diff --git a/tests/src/ipv6.cpp b/tests/src/ipv6.cpp index d27b80c..3df871b 100644 --- a/tests/src/ipv6.cpp +++ b/tests/src/ipv6.cpp @@ -6,7 +6,7 @@ #include "tcp.h" #include "udp.h" #include "icmp.h" -#include "rawpdu.h" +#include "icmpv6.h" #include "ipv6_address.h" #include "utils.h" @@ -54,20 +54,20 @@ void IPv6Test::test_equals(IPv6 &ip1, IPv6 &ip2) { EXPECT_EQ(ip1.dst_addr(), ip2.dst_addr()); EXPECT_EQ(ip1.src_addr(), ip2.src_addr()); - EXPECT_EQ(bool(ip1.search_option(IPv6::HOP_BY_HOP)), bool(ip2.search_option(IPv6::HOP_BY_HOP))); - const IPv6::ipv6_ext_header *header1 = ip1.search_option(IPv6::HOP_BY_HOP), - *header2 = ip2.search_option(IPv6::HOP_BY_HOP); + EXPECT_EQ(bool(ip1.search_header(IPv6::HOP_BY_HOP)), bool(ip2.search_header(IPv6::HOP_BY_HOP))); + const IPv6::ipv6_ext_header *header1 = ip1.search_header(IPv6::HOP_BY_HOP), + *header2 = ip2.search_header(IPv6::HOP_BY_HOP); if(header1 && header2) { EXPECT_EQ(header1->data_size(), header2->data_size()); } EXPECT_EQ(bool(ip1.inner_pdu()), bool(ip2.inner_pdu())); - const RawPDU *raw1 = ip1.find_pdu(), *raw2 = ip2.find_pdu(); - ASSERT_EQ(bool(raw1), bool(raw2)); + const ICMPv6 *icmp1 = ip1.find_pdu(), *icmp2 = ip2.find_pdu(); + ASSERT_EQ(bool(icmp1), bool(icmp2)); - if(raw1) { - EXPECT_EQ(raw1->payload(), raw2->payload()); + if(icmp1 && icmp2) { + EXPECT_EQ(icmp1->checksum(), icmp2->checksum()); } } @@ -111,12 +111,15 @@ TEST_F(IPv6Test, ConstructorFromBuffer2) { EXPECT_EQ(ipv6.hop_limit(), 1); EXPECT_EQ(ipv6.dst_addr(), "ff02::16"); EXPECT_EQ(ipv6.src_addr(), "fe80::2d0:9ff:fee3:e8de"); - // This will have to be changed when ICMPv6 is implemented - RawPDU *pdu = ipv6.find_pdu(); - ASSERT_TRUE(pdu); - EXPECT_EQ(pdu->payload_size(), 28); - const IPv6::ipv6_ext_header *header = ipv6.search_option(IPv6::HOP_BY_HOP); + ICMPv6 *pdu = ipv6.find_pdu(); + ASSERT_TRUE(pdu); + EXPECT_EQ(pdu->type(), 143); + EXPECT_EQ(pdu->code(), 0); + EXPECT_EQ(pdu->checksum(), 0x74fe); + EXPECT_EQ(pdu->checksum(), 0x74fe); + + const IPv6::ipv6_ext_header *header = ipv6.search_header(IPv6::HOP_BY_HOP); ASSERT_TRUE(header); EXPECT_EQ(header->data_size(), 6); }