Skip to content

Commit

Permalink
Added a mechanism to probe for known header signatures to discover th…
Browse files Browse the repository at this point in the history
…e type of ARP message.
  • Loading branch information
Dimi1010 committed Jan 11, 2025
1 parent 85b6c74 commit bbe9904
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 7 deletions.
26 changes: 25 additions & 1 deletion Packet++/header/ArpLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,18 @@ 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
*
Expand Down Expand Up @@ -234,6 +246,13 @@ namespace pcpp
return reinterpret_cast<arphdr*>(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)
Expand Down Expand Up @@ -292,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?
*/
Expand Down
43 changes: 37 additions & 6 deletions Packet++/src/ArpLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ namespace pcpp
gratuitousArpReply.senderIpAddr)
{}

ArpOpcode ArpLayer::getOpcode() const
{
return static_cast<ArpOpcode>(be16toh(getArpHeader()->opcode));
}

void ArpLayer::computeCalculateFields()
{
arphdr* arpHeader = getArpHeader();
Expand All @@ -58,27 +63,53 @@ namespace pcpp
arpHeader->protocolSize = 4; // assume IPv4 over ARP
}

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()) + ")";
}
}

Expand Down
7 changes: 7 additions & 0 deletions Tests/Packet++Test/Tests/EthAndArpTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ PTF_TEST_CASE(ArpPacketCreation)
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(&ethLayer));
Expand All @@ -157,6 +159,8 @@ PTF_TEST_CASE(ArpPacketCreation)
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(&ethLayer));
PTF_ASSERT_TRUE(argRequestPacket.addLayer(&arpLayer));
Expand Down Expand Up @@ -191,6 +195,7 @@ PTF_TEST_CASE(ArpPacketCreation)
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);
Expand All @@ -211,6 +216,7 @@ PTF_TEST_CASE(ArpPacketCreation)
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);
Expand All @@ -231,6 +237,7 @@ PTF_TEST_CASE(ArpPacketCreation)
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);
Expand Down

0 comments on commit bbe9904

Please sign in to comment.