Coverage Report

Created: 2023-01-17 06:15

/src/PcapPlusPlus/Packet++/header/TcpLayer.h
Line
Count
Source (jump to first uncovered line)
1
#ifndef PACKETPP_TCP_LAYER
2
#define PACKETPP_TCP_LAYER
3
4
#include "Layer.h"
5
#include "TLVData.h"
6
#include <string.h>
7
8
/// @file
9
10
/**
11
 * \namespace pcpp
12
 * \brief The main namespace for the PcapPlusPlus lib
13
 */
14
namespace pcpp
15
{
16
17
  /**
18
   * @struct tcphdr
19
   * Represents an TCP protocol header
20
   */
21
#pragma pack(push,1)
22
  struct tcphdr
23
  {
24
    /** Source TCP port */
25
    uint16_t portSrc;
26
    /** Destination TCP port */
27
    uint16_t portDst;
28
    /** Sequence number */
29
    uint32_t sequenceNumber;
30
    /** Acknowledgment number */
31
    uint32_t ackNumber;
32
#if (BYTE_ORDER == LITTLE_ENDIAN)
33
    uint16_t reserved:4,
34
    /** Specifies the size of the TCP header in 32-bit words */
35
    dataOffset:4,
36
    /** FIN flag */
37
    finFlag:1,
38
    /** SYN flag */
39
    synFlag:1,
40
    /** RST flag */
41
    rstFlag:1,
42
    /** PSH flag */
43
    pshFlag:1,
44
    /** ACK flag */
45
    ackFlag:1,
46
    /** URG flag */
47
    urgFlag:1,
48
    /** ECE flag */
49
    eceFlag:1,
50
    /** CWR flag */
51
    cwrFlag:1;
52
#elif (BYTE_ORDER == BIG_ENDIAN)
53
    /** Specifies the size of the TCP header in 32-bit words */
54
    uint16_t dataOffset:4,
55
    reserved:4,
56
    /** CWR flag */
57
    cwrFlag:1,
58
    /** ECE flag */
59
    eceFlag:1,
60
    /** URG flag */
61
    urgFlag:1,
62
    /** ACK flag */
63
    ackFlag:1,
64
    /** PSH flag */
65
    pshFlag:1,
66
    /** RST flag */
67
    rstFlag:1,
68
    /** SYN flag */
69
    synFlag:1,
70
    /** FIN flag */
71
    finFlag:1;
72
#else
73
#error  "Endian is not LE nor BE..."
74
#endif
75
    /** The size of the receive window, which specifies the number of window size units (by default, bytes) */
76
    uint16_t  windowSize;
77
    /** The 16-bit checksum field is used for error-checking of the header and data */
78
    uint16_t  headerChecksum;
79
    /** If the URG flag (@ref tcphdr#urgFlag) is set, then this 16-bit field is an offset from the sequence number indicating the last urgent data byte */
80
    uint16_t  urgentPointer;
81
  };
82
#pragma pack(pop)
83
84
85
  /**
86
   * TCP options types
87
   */
88
  enum TcpOptionType
89
  {
90
    /** Padding */
91
    PCPP_TCPOPT_NOP =       1,
92
    /** End of options */
93
    PCPP_TCPOPT_EOL =       0,
94
    /** Segment size negotiating */
95
    TCPOPT_MSS =            2,
96
    /** Window scaling */
97
    PCPP_TCPOPT_WINDOW =    3,
98
    /** SACK Permitted */
99
    TCPOPT_SACK_PERM =      4,
100
    /** SACK Block */
101
    PCPP_TCPOPT_SACK =      5,
102
    /** Echo (obsoleted by option ::PCPP_TCPOPT_TIMESTAMP) */
103
    TCPOPT_ECHO =           6,
104
    /** Echo Reply (obsoleted by option ::PCPP_TCPOPT_TIMESTAMP) */
105
    TCPOPT_ECHOREPLY =      7,
106
    /** TCP Timestamps */
107
    PCPP_TCPOPT_TIMESTAMP = 8,
108
    /** CC (obsolete) */
109
    TCPOPT_CC =             11,
110
    /** CC.NEW (obsolete) */
111
    TCPOPT_CCNEW =          12,
112
    /** CC.ECHO(obsolete) */
113
    TCPOPT_CCECHO =         13,
114
    /** MD5 Signature Option */
115
    TCPOPT_MD5 =            19,
116
    /** Multipath TCP */
117
    TCPOPT_MPTCP =          0x1e,
118
    /** SCPS Capabilities */
119
    TCPOPT_SCPS =           20,
120
    /** SCPS SNACK */
121
    TCPOPT_SNACK =          21,
122
    /** SCPS Record Boundary */
123
    TCPOPT_RECBOUND =       22,
124
    /** SCPS Corruption Experienced */
125
    TCPOPT_CORREXP =        23,
126
    /** Quick-Start Response */
127
    TCPOPT_QS =             27,
128
    /** User Timeout Option (also, other known unauthorized use) */
129
    TCPOPT_USER_TO =        28,
130
    /** RFC3692-style Experiment 1 (also improperly used for shipping products) */
131
    TCPOPT_EXP_FD =         0xfd,
132
    /** RFC3692-style Experiment 2 (also improperly used for shipping products) */
133
    TCPOPT_EXP_FE =         0xfe,
134
    /** Riverbed probe option, non IANA registered option number */
135
    TCPOPT_RVBD_PROBE =     76,
136
    /** Riverbed transparency option, non IANA registered option number */
137
    TCPOPT_RVBD_TRPY =      78,
138
    /** Unknown option */
139
    TCPOPT_Unknown =        255
140
  };
141
142
143
  // TCP option lengths
144
145
  /** pcpp::PCPP_TCPOPT_NOP length */
146
#define PCPP_TCPOLEN_NOP            1
147
  /** pcpp::PCPP_TCPOPT_EOL length */
148
#define PCPP_TCPOLEN_EOL            1
149
  /** pcpp::TCPOPT_MSS length */
150
#define PCPP_TCPOLEN_MSS            4
151
  /** pcpp::PCPP_TCPOPT_WINDOW length */
152
#define PCPP_TCPOLEN_WINDOW         3
153
  /** pcpp::TCPOPT_SACK_PERM length */
154
#define PCPP_TCPOLEN_SACK_PERM      2
155
  /** pcpp::PCPP_TCPOPT_SACK length */
156
#define PCPP_TCPOLEN_SACK_MIN       2
157
  /** pcpp::TCPOPT_ECHO length */
158
#define PCPP_TCPOLEN_ECHO           6
159
  /** pcpp::TCPOPT_ECHOREPLY length */
160
#define PCPP_TCPOLEN_ECHOREPLY      6
161
  /** pcpp::PCPP_TCPOPT_TIMESTAMP length */
162
#define PCPP_TCPOLEN_TIMESTAMP     10
163
  /** pcpp::TCPOPT_CC length */
164
#define PCPP_TCPOLEN_CC             6
165
  /** pcpp::TCPOPT_CCNEW length */
166
#define PCPP_TCPOLEN_CCNEW          6
167
  /** pcpp::TCPOPT_CCECHO length */
168
#define PCPP_TCPOLEN_CCECHO         6
169
  /** pcpp::TCPOPT_MD5 length */
170
#define PCPP_TCPOLEN_MD5           18
171
  /** pcpp::TCPOPT_MPTCP length */
172
#define PCPP_TCPOLEN_MPTCP_MIN      8
173
  /** pcpp::TCPOPT_SCPS length */
174
#define PCPP_TCPOLEN_SCPS           4
175
  /** pcpp::TCPOPT_SNACK length */
176
#define PCPP_TCPOLEN_SNACK          6
177
  /** pcpp::TCPOPT_RECBOUND length */
178
#define PCPP_TCPOLEN_RECBOUND       2
179
  /** pcpp::TCPOPT_CORREXP length */
180
#define PCPP_TCPOLEN_CORREXP        2
181
  /** pcpp::TCPOPT_QS length */
182
#define PCPP_TCPOLEN_QS             8
183
  /** pcpp::TCPOPT_USER_TO length */
184
#define PCPP_TCPOLEN_USER_TO        4
185
  /** pcpp::TCPOPT_RVBD_PROBE length */
186
#define PCPP_TCPOLEN_RVBD_PROBE_MIN 3
187
  /** pcpp::TCPOPT_RVBD_TRPY length */
188
#define PCPP_TCPOLEN_RVBD_TRPY_MIN 16
189
  /** pcpp::TCPOPT_EXP_FD and pcpp::TCPOPT_EXP_FE length */
190
#define PCPP_TCPOLEN_EXP_MIN        2
191
192
193
  /**
194
   * @class TcpOption
195
   * A wrapper class for TCP options. This class does not create or modify TCP option records, but rather
196
   * serves as a wrapper and provides useful methods for retrieving data from them
197
   */
198
  class TcpOption : public TLVRecord<uint8_t, uint8_t>
199
  {
200
  public:
201
202
    /**
203
     * A c'tor for this class that gets a pointer to the option raw data (byte array)
204
     * @param[in] optionRawData A pointer to the TCP option raw data
205
     */
206
0
    explicit TcpOption(uint8_t* optionRawData) : TLVRecord(optionRawData) { }
207
208
    /**
209
     * A d'tor for this class, currently does nothing
210
     */
211
0
    ~TcpOption() { }
212
213
    /**
214
     * @return TCP option type casted as pcpp::TcpOptionType enum. If the data is null a value
215
     * of ::TCPOPT_Unknown is returned
216
     */
217
    TcpOptionType getTcpOptionType() const
218
0
    {
219
0
      if (m_Data == NULL)
220
0
        return TCPOPT_Unknown;
221
0
222
0
      return (TcpOptionType)m_Data->recordType;
223
0
    }
224
225
    // implement abstract methods
226
227
    size_t getTotalSize() const
228
0
    {
229
0
      if (m_Data == NULL)
230
0
        return (size_t)0;
231
232
0
      if (m_Data->recordType == (uint8_t)PCPP_TCPOPT_NOP || m_Data->recordType == (uint8_t)PCPP_TCPOPT_EOL)
233
0
        return sizeof(uint8_t);
234
235
0
      return (size_t)m_Data->recordLen;
236
0
    }
237
238
    size_t getDataSize() const
239
0
    {
240
0
      if (m_Data == NULL)
241
0
        return 0;
242
243
0
      if (m_Data->recordType == (uint8_t)PCPP_TCPOPT_NOP || m_Data->recordType == (uint8_t)PCPP_TCPOPT_EOL)
244
0
        return (size_t)0;
245
246
0
      return (size_t)m_Data->recordLen - (2*sizeof(uint8_t));
247
0
    }
248
  };
249
250
251
  /**
252
   * @class TcpOptionBuilder
253
   * A class for building TCP option records. This builder receives the TCP option parameters in its c'tor,
254
   * builds the TCP option raw buffer and provides a build() method to get a TcpOption object out of it
255
   */
256
  class TcpOptionBuilder : public TLVRecordBuilder
257
  {
258
259
  public:
260
261
    /**
262
     * An enum to describe NOP and EOL TCP options. Used in one of this class's c'tors
263
     */
264
    enum NopEolOptionTypes
265
    {
266
      /** NOP TCP option */
267
      NOP,
268
      /** EOL TCP option */
269
      EOL
270
    };
271
272
    /**
273
     * A c'tor for building TCP options which their value is a byte array. The TcpOption object can be later
274
     * retrieved by calling build()
275
     * @param[in] optionType TCP option type
276
     * @param[in] optionValue A buffer containing the option value. This buffer is read-only and isn't modified in any way.
277
     * @param[in] optionValueLen Option value length in bytes
278
     */
279
    TcpOptionBuilder(TcpOptionType optionType, const uint8_t* optionValue, uint8_t optionValueLen) :
280
0
      TLVRecordBuilder((uint8_t)optionType, optionValue, optionValueLen) {}
281
282
    /**
283
     * A c'tor for building TCP options which have a 1-byte value. The TcpOption object can be later retrieved
284
     * by calling build()
285
     * @param[in] optionType TCP option type
286
     * @param[in] optionValue A 1-byte option value
287
     */
288
    TcpOptionBuilder(TcpOptionType optionType, uint8_t optionValue) :
289
0
      TLVRecordBuilder((uint8_t)optionType, optionValue) {}
290
291
    /**
292
     * A c'tor for building TCP options which have a 2-byte value. The TcpOption object can be later retrieved
293
     * by calling build()
294
     * @param[in] optionType TCP option type
295
     * @param[in] optionValue A 2-byte option value
296
     */
297
    TcpOptionBuilder(TcpOptionType optionType, uint16_t optionValue) :
298
0
      TLVRecordBuilder((uint8_t)optionType, optionValue) {}
299
300
    /**
301
     * A c'tor for building TCP options which have a 4-byte value. The TcpOption object can be later retrieved
302
     * by calling build()
303
     * @param[in] optionType TCP option type
304
     * @param[in] optionValue A 4-byte option value
305
     */
306
    TcpOptionBuilder(TcpOptionType optionType, uint32_t optionValue) :
307
0
      TLVRecordBuilder((uint8_t)optionType, optionValue) {}
308
309
    /**
310
     * A c'tor for building TCP NOP and EOL options. These option types are special in that they contain only 1 byte
311
     * which is the TCP option type (NOP or EOL). The TcpOption object can be later retrieved
312
     * by calling build()
313
     * @param[in] optionType An enum value indicating which option type to build (NOP or EOL)
314
     */
315
    explicit TcpOptionBuilder(NopEolOptionTypes optionType);
316
317
    /**
318
     * Build the TcpOption object out of the parameters defined in the c'tor
319
     * @return The TcpOption object
320
     */
321
    TcpOption build() const;
322
  };
323
324
325
  /**
326
   * @class TcpLayer
327
   * Represents a TCP (Transmission Control Protocol) protocol layer
328
   */
329
  class TcpLayer : public Layer
330
  {
331
  public:
332
    /**
333
     * A constructor that creates the layer from an existing packet raw data
334
     * @param[in] data A pointer to the raw data (will be casted to @ref tcphdr)
335
     * @param[in] dataLen Size of the data in bytes
336
     * @param[in] prevLayer A pointer to the previous layer
337
     * @param[in] packet A pointer to the Packet instance where layer will be stored in
338
     */
339
    TcpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
340
341
    /**
342
     * A constructor that allocates a new TCP header with zero TCP options
343
     */
344
    TcpLayer();
345
346
    /**
347
     * A constructor that allocates a new TCP header with source port and destination port and zero TCP options
348
     * @param[in] portSrc Source port
349
     * @param[in] portDst Destination port
350
     */
351
    TcpLayer(uint16_t portSrc, uint16_t portDst);
352
353
145k
    ~TcpLayer() {}
354
355
    /**
356
     * A copy constructor that copy the entire header from the other TcpLayer (including TCP options)
357
     */
358
    TcpLayer(const TcpLayer& other);
359
360
    /**
361
     * An assignment operator that first delete all data from current layer and then copy the entire header from the other TcpLayer (including TCP options)
362
     */
363
    TcpLayer& operator=(const TcpLayer& other);
364
365
    /**
366
     * Get a pointer to the TCP header. Notice this points directly to the data, so every change will change the actual packet data
367
     * @return A pointer to the @ref tcphdr
368
     */
369
435k
    tcphdr* getTcpHeader() const { return (tcphdr*)m_Data; }
370
371
    /**
372
     * @return TCP source port
373
     */
374
    uint16_t getSrcPort() const;
375
376
    /**
377
     * @return TCP destination port
378
     */
379
    uint16_t getDstPort() const;
380
381
    /**
382
     * Get a TCP option by type
383
     * @param[in] option TCP option type to retrieve
384
     * @return An TcpOption object that contains the first option that matches this type, or logical NULL
385
     * (TcpOption#isNull() == true) if no such option found
386
     */
387
    TcpOption getTcpOption(TcpOptionType option) const;
388
389
    /**
390
     * @return The first TCP option in the packet. If the current layer contains no options the returned value will contain
391
     * a logical NULL (TcpOption#isNull() == true)
392
     */
393
    TcpOption getFirstTcpOption() const;
394
395
    /**
396
     * Get the TCP option that comes after a given option. If the given option was the last one, the
397
     * returned value will contain a logical NULL (TcpOption#isNull() == true)
398
     * @param[in] tcpOption A TCP option object that exists in the current layer
399
     * @return A TcpOption object that contains the TCP option data that comes next, or logical NULL if the given
400
     * TCP option: (1) was the last one; or (2) contains a logical NULL; or (3) doesn't belong to this packet
401
     */
402
    TcpOption getNextTcpOption(TcpOption& tcpOption) const;
403
404
    /**
405
     * @return The number of TCP options in this layer
406
     */
407
    size_t getTcpOptionCount() const;
408
409
    /**
410
     * Add a new TCP option at the end of the layer (after the last TCP option)
411
     * @param[in] optionBuilder A TcpOptionBuilder object that contains the TCP option data to be added
412
     * @return A TcpOption object that contains the newly added TCP option data or logical NULL
413
     * (TcpOption#isNull() == true) if addition failed. In case of a failure a corresponding error message will be
414
     * printed to log
415
     */
416
    TcpOption addTcpOption(const TcpOptionBuilder& optionBuilder);
417
418
    /**
419
     * Add a new TCP option after an existing one
420
     * @param[in] optionBuilder A TcpOptionBuilder object that contains the requested TCP option data to be added
421
     * @param[in] prevOptionType The TCP option which the newly added option should come after. This is an optional parameter which
422
     * gets a default value of ::TCPOPT_Unknown if omitted, which means the new option will be added as the first option in the layer
423
     * @return A TcpOption object containing the newly added TCP option data or logical NULL
424
     * (TcpOption#isNull() == true) if addition failed. In case of a failure a corresponding error message will be
425
     * printed to log
426
     */
427
    TcpOption addTcpOptionAfter(const TcpOptionBuilder& optionBuilder, TcpOptionType prevOptionType = TCPOPT_Unknown);
428
429
    /**
430
     * Remove an existing TCP option from the layer. TCP option is found by type
431
     * @param[in] optionType The TCP option type to remove
432
     * @return True if TCP option was removed or false if type wasn't found or if removal failed (in each case a proper error
433
     * will be written to log)
434
     */
435
    bool removeTcpOption(TcpOptionType optionType);
436
437
    /**
438
     * Remove all TCP options in this layer
439
     * @return True if all TCP options were successfully removed or false if removal failed for some reason
440
     * (a proper error will be written to log)
441
     */
442
    bool removeAllTcpOptions();
443
444
445
    /**
446
     * Calculate the checksum from header and data and possibly write the result to @ref tcphdr#headerChecksum
447
     * @param[in] writeResultToPacket If set to true then checksum result will be written to @ref tcphdr#headerChecksum
448
     * @return The checksum result
449
     */
450
    uint16_t calculateChecksum(bool writeResultToPacket);
451
452
    /**
453
     * The static method makes validation of input data
454
     * @param[in] data The pointer to the beginning of byte stream of TCP packet
455
     * @param[in] dataLen The length of byte stream
456
     * @return True if the data is valid and can represent a TCP packet
457
     */
458
    static inline bool isDataValid(const uint8_t* data, size_t dataLen);
459
460
    // implement abstract methods
461
462
    /**
463
     * Currently identifies the following next layers: HttpRequestLayer, HttpResponseLayer. Otherwise sets PayloadLayer
464
     */
465
    void parseNextLayer();
466
467
    /**
468
     * @return Size of @ref tcphdr + all TCP options
469
     */
470
145k
    size_t getHeaderLen() const { return getTcpHeader()->dataOffset*4 ;}
471
472
    /**
473
     * Calculate @ref tcphdr#headerChecksum field
474
     */
475
    void computeCalculateFields();
476
477
    std::string toString() const;
478
479
145k
    OsiModelLayer getOsiModelLayer() const { return OsiModelTransportLayer; }
480
481
  private:
482
483
    TLVRecordReader<TcpOption> m_OptionReader;
484
    int m_NumOfTrailingBytes;
485
486
    void initLayer();
487
0
    uint8_t* getOptionsBasePtr() const { return m_Data + sizeof(tcphdr); }
488
    TcpOption addTcpOptionAt(const TcpOptionBuilder& optionBuilder, int offset);
489
    void adjustTcpOptionTrailer(size_t totalOptSize);
490
    void copyLayerData(const TcpLayer& other);
491
  };
492
493
494
  // implementation of inline methods
495
496
  bool TcpLayer::isDataValid(const uint8_t* data, size_t dataLen)
497
162k
  {
498
162k
    const tcphdr* hdr = reinterpret_cast<const tcphdr*>(data);
499
162k
    return dataLen >= sizeof(tcphdr)
500
162k
      && hdr->dataOffset >= 5 /* the minimum TCP header size */
501
162k
      && dataLen >= hdr->dataOffset * sizeof(uint32_t);
502
162k
  }
503
504
} // namespace pcpp
505
506
#endif /* PACKETPP_TCP_LAYER */