diff --git a/Makefile.am b/Makefile.am index 91198a9..3ea1e97 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,6 +13,7 @@ AM_CXXFLAGS = -Wall -pedantic -I@LIBTINS_INCLUDE_DIR@ libtins_la_SOURCES=src/arp.cpp \ src/bootp.cpp \ + src/pppoe.cpp \ src/crypto.cpp \ src/dhcp.cpp \ src/dhcpv6.cpp \ @@ -57,6 +58,7 @@ libtins_include_HEADERS = include/internals.h \ include/dns_record.h \ include/eapol.h \ include/tcp_stream.h \ + include/pppoe.h \ include/ipv6.h \ include/icmpv6.h \ include/endianness.h \ diff --git a/Makefile.in b/Makefile.in index 07abef6..9c1bc66 100644 --- a/Makefile.in +++ b/Makefile.in @@ -100,16 +100,16 @@ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" \ LTLIBRARIES = $(lib_LTLIBRARIES) libtins_la_LIBADD = am__dirstamp = $(am__leading_dot)dirstamp -am_libtins_la_OBJECTS = src/arp.lo src/bootp.lo src/crypto.lo \ - src/dhcp.lo src/dhcpv6.lo src/dns.lo src/dns_record.lo \ - src/dot11.lo src/dot3.lo src/dot1q.lo src/eapol.lo \ - src/ethernetII.lo src/icmp.lo src/icmpv6.lo src/internals.lo \ - src/ip.lo src/ip_address.lo src/ipv6.lo src/ipv6_address.lo \ - src/llc.lo src/loopback.lo src/network_interface.lo \ - src/packet_sender.lo src/packet_writer.lo src/pdu.lo \ - src/radiotap.lo src/rawpdu.lo src/rsn_information.lo \ - src/sll.lo src/snap.lo src/sniffer.lo src/tcp.lo \ - src/tcp_stream.lo src/udp.lo src/utils.lo +am_libtins_la_OBJECTS = src/arp.lo src/bootp.lo src/pppoe.lo \ + src/crypto.lo src/dhcp.lo src/dhcpv6.lo src/dns.lo \ + src/dns_record.lo src/dot11.lo src/dot3.lo src/dot1q.lo \ + src/eapol.lo src/ethernetII.lo src/icmp.lo src/icmpv6.lo \ + src/internals.lo src/ip.lo src/ip_address.lo src/ipv6.lo \ + src/ipv6_address.lo src/llc.lo src/loopback.lo \ + src/network_interface.lo src/packet_sender.lo \ + src/packet_writer.lo src/pdu.lo src/radiotap.lo src/rawpdu.lo \ + src/rsn_information.lo src/sll.lo src/snap.lo src/sniffer.lo \ + src/tcp.lo src/tcp_stream.lo src/udp.lo src/utils.lo libtins_la_OBJECTS = $(am_libtins_la_OBJECTS) libtins_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ @@ -285,6 +285,7 @@ libtins_la_LDFLAGS = -version-info @LIBTINS_VERSION@ AM_CXXFLAGS = -Wall -pedantic -I@LIBTINS_INCLUDE_DIR@ libtins_la_SOURCES = src/arp.cpp \ src/bootp.cpp \ + src/pppoe.cpp \ src/crypto.cpp \ src/dhcp.cpp \ src/dhcpv6.cpp \ @@ -329,6 +330,7 @@ libtins_include_HEADERS = include/internals.h \ include/dns_record.h \ include/eapol.h \ include/tcp_stream.h \ + include/pppoe.h \ include/ipv6.h \ include/icmpv6.h \ include/endianness.h \ @@ -446,6 +448,7 @@ src/$(DEPDIR)/$(am__dirstamp): @: > src/$(DEPDIR)/$(am__dirstamp) src/arp.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/bootp.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) +src/pppoe.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/crypto.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/dhcp.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/dhcpv6.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) @@ -538,6 +541,8 @@ mostlyclean-compile: -rm -f src/packet_writer.lo -rm -f src/pdu.$(OBJEXT) -rm -f src/pdu.lo + -rm -f src/pppoe.$(OBJEXT) + -rm -f src/pppoe.lo -rm -f src/radiotap.$(OBJEXT) -rm -f src/radiotap.lo -rm -f src/rawpdu.$(OBJEXT) @@ -587,6 +592,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/packet_sender.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/packet_writer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/pdu.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/pppoe.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/radiotap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/rawpdu.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/rsn_information.Plo@am__quote@ diff --git a/include/constants.h b/include/constants.h index dbd5d25..3084781 100644 --- a/include/constants.h +++ b/include/constants.h @@ -84,6 +84,7 @@ namespace Tins { VLAN = 0x8100, /* IEEE 802.1Q VLAN tagging */ IPX = 0x8137, /* IPX */ IPV6 = 0x86dd, /* IP protocol version 6 */ + PPPOED = 0x8863, /* PPPoE Discovery */ EAPOL = 0x888e, /* EAPOL */ LOOPBACK = 0x9000 /* used to test interfaces */ }; diff --git a/include/dot1q.h b/include/dot1q.h index 0fb234b..1b8c21f 100644 --- a/include/dot1q.h +++ b/include/dot1q.h @@ -41,6 +41,7 @@ public: * This PDU's flag. */ static const PDU::PDUType pdu_flag = PDU::DOT1Q; + /** * Default constructor */ @@ -177,6 +178,7 @@ public: private: void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); + TINS_BEGIN_PACK struct dot1q_hdr { #if TINS_IS_BIG_ENDIAN uint16_t priority:3, @@ -190,7 +192,7 @@ private: idL:8; uint16_t type; #endif - }; + } TINS_END_PACK; static uint16_t get_id(const dot1q_hdr *hdr); diff --git a/include/pdu.h b/include/pdu.h index 20bee1f..8633ff0 100644 --- a/include/pdu.h +++ b/include/pdu.h @@ -40,6 +40,11 @@ namespace Tins { class PacketSender; + + /** + * The type used to store several PDU option values. + */ + typedef std::vector byte_array; /** \brief Base class for protocol data units. * @@ -55,7 +60,7 @@ namespace Tins { /** * The type that will be returned when serializing PDUs. */ - typedef std::vector serialization_type; + typedef byte_array serialization_type; /** * \brief Enum which identifies each type of PDU. @@ -107,7 +112,8 @@ namespace Tins { ICMPv6, SLL, DHCPv6, - DOT1Q + DOT1Q, + PPPOE }; /** \brief PDU constructor diff --git a/include/pdu_option.h b/include/pdu_option.h index 6eaf8d8..45a6f45 100644 --- a/include/pdu_option.h +++ b/include/pdu_option.h @@ -93,6 +93,25 @@ public: } + /** + * \brief Constructs a PDUOption from iterators, which + * indicate the data to be stored in it. + * + * The length parameter indicates the contents of the length field + * when this option is serialized. Note that this can be different + * to std::distance(start, end). + * + * \param opt The option type. + * \param length The length of this option. + * \param start The beginning of the option data. + * \param end The end of the option data. + */ + template + PDUOption(option_type opt, size_t length, ForwardIterator start, ForwardIterator end) + : option_(opt), size_(length), value_(start, end) { + + } + /** * Retrieves this option's type. * \return uint8_t containing this option's size. @@ -123,9 +142,22 @@ public: } /** - * Retrieves the length of this option's data. + * \brief Retrieves the length of this option's data. + * + * This is the actual size of the data. */ size_t data_size() const { + return value_.size(); + } + + /** + * \brief Retrieves the data length field. + * + * This may be different to the actual size of the data. + * + * \sa data_size. + */ + size_t length_field() const { return size_; } private: diff --git a/include/pppoe.h b/include/pppoe.h new file mode 100644 index 0000000..ad7e526 --- /dev/null +++ b/include/pppoe.h @@ -0,0 +1,430 @@ +/* + * 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_PPPoE_H +#define TINS_PPPoE_H + +#include +#include +#include +#include "pdu.h" +#include "endianness.h" +#include "small_uint.h" +#include "pdu_option.h" +#include "cxxstd.h" + +namespace Tins { +class PPPoE : public PDU { +public: + /** + * The tag types enum. + */ + enum tag_identifiers { + END_OF_LIST = 0, + SERVICE_NAME = 0x101, + #if TINS_IS_LITTLE_ENDIAN + AC_NAME = 0x201, + HOST_UNIQ = 0x301, + AC_COOKIE = 0x401, + VENDOR_SPECIFIC = 0x501, + RELAY_SESSION_ID = 0x101, + SERVICE_NAME_ERROR = 0x201, + AC_SYSTEM_ERROR = 0x202, + GENERIC_ERROR = 0x302 + #else + AC_NAME = 0x102, + HOST_UNIQ = 0x103, + AC_COOKIE = 0x104, + VENDOR_SPECIFIC = 0x105, + RELAY_SESSION_ID = 0x110, + SERVICE_NAME_ERROR = 0x201, + AC_SYSTEM_ERROR = 0x202, + GENERIC_ERROR = 0x203 + #endif + }; + + /** + * The type used to store a TLV option. + */ + typedef PDUOption pppoe_tag; + + /** + * The type used to store the options. + */ + typedef std::list tags_type; + + /** + * The type used to store the Vendor-Specific tag's value. + */ + struct vendor_spec_type { + typedef std::vector data_type; + + uint32_t vendor_id; + data_type data; + + vendor_spec_type(uint32_t vendor_id = 0, const data_type &data = data_type()) + : vendor_id(vendor_id), data(data) { } + }; + + /** + * This PDU's flag. + */ + static const PDU::PDUType pdu_flag = PDU::PPPOE; + + /** + * \brief Default constructor. + * + * This sets the version and type fields to 0x1. + */ + PPPoE(); + + /** + * \brief Constructor which creates an PPPoE object from a buffer. + * + * \param buffer The buffer from which this PDU will be constructed. + * \param total_sz The total size of the buffer. + */ + PPPoE(const uint8_t *buffer, uint32_t total_sz); + + // Getters + + /** + * \brief Getter for the version field. + * \return The stored version field value. + */ + small_uint<4> version() const { + return _header.version; + } + + /** + * \brief Getter for the type field. + * \return The stored type field value. + */ + small_uint<4> type() const { + return _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 session_id field. + * \return The stored session_id field value. + */ + uint16_t session_id() const { + return Endian::be_to_host(_header.session_id); + } + + /** + * \brief Getter for the payload_length field. + * \return The stored payload_length field value. + */ + uint16_t payload_length() const { + return Endian::be_to_host(_header.payload_length); + } + + /** + * \brief Returns the header size. + * + * This metod overrides PDU::header_size. \sa PDU::header_size + */ + uint32_t header_size() const; + + /** + * \brief Returns the list of tags. + */ + const tags_type &tags() const { + return _tags; + } + + /** + * \sa PDU::clone + */ + PPPoE *clone() const { + return new PPPoE(*this); + } + + const pppoe_tag *search_tag(tag_identifiers identifier) const; + + /** + * \brief Getter for the PDU's type. + * \sa PDU::pdu_type + */ + PDUType pdu_type() const { return pdu_flag; } + + // Setters + + /** + * \brief Setter for the version field. + * \param new_version The new version field value. + */ + void version(small_uint<4> new_version); + + /** + * \brief Setter for the type field. + * \param new_type The new type field value. + */ + void type(small_uint<4> 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 session_id field. + * \param new_session_id The new session_id field value. + */ + void session_id(uint16_t new_session_id); + + /** + * \brief Setter for the payload_length field. + * \param new_payload_length The new payload_length field value. + */ + void payload_length(uint16_t new_payload_length); + + /** + * \brief Adds a PPPoE tag. + * + * \param option The option to be added. + */ + void add_tag(const pppoe_tag &option); + + #if TINS_IS_CXX11 + /** + * \brief Adds a PPPoE tag. + * + * This move-constructs the option. + * + * \param option The option to be added. + */ + void add_tag(pppoe_tag &&option); + #endif + + // Option setters + + /** + * \brief Adds an end-of-list tag. + */ + void end_of_list(); + + /** + * \brief Adds a service-name tag. + * + * \param value The service name. + */ + void service_name(const std::string &value); + + /** + * \brief Adds a AC-name tag. + * + * \param value The AC name. + */ + void ac_name(const std::string &value); + + /** + * \brief Adds a host-uniq tag. + * + * \param value The tag's value. + */ + void host_uniq(const byte_array &value); + + /** + * \brief Adds a AC-Cookie tag. + * + * \param value The tag's value. + */ + void ac_cookie(const byte_array &value); + + /** + * \brief Adds a Vendor-Specific tag. + * + * \param value The tag's value. + */ + void vendor_specific(const vendor_spec_type &value); + + /** + * \brief Adds a Relay-Session-Id tag. + * + * \param value The tag's value. + */ + void relay_session_id(const byte_array &value); + + /** + * \brief Adds a Service-Name-Error tag. + * + * \param value The tag's value. + */ + void service_name_error(const std::string &value); + + /** + * \brief Adds a AC-System-Error tag. + * + * \param value The tag's value. + */ + void ac_system_error(const std::string &value); + + /** + * \brief Adds a Generic-Error tag. + * + * \param value The tag's value. + */ + void generic_error(const std::string &value); + + // Option getters + + /** + * \brief Getter for the service-name tag. + * + * This method will throw an option_not_found exception if the + * option is not found. + */ + std::string service_name() const; + + /** + * \brief Getter for the AC-name tag. + * + * This method will throw an option_not_found exception if the + * option is not found. + */ + std::string ac_name() const; + + /** + * \brief Getter for the host-uniq tag. + * + * This method will throw an option_not_found exception if the + * option is not found. + */ + byte_array host_uniq() const; + + /** + * \brief Getter for the AC-Cookie tag. + * + * This method will throw an option_not_found exception if the + * option is not found. + */ + byte_array ac_cookie() const; + + /** + * \brief Getter for the Vendor-Specific tag. + * + * This method will throw an option_not_found exception if the + * option is not found. + */ + vendor_spec_type vendor_specific() const; + + /** + * \brief Getter for the Vendor-Specific tag. + * + * This method will throw an option_not_found exception if the + * option is not found. + */ + byte_array relay_session_id() const; + + /** + * \brief Getter for the Service-Name-Error tag. + * + * This method will throw an option_not_found exception if the + * option is not found. + */ + std::string service_name_error() const; + + /** + * \brief Getter for the AC-System-Error tag. + * + * This method will throw an option_not_found exception if the + * option is not found. + */ + std::string ac_system_error() const; + + /** + * \brief Getter for the Generic-Error tag. + * + * This method will throw an option_not_found exception if the + * option is not found. + */ + std::string generic_error() const; +private: + void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *); + + template + void add_tag_iterable(tag_identifiers id, const T &data) { + add_tag( + pppoe_tag( + id, + data.begin(), + data.end() + ) + ); + } + + template + T retrieve_tag_iterable(tag_identifiers id) const { + const pppoe_tag *tag = search_tag(id); + if(!tag) + throw option_not_found(); + return T(tag->data_ptr(), tag->data_ptr() + tag->data_size()); + } + + template