Coverage Report

Created: 2026-07-16 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/DhcpLayer.cpp
Line
Count
Source
1
863
#define LOG_MODULE PacketLogModuleDhcpLayer
2
3
#include "DhcpLayer.h"
4
#include "Logger.h"
5
6
namespace pcpp
7
{
8
9
3.10k
#define DHCP_MAGIC_NUMBER 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
17.4k
      : Layer(data, dataLen, prevLayer, packet, DHCP)
46
17.4k
  {}
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
3.10k
  {
75
3.10k
    dhcp_header* hdr = getDhcpHeader();
76
3.10k
    if (hdr != nullptr && hdr->hardwareType == 1 && hdr->hardwareAddressLength == 6)
77
2.24k
      return MacAddress(hdr->clientHardwareAddress);
78
79
863
    PCPP_LOG_DEBUG("Hardware type isn't Ethernet or hardware addr len != 6, returning MacAddress:Zero");
80
81
863
    return MacAddress::Zero;
82
3.10k
  }
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
3.10k
  {
94
3.10k
    dhcp_header* hdr = getDhcpHeader();
95
96
3.10k
    hdr->magicNumber = DHCP_MAGIC_NUMBER;
97
98
3.10k
    DhcpMessageType msgType = getMessageType();
99
3.10k
    switch (msgType)
100
3.10k
    {
101
1.48k
    case DHCP_DISCOVER:
102
1.76k
    case DHCP_REQUEST:
103
1.76k
    case DHCP_DECLINE:
104
1.76k
    case DHCP_RELEASE:
105
1.77k
    case DHCP_INFORM:
106
2.47k
    case DHCP_UNKNOWN_MSG_TYPE:
107
2.47k
      hdr->opCode = DHCP_BOOTREQUEST;
108
2.47k
      break;
109
244
    case DHCP_OFFER:
110
325
    case DHCP_ACK:
111
333
    case DHCP_NAK:
112
333
      hdr->opCode = DHCP_BOOTREPLY;
113
333
      break;
114
305
    default:
115
305
      break;
116
3.10k
    }
117
118
3.10k
    hdr->hardwareType = 1;           // Ethernet
119
3.10k
    hdr->hardwareAddressLength = 6;  // MAC address length
120
3.10k
  }
121
122
  std::string DhcpLayer::toString() const
123
6.21k
  {
124
6.21k
    std::string msgType = "Unknown";
125
6.21k
    switch (getMessageType())
126
6.21k
    {
127
2.97k
    case DHCP_DISCOVER:
128
2.97k
    {
129
2.97k
      msgType = "Discover";
130
2.97k
      break;
131
0
    }
132
488
    case DHCP_OFFER:
133
488
    {
134
488
      msgType = "Offer";
135
488
      break;
136
0
    }
137
550
    case DHCP_REQUEST:
138
550
    {
139
550
      msgType = "Request";
140
550
      break;
141
0
    }
142
0
    case DHCP_DECLINE:
143
0
    {
144
0
      msgType = "Decline";
145
0
      break;
146
0
    }
147
162
    case DHCP_ACK:
148
162
    {
149
162
      msgType = "Acknowledge";
150
162
      break;
151
0
    }
152
16
    case DHCP_NAK:
153
16
    {
154
16
      msgType = "Negative Acknowledge";
155
16
      break;
156
0
    }
157
0
    case DHCP_RELEASE:
158
0
    {
159
0
      msgType = "Release";
160
0
      break;
161
0
    }
162
18
    case DHCP_INFORM:
163
18
    {
164
18
      msgType = "Inform";
165
18
      break;
166
0
    }
167
2.01k
    default:
168
2.01k
      break;
169
6.21k
    }
170
171
6.21k
    return "DHCP layer (" + msgType + ")";
172
6.21k
  }
173
174
  DhcpMessageType DhcpLayer::getMessageType() const
175
9.32k
  {
176
9.32k
    DhcpOption opt = getOptionData(DHCPOPT_DHCP_MESSAGE_TYPE);
177
9.32k
    if (opt.isNull())
178
1.79k
      return DHCP_UNKNOWN_MSG_TYPE;
179
180
7.52k
    return (DhcpMessageType)opt.getValueAs<uint8_t>();
181
9.32k
  }
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
12.4k
  {
202
12.4k
    return m_OptionReader.getTLVRecord((uint8_t)option, getOptionsBasePtr(), getHeaderLen() - sizeof(dhcp_header));
203
12.4k
  }
204
205
  DhcpOption DhcpLayer::getFirstOptionData() const
206
3.04k
  {
207
3.04k
    return m_OptionReader.getFirstTLVRecord(getOptionsBasePtr(), getHeaderLen() - sizeof(dhcp_header));
208
3.04k
  }
209
210
  DhcpOption DhcpLayer::getNextOptionData(DhcpOption dhcpOption) const
211
205k
  {
212
205k
    return m_OptionReader.getNextTLVRecord(dhcpOption, getOptionsBasePtr(), getHeaderLen() - sizeof(dhcp_header));
213
205k
  }
214
215
  size_t DhcpLayer::getOptionsCount() const
216
211k
  {
217
211k
    return m_OptionReader.getTLVRecordCount(getOptionsBasePtr(), getHeaderLen() - sizeof(dhcp_header));
218
211k
  }
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