Coverage Report

Created: 2025-10-10 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/IPv6Extensions.cpp
Line
Count
Source
1
#define LOG_MODULE PacketLogModuleIPv6ExtensionLayer
2
3
#include "EndianPortable.h"
4
#include "IPv6Extensions.h"
5
#include "IPv6Layer.h"
6
#include "IPv4Layer.h"
7
#include "UdpLayer.h"
8
#include "TcpLayer.h"
9
10
namespace pcpp
11
{
12
13
  // =============
14
  // IPv6Extension
15
  // =============
16
17
  IPv6Extension& IPv6Extension::operator=(const IPv6Extension& other)
18
0
  {
19
    // notice this is not necessarily safe - it assumes the current extension has enough memory allocated to consume
20
    // the other extension. That's why the assignment operator isn't public (it's currently used only inside
21
    // IPv6Layer)
22
0
    memcpy(getDataPtr(), other.getDataPtr(), other.getExtensionLen());
23
0
    m_NextHeader = nullptr;
24
0
    m_ExtType = other.m_ExtType;
25
26
0
    return *this;
27
0
  }
28
29
  uint8_t* IPv6Extension::getDataPtr() const
30
77.1k
  {
31
77.1k
    if (m_DataContainer != nullptr)
32
77.1k
      return m_DataContainer->getDataPtr(m_Offset);
33
34
0
    return m_ShadowData;
35
77.1k
  }
36
37
  void IPv6Extension::initShadowPtr(size_t size)
38
0
  {
39
0
    m_ShadowData = new uint8_t[size];
40
0
  }
41
42
  IPv6Extension::~IPv6Extension()
43
21.6k
  {
44
21.6k
    if (m_ShadowData != nullptr)
45
0
      delete[] m_ShadowData;
46
21.6k
  }
47
48
  // =======================
49
  // IPv6FragmentationHeader
50
  // =======================
51
52
  IPv6FragmentationHeader::IPv6FragmentationHeader(uint32_t fragId, uint16_t fragOffset, bool lastFragment)
53
0
  {
54
0
    initShadowPtr(sizeof(ipv6_frag_header));
55
0
    m_ExtType = IPv6Fragmentation;
56
0
    memset(getDataPtr(), 0, sizeof(ipv6_frag_header));
57
58
0
    ipv6_frag_header* fragHdr = getFragHeader();
59
0
    fragHdr->nextHeader = 0;
60
0
    fragHdr->headerLen = 0;
61
0
    fragHdr->id = htobe32(fragId);
62
63
0
    fragOffset /= 8;
64
0
    fragOffset = htobe16(fragOffset << 3) & static_cast<uint16_t>(0xf8ff);
65
0
    if (!lastFragment)
66
0
      fragOffset = fragOffset | 0x0100;
67
68
0
    fragHdr->fragOffsetAndFlags = fragOffset;
69
0
  }
70
71
  bool IPv6FragmentationHeader::isFirstFragment() const
72
0
  {
73
0
    return (getFragmentOffset() == 0);
74
0
  }
75
76
  bool IPv6FragmentationHeader::isLastFragment() const
77
0
  {
78
0
    return (!isMoreFragments());
79
0
  }
80
81
  bool IPv6FragmentationHeader::isMoreFragments() const
82
0
  {
83
0
    uint8_t isMoreFragsBit = (getFragHeader()->fragOffsetAndFlags & (uint16_t)0x0100) >> 8;
84
0
    return (isMoreFragsBit == 1);
85
0
  }
86
87
  uint16_t IPv6FragmentationHeader::getFragmentOffset() const
88
0
  {
89
0
    uint16_t fragOffset = (be16toh(getFragHeader()->fragOffsetAndFlags & (uint16_t)0xf8ff) >> 3) * 8;
90
0
    return fragOffset;
91
0
  }
92
93
  // ====================
94
  // IPv6TLVOptionBuilder
95
  // ====================
96
97
  IPv6TLVOptionHeader::IPv6Option IPv6TLVOptionHeader::IPv6TLVOptionBuilder::build() const
98
0
  {
99
0
    size_t optionTotalSize = sizeof(uint8_t);
100
0
    uint8_t recType = static_cast<uint8_t>(m_RecType);
101
0
    if (recType != IPv6TLVOptionHeader::IPv6Option::Pad0OptionType)
102
0
      optionTotalSize += sizeof(uint8_t) + m_RecValueLen;
103
104
0
    uint8_t* recordBuffer = new uint8_t[optionTotalSize];
105
0
    memset(recordBuffer, 0, optionTotalSize);
106
107
0
    if (m_RecType != IPv6TLVOptionHeader::IPv6Option::Pad0OptionType)
108
0
    {
109
0
      recordBuffer[0] = recType;
110
0
      recordBuffer[1] = static_cast<uint8_t>(m_RecValueLen);
111
0
      if (m_RecValueLen > 0)
112
0
        memcpy(recordBuffer + 2, m_RecValue, m_RecValueLen);
113
0
    }
114
115
0
    return IPv6Option(recordBuffer);
116
0
  }
117
118
  // ===================
119
  // IPv6TLVOptionHeader
120
  // ===================
121
122
  IPv6TLVOptionHeader::IPv6Option IPv6TLVOptionHeader::getOption(uint8_t optionType) const
123
0
  {
124
0
    return m_OptionReader.getTLVRecord(optionType, getDataPtr() + sizeof(ipv6_ext_base_header),
125
0
                                       getExtensionLen() - sizeof(ipv6_ext_base_header));
126
0
  }
127
128
  IPv6TLVOptionHeader::IPv6Option IPv6TLVOptionHeader::getFirstOption() const
129
0
  {
130
0
    return m_OptionReader.getFirstTLVRecord(getDataPtr() + sizeof(ipv6_ext_base_header),
131
0
                                            getExtensionLen() - sizeof(ipv6_ext_base_header));
132
0
  }
133
134
  IPv6TLVOptionHeader::IPv6Option IPv6TLVOptionHeader::getNextOption(IPv6TLVOptionHeader::IPv6Option& option) const
135
0
  {
136
0
    return m_OptionReader.getNextTLVRecord(option, getDataPtr() + sizeof(ipv6_ext_base_header),
137
0
                                           getExtensionLen() - sizeof(ipv6_ext_base_header));
138
0
  }
139
140
  size_t IPv6TLVOptionHeader::getOptionCount() const
141
0
  {
142
0
    return m_OptionReader.getTLVRecordCount(getDataPtr() + sizeof(ipv6_ext_base_header),
143
0
                                            getExtensionLen() - sizeof(ipv6_ext_base_header));
144
0
  }
145
146
  IPv6TLVOptionHeader::IPv6TLVOptionHeader(const std::vector<IPv6TLVOptionBuilder>& options)
147
0
  {
148
0
    m_ExtType = IPv6ExtensionUnknown;
149
0
    m_OptionReader.changeTLVRecordCount(options.size());
150
151
0
    size_t totalSize = sizeof(uint16_t);  // nextHeader + headerLen
152
153
0
    for (const auto& iter : options)
154
0
    {
155
0
      IPv6Option option = iter.build();
156
0
      totalSize += option.getTotalSize();
157
0
      option.purgeRecordData();
158
0
    }
159
160
0
    while (totalSize % 8 != 0)
161
0
      totalSize++;
162
163
0
    initShadowPtr(totalSize);
164
0
    memset(getDataPtr(), 0, totalSize);
165
166
0
    getBaseHeader()->headerLen = ((totalSize / 8) - 1);
167
168
0
    size_t offset = sizeof(uint16_t);
169
170
0
    for (const auto& iter : options)
171
0
    {
172
0
      IPv6Option option = iter.build();
173
0
      memcpy(getDataPtr() + offset, option.getRecordBasePtr(), option.getTotalSize());
174
0
      offset += option.getTotalSize();
175
0
      option.purgeRecordData();
176
0
    }
177
0
  }
178
179
  IPv6TLVOptionHeader::IPv6TLVOptionHeader(IDataContainer* dataContainer, size_t offset)
180
20.8k
      : IPv6Extension(dataContainer, offset)
181
20.8k
  {}
182
183
  // =================
184
  // IPv6RoutingHeader
185
  // =================
186
187
  IPv6RoutingHeader::IPv6RoutingHeader(uint8_t routingType, uint8_t segmentsLeft,
188
                                       const uint8_t* additionalRoutingData, size_t additionalRoutingDataLen)
189
0
  {
190
0
    size_t totalSize = sizeof(ipv6_routing_header) + additionalRoutingDataLen;
191
0
    while (totalSize % 8 != 0)
192
0
      totalSize++;
193
194
0
    initShadowPtr(totalSize);
195
0
    memset(getDataPtr(), 0, totalSize);
196
197
0
    m_ExtType = IPv6Routing;
198
199
0
    ipv6_routing_header* routingHeader = getRoutingHeader();
200
0
    routingHeader->nextHeader = 0;
201
0
    routingHeader->headerLen = ((totalSize / 8) - 1);
202
0
    routingHeader->routingType = routingType;
203
0
    routingHeader->segmentsLeft = segmentsLeft;
204
205
0
    if (additionalRoutingDataLen > 0 && additionalRoutingData != nullptr)
206
0
    {
207
0
      uint8_t* additionalDataPtr = getDataPtr() + sizeof(ipv6_routing_header);
208
0
      memcpy(additionalDataPtr, additionalRoutingData, additionalRoutingDataLen);
209
0
    }
210
0
  }
211
212
  uint8_t* IPv6RoutingHeader::getRoutingAdditionalData() const
213
0
  {
214
0
    if (getExtensionLen() > sizeof(ipv6_routing_header))
215
0
      return getDataPtr() + sizeof(ipv6_routing_header);
216
217
0
    return nullptr;
218
0
  }
219
220
  size_t IPv6RoutingHeader::getRoutingAdditionalDataLength() const
221
0
  {
222
0
    int result = getExtensionLen() - sizeof(ipv6_routing_header);
223
0
    if (result < 0)
224
0
      return (size_t)0;
225
226
0
    return (size_t)result;
227
0
  }
228
229
  IPv6Address IPv6RoutingHeader::getRoutingAdditionalDataAsIPv6Address(size_t offset) const
230
0
  {
231
232
0
    size_t routingAddDataLen = getRoutingAdditionalDataLength();
233
0
    if (routingAddDataLen - offset >= 16)
234
0
      return IPv6Address(getRoutingAdditionalData() + offset);
235
236
0
    return IPv6Address();
237
0
  }
238
239
  // ========================
240
  // IPv6AuthenticationHeader
241
  // ========================
242
243
  IPv6AuthenticationHeader::IPv6AuthenticationHeader(uint32_t securityParametersIndex, uint32_t sequenceNumber,
244
                                                     const uint8_t* integrityCheckValue,
245
                                                     size_t integrityCheckValueLen)
246
0
  {
247
0
    size_t totalSize = sizeof(ipv6_authentication_header) + integrityCheckValueLen;
248
0
    while (totalSize % 8 != 0)
249
0
      totalSize++;
250
251
0
    initShadowPtr(totalSize);
252
0
    memset(getDataPtr(), 0, totalSize);
253
254
0
    m_ExtType = IPv6AuthenticationHdr;
255
256
0
    ipv6_authentication_header* authHeader = getAuthHeader();
257
0
    authHeader->nextHeader = 0;
258
0
    authHeader->headerLen = ((totalSize / 4) - 2);
259
0
    authHeader->securityParametersIndex = htobe32(securityParametersIndex);
260
0
    authHeader->sequenceNumber = htobe32(sequenceNumber);
261
262
0
    if (integrityCheckValueLen > 0 && integrityCheckValue != nullptr)
263
0
    {
264
0
      uint8_t* icvPtr = getDataPtr() + sizeof(ipv6_authentication_header);
265
0
      memcpy(icvPtr, integrityCheckValue, integrityCheckValueLen);
266
0
    }
267
0
  }
268
269
  uint8_t* IPv6AuthenticationHeader::getIntegrityCheckValue() const
270
0
  {
271
0
    if (getExtensionLen() > sizeof(ipv6_authentication_header))
272
0
      return getDataPtr() + sizeof(ipv6_authentication_header);
273
274
0
    return nullptr;
275
0
  }
276
277
  size_t IPv6AuthenticationHeader::getIntegrityCheckValueLength() const
278
0
  {
279
0
    int result = getExtensionLen() - sizeof(ipv6_authentication_header);
280
0
    if (result < 0)
281
0
      return (size_t)0;
282
283
0
    return (size_t)result;
284
0
  }
285
286
}  // namespace pcpp