Coverage Report

Created: 2026-02-14 06:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/TcpLayer.cpp
Line
Count
Source
1
479k
#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 "GtpLayer.h"
22
#include "ModbusLayer.h"
23
#include "PacketUtils.h"
24
#include "Logger.h"
25
#include "DeprecationUtils.h"
26
#include <sstream>
27
28
namespace pcpp
29
{
30
31
310k
#define TCPOPT_DUMMY 0xff
32
33
  /// ~~~~~~~~~~~~~~~~
34
  /// TcpOptionBuilder
35
  /// ~~~~~~~~~~~~~~~~
36
37
  TcpOptionBuilder::TcpOptionBuilder(NopEolOptionTypes optionType)
38
0
  {
39
0
    switch (optionType)
40
0
    {
41
0
    case EOL:
42
0
      init(static_cast<uint8_t>(PCPP_TCPOPT_EOL), nullptr, 0);
43
0
      break;
44
0
    case NOP:
45
0
    default:
46
0
      init(static_cast<uint8_t>(PCPP_TCPOPT_NOP), nullptr, 0);
47
0
      break;
48
0
    }
49
0
  }
50
51
  TcpOptionBuilder::TcpOptionBuilder(const NopEolOptionEnumType optionType)
52
149k
  {
53
149k
    switch (optionType)
54
149k
    {
55
0
    case NopEolOptionEnumType::Eol:
56
0
      init(static_cast<uint8_t>(TcpOptionEnumType::Eol), nullptr, 0);
57
0
      break;
58
149k
    case NopEolOptionEnumType::Nop:
59
149k
    default:
60
149k
      init(static_cast<uint8_t>(TcpOptionEnumType::Nop), nullptr, 0);
61
149k
      break;
62
149k
    }
63
149k
  }
64
65
  TcpOption TcpOptionBuilder::build() const
66
59.3k
  {
67
59.3k
    uint8_t recType = static_cast<uint8_t>(m_RecType);
68
59.3k
    size_t optionSize = m_RecValueLen + 2 * sizeof(uint8_t);
69
70
59.3k
    if (recType == static_cast<uint8_t>(TcpOptionEnumType::Eol) ||
71
59.3k
        recType == static_cast<uint8_t>(TcpOptionEnumType::Nop))
72
59.3k
    {
73
59.3k
      if (m_RecValueLen != 0)
74
0
      {
75
0
        PCPP_LOG_ERROR(
76
0
            "TCP NOP and TCP EOL options are 1-byte long and don't have option value. Tried to set option value of size "
77
0
            << m_RecValueLen);
78
0
        return TcpOption(nullptr);
79
0
      }
80
81
59.3k
      optionSize = 1;
82
59.3k
    }
83
84
59.3k
    uint8_t* recordBuffer = new uint8_t[optionSize];
85
59.3k
    memset(recordBuffer, 0, optionSize);
86
59.3k
    recordBuffer[0] = recType;
87
59.3k
    if (optionSize > 1)
88
0
    {
89
0
      recordBuffer[1] = static_cast<uint8_t>(optionSize);
90
0
      if (optionSize > 2 && m_RecValue != nullptr)
91
0
        memcpy(recordBuffer + 2, m_RecValue, m_RecValueLen);
92
0
    }
93
94
59.3k
    return TcpOption(recordBuffer);
95
59.3k
  }
96
97
  /// ~~~~~~~~
98
  /// TcpLayer
99
  /// ~~~~~~~~
100
101
  uint16_t TcpLayer::getSrcPort() const
102
985k
  {
103
985k
    return be16toh(getTcpHeader()->portSrc);
104
985k
  }
105
106
  uint16_t TcpLayer::getDstPort() const
107
985k
  {
108
985k
    return be16toh(getTcpHeader()->portDst);
109
985k
  }
110
111
  TcpOption TcpLayer::getTcpOption(const TcpOptionEnumType option) const
112
149k
  {
113
149k
    return m_OptionReader.getTLVRecord(static_cast<uint8_t>(option), getOptionsBasePtr(),
114
149k
                                       getHeaderLen() - sizeof(tcphdr));
115
149k
  }
116
117
  TcpOption TcpLayer::getFirstTcpOption() const
118
59.3k
  {
119
59.3k
    return m_OptionReader.getFirstTLVRecord(getOptionsBasePtr(), getHeaderLen() - sizeof(tcphdr));
120
59.3k
  }
121
122
  TcpOption TcpLayer::getNextTcpOption(TcpOption& tcpOption) const
123
195k
  {
124
195k
    TcpOption nextOpt =
125
195k
        m_OptionReader.getNextTLVRecord(tcpOption, getOptionsBasePtr(), getHeaderLen() - sizeof(tcphdr));
126
195k
    if (nextOpt.isNotNull() && nextOpt.getType() == TCPOPT_DUMMY)
127
39
      return TcpOption(nullptr);
128
129
195k
    return nextOpt;
130
195k
  }
131
132
  size_t TcpLayer::getTcpOptionCount() const
133
0
  {
134
0
    return m_OptionReader.getTLVRecordCount(getOptionsBasePtr(), getHeaderLen() - sizeof(tcphdr));
135
0
  }
136
137
  TcpOption TcpLayer::addTcpOption(const TcpOptionBuilder& optionBuilder)
138
0
  {
139
0
    return addTcpOptionAt(optionBuilder, getHeaderLen() - m_NumOfTrailingBytes);
140
0
  }
141
142
  TcpOption TcpLayer::insertTcpOptionAfter(const TcpOptionBuilder& optionBuilder,
143
                                           const TcpOptionEnumType prevOptionType)
144
149k
  {
145
149k
    int offset = 0;
146
147
149k
    if (prevOptionType == TcpOptionEnumType::Unknown)
148
0
    {
149
0
      offset = sizeof(tcphdr);
150
0
    }
151
149k
    else
152
149k
    {
153
149k
      const TcpOption prevOpt = getTcpOption(prevOptionType);
154
149k
      if (prevOpt.isNull())
155
90.2k
      {
156
90.2k
        PCPP_LOG_ERROR("Previous option of type " << static_cast<int>(prevOptionType)
157
90.2k
                                                  << " not found, cannot add a new TCP option");
158
90.2k
        return TcpOption(nullptr);
159
90.2k
      }
160
161
59.3k
      offset = prevOpt.getRecordBasePtr() + prevOpt.getTotalSize() - m_Data;
162
59.3k
    }
163
164
59.3k
    return addTcpOptionAt(optionBuilder, offset);
165
149k
  }
166
167
  bool TcpLayer::removeTcpOption(const TcpOptionEnumType optionType)
168
0
  {
169
0
    const TcpOption opt = getTcpOption(optionType);
170
0
    if (opt.isNull())
171
0
    {
172
0
      return false;
173
0
    }
174
175
    // calculate total TCP option size
176
0
    TcpOption curOpt = getFirstTcpOption();
177
0
    size_t totalOptSize = 0;
178
0
    while (!curOpt.isNull())
179
0
    {
180
0
      totalOptSize += curOpt.getTotalSize();
181
0
      curOpt = getNextTcpOption(curOpt);
182
0
    }
183
0
    totalOptSize -= opt.getTotalSize();
184
185
0
    int offset = opt.getRecordBasePtr() - m_Data;
186
187
0
    if (!shortenLayer(offset, opt.getTotalSize()))
188
0
    {
189
0
      return false;
190
0
    }
191
192
0
    adjustTcpOptionTrailer(totalOptSize);
193
194
0
    m_OptionReader.changeTLVRecordCount(-1);
195
196
0
    return true;
197
0
  }
198
199
  bool TcpLayer::removeAllTcpOptions()
200
0
  {
201
0
    const int offset = sizeof(tcphdr);
202
203
0
    if (!shortenLayer(offset, getHeaderLen() - offset))
204
0
      return false;
205
206
0
    getTcpHeader()->dataOffset = sizeof(tcphdr) / 4;
207
0
    m_NumOfTrailingBytes = 0;
208
0
    m_OptionReader.changeTLVRecordCount(0 - getTcpOptionCount());
209
0
    return true;
210
0
  }
211
212
  TcpOption TcpLayer::addTcpOptionAt(const TcpOptionBuilder& optionBuilder, const int offset)
213
59.3k
  {
214
59.3k
    TcpOption newOption = optionBuilder.build();
215
59.3k
    if (newOption.isNull())
216
0
      return newOption;
217
218
    // calculate total TCP option size
219
59.3k
    TcpOption curOpt = getFirstTcpOption();
220
59.3k
    size_t totalOptSize = 0;
221
254k
    while (!curOpt.isNull())
222
195k
    {
223
195k
      totalOptSize += curOpt.getTotalSize();
224
195k
      curOpt = getNextTcpOption(curOpt);
225
195k
    }
226
59.3k
    totalOptSize += newOption.getTotalSize();
227
228
59.3k
    size_t sizeToExtend = newOption.getTotalSize();
229
230
59.3k
    if (!extendLayer(offset, sizeToExtend))
231
0
    {
232
0
      PCPP_LOG_ERROR("Could not extend TcpLayer in [" << sizeToExtend << "] bytes");
233
0
      newOption.purgeRecordData();
234
0
      return TcpOption(nullptr);
235
0
    }
236
237
59.3k
    memcpy(m_Data + offset, newOption.getRecordBasePtr(), newOption.getTotalSize());
238
239
59.3k
    newOption.purgeRecordData();
240
241
59.3k
    adjustTcpOptionTrailer(totalOptSize);
242
243
59.3k
    m_OptionReader.changeTLVRecordCount(1);
244
245
59.3k
    uint8_t* newOptPtr = m_Data + offset;
246
247
59.3k
    return TcpOption(newOptPtr);
248
59.3k
  }
249
250
  void TcpLayer::adjustTcpOptionTrailer(const size_t totalOptSize)
251
59.3k
  {
252
59.3k
    int newNumberOfTrailingBytes = 0;
253
233k
    while ((totalOptSize + newNumberOfTrailingBytes) % 4 != 0)
254
174k
      newNumberOfTrailingBytes++;
255
256
59.3k
    if (newNumberOfTrailingBytes < m_NumOfTrailingBytes)
257
0
      shortenLayer(sizeof(tcphdr) + totalOptSize, m_NumOfTrailingBytes - newNumberOfTrailingBytes - 1);
258
59.3k
    else if (newNumberOfTrailingBytes > m_NumOfTrailingBytes)
259
58.7k
      extendLayer(sizeof(tcphdr) + totalOptSize, newNumberOfTrailingBytes - m_NumOfTrailingBytes);
260
261
59.3k
    m_NumOfTrailingBytes = newNumberOfTrailingBytes;
262
263
233k
    for (int i = 0; i < m_NumOfTrailingBytes; i++)
264
174k
      m_Data[sizeof(tcphdr) + totalOptSize + i] = TCPOPT_DUMMY;
265
266
59.3k
    getTcpHeader()->dataOffset = (sizeof(tcphdr) + totalOptSize + m_NumOfTrailingBytes) / 4;
267
59.3k
  }
268
269
  uint16_t TcpLayer::calculateChecksum(const bool writeResultToPacket)
270
149k
  {
271
149k
    tcphdr* tcpHdr = getTcpHeader();
272
149k
    uint16_t checksumRes = 0;
273
149k
    const uint16_t currChecksumValue = tcpHdr->headerChecksum;
274
275
149k
    if (m_PrevLayer != nullptr)
276
149k
    {
277
149k
      tcpHdr->headerChecksum = 0;
278
149k
      PCPP_LOG_DEBUG("TCP data len = " << m_DataLen);
279
280
149k
      if (m_PrevLayer->getProtocol() == IPv4)
281
102k
      {
282
102k
        const IPv4Address srcIP = static_cast<IPv4Layer*>(m_PrevLayer)->getSrcIPv4Address();
283
102k
        const IPv4Address dstIP = static_cast<IPv4Layer*>(m_PrevLayer)->getDstIPv4Address();
284
285
102k
        checksumRes =
286
102k
            pcpp::computePseudoHdrChecksum(reinterpret_cast<uint8_t*>(tcpHdr), getDataLen(),
287
102k
                                           IPAddress::IPv4AddressType, PACKETPP_IPPROTO_TCP, srcIP, dstIP);
288
289
102k
        PCPP_LOG_DEBUG("calculated IPv4 TCP checksum = 0x" << std::uppercase << std::hex << checksumRes);
290
102k
      }
291
46.9k
      else if (m_PrevLayer->getProtocol() == IPv6)
292
46.9k
      {
293
46.9k
        const IPv6Address srcIP = static_cast<IPv6Layer*>(m_PrevLayer)->getSrcIPv6Address();
294
46.9k
        const IPv6Address dstIP = static_cast<IPv6Layer*>(m_PrevLayer)->getDstIPv6Address();
295
296
46.9k
        checksumRes = computePseudoHdrChecksum(reinterpret_cast<uint8_t*>(tcpHdr), getDataLen(),
297
46.9k
                                               IPAddress::IPv6AddressType, PACKETPP_IPPROTO_TCP, srcIP, dstIP);
298
299
46.9k
        PCPP_LOG_DEBUG("calculated IPv6 TCP checksum = 0xX" << std::uppercase << std::hex << checksumRes);
300
46.9k
      }
301
149k
    }
302
303
149k
    if (writeResultToPacket)
304
149k
      tcpHdr->headerChecksum = htobe16(checksumRes);
305
0
    else
306
0
      tcpHdr->headerChecksum = currChecksumValue;
307
308
149k
    return checksumRes;
309
149k
  }
310
311
  void TcpLayer::initLayer()
312
0
  {
313
0
    m_DataLen = sizeof(tcphdr);
314
0
    m_Data = new uint8_t[m_DataLen];
315
0
    memset(m_Data, 0, m_DataLen);
316
0
    m_Protocol = TCP;
317
0
    m_NumOfTrailingBytes = 0;
318
0
    getTcpHeader()->dataOffset = sizeof(tcphdr) / 4;
319
0
  }
320
321
  TcpLayer::TcpLayer(uint8_t* data, const size_t dataLen, Layer* prevLayer, Packet* packet)
322
774k
      : Layer(data, dataLen, prevLayer, packet, TCP)
323
774k
  {
324
774k
    m_NumOfTrailingBytes = 0;
325
774k
  }
326
327
  TcpLayer::TcpLayer()
328
0
  {
329
0
    initLayer();
330
0
  }
331
332
  TcpLayer::TcpLayer(const uint16_t portSrc, const uint16_t portDst)
333
0
  {
334
0
    initLayer();
335
0
    getTcpHeader()->portDst = htobe16(portDst);
336
0
    getTcpHeader()->portSrc = htobe16(portSrc);
337
0
  }
338
339
  void TcpLayer::copyLayerData(const TcpLayer& other)
340
149k
  {
341
149k
    m_OptionReader = other.m_OptionReader;
342
149k
    m_NumOfTrailingBytes = other.m_NumOfTrailingBytes;
343
149k
  }
344
345
149k
  TcpLayer::TcpLayer(const TcpLayer& other) : Layer(other)
346
149k
  {
347
149k
    copyLayerData(other);
348
149k
  }
349
350
  TcpLayer& TcpLayer::operator=(const TcpLayer& other)
351
0
  {
352
0
    Layer::operator=(other);
353
354
0
    copyLayerData(other);
355
356
0
    return *this;
357
0
  }
358
359
  void TcpLayer::parseNextLayer()
360
774k
  {
361
774k
    const size_t headerLen = getHeaderLen();
362
774k
    if (m_DataLen <= headerLen)
363
87.8k
      return;
364
365
686k
    uint8_t* payload = m_Data + headerLen;
366
686k
    const size_t payloadLen = m_DataLen - headerLen;
367
686k
    const uint16_t portDst = getDstPort();
368
686k
    const uint16_t portSrc = getSrcPort();
369
686k
    const char* payloadChar = reinterpret_cast<const char*>(payload);
370
371
686k
    if (HttpMessage::isHttpPort(portDst) &&
372
115k
        HttpRequestFirstLine::parseMethod(payloadChar, payloadLen) != HttpRequestLayer::HttpMethodUnknown)
373
96.0k
    {
374
96.0k
      constructNextLayer<HttpRequestLayer>(payload, payloadLen, getAttachedPacket());
375
96.0k
    }
376
590k
    else if (HttpMessage::isHttpPort(portSrc) &&
377
24.7k
             HttpResponseFirstLine::parseVersion(payloadChar, payloadLen) != HttpVersion::HttpVersionUnknown &&
378
15.0k
             !HttpResponseFirstLine::parseStatusCode(payloadChar, payloadLen).isUnsupportedCode())
379
14.6k
    {
380
14.6k
      constructNextLayer<HttpResponseLayer>(payload, payloadLen, getAttachedPacket());
381
14.6k
    }
382
575k
    else if (SSLLayer::IsSSLMessage(portSrc, portDst, payload, payloadLen))
383
260k
    {
384
260k
      constructNextLayerFromFactory(SSLLayer::createSSLMessage, payload, payloadLen);
385
260k
    }
386
315k
    else if (SipLayer::isSipPort(portDst) || SipLayer::isSipPort(portSrc))
387
719
    {
388
719
      if (SipRequestFirstLine::parseMethod(payloadChar, payloadLen) != SipRequestLayer::SipMethodUnknown)
389
0
      {
390
0
        constructNextLayer<SipRequestLayer>(payload, payloadLen, getAttachedPacket());
391
0
      }
392
719
      else if (SipResponseFirstLine::parseStatusCode(payloadChar, payloadLen) !=
393
719
               SipResponseLayer::SipStatusCodeUnknown)
394
28
      {
395
28
        constructNextLayer<SipResponseLayer>(payload, payloadLen, getAttachedPacket());
396
28
      }
397
691
      else
398
691
      {
399
691
        constructNextLayer<PayloadLayer>(payload, payloadLen, getAttachedPacket());
400
691
      }
401
719
    }
402
314k
    else if (BgpLayer::isBgpPort(portSrc, portDst))
403
29.7k
    {
404
29.7k
      tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(BgpLayer::parseBgpLayer, payload, payloadLen);
405
29.7k
    }
406
284k
    else if (SSHLayer::isSSHPort(portSrc, portDst))
407
8.94k
    {
408
8.94k
      constructNextLayerFromFactory(SSHLayer::createSSHMessage, payload, payloadLen);
409
8.94k
    }
410
275k
    else if (DnsLayer::isDataValid(payload, payloadLen, true) &&
411
214k
             (DnsLayer::isDnsPort(portDst) || DnsLayer::isDnsPort(portSrc)))
412
2.17k
    {
413
2.17k
      constructNextLayer<DnsOverTcpLayer>(payload, payloadLen, getAttachedPacket());
414
2.17k
    }
415
273k
    else if (TelnetLayer::isDataValid(payload, payloadLen) &&
416
273k
             (TelnetLayer::isTelnetPort(portDst) || TelnetLayer::isTelnetPort(portSrc)))
417
9.36k
    {
418
9.36k
      constructNextLayer<TelnetLayer>(payload, payloadLen, getAttachedPacket());
419
9.36k
    }
420
264k
    else if (FtpLayer::isFtpPort(portSrc) && FtpLayer::isDataValid(payload, payloadLen))
421
9.11k
    {
422
9.11k
      constructNextLayer<FtpResponseLayer>(payload, payloadLen, getAttachedPacket());
423
9.11k
    }
424
255k
    else if (FtpLayer::isFtpPort(portDst) && FtpLayer::isDataValid(payload, payloadLen))
425
4.55k
    {
426
4.55k
      constructNextLayer<FtpRequestLayer>(payload, payloadLen, getAttachedPacket());
427
4.55k
    }
428
250k
    else if (FtpLayer::isFtpDataPort(portSrc) || FtpLayer::isFtpDataPort(portDst))
429
1.20k
    {
430
1.20k
      constructNextLayer<FtpDataLayer>(payload, payloadLen, getAttachedPacket());
431
1.20k
    }
432
249k
    else if ((DoIpLayer::isDoIpPort(portSrc) || DoIpLayer::isDoIpPort(portDst)) &&
433
190
             (DoIpLayer::isDataValid(payload, payloadLen)))
434
0
    {
435
0
      tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(DoIpLayer::parseDoIpLayer, payload, payloadLen);
436
0
    }
437
249k
    else if (SomeIpLayer::isSomeIpPort(portSrc) || SomeIpLayer::isSomeIpPort(portDst))
438
300
    {
439
300
      constructNextLayerFromFactory(SomeIpLayer::parseSomeIpLayer, payload, payloadLen);
440
300
    }
441
249k
    else if (TpktLayer::isDataValid(payload, payloadLen) && TpktLayer::isTpktPort(portSrc, portDst))
442
10.6k
    {
443
10.6k
      constructNextLayer<TpktLayer>(payload, payloadLen, getAttachedPacket());
444
10.6k
    }
445
238k
    else if (SmtpLayer::isSmtpPort(portSrc) && SmtpLayer::isDataValid(payload, payloadLen))
446
6.19k
    {
447
6.19k
      constructNextLayer<SmtpResponseLayer>(payload, payloadLen, getAttachedPacket());
448
6.19k
    }
449
232k
    else if (SmtpLayer::isSmtpPort(portDst) && SmtpLayer::isDataValid(payload, payloadLen))
450
8.55k
    {
451
8.55k
      constructNextLayer<SmtpRequestLayer>(payload, payloadLen, getAttachedPacket());
452
8.55k
    }
453
223k
    else if (LdapLayer::isLdapPort(portDst) || LdapLayer::isLdapPort(portSrc))
454
7.18k
    {
455
7.18k
      tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(LdapLayer::parseLdapMessage, payload,
456
7.18k
                                                                 payloadLen);
457
7.18k
    }
458
216k
    else if ((GtpV2Layer::isGTPv2Port(portDst) || GtpV2Layer::isGTPv2Port(portSrc)) &&
459
50
             GtpV2Layer::isDataValid(payload, payloadLen))
460
25
    {
461
25
      constructNextLayer<GtpV2Layer>(payload, payloadLen, getAttachedPacket());
462
25
    }
463
216k
    else if (ModbusLayer::isModbusPort(portDst))
464
1.96k
    {
465
1.96k
      constructNextLayer<ModbusLayer>(payload, payloadLen, getAttachedPacket());
466
1.96k
    }
467
214k
    else
468
214k
    {
469
214k
      constructNextLayer<PayloadLayer>(payload, payloadLen, getAttachedPacket());
470
214k
    }
471
686k
  }
472
473
  void TcpLayer::computeCalculateFields()
474
149k
  {
475
149k
    tcphdr* tcpHdr = getTcpHeader();
476
477
149k
    tcpHdr->dataOffset = getHeaderLen() >> 2;
478
149k
    calculateChecksum(true);
479
149k
  }
480
481
  std::string TcpLayer::toString() const
482
299k
  {
483
299k
    const tcphdr* hdr = getTcpHeader();
484
299k
    std::string result = "TCP Layer, ";
485
299k
    if (hdr->synFlag)
486
32.6k
    {
487
32.6k
      if (hdr->ackFlag)
488
9.31k
        result += "[SYN, ACK], ";
489
23.3k
      else
490
23.3k
        result += "[SYN], ";
491
32.6k
    }
492
266k
    else if (hdr->finFlag)
493
8.47k
    {
494
8.47k
      if (hdr->ackFlag)
495
7.43k
        result += "[FIN, ACK], ";
496
1.04k
      else
497
1.04k
        result += "[FIN], ";
498
8.47k
    }
499
257k
    else if (hdr->ackFlag)
500
251k
      result += "[ACK], ";
501
502
299k
    std::ostringstream srcPortStream;
503
299k
    srcPortStream << getSrcPort();
504
299k
    std::ostringstream dstPortStream;
505
299k
    dstPortStream << getDstPort();
506
299k
    result += "Src port: " + srcPortStream.str() + ", Dst port: " + dstPortStream.str();
507
508
299k
    return result;
509
299k
  }
510
511
  /// ~~~~~~~~
512
  /// TcpLayer Deprecated Code
513
  /// ~~~~~~~~
514
515
  DISABLE_WARNING_PUSH
516
  DISABLE_WARNING_DEPRECATED
517
  TcpOption TcpLayer::addTcpOptionAfter(const TcpOptionBuilder& optionBuilder, TcpOptionType prevOptionType)
518
0
  {
519
0
    int offset = 0;
520
521
0
    if (prevOptionType == TcpOptionType::TCPOPT_Unknown)
522
0
    {
523
0
      offset = sizeof(tcphdr);
524
0
    }
525
0
    else
526
0
    {
527
0
      TcpOption prevOpt = getTcpOption(prevOptionType);
528
0
      if (prevOpt.isNull())
529
0
      {
530
0
        PCPP_LOG_ERROR("Previous option of type " << static_cast<int>(prevOptionType)
531
0
                                                  << " not found, cannot add a new TCP option");
532
0
        return TcpOption(nullptr);
533
0
      }
534
535
0
      offset = prevOpt.getRecordBasePtr() + prevOpt.getTotalSize() - m_Data;
536
0
    }
537
538
0
    return addTcpOptionAt(optionBuilder, offset);
539
0
  }
540
541
  TcpOption TcpLayer::getTcpOption(TcpOptionType option) const
542
0
  {
543
0
    return m_OptionReader.getTLVRecord(static_cast<uint8_t>(option), getOptionsBasePtr(),
544
0
                                       getHeaderLen() - sizeof(tcphdr));
545
0
  }
546
547
  bool TcpLayer::removeTcpOption(TcpOptionType optionType)
548
0
  {
549
0
    TcpOption opt = getTcpOption(optionType);
550
0
    if (opt.isNull())
551
0
    {
552
0
      return false;
553
0
    }
554
555
    // calculate total TCP option size
556
0
    TcpOption curOpt = getFirstTcpOption();
557
0
    size_t totalOptSize = 0;
558
0
    while (!curOpt.isNull())
559
0
    {
560
0
      totalOptSize += curOpt.getTotalSize();
561
0
      curOpt = getNextTcpOption(curOpt);
562
0
    }
563
0
    totalOptSize -= opt.getTotalSize();
564
565
0
    int offset = opt.getRecordBasePtr() - m_Data;
566
567
0
    if (!shortenLayer(offset, opt.getTotalSize()))
568
0
    {
569
0
      return false;
570
0
    }
571
572
0
    adjustTcpOptionTrailer(totalOptSize);
573
574
0
    m_OptionReader.changeTLVRecordCount(-1);
575
576
0
    return true;
577
0
  }
578
  DISABLE_WARNING_POP
579
580
}  // namespace pcpp