Skip to content

Commit 2f81414

Browse files
authored
Merge branch 'dev' into feature/parse-options
2 parents 00211fd + bdec00b commit 2f81414

36 files changed

+1124
-540
lines changed

.github/workflows/build_and_test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -746,12 +746,12 @@ jobs:
746746
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
747747
- name: Test in FreeBSD
748748
id: test
749-
uses: vmactions/freebsd-vm@c54ba3b62f49de9b67a2f3af017ab6152f0ebb6f # v1.3.4
749+
uses: vmactions/freebsd-vm@a9c0dcaf5ed572d89ea1a59fe2217d3b3da4fd23 # v1.3.7
750750
with:
751751
release: ${{ matrix.version }}
752752
usesh: true
753753
prepare: |
754-
pkg install -y python bash cmake git gmake gsed libpcap tcpreplay libffi openssl py311-cryptography
754+
pkg install -y pcre2 python bash cmake git gmake gsed libpcap tcpreplay libffi openssl rust
755755
sysctl kern.ipc.maxsockbuf=16777216
756756
run: |
757757
set -e

Packet++/header/Layer.h

Lines changed: 200 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,22 @@ namespace pcpp
264264
return m_NextLayer != nullptr;
265265
}
266266

267+
/// @brief Construct the next layer in the protocol stack. No validation is performed on the data.
268+
///
269+
/// This overload infers the Packet from the current layer.
270+
///
271+
/// @tparam T The type of the layer to construct
272+
/// @tparam Args The types of the arguments to pass to the layer constructor
273+
/// @param data The data to construct the layer from
274+
/// @param dataLen The length of the data
275+
/// @param extraArgs Extra arguments to be forwarded to the layer constructor
276+
/// @return The constructed layer
277+
template <typename T, typename... Args>
278+
Layer* constructNextLayer(uint8_t* data, size_t dataLen, Args&&... extraArgs)
279+
{
280+
return constructNextLayer<T>(data, dataLen, getAttachedPacket(), std::forward<Args>(extraArgs)...);
281+
}
282+
267283
/// Construct the next layer in the protocol stack. No validation is performed on the data.
268284
/// @tparam T The type of the layer to construct
269285
/// @tparam Args The types of the arguments to pass to the layer constructor
@@ -285,6 +301,125 @@ namespace pcpp
285301
return newLayer;
286302
}
287303

304+
/// @brief Construct the next layer in the protocol stack using a factory functor.
305+
///
306+
/// No validation is performed on the data, outside of what the factory functor may perform.
307+
/// If the factory returns a nullptr, no next layer is set.
308+
///
309+
/// The factory functor is expected to have the following signature:
310+
/// Layer* factoryFn(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ...);
311+
///
312+
/// This overload infers the Packet from the current layer.
313+
///
314+
/// @tparam TFactory The factory functor type.
315+
/// @tparam ...Args Parameter pack for extra arguments to pass to the factory functor.
316+
/// @param[in] factoryFn The factory functor to create the layer.
317+
/// @param[in] data The data to construct the layer from
318+
/// @param[in] dataLen The length of the data
319+
/// @param[in] extraArgs Extra arguments to be forwarded to the factory.
320+
/// @return The return value of the factory functor.
321+
template <typename TFactory, typename... Args>
322+
Layer* constructNextLayerFromFactory(TFactory factoryFn, uint8_t* data, size_t dataLen, Args&&... extraArgs)
323+
{
324+
return constructNextLayerFromFactory<TFactory>(factoryFn, data, dataLen, getAttachedPacket(),
325+
std::forward<Args>(extraArgs)...);
326+
}
327+
328+
/// @brief Construct the next layer in the protocol stack using a factory functor.
329+
///
330+
/// No validation is performed on the data, outside of what the factory functor may perform.
331+
/// If the factory returns a nullptr, no next layer is set.
332+
///
333+
/// The factory functor is expected to have the following signature:
334+
/// Layer* factoryFn(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ...);
335+
///
336+
/// @tparam TFactory The factory functor type.
337+
/// @tparam ...Args Parameter pack for extra arguments to pass to the factory functor.
338+
/// @param[in] factoryFn The factory functor to create the layer.
339+
/// @param[in] data The data to construct the layer from
340+
/// @param[in] dataLen The length of the data
341+
/// @param[in] packet The packet the layer belongs to
342+
/// @param[in] extraArgs Extra arguments to be forwarded to the factory.
343+
/// @return The return value of the factory functor.
344+
template <typename TFactory, typename... Args>
345+
Layer* constructNextLayerFromFactory(TFactory factoryFn, uint8_t* data, size_t dataLen, Packet* packet,
346+
Args&&... extraArgs)
347+
{
348+
if (hasNextLayer())
349+
{
350+
throw std::runtime_error("Next layer already exists");
351+
}
352+
353+
// cppcheck-suppress redundantInitialization
354+
Layer* newLayer = factoryFn(data, dataLen, this, packet, std::forward<Args>(extraArgs)...);
355+
setNextLayer(newLayer);
356+
return newLayer;
357+
}
358+
359+
/// Try to construct the next layer in the protocol stack.
360+
///
361+
/// This overload infers the Packet from the current layer.
362+
///
363+
/// The method checks if the data is valid for the layer type T before constructing it by calling
364+
/// T::isDataValid(data, dataLen). If the data is invalid, no layer is constructed and a nullptr is returned.
365+
///
366+
/// @tparam T The type of the layer to construct
367+
/// @tparam Args The types of the extra arguments to pass to the layer constructor
368+
/// @param[in] data The data to construct the layer from
369+
/// @param[in] dataLen The length of the data
370+
/// @param[in] extraArgs Extra arguments to be forwarded to the layer constructor
371+
/// @return The constructed layer or nullptr if the data is invalid
372+
template <typename T, typename... Args>
373+
Layer* tryConstructNextLayer(uint8_t* data, size_t dataLen, Args&&... extraArgs)
374+
{
375+
return tryConstructNextLayer<T>(data, dataLen, getAttachedPacket(), std::forward<Args>(extraArgs)...);
376+
}
377+
378+
/// Try to construct the next layer in the protocol stack.
379+
///
380+
/// The method checks if the data is valid for the layer type T before constructing it by calling
381+
/// T::isDataValid(data, dataLen). If the data is invalid, no layer is constructed and a nullptr is returned.
382+
///
383+
/// @tparam T The type of the layer to construct
384+
/// @tparam Args The types of the extra arguments to pass to the layer constructor
385+
/// @param[in] data The data to construct the layer from
386+
/// @param[in] dataLen The length of the data
387+
/// @param[in] packet The packet the layer belongs to
388+
/// @param[in] extraArgs Extra arguments to be forwarded to the layer constructor
389+
/// @return The constructed layer or nullptr if the data is invalid
390+
template <typename T, typename... Args>
391+
Layer* tryConstructNextLayer(uint8_t* data, size_t dataLen, Packet* packet, Args&&... extraArgs)
392+
{
393+
if (T::isDataValid(data, dataLen))
394+
{
395+
return constructNextLayer<T>(data, dataLen, packet, std::forward<Args>(extraArgs)...);
396+
}
397+
return nullptr;
398+
}
399+
400+
/// @brief Try to construct the next layer in the protocol stack with a fallback option.
401+
///
402+
/// This overload infers the Packet from the current layer.
403+
///
404+
/// The method checks if the data is valid for the layer type T before constructing it by calling
405+
/// T::isDataValid(data, dataLen). If the data is invalid, it constructs the layer of type TFallback.
406+
///
407+
/// @tparam T The type of the layer to construct
408+
/// @tparam TFallback The fallback layer type to construct if T fails
409+
/// @tparam Args The types of the extra arguments to pass to the layer constructor of T
410+
/// @param[in] data The data to construct the layer from
411+
/// @param[in] dataLen The length of the data
412+
/// @param[in] extraArgs Extra arguments to be forwarded to the layer constructor of T
413+
/// @return The constructed layer of type T or TFallback
414+
/// @remarks The parameters extraArgs are forwarded to the factory function, but not to the TFallback
415+
/// constructor.
416+
template <typename T, typename TFallback, typename... Args>
417+
Layer* tryConstructNextLayerWithFallback(uint8_t* data, size_t dataLen, Args&&... extraArgs)
418+
{
419+
return tryConstructNextLayerWithFallback<T, TFallback>(data, dataLen, getAttachedPacket(),
420+
std::forward<Args>(extraArgs)...);
421+
}
422+
288423
/// Try to construct the next layer in the protocol stack with a fallback option.
289424
///
290425
/// The method checks if the data is valid for the layer type T before constructing it by calling
@@ -298,6 +433,8 @@ namespace pcpp
298433
/// @param[in] packet The packet the layer belongs to
299434
/// @param[in] extraArgs Extra arguments to be forwarded to the layer constructor of T
300435
/// @return The constructed layer of type T or TFallback
436+
/// @remarks The parameters extraArgs are forwarded to the factory function, but not to the TFallback
437+
/// constructor.
301438
template <typename T, typename TFallback, typename... Args>
302439
Layer* tryConstructNextLayerWithFallback(uint8_t* data, size_t dataLen, Packet* packet, Args&&... extraArgs)
303440
{
@@ -309,40 +446,82 @@ namespace pcpp
309446
return constructNextLayer<TFallback>(data, dataLen, packet);
310447
}
311448

312-
/// @brief Check if the data is large enough to reinterpret as a type
449+
/// @brief Try to construct the next layer in the protocol stack using a factory functor with a fallback option.
313450
///
314-
/// The data must be non-null and at least as large as the type
451+
/// The method will attempt to construct the next layer using the provided factory function.
452+
/// If the factory function returns nullptr, indicating failure to create the layer, the method will then
453+
/// construct a layer of type TFallback.
315454
///
316-
/// @tparam T The type to reinterpret as
317-
/// @param data The data to check
318-
/// @param dataLen The length of the data
319-
/// @return True if the data is large enough to reinterpret as T, false otherwise
320-
template <typename T> static bool canReinterpretAs(const uint8_t* data, size_t dataLen)
455+
/// The factory functor is expected to have the following signature:
456+
/// Layer* factoryFn(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ...);
457+
///
458+
/// This overload infers the Packet from the current layer.
459+
///
460+
/// @tparam TFallback The fallback layer type to construct if the factory fails.
461+
/// @tparam TFactory The factory functor type.
462+
/// @tparam ...Args Parameter pack for extra arguments to pass to the factory functor.
463+
/// @param[in] factoryFn The factory functor to create the layer.
464+
/// @param[in] data The data to construct the layer from
465+
/// @param[in] dataLen The length of the data
466+
/// @param[in] extraArgs Extra arguments to be forwarded to the factory.
467+
/// @return The return value of the factory functor.
468+
/// @remarks The parameters extraArgs are forwarded to the factory function, but not to the TFallback
469+
/// constructor.
470+
template <typename TFallback, typename TFactory, typename... Args>
471+
Layer* tryConstructNextLayerFromFactoryWithFallback(TFactory factoryFn, uint8_t* data, size_t dataLen,
472+
Args&&... extraArgs)
321473
{
322-
return data != nullptr && dataLen >= sizeof(T);
474+
// Note that the fallback is first to allow template argument deduction of the factory type.
475+
return tryConstructNextLayerFromFactoryWithFallback<TFallback, TFactory>(
476+
factoryFn, data, dataLen, getAttachedPacket(), std::forward<Args>(extraArgs)...);
323477
}
324478

325-
private:
326-
/// Try to construct the next layer in the protocol stack.
479+
/// @brief Try to construct the next layer in the protocol stack using a factory functor with a fallback option.
327480
///
328-
/// The method checks if the data is valid for the layer type T before constructing it by calling
329-
/// T::isDataValid(data, dataLen). If the data is invalid, a nullptr is returned.
481+
/// The method will attempt to construct the next layer using the provided factory function.
482+
/// If the factory function returns nullptr, indicating failure to create the layer, the method will then
483+
/// construct a layer of type TFallback.
330484
///
331-
/// @tparam T The type of the layer to construct
332-
/// @tparam Args The types of the extra arguments to pass to the layer constructor
485+
/// The factory functor is expected to have the following signature:
486+
/// Layer* factoryFn(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ...);
487+
///
488+
/// @tparam TFallback The fallback layer type to construct if the factory fails.
489+
/// @tparam TFactory The factory functor type.
490+
/// @tparam ...Args Parameter pack for extra arguments to pass to the factory functor.
491+
/// @param[in] factoryFn The factory functor to create the layer.
333492
/// @param[in] data The data to construct the layer from
334493
/// @param[in] dataLen The length of the data
335494
/// @param[in] packet The packet the layer belongs to
336-
/// @param[in] extraArgs Extra arguments to be forwarded to the layer constructor
337-
/// @return The constructed layer or nullptr if the data is invalid
338-
template <typename T, typename... Args>
339-
Layer* tryConstructNextLayer(uint8_t* data, size_t dataLen, Packet* packet, Args&&... extraArgs)
495+
/// @param[in] extraArgs Extra arguments to be forwarded to the factory.
496+
/// @return The return value of the factory functor.
497+
/// @remarks The parameters extraArgs are forwarded to the factory function, but not to the TFallback
498+
/// constructor.
499+
template <typename TFallback, typename TFactory, typename... Args>
500+
Layer* tryConstructNextLayerFromFactoryWithFallback(TFactory factoryFn, uint8_t* data, size_t dataLen,
501+
Packet* packet, Args&&... extraArgs)
340502
{
341-
if (T::isDataValid(data, dataLen))
503+
auto nextLayer = constructNextLayerFromFactory<TFactory>(factoryFn, data, dataLen, packet,
504+
std::forward<Args>(extraArgs)...);
505+
if (nextLayer != nullptr)
342506
{
343-
return constructNextLayer<T>(data, dataLen, packet, std::forward<Args>(extraArgs)...);
507+
return nextLayer;
344508
}
345-
return nullptr;
509+
510+
// factory failed, construct fallback layer
511+
return constructNextLayer<TFallback>(data, dataLen, packet);
512+
}
513+
514+
/// @brief Check if the data is large enough to reinterpret as a type
515+
///
516+
/// The data must be non-null and at least as large as the type
517+
///
518+
/// @tparam T The type to reinterpret as
519+
/// @param data The data to check
520+
/// @param dataLen The length of the data
521+
/// @return True if the data is large enough to reinterpret as T, false otherwise
522+
template <typename T> static bool canReinterpretAs(const uint8_t* data, size_t dataLen)
523+
{
524+
return data != nullptr && dataLen >= sizeof(T);
346525
}
347526
};
348527

Packet++/src/BgpLayer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ namespace pcpp
8787
uint8_t* payload = m_Data + headerLen;
8888
size_t payloadLen = m_DataLen - headerLen;
8989

90-
m_NextLayer = BgpLayer::parseBgpLayer(payload, payloadLen, this, getAttachedPacket());
90+
constructNextLayerFromFactory(BgpLayer::parseBgpLayer, payload, payloadLen);
9191
}
9292

9393
std::string BgpLayer::toString() const

Packet++/src/CiscoHdlcLayer.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,17 @@ namespace pcpp
5454
{
5555
case CISCO_HDLC_TYPE_IP:
5656
{
57-
m_NextLayer = IPv4Layer::isDataValid(payload, payloadLen)
58-
? static_cast<Layer*>(new IPv4Layer(payload, payloadLen, this, getAttachedPacket()))
59-
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, getAttachedPacket()));
57+
tryConstructNextLayerWithFallback<IPv4Layer, PayloadLayer>(payload, payloadLen);
6058
break;
6159
}
6260
case CISCO_HDLC_TYPE_IPV6:
6361
{
64-
m_NextLayer = IPv6Layer::isDataValid(payload, payloadLen)
65-
? static_cast<Layer*>(new IPv6Layer(payload, payloadLen, this, getAttachedPacket()))
66-
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, getAttachedPacket()));
62+
tryConstructNextLayerWithFallback<IPv6Layer, PayloadLayer>(payload, payloadLen);
6763
break;
6864
}
6965
default:
7066
{
71-
m_NextLayer = new PayloadLayer(payload, payloadLen, this, getAttachedPacket());
67+
constructNextLayer<PayloadLayer>(payload, payloadLen);
7268
break;
7369
}
7470
}

Packet++/src/CotpLayer.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,6 @@ namespace pcpp
7272
uint8_t* payload = m_Data + headerLen;
7373
size_t payloadLen = m_DataLen - headerLen;
7474

75-
if (S7CommLayer::isDataValid(payload, payloadLen))
76-
m_NextLayer = new S7CommLayer(payload, payloadLen, this, getAttachedPacket());
77-
else
78-
m_NextLayer = new PayloadLayer(payload, payloadLen, this, getAttachedPacket());
75+
tryConstructNextLayerWithFallback<S7CommLayer, PayloadLayer>(payload, payloadLen);
7976
}
8077
} // namespace pcpp

Packet++/src/EthDot3Layer.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,7 @@ namespace pcpp
2929
uint8_t* payload = m_Data + sizeof(ether_dot3_header);
3030
size_t payloadLen = m_DataLen - sizeof(ether_dot3_header);
3131

32-
if (LLCLayer::isDataValid(payload, payloadLen))
33-
m_NextLayer = new LLCLayer(payload, payloadLen, this, getAttachedPacket());
34-
else
35-
m_NextLayer = new PayloadLayer(payload, payloadLen, this, getAttachedPacket());
32+
tryConstructNextLayerWithFallback<LLCLayer, PayloadLayer>(payload, payloadLen);
3633
}
3734

3835
std::string EthDot3Layer::toString() const

Packet++/src/EthLayer.cpp

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,37 +39,35 @@ namespace pcpp
3939
switch (be16toh(hdr->etherType))
4040
{
4141
case PCPP_ETHERTYPE_IP:
42-
tryConstructNextLayerWithFallback<IPv4Layer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
42+
tryConstructNextLayerWithFallback<IPv4Layer, PayloadLayer>(payload, payloadLen);
4343
break;
4444
case PCPP_ETHERTYPE_IPV6:
45-
tryConstructNextLayerWithFallback<IPv6Layer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
45+
tryConstructNextLayerWithFallback<IPv6Layer, PayloadLayer>(payload, payloadLen);
4646
break;
4747
case PCPP_ETHERTYPE_ARP:
48-
tryConstructNextLayerWithFallback<ArpLayer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
48+
tryConstructNextLayerWithFallback<ArpLayer, PayloadLayer>(payload, payloadLen);
4949
break;
5050
case PCPP_ETHERTYPE_VLAN:
5151
case PCPP_ETHERTYPE_IEEE_802_1AD:
52-
tryConstructNextLayerWithFallback<VlanLayer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
52+
tryConstructNextLayerWithFallback<VlanLayer, PayloadLayer>(payload, payloadLen);
5353
break;
5454
case PCPP_ETHERTYPE_PPPOES:
55-
tryConstructNextLayerWithFallback<PPPoESessionLayer, PayloadLayer>(payload, payloadLen,
56-
getAttachedPacket());
55+
tryConstructNextLayerWithFallback<PPPoESessionLayer, PayloadLayer>(payload, payloadLen);
5756
break;
5857
case PCPP_ETHERTYPE_PPPOED:
59-
tryConstructNextLayerWithFallback<PPPoEDiscoveryLayer, PayloadLayer>(payload, payloadLen,
60-
getAttachedPacket());
58+
tryConstructNextLayerWithFallback<PPPoEDiscoveryLayer, PayloadLayer>(payload, payloadLen);
6159
break;
6260
case PCPP_ETHERTYPE_MPLS:
63-
tryConstructNextLayerWithFallback<MplsLayer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
61+
tryConstructNextLayerWithFallback<MplsLayer, PayloadLayer>(payload, payloadLen);
6462
break;
6563
case PCPP_ETHERTYPE_WAKE_ON_LAN:
66-
tryConstructNextLayerWithFallback<WakeOnLanLayer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
64+
tryConstructNextLayerWithFallback<WakeOnLanLayer, PayloadLayer>(payload, payloadLen);
6765
break;
6866
}
6967

7068
// If no next layer was constructed, assume it's a payload layer
7169
if (!hasNextLayer())
72-
constructNextLayer<PayloadLayer>(payload, payloadLen, getAttachedPacket());
70+
constructNextLayer<PayloadLayer>(payload, payloadLen);
7371
}
7472

7573
void EthLayer::computeCalculateFields()

0 commit comments

Comments
 (0)