mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-26 18:12:51 +08:00
229 lines
9.8 KiB
Diff
229 lines
9.8 KiB
Diff
--- a/net/netfilter/Kconfig 2026-09-15 14:22:18.467281704 +0800
|
|
+++ b/net/netfilter/Kconfig 2026-09-11 12:51:21.318346650 +0800
|
|
@@ -443,6 +443,20 @@
|
|
config NETFILTER_SYNPROXY
|
|
tristate
|
|
|
|
+config NF_CONNTRACK_CUSTOM_TELEMETRY
|
|
+ bool "Lightweight Layer 7 Payload Telemetry via conntrack"
|
|
+ depends on NF_CONNTRACK
|
|
+ default y
|
|
+ help
|
|
+ This option intercepts the first payload-carrying packet of any
|
|
+ new connection (TCP/UDP) and stores its initial 8 bytes. This
|
|
+ data is then appended to the /proc/net/nf_conntrack stream.
|
|
+
|
|
+ Perfect for lightweight gaming/video traffic identification
|
|
+ without running heavy user-space DPI tools.
|
|
+
|
|
+ If unsure, say Y.
|
|
+
|
|
endif # NF_CONNTRACK
|
|
|
|
config NF_TABLES
|
|
--- a/include/net/netfilter/nf_conntrack.h 2024-01-26 06:34:33.000000000 +0800
|
|
+++ b/include/net/netfilter/nf_conntrack.h 2026-09-14 11:54:57.287192651 +0800
|
|
@@ -103,6 +103,15 @@
|
|
/* Extensions */
|
|
struct nf_ct_ext *ext;
|
|
|
|
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_CUSTOM_TELEMETRY)
|
|
+ /*==================================================================
|
|
+ * CUSTOM FIELDS FOR LIGHTWEIGHT L7 TELEMETRY (STRUCTURE SAFE)
|
|
+ * Placed safely before the protocol union to avoid alignment bugs.
|
|
+ *==================================================================*/
|
|
+ u8 init_payload[64]; /* Stores the 64 bytes of L7 payload that maybe plain text rather than hex string */
|
|
+ u8 has_custom_payload; /* Boolean flag: 1 if raw hex string was captured, 2 if plain text was captured */
|
|
+#endif
|
|
+
|
|
/* Storage reserved for other modules, must be the last member */
|
|
union nf_conntrack_proto proto;
|
|
};
|
|
--- a/net/netfilter/nf_conntrack_core.c 2026-09-15 14:22:18.467281704 +0800
|
|
+++ b/net/netfilter/nf_conntrack_core.c 2026-09-15 14:19:35.912229303 +0800
|
|
@@ -1710,6 +1710,156 @@
|
|
goto out;
|
|
}
|
|
|
|
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_CUSTOM_TELEMETRY)
|
|
+ /* =================== CUSTOM L7 TELEMETRY START =================== */
|
|
+ /* 1. Only process successfully accepted packets if telemetry capture has not locked yet */
|
|
+ if (ret == NF_ACCEPT && ct != NULL && !ct->has_custom_payload) {
|
|
+ struct iphdr *iph = ip_hdr(skb);
|
|
+ if (iph) {
|
|
+ unsigned int l4_header_len = 0;
|
|
+
|
|
+ if (protonum == IPPROTO_TCP) {
|
|
+ struct tcphdr *th = tcp_hdr(skb);
|
|
+ if (th && th->doff >= 5 && th->doff <= 15) {
|
|
+ l4_header_len = th->doff * 4;
|
|
+ }
|
|
+ } else if (protonum == IPPROTO_UDP) {
|
|
+ l4_header_len = sizeof(struct udphdr);
|
|
+ }
|
|
+
|
|
+ if (l4_header_len > 0) {
|
|
+ unsigned int total_len = ntohs(iph->tot_len);
|
|
+ unsigned int payload_offset = dataoff + l4_header_len;
|
|
+
|
|
+ if (total_len > payload_offset && protonum == IPPROTO_UDP) {
|
|
+ unsigned int payload_len = total_len - payload_offset;
|
|
+ if (payload_len >= 8) {
|
|
+ u8 udp_buf[8];
|
|
+ unsigned int target_grab_len = (payload_len > 8) ? 8 : payload_len;
|
|
+ u8 *udp_ptr = skb_header_pointer(skb, payload_offset, target_grab_len, udp_buf);
|
|
+
|
|
+ if (udp_ptr) {
|
|
+ memset(ct->init_payload, 0, 64);
|
|
+ memcpy(ct->init_payload, udp_ptr, target_grab_len);
|
|
+ ct->has_custom_payload = 1;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (total_len > payload_offset && protonum == IPPROTO_TCP) {
|
|
+ unsigned int payload_len = total_len - payload_offset;
|
|
+
|
|
+ /* PRE-FILTER BYPASS ANCHOR: Fast drop non-TLS or ultra-short corrupted flows */
|
|
+ if (payload_len > 44) {
|
|
+ u8 tls_pre_buf[2];
|
|
+ u8 *tls_pre = skb_header_pointer(skb, payload_offset, 2, tls_pre_buf);
|
|
+
|
|
+ if (tls_pre && tls_pre[0] == 0x16 && tls_pre[1] == 0x03) {
|
|
+ unsigned int offset = 5; /* Step 1: Skip TLS Record Layer Header safely */
|
|
+ u8 len_buf[2];
|
|
+ u8 *p;
|
|
+
|
|
+ /* Step 2: Extract Handshake Type (1 byte) and confirm it is Client Hello (0x01) */
|
|
+ p = skb_header_pointer(skb, payload_offset + offset, 1, len_buf);
|
|
+ if (p && p[0] == 0x01) {
|
|
+ offset += 4; /* Move past Handshake Type(1B) + Handshake Length(3B) */
|
|
+ offset += 2; /* Move past Version (2B, e.g., 0x03 0x03) */
|
|
+ offset += 32; /* FLY-OVER: Instantly blast through 32 bytes of static Random data via simple addition */
|
|
+
|
|
+ /* Step 3: Extract dynamic Session ID length field safely (1 byte) */
|
|
+ p = skb_header_pointer(skb, payload_offset + offset, 1, len_buf);
|
|
+ if (p) {
|
|
+ u8 session_id_len = p[0];
|
|
+ offset += 1 + session_id_len; /* Skip length descriptor + payload data bytes */
|
|
+
|
|
+ /* Step 4: Extract dynamic Cipher Suites length field safely (2 bytes) */
|
|
+ p = skb_header_pointer(skb, payload_offset + offset, 2, len_buf);
|
|
+ if (p) {
|
|
+ /* Use safe shift operations to enforce clean endian alignment on all router CPUs */
|
|
+ u16 cipher_suites_len = ((u16)p[0] << 8) | p[1];
|
|
+ offset += 2 + cipher_suites_len; /* Leap over Ciphers grid completely */
|
|
+
|
|
+ /* Step 5: Extract dynamic Compression Methods length field safely (1 byte) */
|
|
+ p = skb_header_pointer(skb, payload_offset + offset, 1, len_buf);
|
|
+ if (p) {
|
|
+ u8 compression_len = p[0];
|
|
+ offset += 1 + compression_len; /* Skip Compression descriptors */
|
|
+
|
|
+ /* Step 6: We have successfully reached the Extensions Array Block! Read Extensions Total Length (2B) */
|
|
+ p = skb_header_pointer(skb, payload_offset + offset, 2, len_buf);
|
|
+ if (p) {
|
|
+ u16 extensions_total_len = ((u16)p[0] << 8) | p[1];
|
|
+ unsigned int extensions_end = offset + 2 + extensions_total_len;
|
|
+ offset += 2; /* Shift layout offset right inside the core extensions list sequence */
|
|
+
|
|
+ /* Strict boundary sanity guard against malicious malformed padding packets */
|
|
+ if (extensions_end <= payload_len) {
|
|
+ u8 loop_guard = 0;
|
|
+ u8 ext_buf[4];
|
|
+ u8 *ext_ptr;
|
|
+
|
|
+ /* Step 7: High-Performance O(1) Leap Loop with anti-hang protection */
|
|
+ while (offset + 4 <= extensions_end && loop_guard++ < 32) {
|
|
+ ext_ptr = skb_header_pointer(skb, payload_offset + offset, 4, ext_buf);
|
|
+ if (!ext_ptr) break;
|
|
+
|
|
+ u16 ext_type = ((u16)ext_ptr[0] << 8) | ext_ptr[1];
|
|
+ u16 ext_len = ((u16)ext_ptr[2] << 8) | ext_ptr[3];
|
|
+
|
|
+ /* TARGET MATCHED: Extension Type 0x0000 matches Server Name Indication (SNI) perfectly! */
|
|
+ if (ext_type == 0x0000) {
|
|
+ unsigned int sni_ptr_offset = offset + 4;
|
|
+ u8 sni_buf[5];
|
|
+ p = skb_header_pointer(skb, payload_offset + sni_ptr_offset, 5, sni_buf);
|
|
+ if (p) {
|
|
+ /* Skip SNI List Length(2B) + Name Type(1B, 0=host_name) + Server Name Length(2B) */
|
|
+ u16 server_name_len = ((u16)p[3] << 8) | p[4];
|
|
+ unsigned int hostname_offset = sni_ptr_offset + 5;
|
|
+
|
|
+ if (hostname_offset + server_name_len <= payload_len && server_name_len > 0) {
|
|
+ u8 name_buf[64];
|
|
+ u8 target_len = (server_name_len > 63) ? 63 : server_name_len;
|
|
+ u8 *name_ptr = skb_header_pointer(skb, payload_offset + hostname_offset, target_len, name_buf);
|
|
+
|
|
+ if (name_ptr) {
|
|
+ memset(ct->init_payload, 0, 64);
|
|
+ memcpy(ct->init_payload, name_ptr, target_len);
|
|
+ ct->has_custom_payload = 2; /* Status '2' -> SNI text successfully harvested and locked! */
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ break; /* Mission accomplished, kill the loop instantly */
|
|
+ }
|
|
+
|
|
+ /* ULTRASONIC JUMP: Jump directly over heavy cryptography chunks (e.g. skip key_share 1263 bytes instantly) */
|
|
+ offset += 4 + ext_len;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Fallback Route C: Standard original 8-byte hex binary telemetry backup if no structural domain was found */
|
|
+ if (!ct->has_custom_payload) {
|
|
+ u8 fallback_buf[8];
|
|
+ u8 *fb_ptr = skb_header_pointer(skb, payload_offset, 8, fallback_buf);
|
|
+ if (fb_ptr) {
|
|
+ memset(ct->init_payload, 0, 64);
|
|
+ memcpy(ct->init_payload, fb_ptr, 8);
|
|
+ ct->has_custom_payload = 1;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ /* ==================== CUSTOM L7 TELEMETRY END ==================== */
|
|
+#endif
|
|
+
|
|
if (ctinfo == IP_CT_ESTABLISHED_REPLY &&
|
|
!test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status))
|
|
nf_conntrack_event_cache(IPCT_REPLY, ct);
|
|
--- a/net/netfilter/nf_conntrack_standalone.c 2026-09-15 14:22:17.815253367 +0800
|
|
+++ b/net/netfilter/nf_conntrack_standalone.c 2026-09-12 16:27:05.964393178 +0800
|
|
@@ -369,6 +369,25 @@
|
|
ct_show_zone(s, ct, NF_CT_DEFAULT_ZONE_DIR);
|
|
ct_show_delta_time(s, ct);
|
|
|
|
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_CUSTOM_TELEMETRY)
|
|
+ /* =================== CUSTOM L7 OUTPUT START =================== */
|
|
+ if (ct->has_custom_payload) {
|
|
+ /* If status flag is '2', we successfully isolated an authentic plain-text ASCII string fragment! */
|
|
+ if (ct->has_custom_payload == 2) {
|
|
+ /* Enforce strict termination rendering using standard %s formatting safely bounded by your size allocation */
|
|
+ seq_printf(s, "payload=%s ", (char *)ct->init_payload);
|
|
+ } else {
|
|
+ /* Fallback status '1': Print classic 8-byte hexadecimal string sequence safely to avoid data corruption */
|
|
+ seq_printf(s, "payload=%02x%02x%02x%02x%02x%02x%02x%02x ",
|
|
+ ct->init_payload[0], ct->init_payload[1],
|
|
+ ct->init_payload[2], ct->init_payload[3],
|
|
+ ct->init_payload[4], ct->init_payload[5],
|
|
+ ct->init_payload[6], ct->init_payload[7]);
|
|
+ }
|
|
+ }
|
|
+ /* ==================== CUSTOM L7 OUTPUT END ==================== */
|
|
+#endif
|
|
+
|
|
seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use));
|
|
|
|
if (seq_has_overflowed(s))
|