Coverage Report

Created: 2026-10-17 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/ArpLayer.cpp
Line
Count
Source
1
#define LOG_MODULE PacketLogModuleArpLayer
2
3
#include "ArpLayer.h"
4
#include "EthLayer.h"
5
#include "EndianPortable.h"
6
7
namespace pcpp
8
{
9
  ArpLayer::ArpLayer(ArpOpcode opCode, const MacAddress& senderMacAddr, const IPv4Address& senderIpAddr,
10
                     const MacAddress& targetMacAddr, const IPv4Address& targetIpAddr)
11
0
  {
12
0
    constexpr size_t headerLen = sizeof(arphdr);
13
0
    allocData(headerLen);
14
0
    m_Protocol = ARP;
15
16
0
    arphdr* arpHeader = getArpHeader();
17
0
    arpHeader->opcode = htobe16(static_cast<uint16_t>(opCode));
18
0
    senderMacAddr.copyTo(arpHeader->senderMacAddr);
19
0
    targetMacAddr.copyTo(arpHeader->targetMacAddr);
20
0
    arpHeader->senderIpAddr = senderIpAddr.toInt();
21
0
    arpHeader->targetIpAddr = targetIpAddr.toInt();
22
0
  }
23
24
  // This constructor zeroes the target MAC address for ARP requests to keep backward compatibility.
25
  ArpLayer::ArpLayer(ArpOpcode opCode, const MacAddress& senderMacAddr, const MacAddress& targetMacAddr,
26
                     const IPv4Address& senderIpAddr, const IPv4Address& targetIpAddr)
27
0
      : ArpLayer(opCode, senderMacAddr, senderIpAddr, opCode == ARP_REQUEST ? MacAddress::Zero : targetMacAddr,
28
0
                 targetIpAddr)
29
0
  {}
30
31
  ArpLayer::ArpLayer(ArpRequest const& arpRequest)
32
0
      : ArpLayer(ARP_REQUEST, arpRequest.senderMacAddr, arpRequest.senderIpAddr, MacAddress::Zero,
33
0
                 arpRequest.targetIpAddr)
34
0
  {}
35
36
  ArpLayer::ArpLayer(ArpReply const& arpReply)
37
0
      : ArpLayer(ARP_REPLY, arpReply.senderMacAddr, arpReply.senderIpAddr, arpReply.targetMacAddr,
38
0
                 arpReply.targetIpAddr)
39
0
  {}
40
41
  ArpLayer::ArpLayer(GratuitousArpRequest const& gratuitousArpRequest)
42
0
      : ArpLayer(ARP_REQUEST, gratuitousArpRequest.senderMacAddr, gratuitousArpRequest.senderIpAddr,
43
0
                 MacAddress::Broadcast, gratuitousArpRequest.senderIpAddr)
44
0
  {}
45
46
  ArpLayer::ArpLayer(GratuitousArpReply const& gratuitousArpReply)
47
0
      : ArpLayer(ARP_REPLY, gratuitousArpReply.senderMacAddr, gratuitousArpReply.senderIpAddr, MacAddress::Broadcast,
48
0
                 gratuitousArpReply.senderIpAddr)
49
0
  {}
50
51
  ArpOpcode ArpLayer::getOpcode() const
52
0
  {
53
0
    return static_cast<ArpOpcode>(be16toh(getArpHeader()->opcode));
54
0
  }
55
56
  void ArpLayer::computeCalculateFields()
57
0
  {
58
0
    arphdr* arpHeader = getArpHeader();
59
0
    arpHeader->hardwareType = htobe16(1);  // Ethernet
60
0
    arpHeader->hardwareSize = 6;
61
0
    arpHeader->protocolType = htobe16(PCPP_ETHERTYPE_IP);  // assume IPv4 over ARP
62
0
    arpHeader->protocolSize = 4;                           // assume IPv4 over ARP
63
0
  }
64
65
  ArpMessageType ArpLayer::getMessageType() const
66
0
  {
67
0
    switch (getOpcode())
68
0
    {
69
0
    case ArpOpcode::ARP_REQUEST:
70
0
    {
71
0
      if (getTargetMacAddress() == MacAddress::Broadcast && getSenderIpAddr() == getTargetIpAddr())
72
0
      {
73
0
        return ArpMessageType::GratuitousRequest;
74
0
      }
75
0
      return ArpMessageType::Request;
76
0
    }
77
0
    case ArpOpcode::ARP_REPLY:
78
0
    {
79
0
      if (getTargetMacAddress() == MacAddress::Broadcast && getSenderIpAddr() == getTargetIpAddr())
80
0
      {
81
0
        return ArpMessageType::GratuitousReply;
82
0
      }
83
0
      return ArpMessageType::Reply;
84
0
    }
85
0
    default:
86
0
      return ArpMessageType::Unknown;
87
0
    }
88
0
  }
89
90
  bool ArpLayer::isRequest() const
91
0
  {
92
0
    return getOpcode() == pcpp::ArpOpcode::ARP_REQUEST;
93
0
  }
94
95
  bool ArpLayer::isReply() const
96
0
  {
97
0
    return getOpcode() == pcpp::ArpOpcode::ARP_REPLY;
98
0
  }
99
100
  std::string ArpLayer::toString() const
101
0
  {
102
0
    switch (getOpcode())
103
0
    {
104
0
    case ArpOpcode::ARP_REQUEST:
105
0
      return "ARP Layer, ARP request, who has " + getTargetIpAddr().toString() + " ? Tell " +
106
0
             getSenderIpAddr().toString();
107
0
    case ArpOpcode::ARP_REPLY:
108
0
      return "ARP Layer, ARP reply, " + getSenderIpAddr().toString() + " is at " +
109
0
             getSenderMacAddress().toString();
110
0
    default:
111
0
      return "ARP Layer, unknown opcode (" + std::to_string(getOpcode()) + ")";
112
0
    }
113
0
  }
114
115
  const FieldDescriptor ArpLayer::SerializedFields::OpCode{ Layer::SerializedFields::MaxID + 1, "opCode" };
116
  const FieldDescriptor ArpLayer::SerializedFields::SenderMacAddress{ Layer::SerializedFields::MaxID + 2,
117
                                                                    "senderMacAddress" };
118
  const FieldDescriptor ArpLayer::SerializedFields::TargetMacAddress{ Layer::SerializedFields::MaxID + 3,
119
                                                                    "targetMacAddress" };
120
  const FieldDescriptor ArpLayer::SerializedFields::SenderIpAddress{ Layer::SerializedFields::MaxID + 4,
121
                                                                   "senderIpAddress" };
122
  const FieldDescriptor ArpLayer::SerializedFields::TargetIpAddress{ Layer::SerializedFields::MaxID + 5,
123
                                                                   "targetIpAddress" };
124
  const FieldDescriptor ArpLayer::SerializedFields::MessageType{ Layer::SerializedFields::MaxID + 6, "messageType" };
125
  const FieldDescriptor ArpLayer::SerializedFields::HardwareType{ Layer::SerializedFields::MaxID + 7,
126
                                                                "hardwareType" };
127
  const FieldDescriptor ArpLayer::SerializedFields::HardwareSize{ Layer::SerializedFields::MaxID + 8,
128
                                                                "hardwareSize" };
129
  const FieldDescriptor ArpLayer::SerializedFields::ProtocolType{ Layer::SerializedFields::MaxID + 9,
130
                                                                "protocolType" };
131
  const FieldDescriptor ArpLayer::SerializedFields::ProtocolSize{ Layer::SerializedFields::MaxID + 10,
132
                                                                "protocolSize" };
133
134
  static constexpr const char* getOpCodeAsString(ArpOpcode opCode)
135
0
  {
136
0
    switch (opCode)
137
0
    {
138
0
    case ARP_REQUEST:
139
0
      return "Request";
140
0
    case ARP_REPLY:
141
0
      return "Reply";
142
0
    default:
143
0
      return "Unknown";
144
0
    }
145
0
  }
146
147
  static constexpr const char* getMessageTypeAsString(ArpMessageType messageType)
148
0
  {
149
0
    switch (messageType)
150
0
    {
151
0
    case ArpMessageType::Request:
152
0
      return "Request";
153
0
    case ArpMessageType::Reply:
154
0
      return "Reply";
155
0
    case ArpMessageType::GratuitousRequest:
156
0
      return "GratuitousRequest";
157
0
    case ArpMessageType::GratuitousReply:
158
0
      return "GratuitousReply";
159
0
    default:
160
0
      return "Unknown";
161
0
    }
162
0
  }
163
164
  void ArpLayer::serializeLayer(ObjectScope& serializer) const
165
0
  {
166
0
    auto* opCode = getOpCodeAsString(getOpcode());
167
0
    auto* messageType = getMessageTypeAsString(getMessageType());
168
169
0
    serializer.writeField(SerializedFields::OpCode, opCode);
170
0
    serializer.writeField(SerializedFields::SenderMacAddress, getSenderMacAddress().toString());
171
0
    serializer.writeField(SerializedFields::TargetMacAddress, getTargetMacAddress().toString());
172
0
    serializer.writeField(SerializedFields::SenderIpAddress, getSenderIpAddr().toString());
173
0
    serializer.writeField(SerializedFields::TargetIpAddress, getTargetIpAddr().toString());
174
0
    serializer.writeField(SerializedFields::MessageType, messageType);
175
0
    auto* header = getArpHeader();
176
0
    serializer.writeField(SerializedFields::HardwareType, be16toh(header->hardwareType));
177
0
    serializer.writeField(SerializedFields::HardwareSize, header->hardwareSize);
178
    serializer.writeField(SerializedFields::ProtocolType, be16toh(header->protocolType));
179
0
    serializer.writeField(SerializedFields::ProtocolSize, header->protocolSize);
180
0
  }
181
}  // namespace pcpp