diff --git a/Makefile.am b/Makefile.am index d88fba9..5181022 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,6 +19,7 @@ libtins_la_SOURCES=src/arp.cpp \ src/dns.cpp \ src/dns_record.cpp \ src/dot11.cpp \ + src/dot1q.cpp \ src/eapol.cpp \ src/ethernetII.cpp \ src/icmp.cpp \ @@ -49,6 +50,7 @@ libtins_includedir = $(includedir)/tins libtins_include_HEADERS = include/internals.h \ include/dhcpv6.h \ include/dot11.h \ + include/dot1q.h \ include/small_uint.h \ include/ip.h \ include/dns_record.h \ diff --git a/Makefile.in b/Makefile.in index 93a2cb2..859ae4c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -57,7 +57,8 @@ subdir = . DIST_COMMON = README $(am__configure_deps) $(libtins_include_HEADERS) \ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/libtins.pc.in $(top_srcdir)/configure AUTHORS THANKS \ - config.guess config.sub depcomp install-sh ltmain.sh missing + TODO config.guess config.sub depcomp install-sh ltmain.sh \ + missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ @@ -101,13 +102,14 @@ 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/eapol.lo src/ethernetII.lo src/icmp.lo \ - src/icmpv6.lo src/ieee802_3.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 + src/dot11.lo src/dot1q.lo src/eapol.lo src/ethernetII.lo \ + src/icmp.lo src/icmpv6.lo src/ieee802_3.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) \ @@ -289,6 +291,7 @@ libtins_la_SOURCES = src/arp.cpp \ src/dns.cpp \ src/dns_record.cpp \ src/dot11.cpp \ + src/dot1q.cpp \ src/eapol.cpp \ src/ethernetII.cpp \ src/icmp.cpp \ @@ -319,6 +322,7 @@ libtins_includedir = $(includedir)/tins libtins_include_HEADERS = include/internals.h \ include/dhcpv6.h \ include/dot11.h \ + include/dot1q.h \ include/small_uint.h \ include/ip.h \ include/dns_record.h \ @@ -448,6 +452,7 @@ src/dhcpv6.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/dns.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/dns_record.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/dot11.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) +src/dot1q.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/eapol.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/ethernetII.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/icmp.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) @@ -499,6 +504,8 @@ mostlyclean-compile: -rm -f src/dns_record.lo -rm -f src/dot11.$(OBJEXT) -rm -f src/dot11.lo + -rm -f src/dot1q.$(OBJEXT) + -rm -f src/dot1q.lo -rm -f src/eapol.$(OBJEXT) -rm -f src/eapol.lo -rm -f src/ethernetII.$(OBJEXT) @@ -563,6 +570,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/dns.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/dns_record.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/dot11.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/dot1q.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/eapol.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/ethernetII.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/icmp.Plo@am__quote@ diff --git a/include/dot1q.h b/include/dot1q.h new file mode 100644 index 0000000..29686cc --- /dev/null +++ b/include/dot1q.h @@ -0,0 +1,166 @@ +/* + * 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_DOT1Q_H +#define TINS_DOT1Q_H + +#include "pdu.h" +#include "endianness.h" +#include "small_uint.h" + +namespace Tins { +class Dot1Q : public PDU { +public: + /** + * This PDU's flag. + */ + static const PDU::PDUType pdu_flag = PDU::DOT1Q; + /** + * Default constructor + */ + Dot1Q(); + + /** + * \brief Constructor which creates an Dot1Q 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. + */ + Dot1Q(const uint8_t *buffer, uint32_t total_sz); + + // Getters + + /** + * \brief Returns the header size. + * + * This metod overrides PDU::header_size. \sa PDU::header_size + */ + uint32_t header_size() const; + + /** + * \brief Returns the frame's trailer size. + * \return The trailer's size. + */ + uint32_t trailer_size() const; + + /** + * \brief Getter for the priority field. + * \return The stored priority field value. + */ + small_uint<3> priority() const { + return _header.priority; + } + + /** + * \brief Getter for the cfi field. + * \return The stored cfi field value. + */ + small_uint<1> cfi() const { + return _header.cfi; + } + + /** + * \brief Getter for the id field. + * \return The stored id field value. + */ + small_uint<12> id() const { + return _header.idL | (_header.idH << 8); + } + + /** + * \brief Getter for the payload type field. + * \return The stored type field value. + */ + uint16_t payload_type() const { + return Endian::be_to_host(_header.type); + } + + /** + * \brief Getter for the PDU's type. + * \sa PDU::pdu_type + */ + PDUType pdu_type() const { return pdu_flag; } + + /** + * \sa PDU::clone + */ + Dot1Q *clone() const { + return new Dot1Q(*this); + } + + // Setters + + /** + * \brief Setter for the priority field. + * \param new_priority The new priority field value. + */ + void priority(small_uint<3> new_priority); + + /** + * \brief Setter for the cfi field. + * \param new_cfi The new cfi field value. + */ + void cfi(small_uint<1> new_cfi); + + /** + * \brief Setter for the id field. + * \param new_id The new id field value. + */ + void id(small_uint<12> new_id); + + /** + * \brief Setter for the payload type field. + * \param new_type The new type field value. + */ + void payload_type(uint16_t new_type); +private: + void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); + + struct dot1q_hdr { + #if TINS_IS_BIG_ENDIAN + uint16_t priority:3, + cfi:1 + id:12; + uint16_t type; + #else + uint16_t idH:4, + cfi:1, + priority:3, + idL:8; + uint16_t type; + #endif + }; + + dot1q_hdr _header; +}; +} + +#endif // TINS_DOT1Q_H diff --git a/include/pdu.h b/include/pdu.h index dbc33ab..f40b64e 100644 --- a/include/pdu.h +++ b/include/pdu.h @@ -105,7 +105,8 @@ namespace Tins { IPv6, ICMPv6, SLL, - DHCPv6 + DHCPv6, + DOT1Q }; /** \brief PDU constructor diff --git a/src/dot1q.cpp b/src/dot1q.cpp new file mode 100644 index 0000000..9874661 --- /dev/null +++ b/src/dot1q.cpp @@ -0,0 +1,107 @@ +/* + * 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 +#include "dot1q.h" +#include "internals.h" + +namespace Tins { + +Dot1Q::Dot1Q() +: _header() +{ + +} + +Dot1Q::Dot1Q(const uint8_t *buffer, uint32_t total_sz) { + if(total_sz < sizeof(_header)) + throw std::runtime_error("Not enough size for a Dot1Q header"); + std::memcpy(&_header, buffer, sizeof(_header)); + buffer += sizeof(_header); + total_sz -= sizeof(_header); + + if(total_sz) { + inner_pdu( + Internals::pdu_from_flag( + (Constants::Ethernet::e)payload_type(), + buffer, + total_sz + ) + ); + } +} + +void Dot1Q::priority(small_uint<3> new_priority) { + _header.priority = new_priority; +} + +void Dot1Q::cfi(small_uint<1> new_cfi) { + _header.cfi = new_cfi; +} + +void Dot1Q::id(small_uint<12> new_id) { + uint16_t value = new_id; + _header.idL = new_id & 0xff; + _header.idH = new_id >> 8; +} + +void Dot1Q::payload_type(uint16_t new_type) { + _header.type = Endian::host_to_be(new_type); +} + +uint32_t Dot1Q::header_size() const { + return sizeof(_header); +} + +uint32_t Dot1Q::trailer_size() const { + uint32_t total_size = sizeof(_header); + if(inner_pdu()) + total_size += inner_pdu()->size(); + return (total_size > 50) ? 0 : (50 - total_size); +} + +void Dot1Q::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) { + uint32_t trailer = trailer_size(); + #ifdef TINS_DEBUG + assert(total_sz >= sizeof(_header) + trailer); + #endif + if ((payload_type() == 0) && inner_pdu()) { + Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type( + inner_pdu()->pdu_type() + ); + payload_type(static_cast(flag)); + } + std::memcpy(buffer, &_header, sizeof(_header)); + + buffer += sizeof(_header) + inner_pdu()->size(); + std::fill(buffer, buffer + trailer, 0); +} +} diff --git a/src/internals.cpp b/src/internals.cpp index ad8412e..d787f7a 100644 --- a/src/internals.cpp +++ b/src/internals.cpp @@ -33,6 +33,7 @@ #include "arp.h" #include "eapol.h" #include "rawpdu.h" +#include "dot1q.h" using std::string; @@ -73,6 +74,8 @@ Tins::PDU *pdu_from_flag(Constants::Ethernet::e flag, const uint8_t *buffer, return new Tins::ARP(buffer, size); case Tins::Constants::Ethernet::EAPOL: return Tins::EAPOL::from_bytes(buffer, size); + case Tins::Constants::Ethernet::VLAN: + return new Tins::Dot1Q(buffer, size); default: return rawpdu_on_no_match ? new RawPDU(buffer, size) : 0; }; diff --git a/src/ipv6.cpp b/src/ipv6.cpp index 484cba8..2a25914 100644 --- a/src/ipv6.cpp +++ b/src/ipv6.cpp @@ -1,3 +1,32 @@ +/* + * 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 #ifndef WIN32 diff --git a/tests/depends.d b/tests/depends.d index df1db77..855b2cb 100644 --- a/tests/depends.d +++ b/tests/depends.d @@ -192,6 +192,23 @@ ../include/packet_sender.h: ../include/snap.h: +../src/dot1q.o: ../src/dot1q.cpp ../include/dot1q.h ../include/pdu.h \ + ../include/endianness.h ../include/macros.h ../include/small_uint.h \ + ../include/internals.h ../include/constants.h + +../include/dot1q.h: + +../include/pdu.h: + +../include/endianness.h: + +../include/macros.h: + +../include/small_uint.h: + +../include/internals.h: + +../include/constants.h: ../src/eapol.o: ../src/eapol.cpp ../include/eapol.h ../include/pdu.h \ ../include/macros.h ../include/small_uint.h ../include/endianness.h \ ../include/dot11.h ../include/hw_address.h ../include/pdu_option.h \ @@ -1563,6 +1580,18 @@ src/dot11/rts.o: src/dot11/rts.cpp ../include/dot11.h ../include/macros.h \ include/tests/dot11.h: include/tests/dot11.h: +src/dot1q.o: src/dot1q.cpp ../include/dot1q.h ../include/pdu.h \ + ../include/endianness.h ../include/macros.h ../include/small_uint.h + +../include/dot1q.h: + +../include/pdu.h: + +../include/endianness.h: + +../include/macros.h: + +../include/small_uint.h: src/ethernetII.o: src/ethernetII.cpp ../include/ethernetII.h \ ../include/macros.h ../include/pdu.h ../include/endianness.h \ ../include/hw_address.h ../include/network_interface.h \ diff --git a/tests/src/dot1q.cpp b/tests/src/dot1q.cpp new file mode 100644 index 0000000..95e3ad1 --- /dev/null +++ b/tests/src/dot1q.cpp @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include "dot1q.h" +#include "arp.h" +#include "ethernetII.h" + +using namespace std; +using namespace Tins; + +class Dot1QTest : public testing::Test { +public: + static const uint8_t expected_packet[]; + + void test_equals(const Dot1Q &pdu1, const Dot1Q &pdu2); +}; + +const uint8_t Dot1QTest::expected_packet[] = { + '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\x00', '\x19', '\x06', + '\xea', '\xb8', '\xc1', '\x81', '\x00', '\xb0', '{', '\x08', '\x06', + '\x00', '\x01', '\x08', '\x00', '\x06', '\x04', '\x00', '\x02', '\x00', + '\x19', '\x06', '\xea', '\xb8', '\xc1', '\xc0', '\xa8', '{', '\x01', + '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xc0', '\xa8', '{', + '\x01', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00' +}; + + +TEST_F(Dot1QTest, DefaultConstructor) { + Dot1Q dot1; + EXPECT_EQ(0, dot1.payload_type()); + EXPECT_EQ(0, dot1.priority()); + EXPECT_EQ(0, dot1.cfi()); + EXPECT_EQ(0, dot1.id()); +} + +TEST_F(Dot1QTest, ConstructorFromBuffer) { + EthernetII eth(expected_packet, sizeof(expected_packet)); + const Dot1Q *dot1 = eth.find_pdu(); + ASSERT_TRUE(dot1); + EXPECT_EQ(0x806, dot1->payload_type()); + EXPECT_EQ(5, dot1->priority()); + EXPECT_EQ(1, dot1->cfi()); + EXPECT_EQ(123, dot1->id()); + + const ARP *arp = dot1->find_pdu(); + ASSERT_TRUE(arp); + // just to check it the offset's OK + EXPECT_EQ(ARP::hwaddress_type("00:19:06:ea:b8:c1"), arp->sender_hw_addr()); +} + +TEST_F(Dot1QTest, PayloadType) { + Dot1Q dot1; + dot1.payload_type(0x9283); + EXPECT_EQ(0x9283, dot1.payload_type()); +} + +TEST_F(Dot1QTest, Priority) { + Dot1Q dot1; + dot1.priority(5); + EXPECT_EQ(5, dot1.priority()); +} + +TEST_F(Dot1QTest, CFI) { + Dot1Q dot1; + dot1.cfi(1); + EXPECT_EQ(1, dot1.cfi()); +} + +TEST_F(Dot1QTest, Id) { + Dot1Q dot1; + dot1.id(3543); + EXPECT_EQ(3543, dot1.id()); +}