Coverage Report

Created: 2026-09-01 08:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/BgpLayer.cpp
Line
Count
Source
1
121k
#define LOG_MODULE PacketLogModuleBgpLayer
2
3
#include "Logger.h"
4
#include "BgpLayer.h"
5
#include "Packet.h"
6
#include "EndianPortable.h"
7
#include "GeneralUtils.h"
8
#include <algorithm>
9
10
namespace pcpp
11
{
12
  // ~~~~~~~~
13
  // BgpLayer
14
  // ~~~~~~~~
15
16
  size_t BgpLayer::getHeaderLen() const
17
1.27M
  {
18
1.27M
    if (m_DataLen < sizeof(bgp_common_header))
19
4
    {
20
4
      return m_DataLen;
21
4
    }
22
23
1.27M
    uint16_t messageLen = be16toh(getBasicHeader()->length);
24
1.27M
    if (m_DataLen < messageLen)
25
132k
    {
26
132k
      return m_DataLen;
27
132k
    }
28
29
1.13M
    return (size_t)messageLen;
30
1.27M
  }
31
32
  BgpLayer* BgpLayer::parseBgpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
33
192k
  {
34
192k
    if (data == nullptr || dataLen < sizeof(bgp_common_header))
35
10.2k
      return nullptr;
36
37
182k
    auto* bgpHeader = reinterpret_cast<bgp_common_header*>(data);
38
39
    // illegal header data - length is too small
40
182k
    uint16_t messageLen = be16toh(bgpHeader->length);
41
182k
    if (dataLen < messageLen || messageLen < static_cast<uint16_t>(sizeof(bgp_common_header)))
42
11.6k
      return nullptr;
43
44
170k
    switch (bgpHeader->messageType)
45
170k
    {
46
26.3k
    case 1:  // OPEN
47
26.3k
      return BgpOpenMessageLayer::isDataValid(data, dataLen)
48
26.3k
                 ? new BgpOpenMessageLayer(data, dataLen, prevLayer, packet)
49
26.3k
                 : nullptr;
50
132k
    case 2:  // UPDATE
51
132k
      return BgpUpdateMessageLayer::isDataValid(data, dataLen)
52
132k
                 ? new BgpUpdateMessageLayer(data, dataLen, prevLayer, packet)
53
132k
                 : nullptr;
54
4.44k
    case 3:  // NOTIFICATION
55
4.44k
      return new BgpNotificationMessageLayer(data, dataLen, prevLayer, packet);
56
3.90k
    case 4:  // KEEPALIVE
57
3.90k
      return new BgpKeepaliveMessageLayer(data, dataLen, prevLayer, packet);
58
2.91k
    case 5:  // ROUTE-REFRESH
59
2.91k
      return new BgpRouteRefreshMessageLayer(data, dataLen, prevLayer, packet);
60
493
    default:
61
493
      return nullptr;
62
170k
    }
63
170k
  }
64
65
  std::string BgpLayer::getMessageTypeAsString() const
66
57.9k
  {
67
57.9k
    switch (getBgpMessageType())
68
57.9k
    {
69
11.4k
    case BgpLayer::Open:
70
11.4k
      return "OPEN";
71
40.1k
    case BgpLayer::Update:
72
40.1k
      return "UPDATE";
73
2.28k
    case BgpLayer::Notification:
74
2.28k
      return "NOTIFICATION";
75
2.32k
    case BgpLayer::Keepalive:
76
2.32k
      return "KEEPALIVE";
77
1.71k
    case BgpLayer::RouteRefresh:
78
1.71k
      return "ROUTE-REFRESH";
79
0
    default:
80
0
      return "Unknown";
81
57.9k
    }
82
57.9k
  }
83
84
  void BgpLayer::parseNextLayer()
85
167k
  {
86
167k
    size_t headerLen = getHeaderLen();
87
167k
    if (m_DataLen <= headerLen || headerLen == 0)
88
28.7k
      return;
89
90
138k
    uint8_t* payload = m_Data + headerLen;
91
138k
    size_t payloadLen = m_DataLen - headerLen;
92
93
138k
    constructNextLayerFromFactory(BgpLayer::parseBgpLayer, payload, payloadLen);
94
138k
  }
95
96
  std::string BgpLayer::toString() const
97
38.6k
  {
98
38.6k
    return "BGP Layer, " + getMessageTypeAsString() + " message";
99
38.6k
  }
100
101
  void BgpLayer::computeCalculateFields()
102
19.3k
  {
103
19.3k
    bgp_common_header* bgpHeader = getBasicHeader();
104
19.3k
    memset(bgpHeader->marker, 0xff, 16 * sizeof(uint8_t));
105
19.3k
    bgpHeader->messageType = (uint8_t)getBgpMessageType();
106
19.3k
    bgpHeader->length = htobe16(getHeaderLen());
107
19.3k
  }
108
109
  void BgpLayer::setBgpFields(size_t messageLen)
110
0
  {
111
0
    bgp_common_header* bgpHdr = getBasicHeader();
112
0
    memset(bgpHdr->marker, 0xff, 16 * sizeof(uint8_t));
113
0
    bgpHdr->messageType = (uint8_t)getBgpMessageType();
114
0
    if (messageLen != 0)
115
0
    {
116
0
      bgpHdr->length = htobe16((uint16_t)messageLen);
117
0
    }
118
0
    else
119
0
    {
120
0
      bgpHdr->length = m_DataLen;
121
0
    }
122
0
  }
123
124
  bool BgpLayer::extendLayer(int offsetInLayer, size_t numOfBytesToExtend)
125
47.2k
  {
126
47.2k
    if (getAttachedPacket() != nullptr)
127
47.2k
    {
128
47.2k
      int rawPacketLen = getAttachedPacket()->getRawPacket()->getRawDataLen();
129
47.2k
      const uint8_t* rawPacketPtr = getAttachedPacket()->getRawPacket()->getRawData();
130
131
47.2k
      if (m_Data - rawPacketPtr + static_cast<ptrdiff_t>(offsetInLayer) > static_cast<ptrdiff_t>(rawPacketLen))
132
5.18k
      {
133
5.18k
        PCPP_LOG_ERROR("Requested offset is larger than total packet length");
134
5.18k
        return false;
135
5.18k
      }
136
137
42.1k
      if (m_NextLayer != nullptr && static_cast<ptrdiff_t>(offsetInLayer) > m_NextLayer->getData() - m_Data)
138
3.65k
      {
139
3.65k
        PCPP_LOG_ERROR("Requested offset exceeds current layer's boundary");
140
3.65k
        return false;
141
3.65k
      }
142
42.1k
    }
143
144
38.4k
    return Layer::extendLayer(offsetInLayer, numOfBytesToExtend);
145
47.2k
  }
146
147
  bool BgpLayer::shortenLayer(int offsetInLayer, size_t numOfBytesToShorten)
148
49.1k
  {
149
49.1k
    if (getAttachedPacket() != nullptr)
150
49.1k
    {
151
49.1k
      int rawPacketLen = getAttachedPacket()->getRawPacket()->getRawDataLen();
152
49.1k
      const uint8_t* rawPacketPtr = getAttachedPacket()->getRawPacket()->getRawData();
153
154
49.1k
      if (m_Data - rawPacketPtr + static_cast<ptrdiff_t>(offsetInLayer) +
155
49.1k
              static_cast<ptrdiff_t>(numOfBytesToShorten) >
156
49.1k
          static_cast<ptrdiff_t>(rawPacketLen))
157
6.59k
      {
158
6.59k
        PCPP_LOG_ERROR("Requested number of bytes to shorten is larger than total packet length");
159
6.59k
        return false;
160
6.59k
      }
161
162
42.5k
      if (m_NextLayer != nullptr &&
163
34.5k
          static_cast<ptrdiff_t>(offsetInLayer) + static_cast<ptrdiff_t>(numOfBytesToShorten) >
164
34.5k
              m_NextLayer->getData() - m_Data)
165
1.95k
      {
166
1.95k
        PCPP_LOG_ERROR("Requested number of bytes to shorten exceeds current layer's boundary");
167
1.95k
        return false;
168
1.95k
      }
169
42.5k
    }
170
171
40.6k
    return Layer::shortenLayer(offsetInLayer, numOfBytesToShorten);
172
49.1k
  }
173
174
  // ~~~~~~~~~~~~~~~~~~~~
175
  // BgpOpenMessageLayer
176
  // ~~~~~~~~~~~~~~~~~~~~
177
178
  BgpOpenMessageLayer::optional_parameter::optional_parameter(uint8_t typeVal, const std::string& valueAsHexString)
179
19.0k
  {
180
19.0k
    type = typeVal;
181
19.0k
    length = hexStringToByteArray(valueAsHexString, value, 32);
182
19.0k
  }
183
184
  bool BgpOpenMessageLayer::isDataValid(const uint8_t* data, size_t dataSize)
185
26.3k
  {
186
26.3k
    if (data == nullptr || dataSize < sizeof(bgp_common_header))
187
0
    {
188
0
      return false;
189
0
    }
190
191
26.3k
    const auto* bgpHeader = reinterpret_cast<const bgp_common_header*>(data);
192
26.3k
    uint16_t messageLen = be16toh(bgpHeader->length);
193
26.3k
    return messageLen >= sizeof(bgp_open_message) && dataSize >= messageLen;
194
26.3k
  }
195
196
  BgpOpenMessageLayer::BgpOpenMessageLayer(uint16_t myAutonomousSystem, uint16_t holdTime, const IPv4Address& bgpId,
197
                                           const std::vector<optional_parameter>& optionalParams)
198
0
  {
199
0
    uint8_t optionalParamsData[1500];
200
0
    size_t optionalParamsDataLen = optionalParamsToByteArray(optionalParams, optionalParamsData, 1500);
201
202
0
    const size_t headerLen = sizeof(bgp_open_message) + optionalParamsDataLen;
203
0
    allocData(headerLen);
204
0
    setBgpFields(headerLen);
205
206
0
    bgp_open_message* msgHdr = getOpenMsgHeader();
207
0
    msgHdr->version = 4;
208
0
    msgHdr->myAutonomousSystem = htobe16(myAutonomousSystem);
209
0
    msgHdr->holdTime = htobe16(holdTime);
210
0
    msgHdr->bgpId = bgpId.toInt();
211
0
    msgHdr->optionalParameterLength = optionalParamsDataLen;
212
0
    if (optionalParamsDataLen > 0)
213
0
    {
214
0
      memcpy(m_Data + sizeof(bgp_open_message), optionalParamsData, optionalParamsDataLen);
215
0
    }
216
217
0
    m_Protocol = BGP;
218
0
  }
219
220
  size_t BgpOpenMessageLayer::optionalParamsToByteArray(const std::vector<optional_parameter>& optionalParams,
221
                                                        uint8_t* resultByteArr, size_t maxByteArrSize)
222
11.4k
  {
223
11.4k
    if (resultByteArr == nullptr || maxByteArrSize == 0)
224
0
    {
225
0
      return 0;
226
0
    }
227
228
11.4k
    size_t dataLen = 0;
229
230
11.4k
    for (const auto& param : optionalParams)
231
57.0k
    {
232
57.0k
      if (param.length > 32)
233
30
      {
234
30
        PCPP_LOG_ERROR("Illegal optional parameter length " << (int)param.length
235
30
                                                            << ", must be 32 bytes or less");
236
30
        break;  // illegal value
237
30
      }
238
239
57.0k
      size_t curDataSize = 2 * sizeof(uint8_t) + (size_t)param.length;
240
241
57.0k
      if (dataLen + curDataSize > maxByteArrSize)
242
0
      {
243
0
        break;
244
0
      }
245
246
57.0k
      resultByteArr[0] = param.type;
247
57.0k
      resultByteArr[1] = param.length;
248
57.0k
      if (param.length > 0)
249
48.9k
      {
250
48.9k
        memcpy(resultByteArr + 2 * sizeof(uint8_t), param.value, param.length);
251
48.9k
      }
252
253
57.0k
      dataLen += curDataSize;
254
57.0k
      resultByteArr += curDataSize;
255
57.0k
    }
256
257
11.4k
    return dataLen;
258
11.4k
  }
259
260
  void BgpOpenMessageLayer::setBgpId(const IPv4Address& newBgpId)
261
0
  {
262
0
    bgp_open_message* msgHdr = getOpenMsgHeader();
263
0
    if (msgHdr == nullptr)
264
0
    {
265
0
      return;
266
0
    }
267
268
0
    msgHdr->bgpId = newBgpId.toInt();
269
0
  }
270
271
  void BgpOpenMessageLayer::getOptionalParameters(std::vector<optional_parameter>& optionalParameters)
272
3.81k
  {
273
3.81k
    size_t headerLen = getHeaderLen();
274
3.81k
    bgp_open_message* msgHdr = getOpenMsgHeader();
275
276
    // Parentheses around std::min avoid clashes with platform min macros (for example on Windows)
277
3.81k
    size_t optionalParamsLen =
278
3.81k
        (std::min)(static_cast<size_t>(msgHdr->optionalParameterLength), headerLen - sizeof(bgp_open_message));
279
280
3.81k
    uint8_t* dataPtr = m_Data + sizeof(bgp_open_message);
281
3.81k
    size_t byteCount = 0;
282
22.8k
    while (byteCount < optionalParamsLen)
283
21.7k
    {
284
21.7k
      size_t remaining = optionalParamsLen - byteCount;
285
21.7k
      constexpr size_t optParamHdrSize = sizeof(optional_parameter::type) + sizeof(optional_parameter::length);
286
21.7k
      if (remaining < optParamHdrSize)
287
431
      {
288
431
        PCPP_LOG_ERROR("Truncated optional parameter header");
289
431
        break;
290
431
      }
291
292
21.2k
      optional_parameter op;
293
21.2k
      op.type = dataPtr[0];
294
21.2k
      op.length = dataPtr[1];
295
296
21.2k
      size_t totalLen = optParamHdrSize + static_cast<size_t>(op.length);
297
21.2k
      if (totalLen > remaining)
298
2.23k
      {
299
2.23k
        PCPP_LOG_ERROR("Optional parameter length is out of bounds: " << static_cast<int>(op.length));
300
2.23k
        break;
301
2.23k
      }
302
303
19.0k
      if (op.length > 0)
304
15.0k
      {
305
15.0k
        memcpy(op.value, dataPtr + optParamHdrSize,
306
15.0k
               (std::min)(static_cast<size_t>(op.length), sizeof(op.value)));
307
15.0k
      }
308
309
19.0k
      optionalParameters.push_back(op);
310
311
19.0k
      byteCount += totalLen;
312
19.0k
      dataPtr += totalLen;
313
19.0k
    }
314
3.81k
  }
315
316
  size_t BgpOpenMessageLayer::getOptionalParametersLength()
317
11.4k
  {
318
11.4k
    size_t headerLen = getHeaderLen();
319
11.4k
    bgp_open_message* msgHdr = getOpenMsgHeader();
320
11.4k
    auto optParamLen = static_cast<size_t>(msgHdr->optionalParameterLength);
321
322
11.4k
    constexpr size_t bgpOpenMsgHeaderSize = sizeof(bgp_open_message);
323
11.4k
    if (headerLen < optParamLen + bgpOpenMsgHeaderSize)
324
1.06k
    {
325
1.06k
      PCPP_LOG_WARN("BGP Layer optional param length exceeds total BGP message. "
326
1.06k
                    "This packet might be malformed! Trimming to maximum allowed by BGP message length.");
327
1.06k
      optParamLen = headerLen >= bgpOpenMsgHeaderSize ? headerLen - bgpOpenMsgHeaderSize : 0;
328
1.06k
    }
329
330
11.4k
    return optParamLen;
331
11.4k
  }
332
333
  bool BgpOpenMessageLayer::setOptionalParameters(const std::vector<optional_parameter>& optionalParameters)
334
11.4k
  {
335
11.4k
    uint8_t newOptionalParamsData[1500];
336
11.4k
    size_t newOptionalParamsDataLen = optionalParamsToByteArray(optionalParameters, newOptionalParamsData, 1500);
337
11.4k
    size_t curOptionalParamsDataLen = getOptionalParametersLength();
338
11.4k
    constexpr int offsetInLayer = sizeof(bgp_open_message);
339
340
11.4k
    if (newOptionalParamsDataLen > curOptionalParamsDataLen)
341
4.15k
    {
342
4.15k
      size_t numOfBytesToExtend = newOptionalParamsDataLen - curOptionalParamsDataLen;
343
344
4.15k
      if (!extendLayer(offsetInLayer, numOfBytesToExtend))
345
162
      {
346
162
        PCPP_LOG_ERROR("Couldn't extend BGP open layer to include the additional optional parameters");
347
162
        return false;
348
162
      }
349
4.15k
    }
350
7.29k
    else if (newOptionalParamsDataLen < curOptionalParamsDataLen)
351
5.88k
    {
352
5.88k
      size_t numOfBytesToShorten = curOptionalParamsDataLen - newOptionalParamsDataLen;
353
354
5.88k
      if (!shortenLayer(offsetInLayer, numOfBytesToShorten))
355
1.13k
      {
356
1.13k
        PCPP_LOG_ERROR("Couldn't shorten BGP open layer to set the right size of the optional parameters data");
357
1.13k
        return false;
358
1.13k
      }
359
5.88k
    }
360
361
10.1k
    if (newOptionalParamsDataLen > 0)
362
5.52k
    {
363
5.52k
      memcpy(m_Data + offsetInLayer, newOptionalParamsData, newOptionalParamsDataLen);
364
5.52k
    }
365
366
10.1k
    getOpenMsgHeader()->optionalParameterLength = static_cast<uint8_t>(newOptionalParamsDataLen);
367
10.1k
    getOpenMsgHeader()->length = htobe16(sizeof(bgp_open_message) + newOptionalParamsDataLen);
368
369
10.1k
    return true;
370
11.4k
  }
371
372
  bool BgpOpenMessageLayer::clearOptionalParameters()
373
3.81k
  {
374
3.81k
    return setOptionalParameters(std::vector<optional_parameter>());
375
3.81k
  }
376
377
  // ~~~~~~~~~~~~~~~~~~~~~
378
  // BgpUpdateMessageLayer
379
  // ~~~~~~~~~~~~~~~~~~~~~
380
381
  BgpUpdateMessageLayer::path_attribute::path_attribute(uint8_t flagsVal, uint8_t typeVal,
382
                                                        const std::string& dataAsHexString)
383
40.1k
  {
384
40.1k
    flags = flagsVal;
385
40.1k
    type = typeVal;
386
40.1k
    length = hexStringToByteArray(dataAsHexString, data, 32);
387
40.1k
  }
388
389
  BgpUpdateMessageLayer::BgpUpdateMessageLayer(const std::vector<prefix_and_ip>& withdrawnRoutes,
390
                                               const std::vector<path_attribute>& pathAttributes,
391
                                               const std::vector<prefix_and_ip>& nlri)
392
0
  {
393
0
    uint8_t withdrawnRoutesData[1500];
394
0
    uint8_t pathAttributesData[1500];
395
0
    uint8_t nlriData[1500];
396
0
    size_t withdrawnRoutesDataLen = prefixAndIPDataToByteArray(withdrawnRoutes, withdrawnRoutesData, 1500);
397
0
    size_t pathAttributesDataLen = pathAttributesToByteArray(pathAttributes, pathAttributesData, 1500);
398
0
    size_t nlriDataLen = prefixAndIPDataToByteArray(nlri, nlriData, 1500);
399
400
0
    size_t headerLen = sizeof(bgp_common_header) + 2 * sizeof(uint16_t) + withdrawnRoutesDataLen +
401
0
                       pathAttributesDataLen + nlriDataLen;
402
0
    allocData(headerLen);
403
0
    setBgpFields(headerLen);
404
405
0
    uint8_t* dataPtr = m_Data + sizeof(bgp_common_header);
406
407
    // copy withdrawn routes data
408
0
    uint16_t withdrawnRoutesDataLenBE = htobe16(withdrawnRoutesDataLen);
409
0
    memcpy(dataPtr, &withdrawnRoutesDataLenBE, sizeof(uint16_t));
410
0
    dataPtr += sizeof(uint16_t);
411
0
    if (withdrawnRoutesDataLen > 0)
412
0
    {
413
0
      memcpy(dataPtr, withdrawnRoutesData, withdrawnRoutesDataLen);
414
0
      dataPtr += withdrawnRoutesDataLen;
415
0
    }
416
417
    // copy path attributes data
418
0
    uint16_t pathAttributesDataLenBE = htobe16(pathAttributesDataLen);
419
0
    memcpy(dataPtr, &pathAttributesDataLenBE, sizeof(uint16_t));
420
0
    dataPtr += sizeof(uint16_t);
421
0
    if (pathAttributesDataLen > 0)
422
0
    {
423
0
      memcpy(dataPtr, pathAttributesData, pathAttributesDataLen);
424
0
      dataPtr += pathAttributesDataLen;
425
0
    }
426
427
    // copy nlri data
428
0
    if (nlriDataLen > 0)
429
0
    {
430
0
      memcpy(dataPtr, nlriData, nlriDataLen);
431
0
    }
432
433
0
    m_Protocol = BGP;
434
0
  }
435
436
  void BgpUpdateMessageLayer::parsePrefixAndIPData(uint8_t* dataPtr, size_t dataLen,
437
                                                   std::vector<prefix_and_ip>& result)
438
10.0k
  {
439
10.0k
    size_t byteCount = 0;
440
20.9k
    while (byteCount < dataLen)
441
14.4k
    {
442
14.4k
      prefix_and_ip wr;
443
14.4k
      wr.prefix = dataPtr[0];
444
14.4k
      size_t curByteCount = 1;
445
14.4k
      if (wr.prefix == 32)
446
5.28k
      {
447
5.28k
        uint8_t octets[4] = { dataPtr[1], dataPtr[2], dataPtr[3], dataPtr[4] };
448
5.28k
        wr.ipAddr = IPv4Address(octets);
449
5.28k
        curByteCount += 4;
450
5.28k
      }
451
9.16k
      else if (wr.prefix == 24)
452
5.51k
      {
453
5.51k
        uint8_t octets[4] = { dataPtr[1], dataPtr[2], dataPtr[3], 0 };
454
5.51k
        wr.ipAddr = IPv4Address(octets);
455
5.51k
        curByteCount += 3;
456
5.51k
      }
457
3.65k
      else if (wr.prefix == 16)
458
61
      {
459
61
        uint8_t octets[4] = { dataPtr[1], dataPtr[2], 0, 0 };
460
61
        wr.ipAddr = IPv4Address(octets);
461
61
        curByteCount += 2;
462
61
      }
463
3.59k
      else if (wr.prefix == 8)
464
134
      {
465
134
        uint8_t octets[4] = { dataPtr[1], 0, 0, 0 };
466
134
        wr.ipAddr = IPv4Address(octets);
467
134
        curByteCount += 1;
468
134
      }
469
3.46k
      else
470
3.46k
      {
471
3.46k
        PCPP_LOG_DEBUG("Illegal prefix value " << (int)wr.prefix);
472
3.46k
        break;  // illegal value
473
3.46k
      }
474
475
10.9k
      result.push_back(wr);
476
10.9k
      dataPtr += curByteCount;
477
10.9k
      byteCount += curByteCount;
478
10.9k
    }
479
10.0k
  }
480
481
  size_t BgpUpdateMessageLayer::prefixAndIPDataToByteArray(const std::vector<prefix_and_ip>& prefixAndIpData,
482
                                                           uint8_t* resultByteArr, size_t maxByteArrSize)
483
80.2k
  {
484
80.2k
    if (resultByteArr == nullptr || maxByteArrSize == 0)
485
0
    {
486
0
      return 0;
487
0
    }
488
489
80.2k
    size_t dataLen = 0;
490
491
80.2k
    for (const auto& prefixAndIp : prefixAndIpData)
492
88.8k
    {
493
88.8k
      uint8_t curData[5];
494
88.8k
      curData[0] = prefixAndIp.prefix;
495
88.8k
      size_t curDataSize = 1;
496
88.8k
      const uint8_t* octets = prefixAndIp.ipAddr.toBytes();
497
88.8k
      if (prefixAndIp.prefix == 32)
498
10.5k
      {
499
10.5k
        curDataSize += 4;
500
10.5k
        curData[1] = octets[0];
501
10.5k
        curData[2] = octets[1];
502
10.5k
        curData[3] = octets[2];
503
10.5k
        curData[4] = octets[3];
504
10.5k
      }
505
78.3k
      else if (prefixAndIp.prefix == 24)
506
64.5k
      {
507
64.5k
        curDataSize += 3;
508
64.5k
        curData[1] = octets[0];
509
64.5k
        curData[2] = octets[1];
510
64.5k
        curData[3] = octets[2];
511
64.5k
      }
512
13.7k
      else if (prefixAndIp.prefix == 16)
513
13.5k
      {
514
13.5k
        curDataSize += 2;
515
13.5k
        curData[1] = octets[0];
516
13.5k
        curData[2] = octets[1];
517
13.5k
      }
518
268
      else if (prefixAndIp.prefix == 8)
519
268
      {
520
268
        curDataSize += 1;
521
268
        curData[1] = octets[0];
522
268
      }
523
0
      else
524
0
      {
525
0
        PCPP_LOG_ERROR("Illegal prefix value " << (int)prefixAndIp.prefix);
526
0
        break;  // illegal value
527
0
      }
528
529
88.8k
      if (dataLen + curDataSize > maxByteArrSize)
530
0
      {
531
0
        break;
532
0
      }
533
534
88.8k
      dataLen += curDataSize;
535
536
88.8k
      memcpy(resultByteArr, curData, curDataSize);
537
88.8k
      resultByteArr += curDataSize;
538
88.8k
    }
539
540
80.2k
    return dataLen;
541
80.2k
  }
542
543
  size_t BgpUpdateMessageLayer::pathAttributesToByteArray(const std::vector<path_attribute>& pathAttributes,
544
                                                          uint8_t* resultByteArr, size_t maxByteArrSize)
545
40.1k
  {
546
40.1k
    if (resultByteArr == nullptr || maxByteArrSize == 0)
547
0
    {
548
0
      return 0;
549
0
    }
550
551
40.1k
    size_t dataLen = 0;
552
553
40.1k
    for (const auto& attribute : pathAttributes)
554
82.7k
    {
555
82.7k
      if (attribute.length > 32)
556
17.0k
      {
557
17.0k
        PCPP_LOG_ERROR("Illegal path attribute length " << (int)attribute.length);
558
17.0k
        break;  // illegal value
559
17.0k
      }
560
561
65.6k
      size_t curDataSize = 3 * sizeof(uint8_t) + (size_t)attribute.length;
562
563
65.6k
      if (dataLen + curDataSize > maxByteArrSize)
564
0
      {
565
0
        break;
566
0
      }
567
568
65.6k
      resultByteArr[0] = attribute.flags;
569
65.6k
      resultByteArr[1] = attribute.type;
570
65.6k
      resultByteArr[2] = attribute.length;
571
65.6k
      if (attribute.length > 0)
572
47.9k
      {
573
47.9k
        memcpy(resultByteArr + 3 * sizeof(uint8_t), attribute.data, attribute.length);
574
47.9k
      }
575
576
65.6k
      dataLen += curDataSize;
577
65.6k
      resultByteArr += curDataSize;
578
65.6k
    }
579
580
40.1k
    return dataLen;
581
40.1k
  }
582
583
  size_t BgpUpdateMessageLayer::getWithdrawnRoutesLength() const
584
334k
  {
585
334k
    size_t headerLen = getHeaderLen();
586
334k
    size_t minLen = sizeof(bgp_common_header) + sizeof(uint16_t);
587
334k
    if (headerLen >= minLen)
588
321k
    {
589
321k
      uint16_t res = be16toh(*(uint16_t*)(m_Data + sizeof(bgp_common_header)));
590
321k
      if ((size_t)res > headerLen - minLen)
591
52.7k
      {
592
52.7k
        return headerLen - minLen;
593
52.7k
      }
594
595
268k
      return (size_t)res;
596
321k
    }
597
598
13.7k
    return 0;
599
334k
  }
600
601
  void BgpUpdateMessageLayer::getWithdrawnRoutes(std::vector<prefix_and_ip>& withdrawnRoutes)
602
13.3k
  {
603
13.3k
    size_t withdrawnRouteLen = getWithdrawnRoutesLength();
604
13.3k
    if (withdrawnRouteLen == 0)
605
11.2k
    {
606
11.2k
      return;
607
11.2k
    }
608
609
2.10k
    uint8_t* dataPtr = m_Data + sizeof(bgp_common_header) + sizeof(uint16_t);
610
2.10k
    parsePrefixAndIPData(dataPtr, withdrawnRouteLen, withdrawnRoutes);
611
2.10k
  }
612
613
  size_t BgpUpdateMessageLayer::getPathAttributesLength() const
614
148k
  {
615
148k
    size_t headerLen = getHeaderLen();
616
148k
    size_t minLen = sizeof(bgp_common_header) + 2 * sizeof(uint16_t);
617
148k
    if (headerLen >= minLen)
618
137k
    {
619
137k
      size_t withdrawnRouteLen = getWithdrawnRoutesLength();
620
      // Ensure the memory access is within bounds
621
137k
      if (sizeof(bgp_common_header) + sizeof(uint16_t) + withdrawnRouteLen + sizeof(uint16_t) > headerLen)
622
23.4k
      {
623
23.4k
        return 0;  // Invalid access, return 0
624
23.4k
      }
625
113k
      uint16_t res =
626
113k
          be16toh(*(uint16_t*)(m_Data + sizeof(bgp_common_header) + sizeof(uint16_t) + withdrawnRouteLen));
627
113k
      if ((size_t)res > headerLen - minLen - withdrawnRouteLen)
628
11.3k
      {
629
11.3k
        return headerLen - minLen - withdrawnRouteLen;
630
11.3k
      }
631
632
102k
      return (size_t)res;
633
113k
    }
634
635
11.0k
    return 0;
636
148k
  }
637
638
  bool BgpUpdateMessageLayer::setWithdrawnRoutes(const std::vector<prefix_and_ip>& withdrawnRoutes)
639
40.1k
  {
640
40.1k
    uint8_t newWithdrawnRoutesData[1500];
641
40.1k
    size_t newWithdrawnRoutesDataLen = prefixAndIPDataToByteArray(withdrawnRoutes, newWithdrawnRoutesData, 1500);
642
40.1k
    size_t curWithdrawnRoutesDataLen = getWithdrawnRoutesLength();
643
40.1k
    int offsetInLayer = sizeof(bgp_common_header) + sizeof(uint16_t);
644
645
40.1k
    if (newWithdrawnRoutesDataLen > curWithdrawnRoutesDataLen)
646
11.6k
    {
647
11.6k
      size_t numOfBytesToExtend = newWithdrawnRoutesDataLen - curWithdrawnRoutesDataLen;
648
649
11.6k
      if (!extendLayer(offsetInLayer, numOfBytesToExtend))
650
2.75k
      {
651
2.75k
        PCPP_LOG_ERROR("Couldn't extend BGP update layer to include the additional withdrawn routes");
652
2.75k
        return false;
653
2.75k
      }
654
11.6k
    }
655
28.5k
    else if (newWithdrawnRoutesDataLen < curWithdrawnRoutesDataLen)
656
15.1k
    {
657
15.1k
      size_t numOfBytesToShorten = curWithdrawnRoutesDataLen - newWithdrawnRoutesDataLen;
658
659
15.1k
      if (!shortenLayer(offsetInLayer, numOfBytesToShorten))
660
6.12k
      {
661
6.12k
        PCPP_LOG_ERROR("Couldn't shorten BGP update layer to set the right size of the withdrawn routes data");
662
6.12k
        return false;
663
6.12k
      }
664
15.1k
    }
665
666
31.2k
    if (newWithdrawnRoutesDataLen > 0)
667
9.00k
    {
668
9.00k
      memcpy(m_Data + offsetInLayer, newWithdrawnRoutesData, newWithdrawnRoutesDataLen);
669
9.00k
    }
670
671
31.2k
    getBasicHeader()->length =
672
31.2k
        htobe16(be16toh(getBasicHeader()->length) + newWithdrawnRoutesDataLen - curWithdrawnRoutesDataLen);
673
674
31.2k
    uint16_t newWithdrawnRoutesDataLenBE = htobe16(newWithdrawnRoutesDataLen);
675
31.2k
    memcpy(m_Data + sizeof(bgp_common_header), &newWithdrawnRoutesDataLenBE, sizeof(uint16_t));
676
677
31.2k
    return true;
678
40.1k
  }
679
680
  bool BgpUpdateMessageLayer::clearWithdrawnRoutes()
681
13.3k
  {
682
13.3k
    return setWithdrawnRoutes(std::vector<prefix_and_ip>());
683
13.3k
  }
684
685
  void BgpUpdateMessageLayer::getPathAttributes(std::vector<path_attribute>& pathAttributes)
686
13.3k
  {
687
13.3k
    size_t pathAttrLen = getPathAttributesLength();
688
13.3k
    if (pathAttrLen == 0)
689
4.52k
    {
690
4.52k
      return;
691
4.52k
    }
692
693
8.85k
    uint8_t* dataPtr = m_Data + sizeof(bgp_common_header) + 2 * sizeof(uint16_t) + getWithdrawnRoutesLength();
694
8.85k
    size_t byteCount = 0;
695
43.4k
    while (byteCount < pathAttrLen)
696
34.6k
    {
697
34.6k
      path_attribute pa;
698
34.6k
      pa.flags = dataPtr[0];
699
34.6k
      pa.type = dataPtr[1];
700
34.6k
      pa.length = dataPtr[2];
701
34.6k
      size_t curByteCount = 3 + pa.length;
702
34.6k
      if (pa.length > 0)
703
25.4k
      {
704
25.4k
        size_t dataLenToCopy = (pa.length <= 32 ? pa.length : 32);
705
25.4k
        memcpy(pa.data, dataPtr + 3, dataLenToCopy);
706
25.4k
      }
707
708
34.6k
      pathAttributes.push_back(pa);
709
34.6k
      dataPtr += curByteCount;
710
34.6k
      byteCount += curByteCount;
711
34.6k
    }
712
8.85k
  }
713
714
  bool BgpUpdateMessageLayer::setPathAttributes(const std::vector<path_attribute>& pathAttributes)
715
40.1k
  {
716
40.1k
    uint8_t newPathAttributesData[1500];
717
40.1k
    size_t newPathAttributesDataLen = pathAttributesToByteArray(pathAttributes, newPathAttributesData, 1500);
718
40.1k
    size_t curPathAttributesDataLen = getPathAttributesLength();
719
40.1k
    size_t curWithdrawnRoutesDataLen = getWithdrawnRoutesLength();
720
40.1k
    int offsetInLayer = sizeof(bgp_common_header) + 2 * sizeof(uint16_t) + curWithdrawnRoutesDataLen;
721
722
40.1k
    if (newPathAttributesDataLen > curPathAttributesDataLen)
723
12.6k
    {
724
12.6k
      size_t numOfBytesToExtend = newPathAttributesDataLen - curPathAttributesDataLen;
725
726
12.6k
      if (!extendLayer(offsetInLayer, numOfBytesToExtend))
727
3.83k
      {
728
3.83k
        PCPP_LOG_ERROR("Couldn't extend BGP update layer to include the additional path attributes");
729
3.83k
        return false;
730
3.83k
      }
731
12.6k
    }
732
27.4k
    else if (newPathAttributesDataLen < curPathAttributesDataLen)
733
18.3k
    {
734
18.3k
      size_t numOfBytesToShorten = curPathAttributesDataLen - newPathAttributesDataLen;
735
736
18.3k
      if (!shortenLayer(offsetInLayer, numOfBytesToShorten))
737
2.08k
      {
738
2.08k
        PCPP_LOG_ERROR("Couldn't shorten BGP update layer to set the right size of the path attributes data");
739
2.08k
        return false;
740
2.08k
      }
741
18.3k
    }
742
743
34.2k
    if (newPathAttributesDataLen > 0)
744
16.3k
    {
745
16.3k
      memcpy(m_Data + offsetInLayer, newPathAttributesData, newPathAttributesDataLen);
746
16.3k
    }
747
748
34.2k
    getBasicHeader()->length =
749
34.2k
        htobe16(be16toh(getBasicHeader()->length) + newPathAttributesDataLen - curPathAttributesDataLen);
750
751
34.2k
    uint16_t newWithdrawnRoutesDataLenBE = htobe16(newPathAttributesDataLen);
752
34.2k
    memcpy(m_Data + sizeof(bgp_common_header) + sizeof(uint16_t) + curWithdrawnRoutesDataLen,
753
34.2k
           &newWithdrawnRoutesDataLenBE, sizeof(uint16_t));
754
755
34.2k
    return true;
756
40.1k
  }
757
758
  bool BgpUpdateMessageLayer::clearPathAttributes()
759
13.3k
  {
760
13.3k
    return setPathAttributes(std::vector<path_attribute>());
761
13.3k
  }
762
763
  size_t BgpUpdateMessageLayer::getNetworkLayerReachabilityInfoLength() const
764
53.5k
  {
765
53.5k
    size_t headerLen = getHeaderLen();
766
53.5k
    size_t minLen = sizeof(bgp_common_header) + 2 * sizeof(uint16_t);
767
53.5k
    if (headerLen >= minLen)
768
46.9k
    {
769
46.9k
      size_t withdrawnRouteLen = getWithdrawnRoutesLength();
770
46.9k
      size_t pathAttrLen = getPathAttributesLength();
771
46.9k
      int nlriSize = headerLen - minLen - withdrawnRouteLen - pathAttrLen;
772
46.9k
      if (nlriSize >= 0)
773
38.4k
      {
774
38.4k
        return (size_t)nlriSize;
775
38.4k
      }
776
777
8.44k
      return 0;
778
46.9k
    }
779
780
6.60k
    return 0;
781
53.5k
  }
782
783
  void BgpUpdateMessageLayer::getNetworkLayerReachabilityInfo(std::vector<prefix_and_ip>& nlri)
784
13.3k
  {
785
13.3k
    size_t nlriSize = getNetworkLayerReachabilityInfoLength();
786
13.3k
    if (nlriSize == 0)
787
5.48k
    {
788
5.48k
      return;
789
5.48k
    }
790
791
7.89k
    uint8_t* dataPtr = m_Data + sizeof(bgp_common_header) + 2 * sizeof(uint16_t) + getWithdrawnRoutesLength() +
792
7.89k
                       getPathAttributesLength();
793
7.89k
    parsePrefixAndIPData(dataPtr, nlriSize, nlri);
794
7.89k
  }
795
796
  bool BgpUpdateMessageLayer::isDataValid(const uint8_t* data, size_t dataSize)
797
132k
  {
798
132k
    if (dataSize < sizeof(bgp_common_header) + 2 * sizeof(uint16_t))
799
131
      return false;
800
801
132k
    uint16_t withdrLen = be16toh(*(uint16_t*)(data + sizeof(bgp_common_header)));
802
132k
    if (dataSize < sizeof(bgp_common_header) + 2 * sizeof(uint16_t) + withdrLen)
803
1.31k
      return false;
804
805
131k
    uint16_t attrLen = be16toh(*(uint16_t*)(data + sizeof(bgp_common_header) + sizeof(uint16_t) + withdrLen));
806
131k
    if (dataSize < sizeof(bgp_common_header) + 2 * sizeof(uint16_t) + withdrLen + attrLen)
807
1.40k
      return false;
808
809
129k
    return true;
810
131k
  }
811
812
  bool BgpUpdateMessageLayer::setNetworkLayerReachabilityInfo(const std::vector<prefix_and_ip>& nlri)
813
40.1k
  {
814
40.1k
    uint8_t newNlriData[1500];
815
40.1k
    size_t newNlriDataLen = prefixAndIPDataToByteArray(nlri, newNlriData, 1500);
816
40.1k
    size_t curNlriDataLen = getNetworkLayerReachabilityInfoLength();
817
40.1k
    size_t curPathAttributesDataLen = getPathAttributesLength();
818
40.1k
    size_t curWithdrawnRoutesDataLen = getWithdrawnRoutesLength();
819
40.1k
    int offsetInLayer =
820
40.1k
        sizeof(bgp_common_header) + 2 * sizeof(uint16_t) + curWithdrawnRoutesDataLen + curPathAttributesDataLen;
821
822
40.1k
    if (newNlriDataLen > curNlriDataLen)
823
18.8k
    {
824
18.8k
      size_t numOfBytesToExtend = newNlriDataLen - curNlriDataLen;
825
826
18.8k
      if (!extendLayer(offsetInLayer, numOfBytesToExtend))
827
4.33k
      {
828
4.33k
        PCPP_LOG_ERROR("Couldn't extend BGP update layer to include the additional NLRI data");
829
4.33k
        return false;
830
4.33k
      }
831
18.8k
    }
832
21.2k
    else if (newNlriDataLen < curNlriDataLen)
833
9.77k
    {
834
9.77k
      size_t numOfBytesToShorten = curNlriDataLen - newNlriDataLen;
835
836
9.77k
      if (!shortenLayer(offsetInLayer, numOfBytesToShorten))
837
493
      {
838
493
        PCPP_LOG_ERROR("Couldn't shorten BGP update layer to set the right size of the NLRI data");
839
493
        return false;
840
493
      }
841
9.77k
    }
842
843
35.3k
    if (newNlriDataLen > 0)
844
15.6k
    {
845
15.6k
      memcpy(m_Data + offsetInLayer, newNlriData, newNlriDataLen);
846
15.6k
    }
847
848
35.3k
    getBasicHeader()->length = htobe16(be16toh(getBasicHeader()->length) + newNlriDataLen - curNlriDataLen);
849
850
35.3k
    return true;
851
40.1k
  }
852
853
  bool BgpUpdateMessageLayer::clearNetworkLayerReachabilityInfo()
854
13.3k
  {
855
13.3k
    return setNetworkLayerReachabilityInfo(std::vector<prefix_and_ip>());
856
13.3k
  }
857
858
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
859
  // BgpNotificationMessageLayer
860
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
861
862
  BgpNotificationMessageLayer::BgpNotificationMessageLayer(uint8_t errorCode, uint8_t errorSubCode)
863
0
  {
864
0
    initMessageData(errorCode, errorSubCode, nullptr, 0);
865
0
  }
866
867
  BgpNotificationMessageLayer::BgpNotificationMessageLayer(uint8_t errorCode, uint8_t errorSubCode,
868
                                                           const uint8_t* notificationData,
869
                                                           size_t notificationDataLen)
870
0
  {
871
0
    initMessageData(errorCode, errorSubCode, notificationData, notificationDataLen);
872
0
  }
873
874
  BgpNotificationMessageLayer::BgpNotificationMessageLayer(uint8_t errorCode, uint8_t errorSubCode,
875
                                                           const std::string& notificationData)
876
0
  {
877
0
    uint8_t notificationDataByteArr[1500];
878
0
    size_t notificationDataLen = hexStringToByteArray(notificationData, notificationDataByteArr, 1500);
879
0
    initMessageData(errorCode, errorSubCode, notificationDataByteArr, notificationDataLen);
880
0
  }
881
882
  void BgpNotificationMessageLayer::initMessageData(uint8_t errorCode, uint8_t errorSubCode,
883
                                                    const uint8_t* notificationData, size_t notificationDataLen)
884
0
  {
885
0
    size_t headerLen = sizeof(bgp_notification_message);
886
0
    if (notificationData != nullptr && notificationDataLen > 0)
887
0
    {
888
0
      headerLen += notificationDataLen;
889
0
    }
890
0
    allocData(headerLen);
891
0
    setBgpFields(headerLen);
892
0
    bgp_notification_message* msgHdr = getNotificationMsgHeader();
893
0
    msgHdr->errorCode = errorCode;
894
0
    msgHdr->errorSubCode = errorSubCode;
895
0
    memcpy(m_Data + sizeof(bgp_notification_message), notificationData, notificationDataLen);
896
0
    m_Protocol = BGP;
897
0
  }
898
899
  size_t BgpNotificationMessageLayer::getNotificationDataLen() const
900
1.04k
  {
901
1.04k
    size_t headerLen = getHeaderLen();
902
1.04k
    if (headerLen > sizeof(bgp_notification_message))
903
566
    {
904
566
      return headerLen - sizeof(bgp_notification_message);
905
566
    }
906
907
478
    return 0;
908
1.04k
  }
909
910
  uint8_t* BgpNotificationMessageLayer::getNotificationData() const
911
761
  {
912
761
    if (getNotificationDataLen() > 0)
913
283
    {
914
283
      return m_Data + sizeof(bgp_notification_message);
915
283
    }
916
917
478
    return nullptr;
918
761
  }
919
920
  std::string BgpNotificationMessageLayer::getNotificationDataAsHexString() const
921
761
  {
922
761
    uint8_t* notificationData = getNotificationData();
923
761
    if (notificationData == nullptr)
924
478
    {
925
478
      return "";
926
478
    }
927
928
283
    return byteArrayToHexString(notificationData, getNotificationDataLen());
929
761
  }
930
931
  bool BgpNotificationMessageLayer::setNotificationData(const uint8_t* newNotificationData,
932
                                                        size_t newNotificationDataLen)
933
0
  {
934
0
    if (newNotificationData == nullptr)
935
0
    {
936
0
      newNotificationDataLen = 0;
937
0
    }
938
939
0
    size_t curNotificationDataLen = getNotificationDataLen();
940
0
    int offsetInLayer = sizeof(bgp_notification_message);
941
942
0
    if (newNotificationDataLen > curNotificationDataLen)
943
0
    {
944
0
      size_t numOfBytesToExtend = newNotificationDataLen - curNotificationDataLen;
945
946
0
      if (!extendLayer(offsetInLayer, numOfBytesToExtend))
947
0
      {
948
0
        PCPP_LOG_ERROR("Couldn't extend BGP notification layer to include the additional notification data");
949
0
        return false;
950
0
      }
951
0
    }
952
0
    else if (newNotificationDataLen < curNotificationDataLen)
953
0
    {
954
0
      size_t numOfBytesToShorten = curNotificationDataLen - newNotificationDataLen;
955
956
0
      if (!shortenLayer(offsetInLayer, numOfBytesToShorten))
957
0
      {
958
0
        PCPP_LOG_ERROR(
959
0
            "Couldn't shorten BGP notification layer to set the right size of the notification data");
960
0
        return false;
961
0
      }
962
0
    }
963
964
0
    if (newNotificationDataLen > 0)
965
0
    {
966
0
      memcpy(m_Data + offsetInLayer, newNotificationData, newNotificationDataLen);
967
0
    }
968
969
0
    getNotificationMsgHeader()->length = htobe16(sizeof(bgp_notification_message) + newNotificationDataLen);
970
971
0
    return true;
972
0
  }
973
974
  bool BgpNotificationMessageLayer::setNotificationData(const std::string& newNotificationDataAsHexString)
975
0
  {
976
0
    if (newNotificationDataAsHexString.empty())
977
0
    {
978
0
      return setNotificationData(nullptr, 0);
979
0
    }
980
981
0
    uint8_t newNotificationData[1500];
982
0
    size_t newNotificationDataLen = hexStringToByteArray(newNotificationDataAsHexString, newNotificationData, 1500);
983
984
0
    if (newNotificationDataLen == 0)
985
0
    {
986
0
      PCPP_LOG_ERROR("newNotificationDataAsHexString is not a valid hex string");
987
0
      return false;
988
0
    }
989
990
0
    return setNotificationData(newNotificationData, newNotificationDataLen);
991
0
  }
992
993
  // ~~~~~~~~~~~~~~~~~~~~~~~~
994
  // BgpKeepaliveMessageLayer
995
  // ~~~~~~~~~~~~~~~~~~~~~~~~
996
997
0
  BgpKeepaliveMessageLayer::BgpKeepaliveMessageLayer() : BgpLayer()
998
0
  {
999
0
    const size_t headerLen = sizeof(bgp_common_header);
1000
0
    allocData(headerLen);
1001
0
    setBgpFields(headerLen);
1002
0
    m_Protocol = BGP;
1003
0
  }
1004
1005
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1006
  // BgpRouteRefreshMessageLayer
1007
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1008
1009
  BgpRouteRefreshMessageLayer::BgpRouteRefreshMessageLayer(uint16_t afi, uint8_t safi)
1010
0
  {
1011
0
    const size_t headerLen = sizeof(bgp_route_refresh_message);
1012
0
    allocData(headerLen);
1013
0
    setBgpFields(headerLen);
1014
0
    bgp_route_refresh_message* msgHdr = getRouteRefreshHeader();
1015
    msgHdr->afi = htobe16(afi);
1016
0
    msgHdr->safi = safi;
1017
0
    m_Protocol = BGP;
1018
0
  }
1019
1020
}  // namespace pcpp