diff --git a/include/constants.h b/include/constants.h index 71c6f94..9eef689 100644 --- a/include/constants.h +++ b/include/constants.h @@ -85,6 +85,7 @@ namespace Tins { IPX = 0x8137, /* IPX */ IPV6 = 0x86dd, /* IP protocol version 6 */ PPPOED = 0x8863, /* PPPoE Discovery */ + PPPOES = 0x8864, /* PPPoE Session */ EAPOL = 0x888e, /* EAPOL */ LOOPBACK = 0x9000 /* used to test interfaces */ }; diff --git a/src/internals.cpp b/src/internals.cpp index b348b2c..a84d34e 100644 --- a/src/internals.cpp +++ b/src/internals.cpp @@ -86,6 +86,7 @@ Tins::PDU *pdu_from_flag(Constants::Ethernet::e flag, const uint8_t *buffer, case Tins::Constants::Ethernet::ARP: return new ARP(buffer, size); case Tins::Constants::Ethernet::PPPOED: + case Tins::Constants::Ethernet::PPPOES: return new PPPoE(buffer, size); case Tins::Constants::Ethernet::EAPOL: return EAPOL::from_bytes(buffer, size); diff --git a/src/pppoe.cpp b/src/pppoe.cpp index d3fe765..7733c5b 100644 --- a/src/pppoe.cpp +++ b/src/pppoe.cpp @@ -32,6 +32,7 @@ #endif #include #include "pppoe.h" +#include "rawpdu.h" #include "exceptions.h" namespace Tins { @@ -52,27 +53,37 @@ PPPoE::PPPoE(const uint8_t *buffer, uint32_t total_sz) buffer += sizeof(_header); total_sz -= sizeof(_header); total_sz = std::min(total_sz, (uint32_t)payload_length()); - const uint8_t *end = buffer + total_sz; - while(buffer < end) { - if(buffer + sizeof(uint32_t) * 2 > end) - throw malformed_packet(); - uint16_t opt_type; - std::memcpy(&opt_type, buffer, sizeof(uint16_t)); - uint16_t opt_len; - std::memcpy(&opt_len, buffer + sizeof(uint16_t), sizeof(uint16_t)); - buffer += sizeof(uint16_t) * 2; - total_sz -= sizeof(uint16_t) * 2; - if(Endian::be_to_host(opt_len) > total_sz) - throw malformed_packet(); - add_tag( - tag( - static_cast(opt_type), - Endian::be_to_host(opt_len), - buffer - ) - ); - buffer += Endian::be_to_host(opt_len); - total_sz -= Endian::be_to_host(opt_len); + // If this is a session data packet + if(code() == 0) { + if(total_sz > 0) { + inner_pdu( + new RawPDU(buffer, total_sz) + ); + } + } + else { + const uint8_t *end = buffer + total_sz; + while(buffer < end) { + if(buffer + sizeof(uint32_t) * 2 > end) + throw malformed_packet(); + uint16_t opt_type; + std::memcpy(&opt_type, buffer, sizeof(uint16_t)); + uint16_t opt_len; + std::memcpy(&opt_len, buffer + sizeof(uint16_t), sizeof(uint16_t)); + buffer += sizeof(uint16_t) * 2; + total_sz -= sizeof(uint16_t) * 2; + if(Endian::be_to_host(opt_len) > total_sz) + throw malformed_packet(); + add_tag( + tag( + static_cast(opt_type), + Endian::be_to_host(opt_len), + buffer + ) + ); + buffer += Endian::be_to_host(opt_len); + total_sz -= Endian::be_to_host(opt_len); + } } } diff --git a/tests/src/pppoe.cpp b/tests/src/pppoe.cpp index b1e3937..9873fa5 100644 --- a/tests/src/pppoe.cpp +++ b/tests/src/pppoe.cpp @@ -4,6 +4,7 @@ #include #include "pppoe.h" #include "ethernetII.h" +#include "rawpdu.h" using namespace std; using namespace Tins; @@ -11,12 +12,27 @@ using namespace Tins; class PPPoETest : public testing::Test { public: static const uint8_t expected_packet[]; + static const uint8_t session_packet[]; + static const uint8_t full_session_packet[]; }; const uint8_t PPPoETest::expected_packet[] = { 17, 9, 0, 0, 0, 16, 1, 1, 0, 0, 1, 2, 0, 0, 1, 3, 0, 4, 97, 98, 99, 100 }; +const uint8_t PPPoETest::session_packet[] = { + 17, 0, 0, 98, 0, 21, 192, 33, 1, 11, 0, 19, 1, 4, 5, 212, 3, 5, + 194, 35, 5, 5, 6, 22, 173, 224, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +const uint8_t PPPoETest::full_session_packet[] = { + 0, 5, 133, 192, 164, 17, 0, 144, 26, 65, 118, 126, 136, 100, 17, + 0, 0, 98, 0, 21, 192, 33, 1, 11, 0, 19, 1, 4, 5, 212, 3, 5, 194, + 35, 5, 5, 6, 22, 173, 224, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + , 0, 0, 0, 0, 0, 0, 0 +}; + TEST_F(PPPoETest, DefaultConstructor) { PPPoE pdu; EXPECT_EQ(1, pdu.version()); @@ -26,6 +42,35 @@ TEST_F(PPPoETest, DefaultConstructor) { EXPECT_EQ(0, pdu.payload_length()); } +TEST_F(PPPoETest, ConstructorFromSessionBuffer) { + PPPoE pdu(session_packet, sizeof(session_packet)); + EXPECT_EQ(1, pdu.version()); + EXPECT_EQ(1, pdu.type()); + EXPECT_EQ(0x00, pdu.code()); + EXPECT_EQ(0x62, pdu.session_id()); + EXPECT_EQ(21, pdu.payload_length()); + EXPECT_EQ(0U, pdu.tags().size()); + + const RawPDU* raw = pdu.find_pdu(); + ASSERT_TRUE(raw); + EXPECT_EQ(21, raw->payload_size()); +} + +TEST_F(PPPoETest, ConstructorFromFullSessionBuffer) { + EthernetII eth(full_session_packet, sizeof(full_session_packet)); + const PPPoE& pdu = eth.rfind_pdu(); + EXPECT_EQ(1, pdu.version()); + EXPECT_EQ(1, pdu.type()); + EXPECT_EQ(0x00, pdu.code()); + EXPECT_EQ(0x62, pdu.session_id()); + EXPECT_EQ(21, pdu.payload_length()); + EXPECT_EQ(0U, pdu.tags().size()); + + const RawPDU* raw = pdu.find_pdu(); + ASSERT_TRUE(raw); + EXPECT_EQ(21, raw->payload_size()); +} + TEST_F(PPPoETest, ConstructorFromBuffer) { PPPoE pdu(expected_packet, sizeof(expected_packet)); EXPECT_EQ(1, pdu.version());