Coverage Report

Created: 2024-02-25 06:29

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