Coverage Report

Created: 2026-10-17 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/header/WireGuardLayer.h
Line
Count
Source
1
#pragma once
2
3
#include "Layer.h"
4
#include "IpAddress.h"
5
#include "MacAddress.h"
6
7
/// @file
8
9
/// @namespace pcpp
10
/// @brief The main namespace for the PcapPlusPlus lib
11
namespace pcpp
12
{
13
  /// @class WireGuardLayer
14
  /// Represents a WireGuard protocol layer
15
  class WireGuardLayer : public Layer
16
  {
17
  protected:
18
#pragma pack(push, 1)
19
    /// @struct wg_common_header
20
    /// Represents the common header for all WireGuard message types
21
    struct wg_common_header
22
    {
23
      /// Message type field
24
      uint8_t messageType;
25
      /// Reserved field (3 bytes)
26
      uint8_t reserved[3];
27
    };
28
#pragma pack(pop)
29
    static_assert(sizeof(wg_common_header) == 4, "wg_common_header size is not 4 bytes");
30
31
    wg_common_header* getBasicHeader() const
32
1.56k
    {
33
1.56k
      return reinterpret_cast<wg_common_header*>(m_Data);
34
1.56k
    }
35
36
0
    WireGuardLayer() = default;
37
38
  public:
39
    /// WireGuard message types
40
    enum class WireGuardMessageType
41
    {
42
      /// Unknown Initiation message
43
      Unknown = 0,
44
      /// Handshake Initiation message
45
      HandshakeInitiation = 1,
46
      /// Handshake Response message
47
      HandshakeResponse = 2,
48
      /// Cookie Reply message
49
      CookieReply = 3,
50
      /// Transport Data message
51
      TransportData = 4
52
    };
53
54
    /// Constructs a WireGuardLayer object.
55
    /// @param data Pointer to the raw data representing the WireGuard layer
56
    /// @param dataLen Length of the data
57
    /// @param prevLayer Pointer to the previous layer in the packet (if any)
58
    /// @param packet Pointer to the packet this layer belongs to
59
    WireGuardLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
60
3.92k
        : Layer(data, dataLen, prevLayer, packet, WireGuard)
61
3.92k
    {}
62
63
    /// Checks if the given port numbers are WireGuard ports.
64
    /// @param portSrc The source port number to check
65
    /// @param portDst The destination port number to check
66
    /// @return True if either port matches the WireGuard port (51820), false otherwise
67
    static bool isWireGuardPorts(uint16_t portSrc, uint16_t portDst)
68
99.4k
    {
69
99.4k
      return (portSrc == 51820 || portDst == 51820);
70
99.4k
    }
71
72
    /// Checks if the given data represents a WireGuard message.
73
    /// @param data Pointer to the raw data
74
    /// @param dataLen Length of the data
75
    /// @return True if the data starts with a valid WireGuard message type, false otherwise
76
    static bool isDataValid(const uint8_t* data, size_t dataLen);
77
78
    /// Parses the raw data into a WireGuard layer.
79
    /// @param data Pointer to the raw data
80
    /// @param dataLen Length of the data
81
    /// @param prevLayer Pointer to the previous layer
82
    /// @param packet Pointer to the packet
83
    /// @return A pointer to the parsed WireGuardLayer, or nullptr if parsing fails
84
    static WireGuardLayer* parseWireGuardLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
85
86
    /// @return String representation of the message type.
87
    std::string getMessageTypeAsString() const;
88
89
    /// @return The message type as an unsigned 32-bit integer.
90
    uint8_t getMessageType() const;
91
92
    /// @return The reserved field as a 32-bit integer.
93
    uint32_t getReserved() const;
94
95
    /// @param reserved The reserved field to set as a An array containing the 3-byte.
96
    void setReserved(const std::array<uint8_t, 3>& reserved);
97
98
    /// Does nothing for this layer (WireGuard layer is always last)
99
    void parseNextLayer() override
100
3.92k
    {}
101
102
    /// @return Size of the header in bytes.
103
    size_t getHeaderLen() const override;
104
105
    /// No fields to compute or update, so this method is left empty.
106
    void computeCalculateFields() override
107
784
    {}
108
109
    /// Converts the WireGuard layer to a string representation.
110
    /// @return String representation of the WireGuard layer
111
    std::string toString() const override;
112
113
    /// @return OSI model layer corresponding to the Network layer
114
    OsiModelLayer getOsiModelLayer() const override
115
784
    {
116
784
      return OsiModelNetworkLayer;
117
784
    }
118
119
    /// @return The message type as a WireGuardMessageType enum value.
120
    virtual WireGuardMessageType getWireGuardMessageType() const
121
0
    {
122
0
      return WireGuardMessageType::Unknown;
123
0
    }
124
  };
125
126
  /// @class WireGuardHandshakeInitiationLayer
127
  /// Represents the Handshake Initiation message layer
128
  class WireGuardHandshakeInitiationLayer : public WireGuardLayer
129
  {
130
  private:
131
#pragma pack(push, 1)
132
    /// @struct wg_handshake_initiation
133
    /// Represents the Handshake Initiation message structure
134
    typedef struct wg_handshake_initiation : wg_common_header
135
    {
136
      /// Sender index
137
      uint32_t senderIndex;
138
      /// Initiator's ephemeral public key
139
      uint8_t initiatorEphemeral[32];
140
      /// Encrypted initiator's static key
141
      uint8_t encryptedInitiatorStatic[48];
142
      /// Encrypted timestamp
143
      uint8_t encryptedTimestamp[28];
144
      /// MAC1 field
145
      uint8_t mac1[16];
146
      /// MAC2 field
147
      uint8_t mac2[16];
148
    } wg_handshake_initiation;
149
#pragma pack(pop)
150
    wg_handshake_initiation* getHandshakeInitiationHeader() const
151
0
    {
152
0
      return reinterpret_cast<wg_handshake_initiation*>(getBasicHeader());
153
0
    }
154
155
  public:
156
    /// A constructor that creates the layer from an existing packet raw data
157
    /// @param[in] data A pointer to the raw data
158
    /// @param[in] dataLen Size of the data in bytes
159
    /// @param[in] prevLayer A pointer to the previous layer
160
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
161
    WireGuardHandshakeInitiationLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
162
651
        : WireGuardLayer(data, dataLen, prevLayer, packet)
163
651
    {}
164
165
    /// A static method that checks whether a byte stream is long enough to hold a WireGuard Handshake Initiation
166
    /// message
167
    /// @param[in] data A pointer to the beginning of the message
168
    /// @param[in] dataLen The length of the byte stream
169
    /// @return True if the data is at least as long as the fixed part of the message, false otherwise
170
    static bool isDataValid(const uint8_t* data, size_t dataLen)
171
651
    {
172
651
      return data != nullptr && dataLen >= sizeof(wg_handshake_initiation);
173
651
    }
174
175
    /// A constructor that creates a new Handshake Initiation message
176
    /// @param[in] senderIndex The sender's index
177
    /// @param[in] initiatorEphemeral The initiator's ephemeral public key
178
    /// @param[in] encryptedInitiatorStatic The encrypted initiator's static key
179
    /// @param[in] encryptedTimestamp The encrypted timestamp
180
    /// @param[in] mac1 The MAC1 field
181
    /// @param[in] mac2 The MAC2 field
182
    WireGuardHandshakeInitiationLayer(uint32_t senderIndex, const uint8_t initiatorEphemeral[32],
183
                                      const uint8_t encryptedInitiatorStatic[48],
184
                                      const uint8_t encryptedTimestamp[28], const uint8_t mac1[16],
185
                                      const uint8_t mac2[16]);
186
187
    /// @return The sender index as a 32-bit integer.
188
    uint32_t getSenderIndex() const;
189
190
    /// @return An array containing the initiator's ephemeral public key.
191
    std::array<uint8_t, 32> getInitiatorEphemeral() const;
192
193
    /// @return An array containing the encrypted initiator's static key.
194
    std::array<uint8_t, 48> getEncryptedInitiatorStatic() const;
195
196
    /// @return An array containing the encrypted timestamp.
197
    std::array<uint8_t, 28> getEncryptedTimestamp() const;
198
199
    /// @return An array containing the MAC1 field.
200
    std::array<uint8_t, 16> getMac1() const;
201
202
    /// @return An array containing the MAC2 field.
203
    std::array<uint8_t, 16> getMac2() const;
204
205
    /// @param senderIndex A 32-bit integer representing the sender index.
206
    void setSenderIndex(uint32_t senderIndex);
207
208
    /// @param initiatorEphemeral An array containing the 32-byte initiator ephemeral public key.
209
    void setInitiatorEphemeral(const std::array<uint8_t, 32>& initiatorEphemeral);
210
211
    /// @param encryptedInitiatorStatic An array containing the 48-byte encrypted initiator's static key.
212
    void setEncryptedInitiatorStatic(const std::array<uint8_t, 48>& encryptedInitiatorStatic);
213
214
    /// @param encryptedTimestamp An array containing the 28-byte encrypted timestamp.
215
    void setEncryptedTimestamp(const std::array<uint8_t, 28>& encryptedTimestamp);
216
217
    /// @param mac1 An array containing the 16-byte MAC1 field.
218
    void setMac1(const std::array<uint8_t, 16>& mac1);
219
220
    /// @param mac2 An array containing the 16-byte MAC2 field.
221
    void setMac2(const std::array<uint8_t, 16>& mac2);
222
223
    // implement abstract methods
224
225
    /// @return WireGuardMessageType enum value indicating HandshakeInitiation.
226
    WireGuardMessageType getWireGuardMessageType() const override
227
0
    {
228
0
      return WireGuardMessageType::HandshakeInitiation;
229
0
    }
230
  };
231
232
  /// @class WireGuardHandshakeResponseLayer
233
  /// Represents a Handshake Response message
234
  class WireGuardHandshakeResponseLayer : public WireGuardLayer
235
  {
236
  private:
237
#pragma pack(push, 1)
238
    /// @struct wg_handshake_response
239
    /// Represents the Handshake Response message structure
240
    typedef struct wg_handshake_response : wg_common_header
241
    {
242
      /// Sender index
243
      uint32_t senderIndex;
244
      /// Receiver index
245
      uint32_t receiverIndex;
246
      /// Responder's ephemeral public key
247
      uint8_t responderEphemeral[32];
248
      /// Encrypted empty field
249
      uint8_t encryptedEmpty[16];
250
      /// MAC1 field
251
      uint8_t mac1[16];
252
      /// MAC2 field
253
      uint8_t mac2[16];
254
    } wg_handshake_response;
255
#pragma pack(pop)
256
257
    wg_handshake_response* getHandshakeResponseHeader() const
258
0
    {
259
0
      return reinterpret_cast<wg_handshake_response*>(getBasicHeader());
260
0
    }
261
262
  public:
263
    /// A constructor that creates the layer from an existing packet raw data
264
    /// @param[in] data A pointer to the raw data
265
    /// @param[in] dataLen Size of the data in bytes
266
    /// @param[in] prevLayer A pointer to the previous layer
267
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
268
    WireGuardHandshakeResponseLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
269
1.05k
        : WireGuardLayer(data, dataLen, prevLayer, packet)
270
1.05k
    {}
271
272
    /// A static method that checks whether a byte stream is long enough to hold a WireGuard Handshake Response
273
    /// message
274
    /// @param[in] data A pointer to the beginning of the message
275
    /// @param[in] dataLen The length of the byte stream
276
    /// @return True if the data is at least as long as the fixed part of the message, false otherwise
277
    static bool isDataValid(const uint8_t* data, size_t dataLen)
278
1.06k
    {
279
1.06k
      return data != nullptr && dataLen >= sizeof(wg_handshake_response);
280
1.06k
    }
281
282
    /// A constructor that creates a new Handshake Response message
283
    /// @param[in] senderIndex The sender index
284
    /// @param[in] receiverIndex The receiver index
285
    /// @param[in] responderEphemeral The responder's ephemeral public key
286
    /// @param[in] encryptedEmpty The encrypted empty field
287
    /// @param[in] mac1 The MAC1 field
288
    /// @param[in] mac2 The MAC2 field
289
    WireGuardHandshakeResponseLayer(uint32_t senderIndex, uint32_t receiverIndex,
290
                                    const uint8_t responderEphemeral[32], const uint8_t encryptedEmpty[16],
291
                                    const uint8_t mac1[16], const uint8_t mac2[16]);
292
293
    /// @return The sender index as a 32-bit unsigned integer.
294
    uint32_t getSenderIndex() const;
295
296
    /// @return The receiver index as a 32-bit unsigned integer.
297
    uint32_t getReceiverIndex() const;
298
299
    /// @return The responder's ephemeral public key as an array of 32 bytes.
300
    std::array<uint8_t, 32> getResponderEphemeral() const;
301
302
    /// @return The encrypted empty field as an array of 16 bytes.
303
    std::array<uint8_t, 16> getEncryptedEmpty() const;
304
305
    /// @return The MAC1 field as an array of 16 bytes.
306
    std::array<uint8_t, 16> getMac1() const;
307
308
    /// @return The MAC2 field as an array of 16 bytes.
309
    std::array<uint8_t, 16> getMac2() const;
310
311
    /// @param senderIndex A 32-bit unsigned integer representing the sender index.
312
    void setSenderIndex(uint32_t senderIndex);
313
314
    /// @param receiverIndex A 32-bit unsigned integer representing the receiver index.
315
    void setReceiverIndex(uint32_t receiverIndex);
316
317
    /// @param responderEphemeral An array containing the 32-byte responder ephemeral public key.
318
    void setResponderEphemeral(const std::array<uint8_t, 32>& responderEphemeral);
319
320
    /// @param encryptedEmpty An array containing the 16-byte encrypted empty field.
321
    void setEncryptedEmpty(const std::array<uint8_t, 16>& encryptedEmpty);
322
323
    /// @param mac1 An array containing the 16-byte MAC1 field.
324
    void setMac1(const std::array<uint8_t, 16>& mac1);
325
326
    /// @param mac2 An array containing the 16-byte MAC2 field.
327
    void setMac2(const std::array<uint8_t, 16>& mac2);
328
329
    // implement abstract methods
330
331
    /// @return The message type as a WireGuardMessageType enum value.
332
    WireGuardMessageType getWireGuardMessageType() const override
333
0
    {
334
0
      return WireGuardMessageType::HandshakeResponse;
335
0
    }
336
  };
337
338
  /// @class WireGuardCookieReplyLayer
339
  /// Represents a Cookie Reply message
340
  class WireGuardCookieReplyLayer : public WireGuardLayer
341
  {
342
  private:
343
#pragma pack(push, 1)
344
    /// @struct wg_cookie_reply
345
    /// Represents the Cookie Reply message structure
346
    typedef struct wg_cookie_reply : wg_common_header
347
    {
348
      /// Receiver index
349
      uint32_t receiverIndex;
350
      /// Nonce field
351
      uint8_t nonce[24];
352
      /// Encrypted cookie
353
      uint8_t encryptedCookie[32];
354
    } wg_cookie_reply;
355
#pragma pack(pop)
356
357
    wg_cookie_reply* getCookieReplyHeader() const
358
0
    {
359
0
      return reinterpret_cast<wg_cookie_reply*>(getBasicHeader());
360
0
    }
361
362
  public:
363
    /// A constructor that creates the layer from an existing packet raw data
364
    /// @param[in] data A pointer to the raw data
365
    /// @param[in] dataLen Size of the data in bytes
366
    /// @param[in] prevLayer A pointer to the previous layer
367
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
368
    WireGuardCookieReplyLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
369
140
        : WireGuardLayer(data, dataLen, prevLayer, packet)
370
140
    {}
371
372
    /// A static method that checks whether a byte stream is long enough to hold a WireGuard Cookie Reply message
373
    /// @param[in] data A pointer to the beginning of the message
374
    /// @param[in] dataLen The length of the byte stream
375
    /// @return True if the data is at least as long as the fixed part of the message, false otherwise
376
    static bool isDataValid(const uint8_t* data, size_t dataLen)
377
140
    {
378
140
      return data != nullptr && dataLen >= sizeof(wg_cookie_reply);
379
140
    }
380
381
    /// A constructor that creates a new Cookie Reply message
382
    /// @param[in] receiverIndex The receiver index
383
    /// @param[in] nonce The nonce field
384
    /// @param[in] encryptedCookie The encrypted cookie
385
    WireGuardCookieReplyLayer(uint32_t receiverIndex, const uint8_t nonce[24], const uint8_t encryptedCookie[32]);
386
387
    /// @return The receiver index as a 32-bit unsigned integer.
388
    uint32_t getReceiverIndex() const;
389
390
    /// @return The nonce field as an array of 24 bytes.
391
    std::array<uint8_t, 24> getNonce() const;
392
393
    /// @return The encrypted cookie as an array of 32 bytes.
394
    std::array<uint8_t, 32> getEncryptedCookie() const;
395
396
    /// @param receiverIndex A 32-bit unsigned integer representing the receiver index.
397
    void setReceiverIndex(uint32_t receiverIndex);
398
399
    /// @param nonce An array containing the 24-byte nonce field.
400
    void setNonce(const std::array<uint8_t, 24>& nonce);
401
402
    /// @param encryptedCookie An array containing the 32-byte encrypted cookie.
403
    void setEncryptedCookie(const std::array<uint8_t, 32>& encryptedCookie);
404
405
    // implement abstract methods
406
407
    /// @return The message type as a WireGuardMessageType enum value.
408
    WireGuardMessageType getWireGuardMessageType() const override
409
0
    {
410
0
      return WireGuardMessageType::CookieReply;
411
0
    }
412
  };
413
414
  /// @class WireGuardTransportDataLayer
415
  /// Represents a Transport Data message
416
  class WireGuardTransportDataLayer : public WireGuardLayer
417
  {
418
  private:
419
#pragma pack(push, 1)
420
    /// @struct wg_transport_data
421
    /// Represents the Transport Data message structure
422
    typedef struct wg_transport_data : wg_common_header
423
    {
424
      /// Receiver index
425
      uint32_t receiverIndex;
426
      /// Counter field
427
      uint64_t counter;
428
      /// Flexible array member for encrypted data
429
      uint8_t encryptedData[0];
430
    } wg_transport_data;
431
#pragma pack(pop)
432
433
    wg_transport_data* getTransportHeader() const
434
0
    {
435
0
      return reinterpret_cast<wg_transport_data*>(getBasicHeader());
436
0
    }
437
438
  public:
439
    /// A constructor that creates the layer from an existing packet raw data
440
    /// @param[in] data A pointer to the raw data
441
    /// @param[in] dataLen Size of the data in bytes
442
    /// @param[in] prevLayer A pointer to the previous layer
443
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
444
    WireGuardTransportDataLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
445
2.07k
        : WireGuardLayer(data, dataLen, prevLayer, packet)
446
2.07k
    {}
447
448
    /// A static method that checks whether a byte stream is long enough to hold a WireGuard Transport Data message
449
    /// @param[in] data A pointer to the beginning of the message
450
    /// @param[in] dataLen The length of the byte stream
451
    /// @return True if the data is at least as long as the fixed part of the message, false otherwise
452
    static bool isDataValid(const uint8_t* data, size_t dataLen)
453
2.08k
    {
454
2.08k
      return data != nullptr && dataLen >= sizeof(wg_transport_data);
455
2.08k
    }
456
457
    /// A constructor that creates a new Transport Data message
458
    /// @param[in] receiverIndex The receiver index
459
    /// @param[in] counter The counter field
460
    /// @param[in] encryptedData The encrypted data
461
    /// @param[in] encryptedDataLen The length of the encrypted data
462
    WireGuardTransportDataLayer(uint32_t receiverIndex, uint64_t counter, const uint8_t* encryptedData,
463
                                size_t encryptedDataLen);
464
465
    /// @return The receiver index as a 32-bit unsigned integer.
466
    uint32_t getReceiverIndex() const;
467
468
    /// @return The counter field as a 64-bit unsigned integer.
469
    uint64_t getCounter() const;
470
471
    /// @return A pointer to the encrypted data field.
472
    const uint8_t* getEncryptedData() const;
473
474
    /// @param receiverIndex A 32-bit unsigned integer representing the receiver index.
475
    void setReceiverIndex(uint32_t receiverIndex);
476
477
    /// @param counter A 64-bit unsigned integer representing the counter field.
478
    void setCounter(uint64_t counter);
479
480
    /// Set the encrypted data, extending or shortening the layer to fit it
481
    /// @param encryptedData A pointer to the encrypted data.
482
    /// @param encryptedDataLen The length of the encrypted data.
483
    void setEncryptedData(const uint8_t* encryptedData, size_t encryptedDataLen);
484
485
    // implement abstract methods
486
487
    /// @return The message type as a WireGuardMessageType enum value.
488
    WireGuardMessageType getWireGuardMessageType() const override
489
0
    {
490
0
      return WireGuardMessageType::TransportData;
491
0
    }
492
  };
493
}  // namespace pcpp