Coverage Report

Created: 2026-09-03 08:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/DhcpLayer.cpp
Line
Count
Source
1
106
#define LOG_MODULE PacketLogModuleDhcpLayer
2
3
#include "DhcpLayer.h"
4
#include "Logger.h"
5
6
namespace pcpp
7
{
8
9
  constexpr uint32_t DhcpMagicNumber = 0x63538263;
10
11
  DhcpOption DhcpOptionBuilder::build() const
12
0
  {
13
0
    size_t recSize = 2 * sizeof(uint8_t) + m_RecValueLen;
14
0
    uint8_t recType = static_cast<uint8_t>(m_RecType);
15
16
0
    if ((recType == DHCPOPT_END || recType == DHCPOPT_PAD))
17
0
    {
18
0
      if (m_RecValueLen != 0)
19
0
      {
20
0
        PCPP_LOG_ERROR(
21
0
            "Can't set DHCP END option or DHCP PAD option with size different than 0, tried to set size "
22
0
            << (int)m_RecValueLen);
23
0
        return DhcpOption(nullptr);
24
0
      }
25
26
0
      recSize = sizeof(uint8_t);
27
0
    }
28
29
0
    uint8_t* recordBuffer = new uint8_t[recSize];
30
0
    memset(recordBuffer, 0, recSize);
31
0
    recordBuffer[0] = recType;
32
0
    if (recSize > 1)
33
0
    {
34
0
      recordBuffer[1] = static_cast<uint8_t>(m_RecValueLen);
35
0
      if (m_RecValue != nullptr)
36
0
        memcpy(recordBuffer + 2, m_RecValue, m_RecValueLen);
37
0
      else
38
0
        memset(recordBuffer + 2, 0, m_RecValueLen);
39
0
    }
40
41
0
    return DhcpOption(recordBuffer);
42
0
  }
43
44
  DhcpLayer::DhcpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
45
14.0k
      : Layer(data, dataLen, prevLayer, packet, DHCP)
46
14.0k
  {}
47
48
  void DhcpLayer::initDhcpLayer(size_t numOfBytesToAllocate)
49
0
  {
50
0
    allocData(numOfBytesToAllocate);
51
0
    m_Protocol = DHCP;
52
0
  }
53
54
0
  DhcpLayer::DhcpLayer() : Layer()
55
0
  {
56
0
    initDhcpLayer(sizeof(dhcp_header));
57
0
  }
58
59
0
  DhcpLayer::DhcpLayer(DhcpMessageType msgType, const MacAddress& clientMacAddr) : Layer()
60
0
  {
61
0
    initDhcpLayer(sizeof(dhcp_header) + 4 * sizeof(uint8_t));
62
63
0
    setClientHardwareAddress(clientMacAddr);
64
65
0
    uint8_t* msgTypeOptionPtr = m_Data + sizeof(dhcp_header);
66
0
    msgTypeOptionPtr[0] = (uint8_t)DHCPOPT_DHCP_MESSAGE_TYPE;  // option code
67
0
    msgTypeOptionPtr[1] = 1;                                   // option len
68
0
    msgTypeOptionPtr[2] = (uint8_t)msgType;                    // option data - message type
69
70
0
    msgTypeOptionPtr[3] = (uint8_t)DHCPOPT_END;
71
0
  }
72
73
  MacAddress DhcpLayer::getClientHardwareAddress() const
74
2.79k
  {
75
2.79k
    dhcp_header* hdr = getDhcpHeader();
76
2.79k
    if (hdr != nullptr && hdr->hardwareType == 1 && hdr->hardwareAddressLength == 6)
77
2.68k
      return MacAddress(hdr->clientHardwareAddress);
78
79
106
    PCPP_LOG_DEBUG("Hardware type isn't Ethernet or hardware addr len != 6, returning MacAddress:Zero");
80
81
106
    return MacAddress::Zero;
82
2.79k
  }
83
84
  void DhcpLayer::setClientHardwareAddress(const MacAddress& addr)
85
0
  {
86
0
    dhcp_header* hdr = getDhcpHeader();
87
0
    hdr->hardwareType = 1;           // Ethernet
88
0
    hdr->hardwareAddressLength = 6;  // MAC address length
89
0
    addr.copyTo(hdr->clientHardwareAddress);
90
0
  }
91
92
  void DhcpLayer::computeCalculateFields()
93
2.79k
  {
94
2.79k
    dhcp_header* hdr = getDhcpHeader();
95
96
2.79k
    hdr->magicNumber = DhcpMagicNumber;
97
98
2.79k
    DhcpMessageType msgType = getMessageType();
99
2.79k
    switch (msgType)
100
2.79k
    {
101
24
    case DHCP_DISCOVER:
102
766
    case DHCP_REQUEST:
103
1.01k
    case DHCP_DECLINE:
104
1.01k
    case DHCP_RELEASE:
105
1.03k
    case DHCP_INFORM:
106
2.19k
    case DHCP_UNKNOWN_MSG_TYPE:
107
2.19k
      hdr->opCode = DHCP_BOOTREQUEST;
108
2.19k
      break;
109
5
    case DHCP_OFFER:
110
588
    case DHCP_ACK:
111
588
    case DHCP_NAK:
112
588
      hdr->opCode = DHCP_BOOTREPLY;
113
588
      break;
114
8
    default:
115
8
      break;
116
2.79k
    }
117
118
2.79k
    hdr->hardwareType = 1;           // Ethernet
119
2.79k
    hdr->hardwareAddressLength = 6;  // MAC address length
120
2.79k
  }
121
122
  std::string DhcpLayer::toString() const
123
5.58k
  {
124
5.58k
    std::string msgType = "Unknown";
125
5.58k
    switch (getMessageType())
126
5.58k
    {
127
48
    case DHCP_DISCOVER:
128
48
    {
129
48
      msgType = "Discover";
130
48
      break;
131
0
    }
132
10
    case DHCP_OFFER:
133
10
    {
134
10
      msgType = "Offer";
135
10
      break;
136
0
    }
137
1.48k
    case DHCP_REQUEST:
138
1.48k
    {
139
1.48k
      msgType = "Request";
140
1.48k
      break;
141
0
    }
142
494
    case DHCP_DECLINE:
143
494
    {
144
494
      msgType = "Decline";
145
494
      break;
146
0
    }
147
1.16k
    case DHCP_ACK:
148
1.16k
    {
149
1.16k
      msgType = "Acknowledge";
150
1.16k
      break;
151
0
    }
152
0
    case DHCP_NAK:
153
0
    {
154
0
      msgType = "Negative Acknowledge";
155
0
      break;
156
0
    }
157
12
    case DHCP_RELEASE:
158
12
    {
159
12
      msgType = "Release";
160
12
      break;
161
0
    }
162
24
    case DHCP_INFORM:
163
24
    {
164
24
      msgType = "Inform";
165
24
      break;
166
0
    }
167
2.35k
    default:
168
2.35k
      break;
169
5.58k
    }
170
171
5.58k
    return "DHCP layer (" + msgType + ")";
172
5.58k
  }
173
174
  DhcpMessageType DhcpLayer::getMessageType() const
175
8.38k
  {
176
8.38k
    DhcpOption opt = getOptionData(DHCPOPT_DHCP_MESSAGE_TYPE);
177
8.38k
    if (opt.isNull())
178
3.45k
      return DHCP_UNKNOWN_MSG_TYPE;
179
180
4.92k
    return (DhcpMessageType)opt.getValueAs<uint8_t>();
181
8.38k
  }
182
183
  bool DhcpLayer::setMessageType(DhcpMessageType msgType)
184
0
  {
185
0
    if (msgType == DHCP_UNKNOWN_MSG_TYPE)
186
0
      return false;
187
188
0
    DhcpOption opt = getOptionData(DHCPOPT_DHCP_MESSAGE_TYPE);
189
0
    if (opt.isNull())
190
0
    {
191
0
      opt = addOptionAfter(DhcpOptionBuilder(DHCPOPT_DHCP_MESSAGE_TYPE, (uint8_t)msgType), DHCPOPT_UNKNOWN);
192
0
      if (opt.isNull())
193
0
        return false;
194
0
    }
195
196
0
    opt.setValue<uint8_t>((uint8_t)msgType);
197
0
    return true;
198
0
  }
199
200
  DhcpOption DhcpLayer::getOptionData(DhcpOptionTypes option) const
201
11.1k
  {
202
11.1k
    return m_OptionReader.getTLVRecord((uint8_t)option, getOptionsBasePtr(), getHeaderLen() - sizeof(dhcp_header));
203
11.1k
  }
204
205
  DhcpOption DhcpLayer::getFirstOptionData() const
206
2.75k
  {
207
2.75k
    return m_OptionReader.getFirstTLVRecord(getOptionsBasePtr(), getHeaderLen() - sizeof(dhcp_header));
208
2.75k
  }
209
210
  DhcpOption DhcpLayer::getNextOptionData(DhcpOption dhcpOption) const
211
53.2k
  {
212
53.2k
    return m_OptionReader.getNextTLVRecord(dhcpOption, getOptionsBasePtr(), getHeaderLen() - sizeof(dhcp_header));
213
53.2k
  }
214
215
  size_t DhcpLayer::getOptionsCount() const
216
58.8k
  {
217
58.8k
    return m_OptionReader.getTLVRecordCount(getOptionsBasePtr(), getHeaderLen() - sizeof(dhcp_header));
218
58.8k
  }
219
220
  DhcpOption DhcpLayer::addOptionAt(const DhcpOptionBuilder& optionBuilder, int offset)
221
0
  {
222
0
    DhcpOption newOpt = optionBuilder.build();
223
224
0
    if (newOpt.isNull())
225
0
    {
226
0
      PCPP_LOG_ERROR("Cannot build new option of type " << (int)newOpt.getType());
227
0
      return DhcpOption(nullptr);
228
0
    }
229
230
0
    size_t sizeToExtend = newOpt.getTotalSize();
231
232
0
    if (!extendLayer(offset, sizeToExtend))
233
0
    {
234
0
      PCPP_LOG_ERROR("Could not extend DhcpLayer in [" << newOpt.getTotalSize() << "] bytes");
235
0
      newOpt.purgeRecordData();
236
0
      return DhcpOption(nullptr);
237
0
    }
238
239
0
    memcpy(m_Data + offset, newOpt.getRecordBasePtr(), newOpt.getTotalSize());
240
241
0
    uint8_t* newOptPtr = m_Data + offset;
242
243
0
    m_OptionReader.changeTLVRecordCount(1);
244
245
0
    newOpt.purgeRecordData();
246
247
0
    return DhcpOption(newOptPtr);
248
0
  }
249
250
  DhcpOption DhcpLayer::addOption(const DhcpOptionBuilder& optionBuilder)
251
0
  {
252
0
    int offset = 0;
253
0
    DhcpOption endOpt = getOptionData(DHCPOPT_END);
254
0
    if (!endOpt.isNull())
255
0
      offset = endOpt.getRecordBasePtr() - m_Data;
256
0
    else
257
0
      offset = getHeaderLen();
258
259
0
    return addOptionAt(optionBuilder, offset);
260
0
  }
261
262
  DhcpOption DhcpLayer::addOptionAfter(const DhcpOptionBuilder& optionBuilder, DhcpOptionTypes prevOption)
263
0
  {
264
0
    int offset = 0;
265
266
0
    DhcpOption prevOpt = getOptionData(prevOption);
267
268
0
    if (prevOpt.isNull())
269
0
    {
270
0
      offset = sizeof(dhcp_header);
271
0
    }
272
0
    else
273
0
    {
274
0
      offset = prevOpt.getRecordBasePtr() + prevOpt.getTotalSize() - m_Data;
275
0
    }
276
277
0
    return addOptionAt(optionBuilder, offset);
278
0
  }
279
280
  bool DhcpLayer::removeOption(DhcpOptionTypes optionType)
281
0
  {
282
0
    DhcpOption optToRemove = getOptionData(optionType);
283
0
    if (optToRemove.isNull())
284
0
    {
285
0
      return false;
286
0
    }
287
288
0
    int offset = optToRemove.getRecordBasePtr() - m_Data;
289
290
0
    if (!shortenLayer(offset, optToRemove.getTotalSize()))
291
0
    {
292
0
      return false;
293
0
    }
294
295
0
    m_OptionReader.changeTLVRecordCount(-1);
296
0
    return true;
297
0
  }
298
299
  bool DhcpLayer::removeAllOptions()
300
0
  {
301
0
    int offset = sizeof(dhcp_header);
302
303
0
    if (!shortenLayer(offset, getHeaderLen() - offset))
304
0
      return false;
305
306
0
    m_OptionReader.changeTLVRecordCount(0 - getOptionsCount());
307
0
    return true;
308
0
  }
309
310
}  // namespace pcpp