srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/include/wireframe/net/icmp.hpp
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2024-05-17 19:54:00 +0200
committersrdusr <[email protected]>2024-05-17 19:54:00 +0200
commite0f4c701028aa81026a17cf9ebfb36112184f4bc (patch)
tree31c05e4ccbba0dd2ab4c0567630275ebfc6cd264 /include/wireframe/net/icmp.hpp
parent08332a4195956611db80a2cfe3710d760cbd6acf (diff)
downloadpacketeer-e0f4c701028aa81026a17cf9ebfb36112184f4bc.tar.gz
packeteer-e0f4c701028aa81026a17cf9ebfb36112184f4bc.zip
Add privilege dropping, AF_PACKET demo, ICMP, checksum validation, --help, and TCP reassembly
Rounds out the build order in PLAN.md with six incremental additions: drop root privileges immediately after opening the capture handle; a standalone AF_PACKET/mmap ring-buffer demo (kept separate from CaptureSession, see its header comment for why); ICMPv4/ICMPv6 type and code decoding; opt-in IPv4/TCP/UDP checksum validation (-c); CLI --help; and opt-in, in-order-only TCP stream reassembly (-a) so HTTP requests/responses split across segments can be seen whole. Each addition is unit-tested and, where it touches live traffic behavior, verified against real captured packets - see PLAN.md's Decisions section for the verification notes on each.
Diffstat (limited to 'include/wireframe/net/icmp.hpp')
-rw-r--r--include/wireframe/net/icmp.hpp84
1 files changed, 84 insertions, 0 deletions
diff --git a/include/wireframe/net/icmp.hpp b/include/wireframe/net/icmp.hpp
new file mode 100644
index 0000000..af83916
--- /dev/null
+++ b/include/wireframe/net/icmp.hpp
@@ -0,0 +1,84 @@
+#pragma once
+
+#include <cstdint>
+#include <optional>
+#include <span>
+#include <string>
+
+#include "wireframe/byteio.hpp"
+
+// ICMPv4 (RFC 792) and ICMPv6 (RFC 4443) share the same first-4-byte
+// shape (Type, Code, Checksum) but a completely different type
+// namespace - the same numeric type means something different in each
+// - so they get separate parse functions and separate type-name
+// tables, sharing only the header struct shape. Neither protocol has
+// ports, so this doesn't fit L7Registry's port-keyed dispatch at all;
+// it's handled directly by protocol number in summarize.hpp instead.
+namespace wireframe::net {
+
+struct IcmpHeader {
+ std::uint8_t type;
+ std::uint8_t code;
+ std::optional<std::uint16_t> identifier; // echo request/reply only
+ std::optional<std::uint16_t> sequence; // echo request/reply only
+};
+
+inline std::optional<IcmpHeader> parse_icmpv4(std::span<const unsigned char> bytes) {
+ if (bytes.size() < 4) return std::nullopt;
+
+ IcmpHeader header{};
+ header.type = bytes[0];
+ header.code = bytes[1];
+ if ((header.type == 8 || header.type == 0) && bytes.size() >= 8) { // echo request/reply
+ header.identifier = read_be16(bytes, 4);
+ header.sequence = read_be16(bytes, 6);
+ }
+ return header;
+}
+
+inline std::string icmpv4_type_name(std::uint8_t type) {
+ switch (type) {
+ case 0: return "Echo Reply";
+ case 3: return "Destination Unreachable";
+ case 4: return "Source Quench";
+ case 5: return "Redirect";
+ case 8: return "Echo Request";
+ case 11: return "Time Exceeded";
+ case 12: return "Parameter Problem";
+ case 13: return "Timestamp Request";
+ case 14: return "Timestamp Reply";
+ default: return "type=" + std::to_string(type);
+ }
+}
+
+inline std::optional<IcmpHeader> parse_icmpv6(std::span<const unsigned char> bytes) {
+ if (bytes.size() < 4) return std::nullopt;
+
+ IcmpHeader header{};
+ header.type = bytes[0];
+ header.code = bytes[1];
+ if ((header.type == 128 || header.type == 129) && bytes.size() >= 8) { // echo request/reply
+ header.identifier = read_be16(bytes, 4);
+ header.sequence = read_be16(bytes, 6);
+ }
+ return header;
+}
+
+inline std::string icmpv6_type_name(std::uint8_t type) {
+ switch (type) {
+ case 1: return "Destination Unreachable";
+ case 2: return "Packet Too Big";
+ case 3: return "Time Exceeded";
+ case 4: return "Parameter Problem";
+ case 128: return "Echo Request";
+ case 129: return "Echo Reply";
+ case 133: return "Router Solicitation";
+ case 134: return "Router Advertisement";
+ case 135: return "Neighbor Solicitation";
+ case 136: return "Neighbor Advertisement";
+ case 137: return "Redirect";
+ default: return "type=" + std::to_string(type);
+ }
+}
+
+} // namespace wireframe::net