diff --git a/include/tins/pdu.h b/include/tins/pdu.h index 6402a129..7fbbe67a 100644 --- a/include/tins/pdu.h +++ b/include/tins/pdu.h @@ -169,6 +169,7 @@ class TINS_API PDU { IPv6, ICMPv6, SLL, + SLL2, DHCPv6, DOT1AD, DOT1Q, diff --git a/include/tins/sll2.h b/include/tins/sll2.h new file mode 100644 index 00000000..40015e93 --- /dev/null +++ b/include/tins/sll2.h @@ -0,0 +1,167 @@ +#ifndef TINS_SLL2_H +#define TINS_SLL2_H + +#include +#include +#include +#include +#include +#include + +namespace Tins { + +/** + * \class SLL2 + * \brief Represents a Linux Cooked Capture v2 (SLL2) PDU. + * + * https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL2.html + * + */ +class TINS_API SLL2 : public PDU { +public: + /** + * This PDU's flag. + */ + static const PDU::PDUType pdu_flag = PDU::SLL2; + + /** + * The type of the address type + */ + typedef HWAddress<8> address_type; + + /** + * Default constructor + */ + SLL2(); + + /** + * \brief Constructs a SLL2 object from a buffer and adds all + * identifiable PDUs found in the buffer as children of this one. + * + * If the next PDU is not recognized, then a RawPDU is used. + * + * If there is not enough size for a SLL header in the + * buffer, a malformed_packet exception is thrown. + * + * \param buffer The buffer from which this PDU will be constructed. + * \param total_sz The total size of the buffer. + */ + SLL2(const uint8_t *buffer, uint32_t total_sz); + + // Getters + + /** + * \brief Getter for the Protocol field. + * \return The stored Protocol field value. + */ + uint16_t protocol() const { return Endian::be_to_host(header_.protocol); } + + /** + * \brief Getter for the Interface Index field. + * \return The stored Interface Index field value. + */ + uint32_t interface_index() const { + return Endian::be_to_host(header_.interface_index); + } + + /** + * \brief Getter for the LLADDR Type field. + * \return The stored LLADDR Type field value. + */ + uint16_t lladdr_type() const { + return Endian::be_to_host(header_.lladdr_type); + } + + /** + * \brief Getter for the Packet Type field. + * \return The stored Packet Type field value. + */ + uint8_t packet_type() const { + return Endian::be_to_host(header_.packet_type); + } + + /** + * \brief Getter for the LLADDR Length field. + * \return The stored LLADDR Length field value. + */ + uint8_t lladdr_len() const { return Endian::be_to_host(header_.lladdr_len); } + + /** + * \brief Getter for the Address field. + * \return The stored Address field value. + */ + address_type address() const { return header_.address; } + + /** + * \brief Getter for the PDU's type. + * \sa PDU::pdu_type + */ + PDUType pdu_type() const { return pdu_flag; } + + // Setters + + /** + * \brief Setter for the Protocol field. + * \param new_protocol The new Protocol field value. + */ + void protocol(uint16_t new_protocol); + + /** + * \brief Setter for the Interface Index field. + * \param new_interface_index The new Interface Index field value. + */ + void interface_index(uint32_t new_interface_index); + + /** + * \brief Setter for the LLADDR Type field. + * \param new_lladdr_type The new LLADDR Type field value. + */ + void lladdr_type(uint16_t new_lladdr_type); + + /** + * \brief Setter for the Packet Type field. + * \param new_packet_type The new Packet Type field value. + */ + void packet_type(uint8_t new_packet_type); + + /** + * \brief Setter for the LLADDR Length field. + * \param new_lladdr_len The new LLADDR Length field value. + */ + void lladdr_len(uint8_t new_lladdr_len); + + /** + * \brief Setter for the Address field. + * \param new_address The new Address field value. + */ + void address(const address_type &new_address); + + /** + * \brief Returns the header size. + * + * This method overrides PDU::header_size. \sa PDU::header_size + */ + uint32_t header_size() const; + + /** + * \sa PDU::clone + */ + SLL2 *clone() const { return new SLL2(*this); } + +private: + TINS_BEGIN_PACK + struct sll2_header { + uint16_t protocol, reserved_mbz; + uint32_t interface_index; + uint16_t lladdr_type; + uint8_t packet_type, lladdr_len; + uint8_t address[8]; + } TINS_END_PACK; + + void write_serialization(uint8_t *buffer, uint32_t total_sz); + + sll2_header header_; +}; +} // namespace Tins + +#endif // TINS_SLL2_H diff --git a/include/tins/tins.h b/include/tins/tins.h index 6526c50e..7feed86d 100644 --- a/include/tins/tins.h +++ b/include/tins/tins.h @@ -70,6 +70,7 @@ #include #include #include +#include #include #include #include diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8dc4fc82..eca99b8b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -56,6 +56,7 @@ set(SOURCES rsn_information.cpp rtp.cpp sll.cpp + sll2.cpp snap.cpp stp.cpp tcp.cpp @@ -134,6 +135,7 @@ set(HEADERS ${LIBTINS_INCLUDE_DIR}/tins/rsn_information.h ${LIBTINS_INCLUDE_DIR}/tins/rtp.h ${LIBTINS_INCLUDE_DIR}/tins/sll.h + ${LIBTINS_INCLUDE_DIR}/tins/sll2.h ${LIBTINS_INCLUDE_DIR}/tins/small_uint.h ${LIBTINS_INCLUDE_DIR}/tins/snap.h ${LIBTINS_INCLUDE_DIR}/tins/tcp.h diff --git a/src/detail/pdu_helpers.cpp b/src/detail/pdu_helpers.cpp index bdda65a4..88d32e54 100644 --- a/src/detail/pdu_helpers.cpp +++ b/src/detail/pdu_helpers.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -147,6 +148,8 @@ PDU* pdu_from_dlt_flag(int flag, return new Loopback(buffer, size); case DLT_LINUX_SLL: return new SLL(buffer, size); + case DLT_LINUX_SLL2: + return new SLL2(buffer, size); case DLT_PPI: return new PPI(buffer, size); default: diff --git a/src/sll2.cpp b/src/sll2.cpp new file mode 100644 index 00000000..410e2c75 --- /dev/null +++ b/src/sll2.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include + +using Tins::Memory::InputMemoryStream; +using Tins::Memory::OutputMemoryStream; + +namespace Tins { + +SLL2::SLL2() : header_() {} + +SLL2::SLL2(const uint8_t *buffer, uint32_t total_sz) { + InputMemoryStream stream(buffer, total_sz); + stream.read(header_); + if (stream) { + inner_pdu(Internals::pdu_from_flag((Constants::Ethernet::e)protocol(), + stream.pointer(), stream.size())); + } +} + +void SLL2::protocol(uint16_t new_protocol) { + header_.protocol = Endian::host_to_be(new_protocol); +} + +void SLL2::interface_index(uint32_t new_interface_index) { + header_.interface_index = Endian::host_to_be(new_interface_index); +} + +void SLL2::lladdr_type(uint16_t new_lladdr_type) { + header_.lladdr_type = Endian::host_to_be(new_lladdr_type); +} + +void SLL2::packet_type(uint8_t new_packet_type) { + header_.packet_type = Endian::host_to_be(new_packet_type); +} + +void SLL2::lladdr_len(uint8_t new_lladdr_len) { + header_.lladdr_len = Endian::host_to_be(new_lladdr_len); +} + +void SLL2::address(const address_type &new_address) { + new_address.copy(header_.address); +} + +uint32_t SLL2::header_size() const { return sizeof(header_); } + +void SLL2::write_serialization(uint8_t *buffer, uint32_t total_sz) { + OutputMemoryStream stream(buffer, total_sz); + if (inner_pdu()) { + Constants::Ethernet::e flag = + Internals::pdu_flag_to_ether_type(inner_pdu()->pdu_type()); + protocol(static_cast(flag)); + } + stream.write(header_); +} + +} // namespace Tins diff --git a/src/sniffer.cpp b/src/sniffer.cpp index 094f9ba8..12ba08f4 100644 --- a/src/sniffer.cpp +++ b/src/sniffer.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -178,6 +179,9 @@ PtrPacket BaseSniffer::next_packet() { case DLT_LINUX_SLL: handler = &sniff_loop_handler; break; + case DLT_LINUX_SLL2: + handler = &sniff_loop_handler; + break; case DLT_PPI: handler = &sniff_loop_handler; break; diff --git a/tests/src/CMakeLists.txt b/tests/src/CMakeLists.txt index aa0c3777..ea9222ee 100644 --- a/tests/src/CMakeLists.txt +++ b/tests/src/CMakeLists.txt @@ -65,6 +65,7 @@ CREATE_TEST(rc4_eapol) CREATE_TEST(rsn_eapol) CREATE_TEST(rtp) CREATE_TEST(sll) +CREATE_TEST(sll2) CREATE_TEST(snap) CREATE_TEST(stp) CREATE_TEST(tcp) diff --git a/tests/src/sll2_test.cpp b/tests/src/sll2_test.cpp new file mode 100644 index 00000000..34606218 --- /dev/null +++ b/tests/src/sll2_test.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace Tins; + +class SLL2Test : public testing::Test { +public: + static const uint8_t expected_packet[]; + + void test_equals(const SLL2 &, const SLL2 &); +}; + +const uint8_t SLL2Test::expected_packet[] = { + 8, 0, 0, 0, 0, 0, 1, 27, 0, 1,0, 6, 0, 27, 17, 210, 27, + 235, 0, 0, 69, 0, 0, 116, 65, 18, 0, 0, 44, 6, 156, 54, + 173, 194, 66, 109, 192, 168, 0, 100, 3, 225, 141, 4, 55, 61, 150, + 161, 85, 106, 73, 189, 128, 24, 1, 0, 202, 119, 0, 0, 1, 1, + 8, 10, 71, 45, 40, 171, 0, 19, 78, 86, 23, 3, 1, 0, 59, + 168, 147, 182, 150, 159, 178, 204, 116, 62, 85, 80, 167, 23, 24, 173, + 236, 55, 46, 190, 205, 255, 19, 248, 129, 198, 140, 208, 60, 79, 59, + 38, 165, 131, 33, 105, 212, 112, 174, 80, 211, 48, 37, 116, 108, 109, + 33, 36, 231, 154, 131, 112, 246, 3, 180, 199, 158, 205, 123, 238}; + +TEST_F(SLL2Test, DefaultConstructor) { + SLL2 sll2; + EXPECT_EQ(0, sll2.protocol()); + EXPECT_EQ(0, sll2.interface_index()); + EXPECT_EQ(0, sll2.lladdr_type()); + EXPECT_EQ(0, sll2.packet_type()); + EXPECT_EQ(0, sll2.lladdr_len()); + EXPECT_EQ(SLL2::address_type("00:00:00:00:00:00:00:00"), sll2.address()); +} + +TEST_F(SLL2Test, ConstructorFromBuffer) { + typedef HWAddress<6> address_type; + address_type addr("00:1b:11:d2:1b:eb"); + SLL2 sll2(expected_packet, sizeof(expected_packet)); + EXPECT_EQ(Constants::Ethernet::IP, sll2.protocol()); + EXPECT_EQ(283, sll2.interface_index()); + EXPECT_EQ(1, sll2.lladdr_type()); + EXPECT_EQ(0, sll2.packet_type()); + EXPECT_EQ(6, sll2.lladdr_len()); + EXPECT_EQ(addr, sll2.address()); + + ASSERT_TRUE(sll2.inner_pdu() != NULL); + EXPECT_EQ(sll2.find_pdu(), sll2.inner_pdu()); +} + +TEST_F(SLL2Test, Serialize) { + SLL2 sll2(expected_packet, sizeof(expected_packet)); + SLL2::serialization_type buffer = sll2.serialize(); + ASSERT_EQ(sizeof(expected_packet), buffer.size()); + EXPECT_TRUE(std::equal(buffer.begin(), buffer.end(), expected_packet)); +} + +TEST_F(SLL2Test, Protocol) { + SLL2 sll2; + sll2.protocol(0x923f); + EXPECT_EQ(0x923f, sll2.protocol()); +} + +TEST_F(SLL2Test, InterfaceIndex) { + SLL2 sll2; + sll2.interface_index(0x1234923f); + EXPECT_EQ(0x1234923f, sll2.interface_index()); +} + +TEST_F(SLL2Test, LLADDRType) { + SLL2 sll; + sll.lladdr_type(0x923f); + EXPECT_EQ(0x923f, sll.lladdr_type()); +} + +TEST_F(SLL2Test, PacketType) { + SLL2 sll; + sll.packet_type(0x3f); + EXPECT_EQ(0x3f, sll.packet_type()); +} + +TEST_F(SLL2Test, LLADDRLen) { + SLL2 sll2; + sll2.lladdr_len(0x92); + EXPECT_EQ(0x92, sll2.lladdr_len()); +} + +TEST_F(SLL2Test, Address) { + HWAddress<6> addr = "00:01:02:03:04:05"; + SLL2 sll2; + sll2.address(addr); + EXPECT_EQ(addr, sll2.address()); +}