Coverage Report

Created: 2025-07-11 07:47

/src/PcapPlusPlus/Packet++/header/GreLayer.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include "Layer.h"
4
5
/// @file
6
7
/// @namespace pcpp
8
/// @brief The main namespace for the PcapPlusPlus lib
9
namespace pcpp
10
{
11
  /// @struct gre_basic_header
12
  /// Represents GRE basic protocol header (common for GREv0 and GREv1)
13
#pragma pack(push, 1)
14
  struct gre_basic_header
15
  {
16
#if (BYTE_ORDER == LITTLE_ENDIAN)
17
    /// Number of additional encapsulations which are permitted. 0 is the default value
18
    uint8_t recursionControl : 3,
19
        /// Strict source routing bit (GRE v0 only)
20
        strictSourceRouteBit : 1,
21
        /// Set if sequence number exists
22
        sequenceNumBit : 1,
23
        /// Set if key exists
24
        keyBit : 1,
25
        /// Set if routing exists (GRE v0 only)
26
        routingBit : 1,
27
        /// Set if checksum exists (GRE v0 only)
28
        checksumBit : 1;
29
#else
30
    /// Set if checksum exists (GRE v0 only)
31
    uint8_t checksumBit : 1,
32
        /// Set if routing exists (GRE v0 only)
33
        routingBit : 1,
34
        /// Set if key exists
35
        keyBit : 1,
36
        /// Set if sequence number exists
37
        sequenceNumBit : 1,
38
        /// Strict source routing bit (GRE v0 only)
39
        strictSourceRouteBit : 1,
40
        /// Number of additional encapsulations which are permitted. 0 is the default value
41
        recursionControl : 3;
42
#endif
43
#if (BYTE_ORDER == LITTLE_ENDIAN)
44
    /// GRE version - can be 0 or 1
45
    uint8_t version : 3,
46
        /// Reserved
47
        flags : 4,
48
        /// Set if acknowledgment number is set (GRE v1 only)
49
        ackSequenceNumBit : 1;
50
#else
51
    /// Set if acknowledgment number is set (GRE v1 only)
52
    uint8_t ackSequenceNumBit : 1,
53
        /// Reserved
54
        flags : 4,
55
        /// GRE version - can be 0 or 1
56
        version : 3;
57
#endif
58
59
    /// Protocol type of the next layer
60
    uint16_t protocol;
61
  };
62
#pragma pack(pop)
63
  static_assert(sizeof(gre_basic_header) == 4, "gre_basic_header size is not 4 bytes");
64
65
  /// @struct gre1_header
66
  /// Represents GREv1 protocol header
67
#pragma pack(push, 1)
68
  struct gre1_header : gre_basic_header
69
  {
70
    /// Size of the payload not including the GRE header
71
    uint16_t payloadLength;
72
    /// Contains the Peer's Call ID for the session to which this packet belongs
73
    uint16_t callID;
74
  };
75
#pragma pack(pop)
76
  static_assert(sizeof(gre1_header) == 8, "gre1_header size is not 8 bytes");
77
78
  /// @struct ppp_pptp_header
79
  /// Represents PPP layer that comes after GREv1 as part of PPTP protocol
80
#pragma pack(push, 1)
81
  struct ppp_pptp_header
82
  {
83
    /// Broadcast address
84
    uint8_t address;
85
    /// Control byte
86
    uint8_t control;
87
    /// Protocol type of the next layer (see PPP_* macros at PPPoELayer.h)
88
    uint16_t protocol;
89
  };
90
#pragma pack(pop)
91
  static_assert(sizeof(ppp_pptp_header) == 4, "ppp_pptp_header size is not 4 bytes");
92
93
  /// @class GreLayer
94
  /// Abstract base class for GRE layers (GREv0Layer and GREv1Layer). Cannot be instantiated and contains common logic
95
  /// for derived classes
96
  class GreLayer : public Layer
97
  {
98
  public:
99
    ~GreLayer() override = default;
100
101
    /// A static method that determines the GRE version of GRE layer raw data by looking at the
102
    /// gre_basic_header#version field
103
    /// @param[in] greData GRE layer raw data
104
    /// @param[in] greDataLen Size of raw data
105
    /// @return ::GREv0 or ::GREv1 values if raw data is GREv0 or GREv1 (accordingly) or ::UnknownProtocol otherwise
106
    static ProtocolType getGREVersion(uint8_t* greData, size_t greDataLen);
107
108
    /// Get sequence number value if field exists in layer
109
    /// @param[out] seqNumber The returned sequence number value if exists in layer. Else remain unchanged
110
    /// @return True if sequence number field exists in layer. In this case seqNumber will be filled with the value.
111
    /// Or false if sequence number field doesn't exist in layer
112
    bool getSequenceNumber(uint32_t& seqNumber) const;
113
114
    /// Set sequence number value. If field already exists (gre_basic_header#sequenceNumBit is set) then only the
115
    /// new value is set. If field doesn't exist it will be added to the layer, gre_basic_header#sequenceNumBit will
116
    /// be set and the new value will be set
117
    /// @param[in] seqNumber The sequence number value to set
118
    /// @return True if managed to set the value successfully, or false otherwise (if couldn't extend the layer)
119
    bool setSequenceNumber(uint32_t seqNumber);
120
121
    /// Unset sequence number and remove it from the layer
122
    /// @return True if managed to unset successfully or false (and error log) if sequence number wasn't set in the
123
    /// first place or if didn't manage to remove it from the layer
124
    bool unsetSequenceNumber();
125
126
    // implement abstract methods
127
128
    /// Currently identifies the following next layers:
129
    ///   IPv4Layer, IPv6Layer, VlanLayer, MplsLayer, PPP_PPTPLayer, EthLayer, EthDot3Layer
130
    /// Otherwise sets PayloadLayer
131
    void parseNextLayer() override;
132
133
    /// @return Size of GRE header (may change if optional fields are added or removed)
134
    size_t getHeaderLen() const override;
135
136
    OsiModelLayer getOsiModelLayer() const override
137
3.75k
    {
138
3.75k
      return OsiModelNetworkLayer;
139
3.75k
    }
140
141
  protected:
142
    GreLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ProtocolType protocol)
143
30.4k
        : Layer(data, dataLen, prevLayer, packet, protocol)
144
30.4k
    {}
145
146
    GreLayer()
147
0
    {}
148
149
    enum GreField
150
    {
151
      GreChecksumOrRouting = 0,
152
      GreKey = 1,
153
      GreSeq = 2,
154
      GreAck = 3
155
    };
156
157
    uint8_t* getFieldValue(GreField field, bool returnOffsetEvenIfFieldMissing) const;
158
159
    void computeCalculateFieldsInner();
160
  };
161
162
  /// @class GREv0Layer
163
  /// Represents a GRE version 0 protocol. Limitation: currently this layer doesn't support GRE routing information
164
  /// parsing and editing. So if a GREv0 packet includes routing information it won't be parse correctly. I didn't add
165
  /// it because of lack of time, but if you need it please tell me and I'll add it
166
  class GREv0Layer : public GreLayer
167
  {
168
  public:
169
    /// A constructor that creates the layer from an existing packet raw data
170
    /// @param[in] data A pointer to the raw data
171
    /// @param[in] dataLen Size of the data in bytes
172
    /// @param[in] prevLayer A pointer to the previous layer
173
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
174
    GREv0Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
175
6.34k
        : GreLayer(data, dataLen, prevLayer, packet, GREv0)
176
6.34k
    {}
177
178
    /// A constructor that creates a new GREv0 header and allocates the data
179
    GREv0Layer();
180
181
    ~GREv0Layer() override = default;
182
183
    /// Get a pointer to the basic GRE header containing only non-optional fields. Notice this points directly to
184
    /// the data, so every change will change the actual packet data. Also please notice that changing the set bits
185
    /// (gre_basic_header#strictSourceRouteBit, gre_basic_header#sequenceNumBit, gre_basic_header#keyBit,
186
    /// gre_basic_header#routingBit, gre_basic_header#checksumBit, gre_basic_header#ackSequenceNumBit) without using
187
    /// the proper set or unset methods (such as setChecksum(), unsetChecksum(), etc.) may result to wrong
188
    /// calculation of header length and really weird bugs. Please avoid doing so
189
    /// @return A pointer to the gre_basic_header
190
    gre_basic_header* getGreHeader() const
191
9.20k
    {
192
9.20k
      return reinterpret_cast<gre_basic_header*>(m_Data);
193
9.20k
    }
194
195
    /// Get checksum value if field exists in layer
196
    /// @param[out] checksum The returned checksum value if exists in layer. Else remain unchanged
197
    /// @return True if checksum field exists in layer. In this case checksum parameter will be filled with the
198
    /// value. Or false if checksum field doesn't exist in layer
199
    bool getChecksum(uint16_t& checksum);
200
201
    /// Set checksum value. If checksum or offset fields already exist (gre_basic_header#checksumBit or
202
    /// gre_basic_header#routingBit are set) then only the new value is set. If both fields don't exist a new 4-byte
203
    /// value will be added to the layer, gre_basic_header#checksumBit will be set (gre_basic_header#routingBit will
204
    /// remain unset), the new checksum value will be set and offset value will be set to 0. The reason both fields
205
    /// are added is that GREv0 protocol states both of them or none of them should exist on packet (even if only
206
    /// one of the bits are set)
207
    /// @param[in] checksum The checksum value to set
208
    /// @return True if managed to set the value/s successfully, or false otherwise (if couldn't extend the layer)
209
    bool setChecksum(uint16_t checksum);
210
211
    /// Unset checksum and possibly remove it from the layer. It will be removed from the layer only if
212
    /// gre_basic_header#routingBit is not set as well. Otherwise checksum field will remain on packet with value of
213
    /// 0
214
    /// @return True if managed to unset successfully or false (and error log) if checksum wasn't set in the first
215
    /// place or if didn't manage to remove it from the layer
216
    bool unsetChecksum();
217
218
    /// Get offset value if field exists in layer. Notice there is no setOffset() method as GRE routing information
219
    /// isn't supported yet (see comment on class description)
220
    /// @param[out] offset The returned offset value if exists in layer. Else remain unchanged
221
    /// @return True if offset field exists in layer. In this case offset parameter will be filled with the value.
222
    /// Or false if offset field doesn't exist in layer
223
    bool getOffset(uint16_t& offset) const;
224
225
    /// Get key value if field exists in layer
226
    /// @param[out] key The returned key value if exists in layer. Else remain unchanged
227
    /// @return True if key field exists in layer. In this case key parameter will be filled with the value.
228
    /// Or false if key field doesn't exist in layer
229
    bool getKey(uint32_t& key) const;
230
231
    /// Set key value. If field already exists (gre_basic_header#keyBit is set) then only the new value is set.
232
    /// If field doesn't exist it will be added to the layer, gre_basic_header#keyBit will be set
233
    /// and the new value will be set
234
    /// @param[in] key The key value to set
235
    /// @return True if managed to set the value successfully, or false otherwise (if couldn't extend the layer)
236
    bool setKey(uint32_t key);
237
238
    /// Unset key and remove it from the layer
239
    /// @return True if managed to unset successfully or false (and error log) if key wasn't set in the first
240
    /// place or if didn't manage to remove it from the layer
241
    bool unsetKey();
242
243
    /// A static method that validates the input data
244
    /// @param[in] data The pointer to the beginning of a byte stream of an GREv0 layer
245
    /// @param[in] dataLen The length of the byte stream
246
    /// @return True if the data is valid and can represent an GREv0 layer
247
    static inline bool isDataValid(const uint8_t* data, size_t dataLen)
248
6.34k
    {
249
6.34k
      return data && dataLen >= sizeof(gre_basic_header);
250
6.34k
    }
251
252
    // implement abstract methods
253
254
    /// Calculate the following fields:
255
    /// - gre_basic_header#protocol
256
    /// - GRE checksum field (if exists in packet)
257
    void computeCalculateFields() override;
258
259
    std::string toString() const override;
260
  };
261
262
  /// @class GREv1Layer
263
  /// Represents a GRE version 1 protocol
264
  class GREv1Layer : public GreLayer
265
  {
266
  public:
267
    /// A constructor that creates the layer from an existing packet raw data
268
    /// @param[in] data A pointer to the raw data
269
    /// @param[in] dataLen Size of the data in bytes
270
    /// @param[in] prevLayer A pointer to the previous layer
271
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
272
    GREv1Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
273
24.1k
        : GreLayer(data, dataLen, prevLayer, packet, GREv1)
274
24.1k
    {}
275
276
    /// A constructor that creates a new GREv1 header and allocates the data
277
    /// @param[in] callID The call ID to set
278
    explicit GREv1Layer(uint16_t callID);
279
280
    ~GREv1Layer() override = default;
281
282
    /// Get a pointer to the basic GREv1 header containing all non-optional fields. Notice this points directly to
283
    /// the data, so every change will change the actual packet data. Also please notice that changing the set bits
284
    /// (gre_basic_header#strictSourceRouteBit, gre_basic_header#sequenceNumBit, gre_basic_header#keyBit,
285
    /// gre_basic_header#routingBit, gre_basic_header#checksumBit, gre_basic_header#ackSequenceNumBit) without using
286
    /// the proper set or unset methods (such as setAcknowledgmentNum(), unsetSequenceNumber(), etc.) may result to
287
    /// wrong calculation of header length or illegal GREv1 packet and to some really weird bugs. Please avoid doing
288
    /// so
289
    /// @return A pointer to the gre1_header
290
    gre1_header* getGreHeader() const
291
4.96k
    {
292
4.96k
      return reinterpret_cast<gre1_header*>(m_Data);
293
4.96k
    }
294
295
    /// Get acknowledgment (ack) number value if field exists in layer
296
    /// @param[out] ackNum The returned ack number value if exists in layer. Else remain unchanged
297
    /// @return True if ack number field exists in layer. In this case ackNum will be filled with the value.
298
    /// Or false if ack number field doesn't exist in layer
299
    bool getAcknowledgmentNum(uint32_t& ackNum) const;
300
301
    /// Set acknowledgment (ack) number value. If field already exists (gre_basic_header#ackSequenceNumBit is set)
302
    /// then only the new value is set. If field doesn't exist it will be added to the layer,
303
    /// gre_basic_header#ackSequenceNumBit will be set and the new value will be set
304
    /// @param[in] ackNum The ack number value to set
305
    /// @return True if managed to set the value successfully, or false otherwise (if couldn't extend the layer)
306
    bool setAcknowledgmentNum(uint32_t ackNum);
307
308
    /// Unset acknowledgment (ack) number and remove it from the layer
309
    /// @return True if managed to unset successfully or false (and error log) if ack number wasn't set in the first
310
    /// place or if didn't manage to remove it from the layer
311
    bool unsetAcknowledgmentNum();
312
313
    /// A static method that validates the input data
314
    /// @param[in] data The pointer to the beginning of a byte stream of an GREv1 layer
315
    /// @param[in] dataLen The length of the byte stream
316
    /// @return True if the data is valid and can represent an GREv1 layer
317
    static inline bool isDataValid(const uint8_t* data, size_t dataLen)
318
24.1k
    {
319
24.1k
      return data && dataLen >= sizeof(gre1_header);
320
24.1k
    }
321
322
    // implement abstract methods
323
324
    /// Calculate the following fields:
325
    /// - gre1_header#payloadLength
326
    /// - gre_basic_header#protocol
327
    void computeCalculateFields() override;
328
329
    std::string toString() const override;
330
  };
331
332
  /// @class PPP_PPTPLayer
333
  /// Represent a PPP (point-to-point) protocol header that comes after GREv1 header, as part of PPTP - Point-to-Point
334
  /// Tunneling Protocol
335
  class PPP_PPTPLayer : public Layer
336
  {
337
  public:
338
    /// A constructor that creates the layer from an existing packet raw data
339
    /// @param[in] data A pointer to the raw data (will be casted to @ref ppp_pptp_header)
340
    /// @param[in] dataLen Size of the data in bytes
341
    /// @param[in] prevLayer A pointer to the previous layer
342
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
343
    PPP_PPTPLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
344
22.1k
        : Layer(data, dataLen, prevLayer, packet, PPP_PPTP)
345
22.1k
    {}
346
347
    /// A constructor that allocates a new PPP-PPTP header
348
    /// @param[in] address Address field
349
    /// @param[in] control Control field
350
    PPP_PPTPLayer(uint8_t address, uint8_t control);
351
352
    ~PPP_PPTPLayer() override = default;
353
354
    /// Get a pointer to the PPP-PPTP header. Notice this points directly to the data, so every change will change
355
    /// the actual packet data
356
    /// @return A pointer to the @ref ppp_pptp_header
357
    ppp_pptp_header* getPPP_PPTPHeader() const
358
24.2k
    {
359
24.2k
      return reinterpret_cast<ppp_pptp_header*>(m_Data);
360
24.2k
    }
361
362
    /// A static method that validates the input data
363
    /// @param[in] data The pointer to the beginning of a byte stream of a PPP-PPTP packet
364
    /// @param[in] dataLen The length of the byte stream
365
    /// @return True if the data is valid and can represent a PPP-PPTP packet
366
    static inline bool isDataValid(const uint8_t* data, size_t dataLen);
367
368
    // implement abstract methods
369
370
    /// Currently identifies the following next layers: IPv4Layer, IPv6Layer. Otherwise sets PayloadLayer
371
    void parseNextLayer() override;
372
373
    /// @return The size of @ref ppp_pptp_header
374
    size_t getHeaderLen() const override
375
24.6k
    {
376
24.6k
      return sizeof(ppp_pptp_header);
377
24.6k
    }
378
379
    /// Calculate the following fields:
380
    /// - ppp_pptp_header#protocol
381
    void computeCalculateFields() override;
382
383
    std::string toString() const override
384
4.21k
    {
385
4.21k
      return "PPP for PPTP Layer";
386
4.21k
    }
387
388
    OsiModelLayer getOsiModelLayer() const override
389
2.10k
    {
390
2.10k
      return OsiModelSesionLayer;
391
2.10k
    }
392
  };
393
394
  bool PPP_PPTPLayer::isDataValid(const uint8_t* data, size_t dataLen)
395
22.1k
  {
396
22.1k
    return data && dataLen >= sizeof(ppp_pptp_header);
397
22.1k
  }
398
399
}  // namespace pcpp