diff --git a/include/dhcpv6.h b/include/dhcpv6.h index fe80ca0..89ccf6a 100644 --- a/include/dhcpv6.h +++ b/include/dhcpv6.h @@ -875,6 +875,15 @@ public: */ uint32_t header_size() const; + /** + * \brief Check wether ptr points to a valid response for this PDU. + * + * \sa PDU::matches_response + * \param ptr The pointer to the buffer. + * \param total_sz The size of the buffer. + */ + bool matches_response(uint8_t *ptr, uint32_t total_sz); + /** * \brief Getter for the PDU's type. * \sa PDU::pdu_type diff --git a/include/dot3.h b/include/dot3.h index 049f22d..7800c73 100644 --- a/include/dot3.h +++ b/include/dot3.h @@ -157,7 +157,8 @@ namespace Tins { void send(PacketSender &sender); #endif // WIN32 - /** \brief Check wether ptr points to a valid response for this PDU. + /** + * \brief Check wether ptr points to a valid response for this PDU. * * \sa PDU::matches_response * \param ptr The pointer to the buffer. @@ -166,7 +167,8 @@ namespace Tins { bool matches_response(uint8_t *ptr, uint32_t total_sz); #ifndef WIN32 - /** \brief Receives a matching response for this packet. + /** + * \brief Receives a matching response for this packet. * * \sa PDU::recv_response * \param sender The packet sender which will receive the packet. diff --git a/include/icmpv6.h b/include/icmpv6.h index c8b7a8f..93f4219 100644 --- a/include/icmpv6.h +++ b/include/icmpv6.h @@ -757,6 +757,15 @@ public: * payload and options size. \sa PDU::header_size */ uint32_t header_size() const; + + /** + * \brief Check wether ptr points to a valid response for this PDU. + * + * \sa PDU::matches_response + * \param ptr The pointer to the buffer. + * \param total_sz The size of the buffer. + */ + bool matches_response(uint8_t *ptr, uint32_t total_sz); /** * \brief Searchs for an option that matchs the given flag. diff --git a/include/ipv6.h b/include/ipv6.h index 9aab25c..889b779 100644 --- a/include/ipv6.h +++ b/include/ipv6.h @@ -257,6 +257,15 @@ public: */ uint32_t header_size() const; + /** + * \brief Check wether ptr points to a valid response for this PDU. + * + * \sa PDU::matches_response + * \param ptr The pointer to the buffer. + * \param total_sz The size of the buffer. + */ + bool matches_response(uint8_t *ptr, uint32_t total_sz); + /** * \sa PDU::clone */ diff --git a/include/pdu.h b/include/pdu.h index a4d4530..20bee1f 100644 --- a/include/pdu.h +++ b/include/pdu.h @@ -165,11 +165,21 @@ namespace Tins { /** * \brief Sets the child PDU. * - * \param next_pdu The new child PDU. * When setting a new inner_pdu, the instance takesownership of * the object, therefore deleting it when it's no longer required. + * + * \param next_pdu The new child PDU. */ void inner_pdu(PDU *next_pdu); + + /** + * \brief Sets the child PDU. + * + * The PDU parameter is cloned using PDU::clone. + * + * \param next_pdu The new child PDU. + */ + void inner_pdu(const PDU &next_pdu); /** diff --git a/include/rawpdu.h b/include/rawpdu.h index 12e62b7..c787a0e 100644 --- a/include/rawpdu.h +++ b/include/rawpdu.h @@ -134,6 +134,15 @@ namespace Tins { */ PDUType pdu_type() const { return PDU::RAW; } + /** + * \brief Constructs the given PDU type from the raw data stored + * in this RawPDU. + */ + template + T to() const { + return T(&_payload[0], _payload.size()); + } + /** * \sa PDU::clone */ diff --git a/include/utils.h b/include/utils.h index e873f0c..deea1ea 100644 --- a/include/utils.h +++ b/include/utils.h @@ -136,8 +136,10 @@ namespace Tins { * \return Returns true if the hardware address was resolved successfully, * false otherwise. */ + TINS_DEPRECATED( bool resolve_hwaddr(const NetworkInterface &iface, IPv4Address ip, - HWAddress<6> *address, PacketSender &sender); + HWAddress<6> *address, PacketSender &sender) + ); /** * \brief Resolves the hardware address for a given ip. diff --git a/src/dhcpv6.cpp b/src/dhcpv6.cpp index ad3d066..1b768a1 100644 --- a/src/dhcpv6.cpp +++ b/src/dhcpv6.cpp @@ -27,7 +27,6 @@ * */ -#include //borrame #include #include #include "dhcpv6.h" @@ -133,6 +132,15 @@ uint32_t DHCPv6::header_size() const { return (is_relay_message() ? (2 + ipaddress_type::address_size * 2) : 4) + options_size; } +bool DHCPv6::matches_response(uint8_t *ptr, uint32_t total_sz) { + if(!is_relay_message()) { + if(total_sz < 4 || (ptr[0] == 12 || ptr[0] == 13)) + return false; + return std::equal(header_data + 1, header_data + 4, ptr + 1); + } + return false; +} + void DHCPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) { const uint32_t required_size = is_relay_message() ? 2 : 4; buffer = std::copy(header_data, header_data + required_size, buffer); diff --git a/src/ethernetII.cpp b/src/ethernetII.cpp index 0457d6c..ee0d418 100644 --- a/src/ethernetII.cpp +++ b/src/ethernetII.cpp @@ -133,7 +133,8 @@ bool EthernetII::matches_response(uint8_t *ptr, uint32_t total_sz) { const size_t addr_sz = address_type::address_size; const ethhdr *eth_ptr = (const ethhdr*)ptr; if(std::equal(_eth.src_mac, _eth.src_mac + addr_sz, eth_ptr->dst_mac)) { - if(std::equal(_eth.src_mac, _eth.src_mac + addr_sz, eth_ptr->dst_mac) || dst_addr() == BROADCAST) + if(std::equal(_eth.src_mac, _eth.src_mac + addr_sz, eth_ptr->dst_mac) || dst_addr() == BROADCAST || + (_eth.src_mac[0] == 0x33 && _eth.src_mac[1] == 0x33)) { return (inner_pdu()) ? inner_pdu()->matches_response(ptr + sizeof(_eth), total_sz - sizeof(_eth)) : true; } diff --git a/src/icmp.cpp b/src/icmp.cpp index 86cf74b..4a38945 100644 --- a/src/icmp.cpp +++ b/src/icmp.cpp @@ -161,9 +161,9 @@ void Tins::ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const P bool Tins::ICMP::matches_response(uint8_t *ptr, uint32_t total_sz) { if(total_sz < sizeof(icmphdr)) return false; - icmphdr *icmp_ptr = (icmphdr*)ptr; - if(_icmp.type == ECHO_REQUEST) { - return icmp_ptr->type == ECHO_REPLY && icmp_ptr->un.echo.id == _icmp.un.echo.id && icmp_ptr->un.echo.sequence == _icmp.un.echo.sequence; + const icmphdr *icmp_ptr = (const icmphdr*)ptr; + if(_icmp.type == ECHO_REQUEST && icmp_ptr->type == ECHO_REPLY) { + return icmp_ptr->un.echo.id == _icmp.un.echo.id && icmp_ptr->un.echo.sequence == _icmp.un.echo.sequence; } return false; } diff --git a/src/icmpv6.cpp b/src/icmpv6.cpp index 8012ccb..ca62bbc 100644 --- a/src/icmpv6.cpp +++ b/src/icmpv6.cpp @@ -174,6 +174,16 @@ uint32_t ICMPv6::header_size() const { (has_dest_addr() ? ipaddress_type::address_size : 0); } +bool ICMPv6::matches_response(uint8_t *ptr, uint32_t total_sz) { + if(total_sz < sizeof(icmp6hdr)) + return false; + const icmp6hdr *hdr_ptr = (const icmp6hdr*)ptr; + if(type() == ECHO_REQUEST && hdr_ptr->type == ECHO_REPLY) + return hdr_ptr->u_echo.identifier == _header.u_echo.identifier && + hdr_ptr->u_echo.sequence == _header.u_echo.sequence; + return false; +} + void ICMPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { #ifdef TINS_DEBUG assert(total_sz >= header_size()); diff --git a/src/ip.cpp b/src/ip.cpp index eb759a2..6b84ff8 100644 --- a/src/ip.cpp +++ b/src/ip.cpp @@ -446,8 +446,10 @@ void IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU* pare bool IP::matches_response(uint8_t *ptr, uint32_t total_sz) { if(total_sz < sizeof(iphdr)) return false; - iphdr *ip_ptr = (iphdr*)ptr; - if(_ip.daddr == ip_ptr->saddr && _ip.saddr == ip_ptr->daddr) { + const iphdr *ip_ptr = (const iphdr*)ptr; + // checks for broadcast addr + if((_ip.saddr == ip_ptr->daddr && (_ip.daddr == ip_ptr->saddr || _ip.daddr == 0xffffffff)) || + (_ip.daddr == 0xffffffff && _ip.saddr == 0)) { uint32_t sz = std::min(_ip.ihl * sizeof(uint32_t), total_sz); return inner_pdu() ? inner_pdu()->matches_response(ptr + sz, total_sz - sz) : true; } diff --git a/src/ipv6.cpp b/src/ipv6.cpp index 2a25914..d959426 100644 --- a/src/ipv6.cpp +++ b/src/ipv6.cpp @@ -35,7 +35,7 @@ #else #include #endif -#include //borrame +#include #include "ipv6.h" #include "constants.h" #include "packet_sender.h" @@ -161,6 +161,33 @@ uint32_t IPv6::header_size() const { return sizeof(_header) + headers_size; } +bool IPv6::matches_response(uint8_t *ptr, uint32_t total_sz) { + if(total_sz < sizeof(ipv6_header)) + return false; + const ipv6_header *hdr_ptr = (const ipv6_header*)ptr; + // checks for ff02 multicast + if(src_addr() == hdr_ptr->dst_addr && + (dst_addr() == hdr_ptr->src_addr || (_header.dst_addr[0] == 0xff && _header.dst_addr[1] == 0x02))) { + // is this OK? there's no inner pdu, simple dst/src addr match should suffice + if(!inner_pdu()) + return true; + ptr += sizeof(ipv6_header); + total_sz -= sizeof(ipv6_header); + uint8_t current = hdr_ptr->next_header; + // 8 == minimum header size + while(total_sz > 8 && is_extension_header(current)) { + if(static_cast(ptr[1] + 1) * 8 > total_sz) + return false; + current = ptr[0]; + total_sz -= (ptr[1] + 1) * 8; + ptr += (ptr[1] + 1) * 8; + } + if(!is_extension_header(current)) + return inner_pdu()->matches_response(ptr, total_sz); + } + return false; +} + void IPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { #ifdef DEBUG assert(total_sz >= header_size()); diff --git a/src/pdu.cpp b/src/pdu.cpp index cc5086f..4aca838 100644 --- a/src/pdu.cpp +++ b/src/pdu.cpp @@ -79,6 +79,10 @@ void PDU::inner_pdu(PDU *next_pdu) { _inner_pdu = next_pdu; } +void PDU::inner_pdu(const PDU &next_pdu) { + inner_pdu(next_pdu.clone()); +} + PDU *PDU::release_inner_pdu() { PDU *result = 0; std::swap(result, _inner_pdu); diff --git a/tests/depends.d b/tests/depends.d index 3fa0108..b5769ee 100644 --- a/tests/depends.d +++ b/tests/depends.d @@ -1979,6 +1979,45 @@ src/llc.o: src/llc.cpp ../include/llc.h ../include/macros.h \ ../include/endianness.h: src/main.o: src/main.cpp +src/matches_response.o: src/matches_response.cpp ../include/ethernetII.h \ + ../include/macros.h ../include/pdu.h ../include/endianness.h \ + ../include/hw_address.h ../include/network_interface.h \ + ../include/ip_address.h ../include/rawpdu.h ../include/udp.h \ + ../include/dhcp.h ../include/bootp.h ../include/pdu_option.h \ + ../include/cxxstd.h ../include/dhcpv6.h ../include/small_uint.h \ + ../include/ipv6_address.h + +../include/ethernetII.h: + +../include/macros.h: + +../include/pdu.h: + +../include/endianness.h: + +../include/hw_address.h: + +../include/network_interface.h: + +../include/ip_address.h: + +../include/rawpdu.h: + +../include/udp.h: + +../include/dhcp.h: + +../include/bootp.h: + +../include/pdu_option.h: + +../include/cxxstd.h: + +../include/dhcpv6.h: + +../include/small_uint.h: + +../include/ipv6_address.h: src/network_interface.o: src/network_interface.cpp \ ../include/network_interface.h ../include/hw_address.h \ ../include/ip_address.h ../include/utils.h ../include/macros.h \ diff --git a/tests/src/matches_response.cpp b/tests/src/matches_response.cpp new file mode 100644 index 0000000..af57418 --- /dev/null +++ b/tests/src/matches_response.cpp @@ -0,0 +1,199 @@ +#include +#include +#include "ethernetII.h" +#include "rawpdu.h" +#include "udp.h" +#include "dhcp.h" +#include "dhcpv6.h" + +using namespace Tins; + +class MatchesResponseTest : public ::testing::Test { +public: + +}; + +TEST_F(MatchesResponseTest, TCPSynAck) { + uint8_t syn_data[] = { + 0, 27, 17, 210, 27, 235, 0, 25, 209, 146, 248, 43, 8, 0, 69, 0, 0, + 60, 21, 131, 64, 0, 64, 6, 163, 131, 192, 168, 0, 100, 192, 168, 0, + 1, 219, 85, 31, 144, 11, 209, 99, 140, 0, 0, 0, 0, 160, 2, 57, 8, + 129, 228, 0, 0, 2, 4, 5, 180, 4, 2, 8, 10, 0, 6, 118, 15, 0, 0, 0, + 0, 1, 3, 3, 7 + }; + uint8_t resp_data[] = { + 0, 25, 209, 146, 248, 43, 0, 27, 17, 210, 27, 235, 8, 0, 69, 0, 0, + 40, 0, 0, 64, 0, 64, 6, 185, 26, 192, 168, 0, 1, 192, 168, 0, 100, + 31, 144, 219, 85, 0, 0, 0, 0, 11, 209, 99, 141, 80, 20, 0, 0, 195, + 214, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + EthernetII sent(syn_data, sizeof(syn_data)); + EXPECT_TRUE(sent.matches_response(resp_data, sizeof(resp_data))); + EXPECT_FALSE(sent.matches_response(syn_data, sizeof(syn_data))); +} + +TEST_F(MatchesResponseTest, DHCP) { + uint8_t dhcp_discover[] = { + 255, 255, 255, 255, 255, 255, 0, 1, 1, 0, 0, 1, 8, 0, 69, 0, 1, + 25, 77, 62, 0, 0, 64, 17, 44, 151, 0, 0, 0, 0, 255, 255, 255, + 255, 0, 68, 0, 67, 1, 5, 0, 0, 1, 1, 6, 0, 217, 7, 133, 224, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 99, 130, 83, 99, 53, 1, 1, 61, 7, 1, 0, 1, 1, + 0, 0, 1, 255 + }; + + uint8_t dhcp_offer[] = { + 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 2, 8, 0, 69, 0, 1, 28, 221, 161, + 0, 0, 64, 17, 158, 45, 127, 0, 0, 1, 127, 0, 0, 1, 0, 67, 0, 68, + 1, 8, 0, 0, 2, 1, 6, 0, 217, 7, 133, 224, 0, 0, 0, 0, 0, 0, 0, 0, + 127, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 99, 130, 83, 99, 53, 1, 2, 54, 4, 127, 0, 0, 1, 51, 4, 0, 0, 1, + 44, 255 + }; + + EthernetII discover(dhcp_discover, sizeof(dhcp_discover)); + UDP *udp = discover.find_pdu(); + const RawPDU *raw = discover.find_pdu(); + ASSERT_TRUE(udp); + ASSERT_TRUE(raw); + + udp->inner_pdu(raw->to()); + EXPECT_TRUE(discover.matches_response(dhcp_offer, sizeof(dhcp_offer))); + EXPECT_FALSE(discover.matches_response(dhcp_discover, sizeof(dhcp_discover))); +} + +TEST_F(MatchesResponseTest, ICMP) { + uint8_t request[] = { + 0, 16, 219, 124, 173, 34, 0, 22, 203, 139, 6, 92, 8, 0, 69, 0, 0, + 84, 226, 159, 0, 0, 64, 1, 150, 133, 10, 10, 1, 89, 209, 131, 36, + 158, 8, 0, 3, 45, 54, 12, 0, 0, 146, 91, 68, 72, 241, 31, 12, 0, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55 + }; + + uint8_t reply[] = { + 0, 22, 203, 139, 6, 92, 0, 16, 219, 124, 173, 34, 8, 0, 69, 0, 0, + 84, 74, 84, 0, 0, 55, 1, 55, 209, 209, 131, 36, 158, 10, 10, 1, + 89, 0, 0, 11, 45, 54, 12, 0, 0, 146, 91, 68, 72, 241, 31, 12, 0, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55 + }; + + EthernetII pkt(request, sizeof(request)); + EXPECT_TRUE(pkt.matches_response(reply, sizeof(reply))); + EXPECT_FALSE(pkt.matches_response(request, sizeof(request))); +} + +TEST_F(MatchesResponseTest, ARP) { + uint8_t request[] = { + 255, 255, 255, 255, 255, 255, 0, 1, 1, 0, 0, 1, 8, 6, 0, 1, 8, 0, + 6, 4, 0, 1, 0, 1, 1, 0, 0, 1, 127, 0, 0, 1, 255, 255, 255, 255, + 255, 255, 127, 0, 0, 1 + }; + + uint8_t reply[] = { + 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 2, 8, 6, 0, 1, 8, 0, 6, 4, 0, 2, + 0, 1, 1, 0, 0, 2, 127, 0, 0, 1, 0, 1, 1, 0, 0, 1, 127, 0, 0, 1 + }; + + EthernetII pkt(request, sizeof(request)); + EXPECT_TRUE(pkt.matches_response(reply, sizeof(reply))); + EXPECT_FALSE(pkt.matches_response(request, sizeof(request))); +} + +TEST_F(MatchesResponseTest, ICMPv6) { + uint8_t request[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 221, 96, 0, 0, 0, 0, 64, + 58, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 128, 0, 91, 104, 25, 156, + 0, 1, 226, 206, 89, 81, 0, 0, 0, 0, 14, 139, 1, 0, 0, 0, 0, 0, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55 + }; + + uint8_t reply[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 221, 96, 0, 0, 0, 0, 64, + 58, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 129, 0, 90, 104, 25, 156, + 0, 1, 226, 206, 89, 81, 0, 0, 0, 0, 14, 139, 1, 0, 0, 0, 0, 0, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55 + }; + + uint8_t not_a_reply[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 221, 96, 0, 0, 0, 0, 26, + 60, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 17, 0, 11, 1, 9, 1, 1, 0, + 166, 17, 0, 42, 0, 18, 104, 137, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106 + }; + + EthernetII pkt(request, sizeof(request)); + EXPECT_TRUE(pkt.matches_response(reply, sizeof(reply))); + EXPECT_FALSE(pkt.matches_response(request, sizeof(request))); + EXPECT_FALSE(pkt.matches_response(not_a_reply, sizeof(not_a_reply))); +} + +TEST_F(MatchesResponseTest, DHCPv6) { + uint8_t request[] = { + 51, 51, 0, 1, 0, 2, 0, 2, 179, 193, 64, 207, 134, 221, 96, 0, 0, + 0, 0, 52, 17, 128, 254, 128, 0, 0, 0, 0, 0, 0, 2, 2, 179, 255, + 254, 193, 64, 207, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 2, 2, 34, 2, 35, 0, 52, 243, 80, 1, 0, 83, 101, 0, 1, 0, 14, + 0, 1, 0, 6, 17, 195, 100, 52, 0, 22, 118, 189, 211, 18, 0, 3, 0, + 12, 0, 0, 0, 1, 255, 255, 255, 255, 255, 255, 255, 255, 0, 8, 0, + 2, 0, 100 + }; + + uint8_t reply[] = { + 0, 2, 179, 193, 64, 207, 0, 21, 242, 4, 141, 219, 134, 221, 96, 0, + 0, 0, 0, 209, 17, 128, 254, 128, 0, 0, 0, 0, 0, 0, 2, 21, 242, 255, + 254, 4, 141, 219, 254, 128, 0, 0, 0, 0, 0, 0, 2, 2, 179, 255, 254, + 193, 64, 207, 2, 35, 2, 34, 0, 209, 127, 59, 2, 0, 83, 101, 0, 1, + 0, 14, 0, 1, 0, 6, 17, 195, 100, 52, 0, 22, 118, 189, 211, 18, 0, + 3, 0, 132, 0, 0, 0, 1, 0, 0, 14, 16, 0, 0, 21, 24, 0, 5, 0, 24, + 102, 0, 0, 0, 0, 0, 0, 0, 213, 240, 138, 111, 157, 131, 93, 191, + 0, 1, 81, 128, 0, 2, 163, 0, 0, 13, 0, 88, 0, 0, 49, 32, 97, 100, + 100, 114, 101, 115, 115, 32, 103, 114, 97, 110, 116, 101, 100, 46, + 32, 89, 111, 117, 32, 109, 97, 121, 32, 105, 110, 99, 108, 117, + 100, 101, 32, 73, 65, 65, 68, 68, 82, 32, 105, 110, 32, 73, 65, + 32, 111, 112, 116, 105, 111, 110, 44, 32, 105, 102, 32, 121, 111, + 117, 32, 119, 97, 110, 116, 32, 116, 111, 32, 112, 114, 111, 118, + 105, 100, 101, 32, 97, 32, 104, 105, 110, 116, 46, 0, 2, 0, 14, 0, + 1, 0, 1, 17, 195, 197, 84, 0, 224, 129, 73, 16, 201, 0, 7, 0, 1, + 0, 0, 12, 0, 16, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6 + }; + + EthernetII pkt(request, sizeof(request)); + UDP *udp = pkt.find_pdu(); + const RawPDU *raw = pkt.find_pdu(); + ASSERT_TRUE(udp); + ASSERT_TRUE(raw); + + udp->inner_pdu(raw->to()); + EXPECT_TRUE(pkt.matches_response(reply, sizeof(reply))); + EXPECT_FALSE(pkt.matches_response(request, sizeof(request))); +}