Coverage Report

Created: 2026-10-17 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/TcpLayer.cpp
Line
Count
Source
1
0
#define LOG_MODULE PacketLogModuleTcpLayer
2
3
#include "EndianPortable.h"
4
#include "TcpLayer.h"
5
#include "IPv4Layer.h"
6
#include "IPv6Layer.h"
7
#include "PayloadLayer.h"
8
#include "HttpLayer.h"
9
#include "SSLLayer.h"
10
#include "SipLayer.h"
11
#include "BgpLayer.h"
12
#include "SSHLayer.h"
13
#include "DnsLayer.h"
14
#include "DoIpLayer.h"
15
#include "TelnetLayer.h"
16
#include "TpktLayer.h"
17
#include "FtpLayer.h"
18
#include "SomeIpLayer.h"
19
#include "SmtpLayer.h"
20
#include "LdapLayer.h"
21
#include "PostgresLayer.h"
22
#include "MySqlLayer.h"
23
#include "GtpLayer.h"
24
#include "ModbusLayer.h"
25
#include "PacketUtils.h"
26
#include "Logger.h"
27
#include "DeprecationUtils.h"
28
#include "SystemUtils.h"
29
#include <sstream>
30
31
namespace pcpp
32
{
33
  constexpr uint8_t TcpOptionDummy = 0xff;
34
35
  static constexpr const char* tcpOptionTypeToString(TcpOptionEnumType type)
36
0
  {
37
0
    switch (type)
38
0
    {
39
0
    case TcpOptionEnumType::Eol:
40
0
      return "Eol";
41
0
    case TcpOptionEnumType::Nop:
42
0
      return "Nop";
43
0
    case TcpOptionEnumType::Mss:
44
0
      return "Mss";
45
0
    case TcpOptionEnumType::Window:
46
0
      return "Window";
47
0
    case TcpOptionEnumType::SackPerm:
48
0
      return "SackPerm";
49
0
    case TcpOptionEnumType::Sack:
50
0
      return "Sack";
51
0
    case TcpOptionEnumType::Echo:
52
0
      return "Echo";
53
0
    case TcpOptionEnumType::EchoReply:
54
0
      return "EchoReply";
55
0
    case TcpOptionEnumType::Timestamp:
56
0
      return "Timestamp";
57
0
    case TcpOptionEnumType::Cc:
58
0
      return "Cc";
59
0
    case TcpOptionEnumType::CcNew:
60
0
      return "CcNew";
61
0
    case TcpOptionEnumType::CcEcho:
62
0
      return "CcEcho";
63
0
    case TcpOptionEnumType::Md5:
64
0
      return "Md5";
65
0
    case TcpOptionEnumType::MpTcp:
66
0
      return "MpTcp";
67
0
    case TcpOptionEnumType::Scps:
68
0
      return "Scps";
69
0
    case TcpOptionEnumType::Snack:
70
0
      return "Snack";
71
0
    case TcpOptionEnumType::RecBound:
72
0
      return "RecBound";
73
0
    case TcpOptionEnumType::CorrExp:
74
0
      return "CorrExp";
75
0
    case TcpOptionEnumType::Qs:
76
0
      return "Qs";
77
0
    case TcpOptionEnumType::UserTo:
78
0
      return "UserTo";
79
0
    case TcpOptionEnumType::ExpFd:
80
0
      return "ExpFd";
81
0
    case TcpOptionEnumType::ExpFe:
82
0
      return "ExpFe";
83
0
    case TcpOptionEnumType::RvbdProbe:
84
0
      return "RvbdProbe";
85
0
    case TcpOptionEnumType::RvbdTrpy:
86
0
      return "RvbdTrpy";
87
0
    case TcpOptionEnumType::Unknown:
88
0
    default:
89
0
      return "Unknown";
90
0
    }
91
0
  }
92
93
  /// ~~~~~~~~~~~~~~~~
94
  /// TcpOptionBuilder
95
  /// ~~~~~~~~~~~~~~~~
96
97
  TcpOptionBuilder::TcpOptionBuilder(NopEolOptionTypes optionType)
98
0
  {
99
0
    switch (optionType)
100
0
    {
101
0
    case EOL:
102
0
      init(static_cast<uint8_t>(PCPP_TCPOPT_EOL), nullptr, 0);
103
0
      break;
104
0
    case NOP:
105
0
    default:
106
0
      init(static_cast<uint8_t>(PCPP_TCPOPT_NOP), nullptr, 0);
107
0
      break;
108
0
    }
109
0
  }
110
111
  TcpOptionBuilder::TcpOptionBuilder(const NopEolOptionEnumType optionType)
112
0
  {
113
0
    switch (optionType)
114
0
    {
115
0
    case NopEolOptionEnumType::Eol:
116
0
      init(static_cast<uint8_t>(TcpOptionEnumType::Eol), nullptr, 0);
117
0
      break;
118
0
    case NopEolOptionEnumType::Nop:
119
0
    default:
120
0
      init(static_cast<uint8_t>(TcpOptionEnumType::Nop), nullptr, 0);
121
0
      break;
122
0
    }
123
0
  }
124
125
  TcpOption TcpOptionBuilder::build() const
126
0
  {
127
0
    uint8_t recType = static_cast<uint8_t>(m_RecType);
128
0
    size_t optionSize = m_RecValueLen + 2 * sizeof(uint8_t);
129
130
0
    if (recType == static_cast<uint8_t>(TcpOptionEnumType::Eol) ||
131
0
        recType == static_cast<uint8_t>(TcpOptionEnumType::Nop))
132
0
    {
133
0
      if (m_RecValueLen != 0)
134
0
      {
135
0
        PCPP_LOG_ERROR(
136
0
            "TCP NOP and TCP EOL options are 1-byte long and don't have option value. Tried to set option value of size "
137
0
            << m_RecValueLen);
138
0
        return TcpOption(nullptr);
139
0
      }
140
141
0
      optionSize = 1;
142
0
    }
143
144
0
    uint8_t* recordBuffer = new uint8_t[optionSize];
145
0
    memset(recordBuffer, 0, optionSize);
146
0
    recordBuffer[0] = recType;
147
0
    if (optionSize > 1)
148
0
    {
149
0
      recordBuffer[1] = static_cast<uint8_t>(optionSize);
150
0
      if (optionSize > 2 && m_RecValue != nullptr)
151
0
        memcpy(recordBuffer + 2, m_RecValue, m_RecValueLen);
152
0
    }
153
154
0
    return TcpOption(recordBuffer);
155
0
  }
156
157
  /// ~~~~~~~~
158
  /// TcpLayer
159
  /// ~~~~~~~~
160
161
  uint16_t TcpLayer::getSrcPort() const
162
0
  {
163
0
    return be16toh(getTcpHeader()->portSrc);
164
0
  }
165
166
  uint16_t TcpLayer::getDstPort() const
167
0
  {
168
0
    return be16toh(getTcpHeader()->portDst);
169
0
  }
170
171
  TcpOption TcpLayer::getTcpOption(const TcpOptionEnumType option) const
172
0
  {
173
0
    return m_OptionReader.getTLVRecord(static_cast<uint8_t>(option), getOptionsBasePtr(),
174
0
                                       getHeaderLen() - sizeof(tcphdr));
175
0
  }
176
177
  TcpOption TcpLayer::getFirstTcpOption() const
178
0
  {
179
0
    return m_OptionReader.getFirstTLVRecord(getOptionsBasePtr(), getHeaderLen() - sizeof(tcphdr));
180
0
  }
181
182
  TcpOption TcpLayer::getNextTcpOption(TcpOption& tcpOption) const
183
0
  {
184
0
    TcpOption nextOpt =
185
0
        m_OptionReader.getNextTLVRecord(tcpOption, getOptionsBasePtr(), getHeaderLen() - sizeof(tcphdr));
186
0
    if (nextOpt.isNotNull() && nextOpt.getType() == TcpOptionDummy)
187
0
      return TcpOption(nullptr);
188
189
0
    return nextOpt;
190
0
  }
191
192
  size_t TcpLayer::getTcpOptionCount() const
193
0
  {
194
0
    return m_OptionReader.getTLVRecordCount(getOptionsBasePtr(), getHeaderLen() - sizeof(tcphdr));
195
0
  }
196
197
  TcpOption TcpLayer::addTcpOption(const TcpOptionBuilder& optionBuilder)
198
0
  {
199
0
    return addTcpOptionAt(optionBuilder, getHeaderLen() - m_NumOfTrailingBytes);
200
0
  }
201
202
  TcpOption TcpLayer::insertTcpOptionAfter(const TcpOptionBuilder& optionBuilder,
203
                                           const TcpOptionEnumType prevOptionType)
204
0
  {
205
0
    int offset = 0;
206
207
0
    if (prevOptionType == TcpOptionEnumType::Unknown)
208
0
    {
209
0
      offset = sizeof(tcphdr);
210
0
    }
211
0
    else
212
0
    {
213
0
      const TcpOption prevOpt = getTcpOption(prevOptionType);
214
0
      if (prevOpt.isNull())
215
0
      {
216
0
        PCPP_LOG_ERROR("Previous option of type " << static_cast<int>(prevOptionType)
217
0
                                                  << " not found, cannot add a new TCP option");
218
0
        return TcpOption(nullptr);
219
0
      }
220
221
0
      offset = prevOpt.getRecordBasePtr() + prevOpt.getTotalSize() - m_Data;
222
0
    }
223
224
0
    return addTcpOptionAt(optionBuilder, offset);
225
0
  }
226
227
  bool TcpLayer::removeTcpOption(const TcpOptionEnumType optionType)
228
0
  {
229
0
    const TcpOption opt = getTcpOption(optionType);
230
0
    if (opt.isNull())
231
0
    {
232
0
      return false;
233
0
    }
234
235
    // calculate total TCP option size
236
0
    TcpOption curOpt = getFirstTcpOption();
237
0
    size_t totalOptSize = 0;
238
0
    while (!curOpt.isNull())
239
0
    {
240
0
      totalOptSize += curOpt.getTotalSize();
241
0
      curOpt = getNextTcpOption(curOpt);
242
0
    }
243
0
    totalOptSize -= opt.getTotalSize();
244
245
0
    int offset = opt.getRecordBasePtr() - m_Data;
246
247
0
    if (!shortenLayer(offset, opt.getTotalSize()))
248
0
    {
249
0
      return false;
250
0
    }
251
252
0
    adjustTcpOptionTrailer(totalOptSize);
253
254
0
    m_OptionReader.changeTLVRecordCount(-1);
255
256
0
    return true;
257
0
  }
258
259
  bool TcpLayer::removeAllTcpOptions()
260
0
  {
261
0
    const int offset = sizeof(tcphdr);
262
263
0
    if (!shortenLayer(offset, getHeaderLen() - offset))
264
0
      return false;
265
266
0
    getTcpHeader()->dataOffset = sizeof(tcphdr) / 4;
267
0
    m_NumOfTrailingBytes = 0;
268
0
    m_OptionReader.changeTLVRecordCount(0 - getTcpOptionCount());
269
0
    return true;
270
0
  }
271
272
  TcpOption TcpLayer::addTcpOptionAt(const TcpOptionBuilder& optionBuilder, const int offset)
273
0
  {
274
0
    TcpOption newOption = optionBuilder.build();
275
0
    if (newOption.isNull())
276
0
      return newOption;
277
278
    // calculate total TCP option size
279
0
    TcpOption curOpt = getFirstTcpOption();
280
0
    size_t totalOptSize = 0;
281
0
    while (!curOpt.isNull())
282
0
    {
283
0
      totalOptSize += curOpt.getTotalSize();
284
0
      curOpt = getNextTcpOption(curOpt);
285
0
    }
286
0
    totalOptSize += newOption.getTotalSize();
287
288
0
    size_t sizeToExtend = newOption.getTotalSize();
289
290
0
    if (!extendLayer(offset, sizeToExtend))
291
0
    {
292
0
      PCPP_LOG_ERROR("Could not extend TcpLayer in [" << sizeToExtend << "] bytes");
293
0
      newOption.purgeRecordData();
294
0
      return TcpOption(nullptr);
295
0
    }
296
297
0
    memcpy(m_Data + offset, newOption.getRecordBasePtr(), newOption.getTotalSize());
298
299
0
    newOption.purgeRecordData();
300
301
0
    adjustTcpOptionTrailer(totalOptSize);
302
303
0
    m_OptionReader.changeTLVRecordCount(1);
304
305
0
    uint8_t* newOptPtr = m_Data + offset;
306
307
0
    return TcpOption(newOptPtr);
308
0
  }
309
310
  void TcpLayer::adjustTcpOptionTrailer(const size_t totalOptSize)
311
0
  {
312
0
    int newNumberOfTrailingBytes = 0;
313
0
    while ((totalOptSize + newNumberOfTrailingBytes) % 4 != 0)
314
0
      newNumberOfTrailingBytes++;
315
316
0
    if (newNumberOfTrailingBytes < m_NumOfTrailingBytes)
317
0
      shortenLayer(sizeof(tcphdr) + totalOptSize, m_NumOfTrailingBytes - newNumberOfTrailingBytes - 1);
318
0
    else if (newNumberOfTrailingBytes > m_NumOfTrailingBytes)
319
0
      extendLayer(sizeof(tcphdr) + totalOptSize, newNumberOfTrailingBytes - m_NumOfTrailingBytes);
320
321
0
    m_NumOfTrailingBytes = newNumberOfTrailingBytes;
322
323
0
    for (int i = 0; i < m_NumOfTrailingBytes; i++)
324
0
      m_Data[sizeof(tcphdr) + totalOptSize + i] = TcpOptionDummy;
325
326
0
    getTcpHeader()->dataOffset = (sizeof(tcphdr) + totalOptSize + m_NumOfTrailingBytes) / 4;
327
0
  }
328
329
  uint16_t TcpLayer::calculateChecksum(const bool writeResultToPacket)
330
0
  {
331
0
    tcphdr* tcpHdr = getTcpHeader();
332
0
    uint16_t checksumRes = 0;
333
0
    const uint16_t currChecksumValue = tcpHdr->headerChecksum;
334
335
0
    if (m_PrevLayer != nullptr)
336
0
    {
337
0
      tcpHdr->headerChecksum = 0;
338
0
      PCPP_LOG_DEBUG("TCP data len = " << m_DataLen);
339
340
0
      if (m_PrevLayer->getProtocol() == IPv4)
341
0
      {
342
0
        const IPv4Address srcIP = static_cast<IPv4Layer*>(m_PrevLayer)->getSrcIPv4Address();
343
0
        const IPv4Address dstIP = static_cast<IPv4Layer*>(m_PrevLayer)->getDstIPv4Address();
344
345
0
        checksumRes =
346
0
            pcpp::computePseudoHdrChecksum(reinterpret_cast<uint8_t*>(tcpHdr), getDataLen(),
347
0
                                           IPAddress::IPv4AddressType, PACKETPP_IPPROTO_TCP, srcIP, dstIP);
348
349
0
        PCPP_LOG_DEBUG("calculated IPv4 TCP checksum = 0x" << std::uppercase << std::hex << checksumRes);
350
0
      }
351
0
      else if (m_PrevLayer->getProtocol() == IPv6)
352
0
      {
353
0
        const IPv6Address srcIP = static_cast<IPv6Layer*>(m_PrevLayer)->getSrcIPv6Address();
354
0
        const IPv6Address dstIP = static_cast<IPv6Layer*>(m_PrevLayer)->getDstIPv6Address();
355
356
0
        checksumRes = computePseudoHdrChecksum(reinterpret_cast<uint8_t*>(tcpHdr), getDataLen(),
357
0
                                               IPAddress::IPv6AddressType, PACKETPP_IPPROTO_TCP, srcIP, dstIP);
358
359
0
        PCPP_LOG_DEBUG("calculated IPv6 TCP checksum = 0xX" << std::uppercase << std::hex << checksumRes);
360
0
      }
361
0
    }
362
363
0
    if (writeResultToPacket)
364
0
      tcpHdr->headerChecksum = htobe16(checksumRes);
365
0
    else
366
0
      tcpHdr->headerChecksum = currChecksumValue;
367
368
0
    return checksumRes;
369
0
  }
370
371
  void TcpLayer::initLayer()
372
0
  {
373
0
    allocData(sizeof(tcphdr));
374
375
0
    m_Protocol = TCP;
376
0
    m_NumOfTrailingBytes = 0;
377
0
    getTcpHeader()->dataOffset = sizeof(tcphdr) / 4;
378
0
  }
379
380
  TcpLayer::TcpLayer(uint8_t* data, const size_t dataLen, Layer* prevLayer, Packet* packet)
381
0
      : Layer(data, dataLen, prevLayer, packet, TCP)
382
0
  {
383
0
    m_NumOfTrailingBytes = 0;
384
0
  }
385
386
  TcpLayer::TcpLayer()
387
0
  {
388
0
    initLayer();
389
0
  }
390
391
  TcpLayer::TcpLayer(const uint16_t portSrc, const uint16_t portDst)
392
0
  {
393
0
    initLayer();
394
0
    getTcpHeader()->portDst = htobe16(portDst);
395
0
    getTcpHeader()->portSrc = htobe16(portSrc);
396
0
  }
397
398
  void TcpLayer::copyLayerData(const TcpLayer& other)
399
0
  {
400
0
    m_OptionReader = other.m_OptionReader;
401
0
    m_NumOfTrailingBytes = other.m_NumOfTrailingBytes;
402
0
  }
403
404
0
  TcpLayer::TcpLayer(const TcpLayer& other) : Layer(other)
405
0
  {
406
0
    copyLayerData(other);
407
0
  }
408
409
  TcpLayer& TcpLayer::operator=(const TcpLayer& other)
410
0
  {
411
0
    Layer::operator=(other);
412
413
0
    copyLayerData(other);
414
415
0
    return *this;
416
0
  }
417
418
  void TcpLayer::parseNextLayer()
419
0
  {
420
0
    const size_t headerLen = getHeaderLen();
421
0
    if (m_DataLen <= headerLen)
422
0
      return;
423
424
0
    uint8_t* payload = m_Data + headerLen;
425
0
    const size_t payloadLen = m_DataLen - headerLen;
426
0
    const uint16_t portDst = getDstPort();
427
0
    const uint16_t portSrc = getSrcPort();
428
0
    const char* payloadChar = reinterpret_cast<const char*>(payload);
429
430
0
    if (HttpMessage::isHttpPort(portDst) &&
431
0
        HttpRequestFirstLine::parseMethod(payloadChar, payloadLen) != HttpRequestLayer::HttpMethodUnknown)
432
0
    {
433
0
      constructNextLayer<HttpRequestLayer>(payload, payloadLen, getAttachedPacket());
434
0
    }
435
0
    else if (HttpMessage::isHttpPort(portSrc) &&
436
0
             HttpResponseFirstLine::parseVersion(payloadChar, payloadLen) != HttpVersion::HttpVersionUnknown &&
437
0
             !HttpResponseFirstLine::parseStatusCode(payloadChar, payloadLen).isUnsupportedCode())
438
0
    {
439
0
      constructNextLayer<HttpResponseLayer>(payload, payloadLen, getAttachedPacket());
440
0
    }
441
0
    else if (SSLLayer::IsSSLMessage(portSrc, portDst, payload, payloadLen))
442
0
    {
443
0
      constructNextLayerFromFactory(SSLLayer::createSSLMessage, payload, payloadLen);
444
0
    }
445
0
    else if (SipLayer::isSipPort(portDst) || SipLayer::isSipPort(portSrc))
446
0
    {
447
0
      if (SipRequestFirstLine::parseMethod(payloadChar, payloadLen) != SipRequestLayer::SipMethodUnknown)
448
0
      {
449
0
        constructNextLayer<SipRequestLayer>(payload, payloadLen, getAttachedPacket());
450
0
      }
451
0
      else if (SipResponseFirstLine::parseStatusCode(payloadChar, payloadLen) !=
452
0
               SipResponseLayer::SipStatusCodeUnknown)
453
0
      {
454
0
        constructNextLayer<SipResponseLayer>(payload, payloadLen, getAttachedPacket());
455
0
      }
456
0
      else
457
0
      {
458
0
        constructNextLayer<PayloadLayer>(payload, payloadLen, getAttachedPacket());
459
0
      }
460
0
    }
461
0
    else if (BgpLayer::isBgpPort(portSrc, portDst))
462
0
    {
463
0
      tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(BgpLayer::parseBgpLayer, payload, payloadLen);
464
0
    }
465
0
    else if (SSHLayer::isSSHPort(portSrc, portDst))
466
0
    {
467
0
      constructNextLayerFromFactory(SSHLayer::createSSHMessage, payload, payloadLen);
468
0
    }
469
0
    else if (DnsLayer::isDataValid(payload, payloadLen, true) &&
470
0
             (DnsLayer::isDnsPort(portDst) || DnsLayer::isDnsPort(portSrc)))
471
0
    {
472
0
      constructNextLayer<DnsOverTcpLayer>(payload, payloadLen, getAttachedPacket());
473
0
    }
474
0
    else if (TelnetLayer::isDataValid(payload, payloadLen) &&
475
0
             (TelnetLayer::isTelnetPort(portDst) || TelnetLayer::isTelnetPort(portSrc)))
476
0
    {
477
0
      constructNextLayer<TelnetLayer>(payload, payloadLen, getAttachedPacket());
478
0
    }
479
0
    else if (FtpLayer::isFtpPort(portSrc) && FtpLayer::isDataValid(payload, payloadLen))
480
0
    {
481
0
      constructNextLayer<FtpResponseLayer>(payload, payloadLen, getAttachedPacket());
482
0
    }
483
0
    else if (FtpLayer::isFtpPort(portDst) && FtpLayer::isDataValid(payload, payloadLen))
484
0
    {
485
0
      constructNextLayer<FtpRequestLayer>(payload, payloadLen, getAttachedPacket());
486
0
    }
487
0
    else if (FtpLayer::isFtpDataPort(portSrc) || FtpLayer::isFtpDataPort(portDst))
488
0
    {
489
0
      constructNextLayer<FtpDataLayer>(payload, payloadLen, getAttachedPacket());
490
0
    }
491
0
    else if ((DoIpLayer::isDoIpPort(portSrc) || DoIpLayer::isDoIpPort(portDst)) &&
492
0
             (DoIpLayer::isDataValid(payload, payloadLen)))
493
0
    {
494
0
      tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(DoIpLayer::parseDoIpLayer, payload, payloadLen);
495
0
    }
496
0
    else if (SomeIpLayer::isSomeIpPort(portSrc) || SomeIpLayer::isSomeIpPort(portDst))
497
0
    {
498
0
      constructNextLayerFromFactory(SomeIpLayer::parseSomeIpLayer, payload, payloadLen);
499
0
    }
500
0
    else if (TpktLayer::isDataValid(payload, payloadLen) && TpktLayer::isTpktPort(portSrc, portDst))
501
0
    {
502
0
      constructNextLayer<TpktLayer>(payload, payloadLen, getAttachedPacket());
503
0
    }
504
0
    else if (SmtpLayer::isSmtpPort(portSrc) && SmtpLayer::isDataValid(payload, payloadLen))
505
0
    {
506
0
      constructNextLayer<SmtpResponseLayer>(payload, payloadLen, getAttachedPacket());
507
0
    }
508
0
    else if (SmtpLayer::isSmtpPort(portDst) && SmtpLayer::isDataValid(payload, payloadLen))
509
0
    {
510
0
      constructNextLayer<SmtpRequestLayer>(payload, payloadLen, getAttachedPacket());
511
0
    }
512
0
    else if (LdapLayer::isLdapPort(portDst) || LdapLayer::isLdapPort(portSrc))
513
0
    {
514
0
      tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(LdapLayer::parseLdapMessage, payload,
515
0
                                                                 payloadLen);
516
0
    }
517
0
    else if (PostgresLayer::isPostgresPort(portDst))
518
0
    {
519
0
      tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(PostgresLayer::parsePostgresFrontendMessages,
520
0
                                                                 payload, payloadLen);
521
0
    }
522
0
    else if (PostgresLayer::isPostgresPort(portSrc))
523
0
    {
524
0
      tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(PostgresLayer::parsePostgresBackendMessages,
525
0
                                                                 payload, payloadLen);
526
0
    }
527
0
    else if (MySqlLayer::isMySqlPort(portSrc))
528
0
    {
529
0
      tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(MySqlLayer::parseMySqlServerMessage, payload,
530
0
                                                                 payloadLen);
531
0
    }
532
0
    else if (MySqlLayer::isMySqlPort(portDst))
533
0
    {
534
0
      tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(MySqlLayer::parseMySqlClientMessage, payload,
535
0
                                                                 payloadLen);
536
0
    }
537
0
    else if ((GtpV2Layer::isGTPv2Port(portDst) || GtpV2Layer::isGTPv2Port(portSrc)) &&
538
0
             GtpV2Layer::isDataValid(payload, payloadLen))
539
0
    {
540
0
      constructNextLayer<GtpV2Layer>(payload, payloadLen, getAttachedPacket());
541
0
    }
542
0
    else if (ModbusLayer::isModbusPort(portDst) && ModbusLayer::isDataValid(payload, payloadLen))
543
0
    {
544
0
      constructNextLayer<ModbusLayer>(payload, payloadLen, getAttachedPacket());
545
0
    }
546
0
    else
547
0
    {
548
0
      constructNextLayer<PayloadLayer>(payload, payloadLen, getAttachedPacket());
549
0
    }
550
0
  }
551
552
  void TcpLayer::computeCalculateFields()
553
0
  {
554
0
    tcphdr* tcpHdr = getTcpHeader();
555
556
0
    tcpHdr->dataOffset = getHeaderLen() >> 2;
557
0
    calculateChecksum(true);
558
0
  }
559
560
  std::string TcpLayer::toString() const
561
0
  {
562
0
    const tcphdr* hdr = getTcpHeader();
563
0
    std::string result = "TCP Layer, ";
564
0
    if (hdr->synFlag)
565
0
    {
566
0
      if (hdr->ackFlag)
567
0
        result += "[SYN, ACK], ";
568
0
      else
569
0
        result += "[SYN], ";
570
0
    }
571
0
    else if (hdr->finFlag)
572
0
    {
573
0
      if (hdr->ackFlag)
574
0
        result += "[FIN, ACK], ";
575
0
      else
576
0
        result += "[FIN], ";
577
0
    }
578
0
    else if (hdr->ackFlag)
579
0
      result += "[ACK], ";
580
581
0
    std::ostringstream srcPortStream;
582
0
    srcPortStream << getSrcPort();
583
0
    std::ostringstream dstPortStream;
584
0
    dstPortStream << getDstPort();
585
0
    result += "Src port: " + srcPortStream.str() + ", Dst port: " + dstPortStream.str();
586
587
0
    return result;
588
0
  }
589
590
  /// ~~~~~~~~
591
  /// TcpLayer Deprecated Code
592
  /// ~~~~~~~~
593
594
  DISABLE_WARNING_PUSH
595
  DISABLE_WARNING_DEPRECATED
596
  TcpOption TcpLayer::addTcpOptionAfter(const TcpOptionBuilder& optionBuilder, TcpOptionType prevOptionType)
597
0
  {
598
0
    int offset = 0;
599
600
0
    if (prevOptionType == TcpOptionType::TCPOPT_Unknown)
601
0
    {
602
0
      offset = sizeof(tcphdr);
603
0
    }
604
0
    else
605
0
    {
606
0
      TcpOption prevOpt = getTcpOption(prevOptionType);
607
0
      if (prevOpt.isNull())
608
0
      {
609
0
        PCPP_LOG_ERROR("Previous option of type " << static_cast<int>(prevOptionType)
610
0
                                                  << " not found, cannot add a new TCP option");
611
0
        return TcpOption(nullptr);
612
0
      }
613
614
0
      offset = prevOpt.getRecordBasePtr() + prevOpt.getTotalSize() - m_Data;
615
0
    }
616
617
0
    return addTcpOptionAt(optionBuilder, offset);
618
0
  }
619
620
  TcpOption TcpLayer::getTcpOption(TcpOptionType option) const
621
0
  {
622
0
    return m_OptionReader.getTLVRecord(static_cast<uint8_t>(option), getOptionsBasePtr(),
623
0
                                       getHeaderLen() - sizeof(tcphdr));
624
0
  }
625
626
  bool TcpLayer::removeTcpOption(TcpOptionType optionType)
627
0
  {
628
0
    TcpOption opt = getTcpOption(optionType);
629
0
    if (opt.isNull())
630
0
    {
631
0
      return false;
632
0
    }
633
634
    // calculate total TCP option size
635
0
    TcpOption curOpt = getFirstTcpOption();
636
0
    size_t totalOptSize = 0;
637
0
    while (!curOpt.isNull())
638
0
    {
639
0
      totalOptSize += curOpt.getTotalSize();
640
0
      curOpt = getNextTcpOption(curOpt);
641
0
    }
642
0
    totalOptSize -= opt.getTotalSize();
643
644
0
    int offset = opt.getRecordBasePtr() - m_Data;
645
646
0
    if (!shortenLayer(offset, opt.getTotalSize()))
647
0
    {
648
0
      return false;
649
0
    }
650
651
0
    adjustTcpOptionTrailer(totalOptSize);
652
653
0
    m_OptionReader.changeTLVRecordCount(-1);
654
655
0
    return true;
656
0
  }
657
  DISABLE_WARNING_POP
658
659
  const FieldDescriptor TcpLayer::SerializedFields::SrcPort{ Layer::SerializedFields::MaxID + 1, "srcPort" };
660
  const FieldDescriptor TcpLayer::SerializedFields::DstPort{ Layer::SerializedFields::MaxID + 2, "dstPort" };
661
  const FieldDescriptor TcpLayer::SerializedFields::SequenceNumber{ Layer::SerializedFields::MaxID + 3,
662
                                                                  "sequenceNumber" };
663
  const FieldDescriptor TcpLayer::SerializedFields::TcpFlags{ Layer::SerializedFields::MaxID + 4, "tcpFlags" };
664
  const FieldDescriptor TcpLayer::SerializedFields::TcpFlag{ 0, "tcpFlag" };
665
  const FieldDescriptor TcpLayer::SerializedFields::WindowSize{ Layer::SerializedFields::MaxID + 5, "windowSize" };
666
  const FieldDescriptor TcpLayer::SerializedFields::Checksum{ Layer::SerializedFields::MaxID + 6, "checksum" };
667
  const FieldDescriptor TcpLayer::SerializedFields::Options{ Layer::SerializedFields::MaxID + 7, "options" };
668
  const FieldDescriptor TcpLayer::SerializedFields::Option{ 0, "option" };
669
670
  void TcpLayer::serializeLayer(ObjectScope& serializer) const
671
0
  {
672
0
    auto* header = getTcpHeader();
673
0
    serializer.writeField(SerializedFields::SrcPort, netToHost16(header->portSrc));
674
0
    serializer.writeField(SerializedFields::DstPort, netToHost16(header->portDst));
675
0
    serializer.writeField(SerializedFields::SequenceNumber, netToHost32(header->sequenceNumber));
676
0
    {
677
0
      auto tcpFlagsArray = serializer.writeArray(SerializedFields::TcpFlags);
678
0
      if (header->finFlag)
679
0
      {
680
0
        tcpFlagsArray.writeField(SerializedFields::TcpFlag, "FIN");
681
0
      }
682
0
      if (header->synFlag)
683
0
      {
684
0
        tcpFlagsArray.writeField(SerializedFields::TcpFlag, "SYN");
685
0
      }
686
0
      if (header->rstFlag)
687
0
      {
688
0
        tcpFlagsArray.writeField(SerializedFields::TcpFlag, "RST");
689
0
      }
690
0
      if (header->pshFlag)
691
0
      {
692
0
        tcpFlagsArray.writeField(SerializedFields::TcpFlag, "PSH");
693
0
      }
694
0
      if (header->ackFlag)
695
0
      {
696
0
        tcpFlagsArray.writeField(SerializedFields::TcpFlag, "ACK");
697
0
      }
698
0
      if (header->urgFlag)
699
0
      {
700
0
        tcpFlagsArray.writeField(SerializedFields::TcpFlag, "URG");
701
0
      }
702
0
      if (header->eceFlag)
703
0
      {
704
0
        tcpFlagsArray.writeField(SerializedFields::TcpFlag, "ECE");
705
0
      }
706
0
      if (header->cwrFlag)
707
0
      {
708
0
        tcpFlagsArray.writeField(SerializedFields::TcpFlag, "CWR");
709
0
      }
710
0
    }
711
0
    serializer.writeField(SerializedFields::WindowSize, netToHost16(header->windowSize));
712
0
    serializer.writeHexField(SerializedFields::Checksum, netToHost16(header->headerChecksum));
713
0
    {
714
0
      auto options = serializer.writeArray(SerializedFields::Options);
715
0
      for (auto option = getFirstTcpOption(); option.isNotNull(); option = getNextTcpOption(option))
716
0
      {
717
0
        options.writeField(SerializedFields::Option, tcpOptionTypeToString(option.getTcpOptionEnumType()));
718
0
      }
719
0
    }
720
0
  }
721
}  // namespace pcpp