Coverage Report

Created: 2026-02-14 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/DhcpV6Layer.cpp
Line
Count
Source
1
0
#define LOG_MODULE PacketLogModuleDhcpV6Layer
2
3
#include "DhcpV6Layer.h"
4
#include "Logger.h"
5
#include "GeneralUtils.h"
6
#include "EndianPortable.h"
7
8
namespace pcpp
9
{
10
11
  DhcpV6OptionType DhcpV6Option::getType() const
12
2.95k
  {
13
2.95k
    if (m_Data == nullptr)
14
0
      return DhcpV6OptionType::DHCPV6_OPT_UNKNOWN;
15
16
2.95k
    uint16_t optionType = be16toh(m_Data->recordType);
17
2.95k
    if (optionType <= 62 && optionType != 10 && optionType != 35 && optionType != 57 && optionType != 58)
18
1.97k
    {
19
1.97k
      return static_cast<DhcpV6OptionType>(optionType);
20
1.97k
    }
21
981
    if (optionType == 65 || optionType == 66 || optionType == 68 || optionType == 79 || optionType == 112)
22
414
    {
23
414
      return static_cast<DhcpV6OptionType>(optionType);
24
414
    }
25
26
567
    return DHCPV6_OPT_UNKNOWN;
27
981
  }
28
29
  std::string DhcpV6Option::getValueAsHexString() const
30
930
  {
31
930
    if (m_Data == nullptr)
32
0
      return "";
33
34
930
    return byteArrayToHexString(m_Data->recordValue, getDataSize());
35
930
  }
36
37
  size_t DhcpV6Option::getTotalSize() const
38
54.0k
  {
39
54.0k
    if (m_Data == nullptr)
40
0
      return 0;
41
42
54.0k
    return 2 * sizeof(uint16_t) + be16toh(m_Data->recordLen);
43
54.0k
  }
44
45
  size_t DhcpV6Option::getDataSize() const
46
930
  {
47
930
    if (m_Data == nullptr)
48
0
      return 0;
49
50
930
    return static_cast<size_t>(be16toh(m_Data->recordLen));
51
930
  }
52
53
  DhcpV6Option DhcpV6OptionBuilder::build() const
54
0
  {
55
0
    if (m_RecType == 0)
56
0
      return DhcpV6Option(nullptr);
57
58
0
    size_t optionSize = 2 * sizeof(uint16_t) + m_RecValueLen;
59
0
    uint8_t* recordBuffer = new uint8_t[optionSize];
60
0
    uint16_t optionTypeVal = htobe16(static_cast<uint16_t>(m_RecType));
61
0
    uint16_t optionLength = htobe16(static_cast<uint16_t>(m_RecValueLen));
62
0
    memcpy(recordBuffer, &optionTypeVal, sizeof(uint16_t));
63
0
    memcpy(recordBuffer + sizeof(uint16_t), &optionLength, sizeof(uint16_t));
64
0
    if (optionSize > 0 && m_RecValue != nullptr)
65
0
      memcpy(recordBuffer + 2 * sizeof(uint16_t), m_RecValue, m_RecValueLen);
66
67
0
    return DhcpV6Option(recordBuffer);
68
0
  }
69
70
  DhcpV6Layer::DhcpV6Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
71
5.29k
      : Layer(data, dataLen, prevLayer, packet, DHCPv6)
72
5.29k
  {}
73
74
  DhcpV6Layer::DhcpV6Layer(DhcpV6MessageType messageType, uint32_t transactionId)
75
0
  {
76
0
    m_DataLen = sizeof(dhcpv6_header);
77
0
    m_Data = new uint8_t[m_DataLen];
78
0
    memset(m_Data, 0, m_DataLen);
79
0
    m_Protocol = DHCPv6;
80
81
0
    setMessageType(messageType);
82
0
    setTransactionID(transactionId);
83
0
  }
84
85
  DhcpV6MessageType DhcpV6Layer::getMessageType() const
86
1.98k
  {
87
1.98k
    uint8_t messageType = getDhcpHeader()->messageType;
88
1.98k
    if (messageType > 13)
89
108
    {
90
108
      return DHCPV6_UNKNOWN_MSG_TYPE;
91
108
    }
92
93
1.88k
    return static_cast<DhcpV6MessageType>(messageType);
94
1.98k
  }
95
96
  std::string DhcpV6Layer::getMessageTypeAsString() const
97
1.98k
  {
98
1.98k
    DhcpV6MessageType messageType = getMessageType();
99
1.98k
    switch (messageType)
100
1.98k
    {
101
906
    case DHCPV6_SOLICIT:
102
906
      return "Solicit";
103
336
    case DHCPV6_ADVERTISE:
104
336
      return "Advertise";
105
278
    case DHCPV6_REQUEST:
106
278
      return "Request";
107
14
    case DHCPV6_CONFIRM:
108
14
      return "Confirm";
109
18
    case DHCPV6_RENEW:
110
18
      return "Renew";
111
10
    case DHCPV6_REBIND:
112
10
      return "Rebind";
113
82
    case DHCPV6_REPLY:
114
82
      return "Reply";
115
4
    case DHCPV6_RELEASE:
116
4
      return "Release";
117
16
    case DHCPV6_DECLINE:
118
16
      return "Decline";
119
2
    case DHCPV6_RECONFIGURE:
120
2
      return "Reconfigure";
121
68
    case DHCPV6_INFORMATION_REQUEST:
122
68
      return "Information-Request";
123
14
    case DHCPV6_RELAY_FORWARD:
124
14
      return "Relay-Forward";
125
2
    case DHCPV6_RELAY_REPLY:
126
2
      return "Relay-Reply";
127
238
    default:
128
238
      return "Unknown";
129
1.98k
    }
130
1.98k
  }
131
132
  void DhcpV6Layer::setMessageType(DhcpV6MessageType messageType)
133
0
  {
134
0
    getDhcpHeader()->messageType = static_cast<uint8_t>(messageType);
135
0
  }
136
137
  uint32_t DhcpV6Layer::getTransactionID() const
138
994
  {
139
994
    dhcpv6_header* hdr = getDhcpHeader();
140
994
    uint32_t result = hdr->transactionId1 << 16 | hdr->transactionId2 << 8 | hdr->transactionId3;
141
994
    return result;
142
994
  }
143
144
  void DhcpV6Layer::setTransactionID(uint32_t transactionId) const
145
0
  {
146
0
    dhcpv6_header* hdr = getDhcpHeader();
147
0
    hdr->transactionId1 = (transactionId >> 16) & 0xff;
148
0
    hdr->transactionId2 = (transactionId >> 8) & 0xff;
149
0
    hdr->transactionId3 = transactionId & 0xff;
150
0
  }
151
152
  DhcpV6Option DhcpV6Layer::getFirstOptionData() const
153
930
  {
154
930
    return m_OptionReader.getFirstTLVRecord(getOptionsBasePtr(), getHeaderLen() - sizeof(dhcpv6_header));
155
930
  }
156
157
  DhcpV6Option DhcpV6Layer::getNextOptionData(DhcpV6Option dhcpv6Option) const
158
4.25k
  {
159
4.25k
    return m_OptionReader.getNextTLVRecord(dhcpv6Option, getOptionsBasePtr(),
160
4.25k
                                           getHeaderLen() - sizeof(dhcpv6_header));
161
4.25k
  }
162
163
  DhcpV6Option DhcpV6Layer::getOptionData(DhcpV6OptionType option) const
164
930
  {
165
930
    return m_OptionReader.getTLVRecord(static_cast<uint32_t>(option), getOptionsBasePtr(),
166
930
                                       getHeaderLen() - sizeof(dhcpv6_header));
167
930
  }
168
169
  size_t DhcpV6Layer::getOptionCount() const
170
6.18k
  {
171
6.18k
    return m_OptionReader.getTLVRecordCount(getOptionsBasePtr(), getHeaderLen() - sizeof(dhcpv6_header));
172
6.18k
  }
173
174
  DhcpV6Option DhcpV6Layer::addOptionAt(const DhcpV6OptionBuilder& optionBuilder, int offset)
175
0
  {
176
0
    DhcpV6Option newOpt = optionBuilder.build();
177
0
    if (newOpt.isNull())
178
0
    {
179
0
      PCPP_LOG_ERROR("Cannot build new option");
180
0
      return DhcpV6Option(nullptr);
181
0
    }
182
183
0
    size_t sizeToExtend = newOpt.getTotalSize();
184
185
0
    if (!extendLayer(offset, sizeToExtend))
186
0
    {
187
0
      PCPP_LOG_ERROR("Could not extend DhcpLayer in [" << newOpt.getTotalSize() << "] bytes");
188
0
      newOpt.purgeRecordData();
189
0
      return DhcpV6Option(nullptr);
190
0
    }
191
192
0
    memcpy(m_Data + offset, newOpt.getRecordBasePtr(), newOpt.getTotalSize());
193
194
0
    uint8_t* newOptPtr = m_Data + offset;
195
196
0
    m_OptionReader.changeTLVRecordCount(1);
197
198
0
    newOpt.purgeRecordData();
199
200
0
    return DhcpV6Option(newOptPtr);
201
0
  }
202
203
  DhcpV6Option DhcpV6Layer::addOption(const DhcpV6OptionBuilder& optionBuilder)
204
0
  {
205
0
    return addOptionAt(optionBuilder, getHeaderLen());
206
0
  }
207
208
  DhcpV6Option DhcpV6Layer::addOptionAfter(const DhcpV6OptionBuilder& optionBuilder, DhcpV6OptionType optionType)
209
0
  {
210
0
    int offset = 0;
211
212
0
    DhcpV6Option prevOpt = getOptionData(optionType);
213
214
0
    if (prevOpt.isNull())
215
0
    {
216
0
      PCPP_LOG_ERROR("Option type " << optionType << " doesn't exist in layer");
217
0
      return DhcpV6Option(nullptr);
218
0
    }
219
0
    offset = prevOpt.getRecordBasePtr() + prevOpt.getTotalSize() - m_Data;
220
0
    return addOptionAt(optionBuilder, offset);
221
0
  }
222
223
  DhcpV6Option DhcpV6Layer::addOptionBefore(const DhcpV6OptionBuilder& optionBuilder, DhcpV6OptionType optionType)
224
0
  {
225
0
    int offset = 0;
226
227
0
    DhcpV6Option nextOpt = getOptionData(optionType);
228
229
0
    if (nextOpt.isNull())
230
0
    {
231
0
      PCPP_LOG_ERROR("Option type " << optionType << " doesn't exist in layer");
232
0
      return DhcpV6Option(nullptr);
233
0
    }
234
235
0
    offset = nextOpt.getRecordBasePtr() - m_Data;
236
0
    return addOptionAt(optionBuilder, offset);
237
0
  }
238
239
  bool DhcpV6Layer::removeOption(DhcpV6OptionType optionType)
240
0
  {
241
0
    DhcpV6Option optToRemove = getOptionData(optionType);
242
0
    if (optToRemove.isNull())
243
0
    {
244
0
      return false;
245
0
    }
246
247
0
    int offset = optToRemove.getRecordBasePtr() - m_Data;
248
249
0
    if (!shortenLayer(offset, optToRemove.getTotalSize()))
250
0
    {
251
0
      return false;
252
0
    }
253
254
0
    m_OptionReader.changeTLVRecordCount(-1);
255
0
    return true;
256
0
  }
257
258
  bool DhcpV6Layer::removeAllOptions()
259
0
  {
260
0
    int offset = sizeof(dhcpv6_header);
261
262
0
    if (!shortenLayer(offset, getHeaderLen() - offset))
263
0
      return false;
264
265
0
    m_OptionReader.changeTLVRecordCount(0 - getOptionCount());
266
0
    return true;
267
0
  }
268
269
  std::string DhcpV6Layer::toString() const
270
1.98k
  {
271
1.98k
    return "DHCPv6 Layer, " + getMessageTypeAsString() + " message";
272
1.98k
  }
273
274
}  // namespace pcpp