Coverage Report

Created: 2026-10-17 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/QuicLayer.cpp
Line
Count
Source
1
#include "QuicLayer.h"
2
#include "PayloadLayer.h"
3
#include "GeneralUtils.h"
4
#include "SystemUtils.h"
5
#include <algorithm>
6
#include <cstring>
7
8
namespace pcpp
9
{
10
  QuicV1Layer* QuicV1Layer::parseQuicLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
11
0
  {
12
0
    if (data == nullptr || dataLen <= sizeof(quic_common_header))
13
0
    {
14
0
      return nullptr;
15
0
    }
16
17
0
    auto headerForm = static_cast<QuicHeaderForm>(reinterpret_cast<quic_common_header*>(data)->headerForm);
18
19
0
    if (headerForm == QuicHeaderForm::ShortHeader && QuicV1OneRttLayer::isDataValid(data, dataLen))
20
0
    {
21
0
      return new QuicV1OneRttLayer(data, dataLen, prevLayer, packet);
22
0
    }
23
24
0
    if (headerForm == QuicHeaderForm::LongHeader && QuicV1LongHeaderLayer::isDataValid(data, dataLen))
25
0
    {
26
0
      auto header = reinterpret_cast<quic_long_header*>(data);
27
0
      if (header->version == 0x00000000)
28
0
      {
29
0
        return new QuicV1VersionNegotiationLayer(data, dataLen, prevLayer, packet);
30
0
      }
31
0
      if (netToHost32(header->version) != 0x00000001)
32
0
      {
33
0
        return nullptr;
34
0
      }
35
36
0
      switch (header->longPacketType)
37
0
      {
38
0
      case static_cast<uint8_t>(QuicPacketType::Initial):
39
0
      {
40
0
        return new QuicV1InitialLayer(data, dataLen, prevLayer, packet);
41
0
      }
42
0
      case static_cast<uint8_t>(QuicPacketType::Handshake):
43
0
      {
44
0
        return new QuicV1HandshakeLayer(data, dataLen, prevLayer, packet);
45
0
      }
46
0
      case static_cast<uint8_t>(QuicPacketType::ZeroRTT):
47
0
      {
48
0
        return new QuicV1ZeroRttLayer(data, dataLen, prevLayer, packet);
49
0
      }
50
0
      default:  // QuicPacketType::Retry
51
0
      {
52
0
        return new QuicV1RetryLayer(data, dataLen, prevLayer, packet);
53
0
      }
54
0
      }
55
0
    }
56
57
0
    return nullptr;
58
0
  }
59
60
  void QuicV1Layer::parseNextLayer()
61
0
  {
62
0
    auto headerLen = getHeaderLen();
63
64
0
    if (headerLen < m_DataLen)
65
0
    {
66
0
      tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(parseQuicLayer, m_Data + headerLen,
67
0
                                                                 m_DataLen - headerLen);
68
0
    }
69
0
  }
70
71
  QuicV1Layer::QuicHeaderForm QuicV1Layer::getHeaderForm() const
72
0
  {
73
0
    return static_cast<QuicHeaderForm>(getCommonHeader()->headerForm);
74
0
  }
75
76
  uint8_t QuicV1Layer::getFixedBit() const
77
0
  {
78
0
    return getCommonHeader()->fixedBit;
79
0
  }
80
81
  std::string QuicV1Layer::toString() const
82
0
  {
83
0
    std::string packetType;
84
85
0
    switch (getPacketType())
86
0
    {
87
0
    case QuicPacketType::Initial:
88
0
    {
89
0
      packetType = "Initial";
90
0
      break;
91
0
    }
92
0
    case QuicPacketType::Handshake:
93
0
    {
94
0
      packetType = "Handshake";
95
0
      break;
96
0
    }
97
0
    case QuicPacketType::ZeroRTT:
98
0
    {
99
0
      packetType = "0-RTT";
100
0
      break;
101
0
    }
102
0
    case QuicPacketType::Retry:
103
0
    {
104
0
      packetType = "Retry";
105
0
      break;
106
0
    }
107
0
    case QuicPacketType::OneRtt:
108
0
    {
109
0
      packetType = "1-RTT";
110
0
      break;
111
0
    }
112
0
    default:  // QuicPacketType::VersionNegotiation
113
0
    {
114
0
      packetType = "Version Negotiation";
115
0
      break;
116
0
    }
117
0
    }
118
119
0
    return "QUIC v1 Layer, " + packetType + " message";
120
0
  }
121
122
  bool QuicV1LongHeaderLayer::isDataValid(const uint8_t* data, size_t dataLen)
123
0
  {
124
0
    return data != nullptr && dataLen >= sizeof(quic_long_header);
125
0
  }
126
127
  QuicV1Layer::QuicPacketType QuicV1LongHeaderLayer::getPacketType() const
128
0
  {
129
0
    return static_cast<QuicPacketType>(getLongHeader()->longPacketType);
130
0
  }
131
132
  uint32_t QuicV1LongHeaderLayer::getVersion() const
133
0
  {
134
0
    return netToHost32(getLongHeader()->version);
135
0
  }
136
137
  constexpr int QuicV1LongHeaderLayer::destinationConnectionIdOffset;
138
139
  QuicV1LongHeaderLayer::OffsetAndLength QuicV1LongHeaderLayer::getDestConIdOffsetAndLength() const
140
0
  {
141
0
    if (m_DataLen <= destinationConnectionIdOffset)
142
0
    {
143
0
      throw std::out_of_range("Not enough data to read destination connection ID length");
144
0
    }
145
146
0
    auto length = static_cast<size_t>(getLongHeader()->destinationConnectionIdLength);
147
0
    if (destinationConnectionIdOffset + length > m_DataLen)
148
0
    {
149
0
      throw std::out_of_range("Not enough data to read destination connection ID");
150
0
    }
151
152
0
    return { length, destinationConnectionIdOffset };
153
0
  }
154
155
  std::vector<uint8_t> QuicV1LongHeaderLayer::getDestinationConnectionId() const
156
0
  {
157
0
    try
158
0
    {
159
0
      auto offsetAndLength = getDestConIdOffsetAndLength();
160
0
      return { m_Data + offsetAndLength.offset, m_Data + offsetAndLength.offset + offsetAndLength.length };
161
0
    }
162
0
    catch (std::out_of_range&)
163
0
    {
164
0
      return {};
165
0
    }
166
0
  }
167
168
  std::string QuicV1LongHeaderLayer::getDestinationConnectionIdAsString() const
169
0
  {
170
0
    auto connectionId = getDestinationConnectionId();
171
0
    return byteArrayToHexString(connectionId.data(), connectionId.size());
172
0
  }
173
174
  QuicV1LongHeaderLayer::OffsetAndLength QuicV1LongHeaderLayer::getSrcConIdOffsetAndLength() const
175
0
  {
176
0
    auto destOffsetAndLength = getDestConIdOffsetAndLength();
177
0
    auto sourceConnectionIdLengthOffset = destOffsetAndLength.offset + destOffsetAndLength.length;
178
0
    if (m_DataLen <= sourceConnectionIdLengthOffset + sizeof(uint8_t))
179
0
    {
180
0
      throw std::out_of_range("Not enough data to read source connection ID length");
181
0
    }
182
183
0
    auto offset = sourceConnectionIdLengthOffset + sizeof(uint8_t);
184
0
    auto length = static_cast<size_t>(m_Data[sourceConnectionIdLengthOffset]);
185
0
    if (offset + length > m_DataLen)
186
0
    {
187
0
      throw std::out_of_range("Not enough data to read source connection ID");
188
0
    }
189
190
0
    return { length, offset };
191
0
  }
192
193
  std::vector<uint8_t> QuicV1LongHeaderLayer::getSourceConnectionId() const
194
0
  {
195
0
    try
196
0
    {
197
0
      auto offsetAndLength = getSrcConIdOffsetAndLength();
198
0
      return { m_Data + offsetAndLength.offset, m_Data + offsetAndLength.offset + offsetAndLength.length };
199
0
    }
200
0
    catch (std::out_of_range&)
201
0
    {
202
0
      return {};
203
0
    }
204
0
  }
205
206
  std::string QuicV1LongHeaderLayer::getSourceConnectionIdAsString() const
207
0
  {
208
0
    auto connectionId = getSourceConnectionId();
209
0
    return byteArrayToHexString(connectionId.data(), connectionId.size());
210
0
  }
211
212
  size_t QuicV1EstablishmentLayer::getLengthOffset() const
213
0
  {
214
0
    auto srcConOffsetAndLength = getSrcConIdOffsetAndLength();
215
0
    if (srcConOffsetAndLength.offset + srcConOffsetAndLength.length + sizeof(uint8_t) > m_DataLen)
216
0
    {
217
0
      throw std::out_of_range("Not enough data to read length offset");
218
0
    }
219
220
0
    return srcConOffsetAndLength.offset + srcConOffsetAndLength.length;
221
0
  }
222
223
  QuicV1EstablishmentLayer::VarintValueAndSize QuicV1EstablishmentLayer::getVarintValueAndSize(size_t offset) const
224
0
  {
225
0
    uint8_t prefix = (m_Data[offset] & 0xc0) >> 6;
226
0
    auto size = static_cast<size_t>(1) << prefix;
227
228
0
    if (offset + size > m_DataLen)
229
0
    {
230
0
      throw std::out_of_range("Not enough data to read varint value");
231
0
    }
232
233
0
    uint64_t value = m_Data[offset] & 0x3f;
234
0
    for (size_t i = 1; i < size; i++)
235
0
    {
236
0
      value = (value << 8) | m_Data[offset + i];
237
0
    }
238
239
0
    return { value, size };
240
0
  }
241
242
  uint64_t QuicV1EstablishmentLayer::getLength() const
243
0
  {
244
0
    try
245
0
    {
246
0
      auto offset = getLengthOffset();
247
0
      auto valueAndSize = getVarintValueAndSize(offset);
248
0
      return valueAndSize.value;
249
0
    }
250
0
    catch (std::out_of_range&)
251
0
    {
252
0
      return 0;
253
0
    }
254
0
  }
255
256
  size_t QuicV1EstablishmentLayer::getHeaderLen() const
257
0
  {
258
0
    try
259
0
    {
260
0
      auto offset = getLengthOffset();
261
0
      auto lengthValueAndSize = getVarintValueAndSize(offset);
262
0
      return (std::min)(static_cast<size_t>(offset + lengthValueAndSize.size + lengthValueAndSize.value),
263
0
                        m_DataLen);
264
0
    }
265
0
    catch (std::out_of_range&)
266
0
    {
267
0
      return m_DataLen;
268
0
    }
269
0
  }
270
271
  QuicV1EstablishmentLayer::ProtectedPayload QuicV1EstablishmentLayer::getProtectedPayload() const
272
0
  {
273
0
    try
274
0
    {
275
0
      auto lengthOffset = getLengthOffset();
276
0
      auto lengthValueAndSize = getVarintValueAndSize(lengthOffset);
277
278
0
      auto payloadOffset = lengthOffset + lengthValueAndSize.size;
279
0
      auto payloadLength = static_cast<size_t>(lengthValueAndSize.value);
280
281
0
      payloadLength = (std::min)(payloadLength, m_DataLen - payloadOffset);
282
283
0
      return { m_Data + payloadOffset, payloadLength };
284
0
    }
285
0
    catch (std::out_of_range&)
286
0
    {
287
0
      return { nullptr, 0 };
288
0
    }
289
0
  }
290
291
  std::vector<uint8_t> QuicV1InitialLayer::getToken() const
292
0
  {
293
0
    try
294
0
    {
295
0
      auto tokenLengthOffset = getTokenLengthOffset();
296
0
      auto tokenLengthValueAndSize = getVarintValueAndSize(tokenLengthOffset);
297
0
      if (tokenLengthValueAndSize.value == 0 ||
298
0
          tokenLengthOffset + tokenLengthValueAndSize.size + tokenLengthValueAndSize.value > m_DataLen)
299
0
      {
300
0
        return {};
301
0
      }
302
0
      auto tokenOffset = m_Data + tokenLengthOffset + tokenLengthValueAndSize.size;
303
0
      return { tokenOffset, tokenOffset + tokenLengthValueAndSize.value };
304
0
    }
305
0
    catch (std::out_of_range&)
306
0
    {
307
0
      return {};
308
0
    }
309
0
  }
310
311
  std::string QuicV1InitialLayer::getTokenAsString() const
312
0
  {
313
0
    auto token = getToken();
314
0
    return byteArrayToHexString(token.data(), token.size());
315
0
  }
316
317
  size_t QuicV1InitialLayer::getLengthOffset() const
318
0
  {
319
0
    auto tokenLengthOffset = getTokenLengthOffset();
320
0
    auto tokenLengthValueAndSize = getVarintValueAndSize(tokenLengthOffset);
321
0
    if (tokenLengthOffset + tokenLengthValueAndSize.size + tokenLengthValueAndSize.value > m_DataLen)
322
0
    {
323
0
      throw std::out_of_range("Not enough data to read length offset");
324
0
    }
325
0
    return tokenLengthOffset + tokenLengthValueAndSize.size + tokenLengthValueAndSize.value;
326
0
  }
327
328
  size_t QuicV1InitialLayer::getTokenLengthOffset() const
329
0
  {
330
0
    auto srcConOffsetAndLength = getSrcConIdOffsetAndLength();
331
0
    if (srcConOffsetAndLength.offset + srcConOffsetAndLength.length + sizeof(uint8_t) > m_DataLen)
332
0
    {
333
0
      throw std::out_of_range("Not enough data to read token length offset");
334
0
    }
335
0
    return srcConOffsetAndLength.offset + srcConOffsetAndLength.length;
336
0
  }
337
338
  size_t QuicV1RetryLayer::getRetryTokenOffset() const
339
0
  {
340
0
    try
341
0
    {
342
0
      auto offsetAndLength = getSrcConIdOffsetAndLength();
343
0
      return offsetAndLength.offset + offsetAndLength.length;
344
0
    }
345
0
    catch (std::out_of_range&)
346
0
    {
347
0
      return m_DataLen;
348
0
    }
349
0
  }
350
351
  std::vector<uint8_t> QuicV1RetryLayer::getRetryToken() const
352
0
  {
353
0
    auto retryTokenOffset = getRetryTokenOffset();
354
0
    if (m_DataLen - retryTokenOffset < retryIntegritySize)
355
0
    {
356
0
      return {};
357
0
    }
358
359
0
    return { m_Data + retryTokenOffset, m_Data + m_DataLen - retryIntegritySize };
360
0
  }
361
362
  std::string QuicV1RetryLayer::getRetryTokenAsString() const
363
0
  {
364
0
    auto retryToken = getRetryToken();
365
0
    return byteArrayToHexString(retryToken.data(), retryToken.size());
366
0
  }
367
368
  std::vector<uint8_t> QuicV1RetryLayer::getRetryIntegrityTag() const
369
0
  {
370
0
    auto retryTokenOffset = getRetryTokenOffset();
371
0
    if (m_DataLen - retryTokenOffset < retryIntegritySize)
372
0
    {
373
0
      return {};
374
0
    }
375
376
0
    return { m_Data + m_DataLen - retryIntegritySize, m_Data + m_DataLen };
377
0
  }
378
379
  std::string QuicV1RetryLayer::getRetryIntegrityTagAsString() const
380
0
  {
381
0
    auto retryIntegrityTag = getRetryIntegrityTag();
382
0
    return byteArrayToHexString(retryIntegrityTag.data(), retryIntegrityTag.size());
383
0
  }
384
385
  std::vector<uint32_t> QuicV1VersionNegotiationLayer::getSupportedVersions() const
386
0
  {
387
0
    try
388
0
    {
389
0
      auto offsetAndLength = getSrcConIdOffsetAndLength();
390
0
      auto supportedVersionsOffset = offsetAndLength.offset + offsetAndLength.length;
391
0
      std::vector<uint32_t> supportedVersions;
392
0
      while (supportedVersionsOffset < m_DataLen)
393
0
      {
394
0
        if (m_DataLen - supportedVersionsOffset < sizeof(uint32_t))
395
0
        {
396
0
          break;
397
0
        }
398
0
        uint32_t version;
399
0
        std::memcpy(&version, m_Data + supportedVersionsOffset, sizeof(uint32_t));
400
0
        supportedVersions.push_back(netToHost32(version));
401
0
        supportedVersionsOffset += sizeof(uint32_t);
402
0
      }
403
0
      return supportedVersions;
404
0
    }
405
0
    catch (std::out_of_range&)
406
0
    {
407
0
      return {};
408
0
    }
409
0
  }
410
411
  QuicV1Layer::ProtectedPayload QuicV1OneRttLayer::getProtectedPayload() const
412
0
  {
413
0
    return { m_Data + sizeof(quic_short_header), m_DataLen - sizeof(quic_short_header) };
414
0
  }
415
416
  bool QuicV1OneRttLayer::isDataValid(const uint8_t* data, size_t dataLen)
417
0
  {
418
0
    return data != nullptr && dataLen >= sizeof(quic_short_header);
419
0
  }
420
}  // namespace pcpp