diff --git a/Common++/header/MacAddress.h b/Common++/header/MacAddress.h index 6e0834b013..cbd1dd6575 100644 --- a/Common++/header/MacAddress.h +++ b/Common++/header/MacAddress.h @@ -137,6 +137,8 @@ namespace pcpp /// A static value representing a zero value of MAC address, meaning address of value "00:00:00:00:00:00" static MacAddress Zero; + /// A static value representing a broadcast MAC address, meaning address of value "ff:ff:ff:ff:ff:ff" + static MacAddress Broadcast; private: uint8_t m_Address[6] = { 0 }; diff --git a/Common++/src/MacAddress.cpp b/Common++/src/MacAddress.cpp index 47d990a017..284cffbc3f 100644 --- a/Common++/src/MacAddress.cpp +++ b/Common++/src/MacAddress.cpp @@ -5,6 +5,8 @@ namespace pcpp MacAddress MacAddress::Zero(0, 0, 0, 0, 0, 0); + MacAddress MacAddress::Broadcast(0xff, 0xff, 0xff, 0xff, 0xff, 0xff); + std::string MacAddress::toString() const { char str[19]; diff --git a/Packet++/header/ArpLayer.h b/Packet++/header/ArpLayer.h index 4fb1b0db4c..c1a125ce3c 100644 --- a/Packet++/header/ArpLayer.h +++ b/Packet++/header/ArpLayer.h @@ -3,6 +3,7 @@ #include "Layer.h" #include "IpAddress.h" #include "MacAddress.h" +#include "DeprecationUtils.h" /// @file @@ -42,6 +43,7 @@ namespace pcpp uint32_t targetIpAddr; }; #pragma pack(pop) + static_assert(sizeof(arphdr) == 28, "arphdr size is not 28 bytes"); /** * An enum for ARP message type @@ -52,6 +54,115 @@ namespace pcpp ARP_REPLY = 0x0002 ///< ARP reply (response) }; + /** + * @brief An enum representing the ARP message type + */ + enum class ArpMessageType + { + Unknown, ///< Unknown ARP message type + Request, ///< ARP request + Reply, ///< ARP reply + GratuitousRequest, ///< Gratuitous ARP request + GratuitousReply, ///< Gratuitous ARP reply + }; + + /** + * @brief A struct representing the build data for an ARP request + * + * An ARP request is a message sent by a machine to request the MAC address of another machine on the network. + */ + struct ArpRequest + { + MacAddress senderMacAddr; + IPv4Address senderIpAddr; + IPv4Address targetIpAddr; + + /** + * @brief Construct a new Arp Request object + * @param senderMacAddress The MAC address of the machine sending the query. + * @param senderIPAddress The IP address of the machine sending the query. + * @param targetIPAddress The IP address of the target machine being queried. + */ + ArpRequest(MacAddress const& senderMacAddress, IPv4Address const& senderIPAddress, + IPv4Address const& targetIPAddress) + : senderMacAddr(senderMacAddress), senderIpAddr(senderIPAddress), targetIpAddr(targetIPAddress) {}; + }; + + /** + * @brief A struct representing the build data for an ARP reply + * + * An ARP reply is a message sent by a machine in response to an ARP request. It contains the MAC address of the + * answering machine, and is sent to the IP/MAC address of the machine that sent the original ARP request. + */ + struct ArpReply + { + MacAddress senderMacAddr; + IPv4Address senderIpAddr; + MacAddress targetMacAddr; + IPv4Address targetIpAddr; + + /** + * @brief Construct a new Arp Reply object + * @param senderMacAddress The MAC address of the machine sending the reply. + * @param senderIPAddress The IP address of the machine sending the reply. + * @param targetMacAddress The MAC address of the target machine being replied to. + * @param targetIPAddress The IP address of the target machine being replied to. + * @remarks The target machine is considered the machine that sent the original ARP request. + */ + ArpReply(MacAddress const& senderMacAddress, IPv4Address const& senderIPAddress, + MacAddress const& targetMacAddress, IPv4Address const& targetIPAddress) + : senderMacAddr(senderMacAddress), senderIpAddr(senderIPAddress), targetMacAddr(targetMacAddress), + targetIpAddr(targetIPAddress) {}; + }; + + /** + * @brief A struct representing the build data for a gratuitous ARP request + * + * A gratuitous ARP request is an ARP request that is sent by a machine to announce its presence on the network. + * It is an ARP request that has both the sender and target IP addresses set to the IP address of the machine + * and the target MAC address set to the broadcast address. Normally such a request will not receive a reply. + * + * These requests can be used to update ARP caches on other machines on the network, or to help in detecting IP + * address conflicts. + */ + struct GratuitousArpRequest + { + MacAddress senderMacAddr; + IPv4Address senderIpAddr; + + /** + * @brief Construct a new Gratuitous Arp Request object + * @param senderMacAddress The MAC address of the machine sending the gratuitous ARP request. + * @param senderIPAddress The IP address of the machine sending the gratuitous ARP request. + * @remarks The target MAC address is set to the broadcast address and the target IP address is set to the + * sender's. + */ + GratuitousArpRequest(MacAddress const& senderMacAddress, IPv4Address const& senderIPAddress) + : senderMacAddr(senderMacAddress), senderIpAddr(senderIPAddress) {}; + }; + + /** + * @brief A struct representing the build data a gratuitous ARP reply + * + * A gratuitous ARP reply is an ARP reply that is sent by a machine to announce its presence on the network. + * It is gratuitous in the sense that it is not in response to an ARP request, but sent unsolicited to the network. + */ + struct GratuitousArpReply + { + MacAddress senderMacAddr; + IPv4Address senderIpAddr; + + /** + * @brief Construct a new Gratuitous Arp Reply object + * @param senderMacAddress The MAC address of the machine sending the gratuitous ARP reply. + * @param senderIPAddress The IP address of the machine sending the gratuitous ARP reply. + * @remarks The target MAC address is set to the broadcast address and the target IP address is set to the + * sender's. + */ + GratuitousArpReply(MacAddress const& senderMacAddress, IPv4Address const& senderIPAddress) + : senderMacAddr(senderMacAddress), senderIpAddr(senderIPAddress) {}; + }; + /** * @class ArpLayer * Represents an ARP protocol layer. Currently only IPv4 ARP messages are supported @@ -72,6 +183,19 @@ namespace pcpp m_DataLen = sizeof(arphdr); } + /** + * @brief A constructor that creates an ARP header + * @param[in] opCode ARP message type (ARP request or ARP reply) + * @param[in] senderMacAddr The sender MAC address (will be put in arphdr#senderMacAddr) + * @param[in] senderIpAddr The sender IP address (will be put in arphdr#senderIpAddr) + * @param[in] targetMacAddr The target MAC address (will be put in arphdr#targetMacAddr) + * @param[in] targetIpAddr The target IP address (will be put in arphdr#targetIpAddr) + * @remarks No validation is done on the input parameters. The caller must ensure that the input creates a valid + * header. + */ + ArpLayer(ArpOpcode opCode, const MacAddress& senderMacAddr, const IPv4Address& senderIpAddr, + const MacAddress& targetMacAddr, const IPv4Address& targetIpAddr); + /** * A constructor that allocates a new ARP header * @param[in] opCode ARP message type (ARP request or ARP reply) @@ -79,10 +203,37 @@ namespace pcpp * @param[in] targetMacAddr The target MAC address (will be put in arphdr#targetMacAddr) * @param[in] senderIpAddr The sender IP address (will be put in arphdr#senderIpAddr) * @param[in] targetIpAddr The target IP address (will be put in arphdr#targetIpAddr) + * @deprecated This constructor has been deprecated. Please use one of the other overloads. + * @remarks This constructor zeroes the target MAC address for ARP requests to keep backward compatibility. */ + PCPP_DEPRECATED("This constructor has been deprecated. Please use one of the other overloads.") ArpLayer(ArpOpcode opCode, const MacAddress& senderMacAddr, const MacAddress& targetMacAddr, const IPv4Address& senderIpAddr, const IPv4Address& targetIpAddr); + /** + * @brief A constructor that creates an ARP request header. + * @param arpRequest The ARP request data + */ + explicit ArpLayer(ArpRequest const& arpRequest); + + /** + * @brief A constructor that creates an ARP reply header. + * @param arpReply The ARP reply data + */ + explicit ArpLayer(ArpReply const& arpReply); + + /** + * @brief A constructor that creates a gratuitous ARP request header. + * @param gratuitousArpRequest The gratuitous ARP request data + */ + explicit ArpLayer(GratuitousArpRequest const& gratuitousArpRequest); + + /** + * @brief A constructor that creates a gratuitous ARP reply header. + * @param gratuitousArpReply The gratuitous ARP reply data + */ + explicit ArpLayer(GratuitousArpReply const& gratuitousArpReply); + ~ArpLayer() override = default; /** @@ -95,6 +246,13 @@ namespace pcpp return reinterpret_cast(m_Data); } + /** + * Get the ARP opcode + * @return The ARP opcode + * @remarks The opcode may not be one of the values in @ref ArpOpcode + */ + ArpOpcode getOpcode() const; + /** * Get the sender hardware address (SHA) in the form of MacAddress * @return A MacAddress containing the sender hardware address (SHA) @@ -153,10 +311,15 @@ namespace pcpp * - @ref arphdr#hardwareSize = 6 * - @ref arphdr#protocolType = ETHERTYPE_IP (assume IPv4 over ARP) * - @ref arphdr#protocolSize = 4 (assume IPv4 over ARP) - * - if it's an ARP request: @ref arphdr#targetMacAddr = MacAddress("00:00:00:00:00:00") */ void computeCalculateFields() override; + /** + * @brief Attempts to determine the ARP message type based on the header signature. + * @return An @ref ArpMessageType representing the ARP message type. + */ + ArpMessageType getMessageType() const; + /** * Is this packet an ARP request? */ diff --git a/Packet++/src/ArpLayer.cpp b/Packet++/src/ArpLayer.cpp index 4971addd37..0ae415d27f 100644 --- a/Packet++/src/ArpLayer.cpp +++ b/Packet++/src/ArpLayer.cpp @@ -6,22 +6,52 @@ namespace pcpp { - - ArpLayer::ArpLayer(ArpOpcode opCode, const MacAddress& senderMacAddr, const MacAddress& targetMacAddr, - const IPv4Address& senderIpAddr, const IPv4Address& targetIpAddr) + ArpLayer::ArpLayer(ArpOpcode opCode, const MacAddress& senderMacAddr, const IPv4Address& senderIpAddr, + const MacAddress& targetMacAddr, const IPv4Address& targetIpAddr) { - const size_t headerLen = sizeof(arphdr); + constexpr size_t headerLen = sizeof(arphdr); m_DataLen = headerLen; - m_Data = new uint8_t[headerLen]; - memset(m_Data, 0, sizeof(headerLen)); + m_Data = new uint8_t[headerLen]{}; // zero-initialized m_Protocol = ARP; arphdr* arpHeader = getArpHeader(); arpHeader->opcode = htobe16(static_cast(opCode)); - targetMacAddr.copyTo(arpHeader->targetMacAddr); senderMacAddr.copyTo(arpHeader->senderMacAddr); - arpHeader->targetIpAddr = targetIpAddr.toInt(); + targetMacAddr.copyTo(arpHeader->targetMacAddr); arpHeader->senderIpAddr = senderIpAddr.toInt(); + arpHeader->targetIpAddr = targetIpAddr.toInt(); + } + + // This constructor zeroes the target MAC address for ARP requests to keep backward compatibility. + ArpLayer::ArpLayer(ArpOpcode opCode, const MacAddress& senderMacAddr, const MacAddress& targetMacAddr, + const IPv4Address& senderIpAddr, const IPv4Address& targetIpAddr) + : ArpLayer(opCode, senderMacAddr, senderIpAddr, opCode == ARP_REQUEST ? MacAddress::Zero : targetMacAddr, + targetIpAddr) + {} + + ArpLayer::ArpLayer(ArpRequest const& arpRequest) + : ArpLayer(ARP_REQUEST, arpRequest.senderMacAddr, arpRequest.senderIpAddr, MacAddress::Zero, + arpRequest.targetIpAddr) + {} + + ArpLayer::ArpLayer(ArpReply const& arpReply) + : ArpLayer(ARP_REPLY, arpReply.senderMacAddr, arpReply.senderIpAddr, arpReply.targetMacAddr, + arpReply.targetIpAddr) + {} + + ArpLayer::ArpLayer(GratuitousArpRequest const& gratuitousArpRequest) + : ArpLayer(ARP_REQUEST, gratuitousArpRequest.senderMacAddr, gratuitousArpRequest.senderIpAddr, + MacAddress::Broadcast, gratuitousArpRequest.senderIpAddr) + {} + + ArpLayer::ArpLayer(GratuitousArpReply const& gratuitousArpReply) + : ArpLayer(ARP_REPLY, gratuitousArpReply.senderMacAddr, gratuitousArpReply.senderIpAddr, MacAddress::Broadcast, + gratuitousArpReply.senderIpAddr) + {} + + ArpOpcode ArpLayer::getOpcode() const + { + return static_cast(be16toh(getArpHeader()->opcode)); } void ArpLayer::computeCalculateFields() @@ -31,31 +61,55 @@ namespace pcpp arpHeader->hardwareSize = 6; arpHeader->protocolType = htobe16(PCPP_ETHERTYPE_IP); // assume IPv4 over ARP arpHeader->protocolSize = 4; // assume IPv4 over ARP - if (arpHeader->opcode == htobe16(ARP_REQUEST)) - MacAddress::Zero.copyTo(arpHeader->targetMacAddr); + } + + ArpMessageType ArpLayer::getMessageType() const + { + switch (getOpcode()) + { + case ArpOpcode::ARP_REQUEST: + { + if (getTargetMacAddress() == MacAddress::Broadcast && getSenderIpAddr() == getTargetIpAddr()) + { + return ArpMessageType::GratuitousRequest; + } + return ArpMessageType::Request; + } + case ArpOpcode::ARP_REPLY: + { + if (getTargetMacAddress() == MacAddress::Broadcast && getSenderIpAddr() == getTargetIpAddr()) + { + return ArpMessageType::GratuitousReply; + } + return ArpMessageType::Reply; + } + default: + return ArpMessageType::Unknown; + } } bool ArpLayer::isRequest() const { - return be16toh(getArpHeader()->opcode) == pcpp::ArpOpcode::ARP_REQUEST; + return getOpcode() == pcpp::ArpOpcode::ARP_REQUEST; } bool ArpLayer::isReply() const { - return be16toh(getArpHeader()->opcode) == pcpp::ArpOpcode::ARP_REPLY; + return getOpcode() == pcpp::ArpOpcode::ARP_REPLY; } std::string ArpLayer::toString() const { - if (be16toh(getArpHeader()->opcode) == ARP_REQUEST) + switch (getOpcode()) { + case ArpOpcode::ARP_REQUEST: return "ARP Layer, ARP request, who has " + getTargetIpAddr().toString() + " ? Tell " + getSenderIpAddr().toString(); - } - else - { + case ArpOpcode::ARP_REPLY: return "ARP Layer, ARP reply, " + getSenderIpAddr().toString() + " is at " + getSenderMacAddress().toString(); + default: + return "ARP Layer, unknown opcode (" + std::to_string(getOpcode()) + ")"; } } diff --git a/Pcap++/src/NetworkUtils.cpp b/Pcap++/src/NetworkUtils.cpp index 61269bc26c..27fd3a62a4 100644 --- a/Pcap++/src/NetworkUtils.cpp +++ b/Pcap++/src/NetworkUtils.cpp @@ -106,10 +106,8 @@ namespace pcpp Packet arpRequest(100); - MacAddress destMac(0xff, 0xff, 0xff, 0xff, 0xff, 0xff); - EthLayer ethLayer(sourceMac, destMac); - - ArpLayer arpLayer(ARP_REQUEST, sourceMac, destMac, sourceIP, ipAddr); + EthLayer ethLayer(sourceMac, MacAddress::Broadcast); + ArpLayer arpLayer(ArpRequest(sourceMac, sourceIP, ipAddr)); if (!arpRequest.addLayer(ðLayer)) { diff --git a/Tests/Packet++Test/Tests/EthAndArpTests.cpp b/Tests/Packet++Test/Tests/EthAndArpTests.cpp index b8faea90aa..950fdfadcf 100644 --- a/Tests/Packet++Test/Tests/EthAndArpTests.cpp +++ b/Tests/Packet++Test/Tests/EthAndArpTests.cpp @@ -120,32 +120,129 @@ PTF_TEST_CASE(EthAndArpPacketParsing) PTF_TEST_CASE(ArpPacketCreation) { - pcpp::MacAddress srcMac("6c:f0:49:b2:de:6e"); - pcpp::MacAddress dstMac("ff:ff:ff:ff:ff:ff"); - pcpp::EthLayer ethLayer(srcMac, dstMac, PCPP_ETHERTYPE_ARP); - - pcpp::ArpLayer arpLayer(pcpp::ARP_REQUEST, srcMac, srcMac, pcpp::IPv4Address("10.0.0.1"), - pcpp::IPv4Address("10.0.0.138")); - - pcpp::Packet arpRequestPacket(1); - PTF_ASSERT_TRUE(arpRequestPacket.addLayer(ðLayer)); - PTF_ASSERT_TRUE(arpRequestPacket.addLayer(&arpLayer)); - arpRequestPacket.computeCalculateFields(); - PTF_ASSERT_EQUAL(arpRequestPacket.getRawPacket()->getRawDataLen(), 42); - - pcpp::ArpLayer* pArpLayer = arpRequestPacket.getLayerOfType(); - PTF_ASSERT_NOT_NULL(pArpLayer); - - pcpp::arphdr* arpHeader = pArpLayer->getArpHeader(); - PTF_ASSERT_EQUAL(arpHeader->hardwareSize, 6); - PTF_ASSERT_EQUAL(arpHeader->protocolType, htobe16(PCPP_ETHERTYPE_IP)); - READ_FILE_INTO_BUFFER(1, "PacketExamples/ArpRequestPacket.dat"); - - PTF_ASSERT_EQUAL(bufferLength1, arpRequestPacket.getRawPacket()->getRawDataLen()); - PTF_ASSERT_BUF_COMPARE(arpRequestPacket.getRawPacket()->getRawData(), buffer1, bufferLength1); - - delete[] buffer1; + // Stores the buffer in a unique_ptr to ensure it's deleted when the test ends. + std::unique_ptr buffer1Uptr(buffer1); + + { + pcpp::MacAddress srcMac("6c:f0:49:b2:de:6e"); + pcpp::MacAddress dstMac("ff:ff:ff:ff:ff:ff"); + pcpp::EthLayer ethLayer(srcMac, dstMac, PCPP_ETHERTYPE_ARP); + pcpp::ArpLayer arpLayer(pcpp::ARP_REQUEST, srcMac, srcMac, pcpp::IPv4Address("10.0.0.1"), + pcpp::IPv4Address("10.0.0.138")); + + PTF_ASSERT_TRUE(arpLayer.getMessageType() == pcpp::ArpMessageType::Request); + + pcpp::Packet arpRequestPacket(1); + + PTF_ASSERT_TRUE(arpRequestPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(arpRequestPacket.addLayer(&arpLayer)); + arpRequestPacket.computeCalculateFields(); + PTF_ASSERT_EQUAL(arpRequestPacket.getRawPacket()->getRawDataLen(), 42); + + pcpp::ArpLayer* pArpLayer = arpRequestPacket.getLayerOfType(); + PTF_ASSERT_NOT_NULL(pArpLayer); + + pcpp::arphdr* arpHeader = pArpLayer->getArpHeader(); + PTF_ASSERT_EQUAL(arpHeader->hardwareSize, 6); + PTF_ASSERT_EQUAL(arpHeader->protocolType, htobe16(PCPP_ETHERTYPE_IP)); + + PTF_ASSERT_EQUAL(bufferLength1, arpRequestPacket.getRawPacket()->getRawDataLen()); + PTF_ASSERT_BUF_COMPARE(arpRequestPacket.getRawPacket()->getRawData(), buffer1, bufferLength1); + } + + { + pcpp::MacAddress srcMac("6c:f0:49:b2:de:6e"); + pcpp::IPv4Address srcIp("10.0.0.1"); + pcpp::IPv4Address dstIp("10.0.0.138"); + + pcpp::EthLayer ethLayer(srcMac, pcpp::MacAddress::Broadcast, PCPP_ETHERTYPE_ARP); + pcpp::ArpLayer arpLayer(pcpp::ArpRequest(srcMac, srcIp, dstIp)); + + PTF_ASSERT_TRUE(arpLayer.getMessageType() == pcpp::ArpMessageType::Request); + + pcpp::Packet argRequestPacket(1); + PTF_ASSERT_TRUE(argRequestPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(argRequestPacket.addLayer(&arpLayer)); + + argRequestPacket.computeCalculateFields(); + PTF_ASSERT_EQUAL(argRequestPacket.getRawPacket()->getRawDataLen(), 42); + + pcpp::ArpLayer* pArpLayer = argRequestPacket.getLayerOfType(); + PTF_ASSERT_NOT_NULL(pArpLayer); + + pcpp::arphdr* arpHeader = pArpLayer->getArpHeader(); + PTF_ASSERT_EQUAL(arpHeader->hardwareSize, 6); + PTF_ASSERT_EQUAL(arpHeader->protocolType, htobe16(PCPP_ETHERTYPE_IP)); + + PTF_ASSERT_EQUAL(bufferLength1, argRequestPacket.getRawPacket()->getRawDataLen()); + PTF_ASSERT_BUF_COMPARE(argRequestPacket.getRawPacket()->getRawData(), buffer1, bufferLength1); + } + + { + // TODO: Add an actual packet to test against. + pcpp::MacAddress srcMac("02:00:00:00:00:02"); + pcpp::IPv4Address srcIp("10.0.0.138"); + pcpp::MacAddress dstMac("02:00:00:00:00:01"); + pcpp::IPv4Address dstIp("10.0.0.1"); + + pcpp::ArpLayer arpLayer(pcpp::ArpReply(srcMac, srcIp, dstMac, dstIp)); + + arpLayer.computeCalculateFields(); + PTF_ASSERT_EQUAL(arpLayer.getHeaderLen(), 28); + PTF_ASSERT_EQUAL(arpLayer.getArpHeader()->hardwareSize, 6); + PTF_ASSERT_EQUAL(arpLayer.getArpHeader()->protocolSize, 4); + PTF_ASSERT_EQUAL(arpLayer.getArpHeader()->hardwareType, htobe16(1)); + PTF_ASSERT_EQUAL(arpLayer.getArpHeader()->protocolType, htobe16(PCPP_ETHERTYPE_IP)); + PTF_ASSERT_EQUAL(arpLayer.getArpHeader()->opcode, htobe16(pcpp::ARP_REPLY)); + PTF_ASSERT_TRUE(arpLayer.getMessageType() == pcpp::ArpMessageType::Reply); + PTF_ASSERT_EQUAL(arpLayer.getSenderMacAddress(), srcMac); + PTF_ASSERT_EQUAL(arpLayer.getSenderIpAddr(), srcIp); + PTF_ASSERT_EQUAL(arpLayer.getTargetMacAddress(), dstMac); + PTF_ASSERT_EQUAL(arpLayer.getTargetIpAddr(), dstIp); + } + + { + // TODO: Add an actual packet to test against. + pcpp::MacAddress srcMac("02:00:00:00:00:01"); + pcpp::IPv4Address srcIp("10.0.0.1"); + + pcpp::ArpLayer arpLayer(pcpp::GratuitousArpRequest(srcMac, srcIp)); + arpLayer.computeCalculateFields(); + + PTF_ASSERT_EQUAL(arpLayer.getHeaderLen(), 28); + PTF_ASSERT_EQUAL(arpLayer.getArpHeader()->hardwareSize, 6); + PTF_ASSERT_EQUAL(arpLayer.getArpHeader()->protocolSize, 4); + PTF_ASSERT_EQUAL(arpLayer.getArpHeader()->hardwareType, htobe16(1)); + PTF_ASSERT_EQUAL(arpLayer.getArpHeader()->protocolType, htobe16(PCPP_ETHERTYPE_IP)); + PTF_ASSERT_EQUAL(arpLayer.getArpHeader()->opcode, htobe16(pcpp::ARP_REQUEST)); + PTF_ASSERT_TRUE(arpLayer.getMessageType() == pcpp::ArpMessageType::GratuitousRequest); + PTF_ASSERT_EQUAL(arpLayer.getSenderMacAddress(), srcMac); + PTF_ASSERT_EQUAL(arpLayer.getSenderIpAddr(), srcIp); + PTF_ASSERT_EQUAL(arpLayer.getTargetMacAddress(), pcpp::MacAddress::Broadcast); + PTF_ASSERT_EQUAL(arpLayer.getTargetIpAddr(), srcIp); + } + + { + // TODO: Add an actual packet to test against. + pcpp::MacAddress srcMac("02:00:00:00:00:01"); + pcpp::IPv4Address srcIp("10.0.0.1"); + + pcpp::ArpLayer arpLayer(pcpp::GratuitousArpReply(srcMac, srcIp)); + arpLayer.computeCalculateFields(); + + PTF_ASSERT_EQUAL(arpLayer.getHeaderLen(), 28); + PTF_ASSERT_EQUAL(arpLayer.getArpHeader()->hardwareSize, 6); + PTF_ASSERT_EQUAL(arpLayer.getArpHeader()->protocolSize, 4); + PTF_ASSERT_EQUAL(arpLayer.getArpHeader()->hardwareType, htobe16(1)); + PTF_ASSERT_EQUAL(arpLayer.getArpHeader()->protocolType, htobe16(PCPP_ETHERTYPE_IP)); + PTF_ASSERT_EQUAL(arpLayer.getArpHeader()->opcode, htobe16(pcpp::ARP_REPLY)); + PTF_ASSERT_TRUE(arpLayer.getMessageType() == pcpp::ArpMessageType::GratuitousReply); + PTF_ASSERT_EQUAL(arpLayer.getSenderMacAddress(), srcMac); + PTF_ASSERT_EQUAL(arpLayer.getSenderIpAddr(), srcIp); + PTF_ASSERT_EQUAL(arpLayer.getTargetMacAddress(), pcpp::MacAddress::Broadcast); + PTF_ASSERT_EQUAL(arpLayer.getTargetIpAddr(), srcIp); + } } // ArpPacketCreation PTF_TEST_CASE(EthDot3LayerParsingTest)