Coverage Report

Created: 2025-07-11 07:47

/src/PcapPlusPlus/Packet++/header/WireGuardLayer.h
Line
Count
Source (jump to first uncovered line)
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
172
    {
33
172
      return reinterpret_cast<wg_common_header*>(m_Data);
34
172
    }
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
430
        : Layer(data, dataLen, prevLayer, packet, WireGuard)
61
430
    {}
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
16.4k
    {
69
16.4k
      return (portSrc == 51820 || portDst == 51820);
70
16.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
430
    {}
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
86
    {}
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
86
    {
116
86
      return OsiModelNetworkLayer;
117
86
    }
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
75
        : WireGuardLayer(data, dataLen, prevLayer, packet)
163
75
    {}
164
165
    /// A constructor that creates a new Handshake Initiation message
166
    /// @param[in] senderIndex The sender's index
167
    /// @param[in] initiatorEphemeral The initiator's ephemeral public key
168
    /// @param[in] encryptedInitiatorStatic The encrypted initiator's static key
169
    /// @param[in] encryptedTimestamp The encrypted timestamp
170
    /// @param[in] mac1 The MAC1 field
171
    /// @param[in] mac2 The MAC2 field
172
    WireGuardHandshakeInitiationLayer(uint32_t senderIndex, const uint8_t initiatorEphemeral[32],
173
                                      const uint8_t encryptedInitiatorStatic[48],
174
                                      const uint8_t encryptedTimestamp[28], const uint8_t mac1[16],
175
                                      const uint8_t mac2[16]);
176
177
    /// @return The sender index as a 32-bit integer.
178
    uint32_t getSenderIndex() const;
179
180
    /// @return An array containing the initiator's ephemeral public key.
181
    std::array<uint8_t, 32> getInitiatorEphemeral() const;
182
183
    /// @return An array containing the encrypted initiator's static key.
184
    std::array<uint8_t, 48> getEncryptedInitiatorStatic() const;
185
186
    /// @return An array containing the encrypted timestamp.
187
    std::array<uint8_t, 28> getEncryptedTimestamp() const;
188
189
    /// @return An array containing the MAC1 field.
190
    std::array<uint8_t, 16> getMac1() const;
191
192
    /// @return An array containing the MAC2 field.
193
    std::array<uint8_t, 16> getMac2() const;
194
195
    /// @param senderIndex A 32-bit integer representing the sender index.
196
    void setSenderIndex(uint32_t senderIndex);
197
198
    /// @param initiatorEphemeral An array containing the 32-byte initiator ephemeral public key.
199
    void setInitiatorEphemeral(const std::array<uint8_t, 32>& initiatorEphemeral);
200
201
    /// @param encryptedInitiatorStatic An array containing the 48-byte encrypted initiator's static key.
202
    void setEncryptedInitiatorStatic(const std::array<uint8_t, 48>& encryptedInitiatorStatic);
203
204
    /// @param encryptedTimestamp An array containing the 28-byte encrypted timestamp.
205
    void setEncryptedTimestamp(const std::array<uint8_t, 28>& encryptedTimestamp);
206
207
    /// @param mac1 An array containing the 16-byte MAC1 field.
208
    void setMac1(const std::array<uint8_t, 16>& mac1);
209
210
    /// @param mac2 An array containing the 16-byte MAC2 field.
211
    void setMac2(const std::array<uint8_t, 16>& mac2);
212
213
    // implement abstract methods
214
215
    /// @return WireGuardMessageType enum value indicating HandshakeInitiation.
216
    WireGuardMessageType getWireGuardMessageType() const override
217
0
    {
218
0
      return WireGuardMessageType::HandshakeInitiation;
219
0
    }
220
  };
221
222
  /// @class WireGuardHandshakeResponseLayer
223
  /// Represents a Handshake Response message
224
  class WireGuardHandshakeResponseLayer : public WireGuardLayer
225
  {
226
  private:
227
#pragma pack(push, 1)
228
    /// @struct wg_handshake_response
229
    /// Represents the Handshake Response message structure
230
    typedef struct wg_handshake_response : wg_common_header
231
    {
232
      /// Sender index
233
      uint32_t senderIndex;
234
      /// Receiver index
235
      uint32_t receiverIndex;
236
      /// Responder's ephemeral public key
237
      uint8_t responderEphemeral[32];
238
      /// Encrypted empty field
239
      uint8_t encryptedEmpty[16];
240
      /// MAC1 field
241
      uint8_t mac1[16];
242
      /// MAC2 field
243
      uint8_t mac2[16];
244
    } wg_handshake_response;
245
#pragma pack(pop)
246
247
    wg_handshake_response* getHandshakeResponseHeader() const
248
0
    {
249
0
      return reinterpret_cast<wg_handshake_response*>(getBasicHeader());
250
0
    }
251
252
  public:
253
    /// A constructor that creates the layer from an existing packet raw data
254
    /// @param[in] data A pointer to the raw data
255
    /// @param[in] dataLen Size of the data in bytes
256
    /// @param[in] prevLayer A pointer to the previous layer
257
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
258
    WireGuardHandshakeResponseLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
259
55
        : WireGuardLayer(data, dataLen, prevLayer, packet)
260
55
    {}
261
262
    /// A constructor that creates a new Handshake Response message
263
    /// @param[in] senderIndex The sender index
264
    /// @param[in] receiverIndex The receiver index
265
    /// @param[in] responderEphemeral The responder's ephemeral public key
266
    /// @param[in] encryptedEmpty The encrypted empty field
267
    /// @param[in] mac1 The MAC1 field
268
    /// @param[in] mac2 The MAC2 field
269
    WireGuardHandshakeResponseLayer(uint32_t senderIndex, uint32_t receiverIndex,
270
                                    const uint8_t responderEphemeral[32], const uint8_t encryptedEmpty[16],
271
                                    const uint8_t mac1[16], const uint8_t mac2[16]);
272
273
    /// @return The sender index as a 32-bit unsigned integer.
274
    uint32_t getSenderIndex() const;
275
276
    /// @return The receiver index as a 32-bit unsigned integer.
277
    uint32_t getReceiverIndex() const;
278
279
    /// @return The responder's ephemeral public key as an array of 32 bytes.
280
    std::array<uint8_t, 32> getResponderEphemeral() const;
281
282
    /// @return The encrypted empty field as an array of 16 bytes.
283
    std::array<uint8_t, 16> getEncryptedEmpty() const;
284
285
    /// @return The MAC1 field as an array of 16 bytes.
286
    std::array<uint8_t, 16> getMac1() const;
287
288
    /// @return The MAC2 field as an array of 16 bytes.
289
    std::array<uint8_t, 16> getMac2() const;
290
291
    /// @param senderIndex A 32-bit unsigned integer representing the sender index.
292
    void setSenderIndex(uint32_t senderIndex);
293
294
    /// @param receiverIndex A 32-bit unsigned integer representing the receiver index.
295
    void setReceiverIndex(uint32_t receiverIndex);
296
297
    /// @param responderEphemeral An array containing the 32-byte responder ephemeral public key.
298
    void setResponderEphemeral(const std::array<uint8_t, 32>& responderEphemeral);
299
300
    /// @param encryptedEmpty An array containing the 16-byte encrypted empty field.
301
    void setEncryptedEmpty(const std::array<uint8_t, 16>& encryptedEmpty);
302
303
    /// @param mac1 An array containing the 16-byte MAC1 field.
304
    void setMac1(const std::array<uint8_t, 16>& mac1);
305
306
    /// @param mac2 An array containing the 16-byte MAC2 field.
307
    void setMac2(const std::array<uint8_t, 16>& mac2);
308
309
    // implement abstract methods
310
311
    /// @return The message type as a WireGuardMessageType enum value.
312
    WireGuardMessageType getWireGuardMessageType() const override
313
0
    {
314
0
      return WireGuardMessageType::HandshakeResponse;
315
0
    }
316
  };
317
318
  /// @class WireGuardCookieReplyLayer
319
  /// Represents a Cookie Reply message
320
  class WireGuardCookieReplyLayer : public WireGuardLayer
321
  {
322
  private:
323
#pragma pack(push, 1)
324
    /// @struct wg_cookie_reply
325
    /// Represents the Cookie Reply message structure
326
    typedef struct wg_cookie_reply : wg_common_header
327
    {
328
      /// Receiver index
329
      uint32_t receiverIndex;
330
      /// Nonce field
331
      uint8_t nonce[24];
332
      /// Encrypted cookie
333
      uint8_t encryptedCookie[32];
334
    } wg_cookie_reply;
335
#pragma pack(pop)
336
337
    wg_cookie_reply* getCookieReplyHeader() const
338
0
    {
339
0
      return reinterpret_cast<wg_cookie_reply*>(getBasicHeader());
340
0
    }
341
342
  public:
343
    /// A constructor that creates the layer from an existing packet raw data
344
    /// @param[in] data A pointer to the raw data
345
    /// @param[in] dataLen Size of the data in bytes
346
    /// @param[in] prevLayer A pointer to the previous layer
347
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
348
    WireGuardCookieReplyLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
349
5
        : WireGuardLayer(data, dataLen, prevLayer, packet)
350
5
    {}
351
352
    /// A constructor that creates a new Cookie Reply message
353
    /// @param[in] receiverIndex The receiver index
354
    /// @param[in] nonce The nonce field
355
    /// @param[in] encryptedCookie The encrypted cookie
356
    WireGuardCookieReplyLayer(uint32_t receiverIndex, const uint8_t nonce[24], const uint8_t encryptedCookie[32]);
357
358
    /// @return The receiver index as a 32-bit unsigned integer.
359
    uint32_t getReceiverIndex() const;
360
361
    /// @return The nonce field as an array of 24 bytes.
362
    std::array<uint8_t, 24> getNonce() const;
363
364
    /// @return The encrypted cookie as an array of 32 bytes.
365
    std::array<uint8_t, 32> getEncryptedCookie() const;
366
367
    /// @param receiverIndex A 32-bit unsigned integer representing the receiver index.
368
    void setReceiverIndex(uint32_t receiverIndex);
369
370
    /// @param nonce An array containing the 24-byte nonce field.
371
    void setNonce(const std::array<uint8_t, 24>& nonce);
372
373
    /// @param encryptedCookie An array containing the 32-byte encrypted cookie.
374
    void setEncryptedCookie(const std::array<uint8_t, 32>& encryptedCookie);
375
376
    // implement abstract methods
377
378
    /// @return The message type as a WireGuardMessageType enum value.
379
    WireGuardMessageType getWireGuardMessageType() const override
380
0
    {
381
0
      return WireGuardMessageType::CookieReply;
382
0
    }
383
  };
384
385
  /// @class WireGuardTransportDataLayer
386
  /// Represents a Transport Data message
387
  class WireGuardTransportDataLayer : public WireGuardLayer
388
  {
389
  private:
390
#pragma pack(push, 1)
391
    /// @struct wg_transport_data
392
    /// Represents the Transport Data message structure
393
    typedef struct wg_transport_data : wg_common_header
394
    {
395
      /// Receiver index
396
      uint32_t receiverIndex;
397
      /// Counter field
398
      uint64_t counter;
399
      /// Flexible array member for encrypted data
400
      uint8_t encryptedData[0];
401
    } wg_transport_data;
402
#pragma pack(pop)
403
404
    wg_transport_data* getTransportHeader() const
405
0
    {
406
0
      return reinterpret_cast<wg_transport_data*>(getBasicHeader());
407
0
    }
408
409
  public:
410
    /// A constructor that creates the layer from an existing packet raw data
411
    /// @param[in] data A pointer to the raw data
412
    /// @param[in] dataLen Size of the data in bytes
413
    /// @param[in] prevLayer A pointer to the previous layer
414
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
415
    WireGuardTransportDataLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
416
295
        : WireGuardLayer(data, dataLen, prevLayer, packet)
417
295
    {}
418
419
    /// A constructor that creates a new Transport Data message
420
    /// @param[in] receiverIndex The receiver index
421
    /// @param[in] counter The counter field
422
    /// @param[in] encryptedData The encrypted data
423
    /// @param[in] encryptedDataLen The length of the encrypted data
424
    WireGuardTransportDataLayer(uint32_t receiverIndex, uint64_t counter, const uint8_t* encryptedData,
425
                                size_t encryptedDataLen);
426
427
    /// @return The receiver index as a 32-bit unsigned integer.
428
    uint32_t getReceiverIndex() const;
429
430
    /// @return The counter field as a 64-bit unsigned integer.
431
    uint64_t getCounter() const;
432
433
    /// @return A pointer to the encrypted data field.
434
    const uint8_t* getEncryptedData() const;
435
436
    /// @param receiverIndex A 32-bit unsigned integer representing the receiver index.
437
    void setReceiverIndex(uint32_t receiverIndex);
438
439
    /// @param counter A 64-bit unsigned integer representing the counter field.
440
    void setCounter(uint64_t counter);
441
442
    /// @param encryptedData A pointer to the encrypted data.
443
    /// @param encryptedDataLen The length of the encrypted data.
444
    void setEncryptedData(const uint8_t* encryptedData, size_t encryptedDataLen);
445
446
    // implement abstract methods
447
448
    /// @return The message type as a WireGuardMessageType enum value.
449
    WireGuardMessageType getWireGuardMessageType() const override
450
0
    {
451
0
      return WireGuardMessageType::TransportData;
452
0
    }
453
  };
454
}  // namespace pcpp