Coverage Report

Created: 2025-08-29 07:34

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