Coverage Report

Created: 2026-08-15 08:03

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