Coverage Report

Created: 2025-09-27 08:03

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