Commit Graph

20 Commits

Author SHA1 Message Date
Red Bear OS 917cda18e5 nat: active SNAT binding tracking + display
NatTable gains bindings: Vec<NatBinding> field. record_snat()
called after successful SNAT rewrite captures original→translated
src_addr/port mapping. Bindings capped at 1024 entries (FIFO).

format_bindings() returns:
  Active SNAT bindings: 3
    10.0.0.1:1234 -> 192.168.1.100:40001
    10.0.0.2:5678 -> 192.168.1.100:40002

Useful for diagnosing NAT issues and seeing which internal
connections are being source-NAT'd. Mirrors Linux
/proc/net/ip_conntrack display.

All 31 tests pass.
2026-07-09 11:04:25 +03:00
Red Bear OS 7370d6a818 conntrack: max_entries limit (mirrors nf_conntrack_max)
ConntrackTable gains max_entries: usize field (default 65536).
When the table reaches this limit, new connections return
ConnState::OverLimit instead of being inserted.

Enforced at both insertion points:
- TCP/UDP track() path (new connections)
- ICMP echo track_icmp() path (new ICMP entries)

Stats output now includes max_entries: N.

Mirrors Linux net.netfilter.nf_conntrack_max (default 65536).

All 31 tests pass.
2026-07-09 10:41:12 +03:00
Red Bear OS cc22f259b3 conntrack: icmp_error_count counter + display in stats
ConntrackTable gains icmp_error_count: u64 field, incremented
whenever track_icmp_error() processes an ICMP error that doesn't
match an existing tracked connection.

Stats output now includes:
  icmp_errors: N

Useful for diagnosing ICMP error processing and detecting
anomalies in ICMP error rate.

All 31 tests pass.
2026-07-09 10:19:08 +03:00
Red Bear OS d1f76a3aa1 filter: add --ctstate flag + case-insensitive states + CSV support
Rule parser now accepts iptables-style:
  ACCEPT input -p tcp --ctstate ESTABLISHED,RELATED
  DROP forward state NEW

Both 'state' and '--ctstate' keywords work. States are case-
insensitive: NEW/New/new, ESTABLISHED/Established/established,
RELATED/Related/related, INVALID/Invalid/invalid.

Comma-separated lists (e.g. 'ESTABLISHED,RELATED') use the FIRST
recognized state only — FilterRule stores a single StateMatch field.

Docstring updated with new examples.

All 31 tests pass.
2026-07-09 10:01:18 +03:00
Red Bear OS b50fb644a9 conntrack: ICMP error tracking with ConnState::Error variant
Added ConnState::Error to the connection state enum for ICMP error
packets. Added is_error detection for ICMPv4/v6 Dest Unreachable
and Time Exceeded types. When an ICMP error is detected, delegates
to track_icmp_error() which extracts the embedded original packet
tuple and relates it to an existing tracked connection (mirrors
Linux 7.1 nf_conntrack_icmp_error() in net/netfilter/nf_conntrack_proto_icmp.c).

Previously WIP — now committed to stabilize the base fork build.
2026-07-09 09:57:54 +03:00
Red Bear OS d51320ebff conntrack: fin_from_orig tracking + TCP state in format output
ConnEntry gains fin_from_orig: bool field to track which direction
sent the first FIN. This enables correct TimeWait transition:
FinWait→TimeWait now only fires when the OPPOSITE direction sends
FIN (not when the same side retransmits).

Per Linux nf_conntrack_proto_tcp.c:
- fin_from_orig=true means orig sent first FIN
- TimeWait transition requires reply FIN next
- fin_from_orig=false means reply sent first FIN
- TimeWait transition requires orig FIN next

TCP state now included in format() output:
  Established tcp=Established src=10.0.0.1 dst=10.0.0.2 sport=80 dport=1234 ...
  New tcp=SynSent src=...
  Established tcp=TimeWait src=...

All 31 tests pass.
2026-07-09 01:33:26 +03:00
Red Bear OS 102d00b516 conntrack: fix SynRecv→Established transition direction
The TCP three-way handshake completion (initiator's ACK after
SYN-ACK) arrives on the ORIGINAL direction, not the reply
direction. Previously the SynRecv→Established transition was
gated on is_orig==false, which meant it would never fire after
the initial SYN-ACK reply. Connections would stay in SynRecv
state forever with ConnState::New.

Fix: move SynRecv→Established from reply to orig direction, per
Linux nf_conntrack_proto_tcp.c (TCP_CONNTRACK_SYN_RECV fires on
IP_CT_DIR_ORIGINAL packets).

Reply direction now only handles:
- SYN-ACK from responder (SynSent→SynRecv)
- FIN from responder (Established→FinWait)
- Second FIN from responder (FinWait→TimeWait)
- TimeWait timeout extension

Orig direction now handles:
- ACK from initiator (SynRecv→Established)
- FIN from initiator (Established→FinWait)
- Second FIN from initiator (FinWait→TimeWait)

RST still closes from either direction.

All 31 tests pass.
2026-07-09 01:28:08 +03:00
Red Bear OS b0e3f8e9ad conntrack: per-protocol and per-state statistics
ConntrackTable gains stats() method returning per-protocol breakdown:
  tcp_entries: N (est=N syn=N syn_recv=N fin=N tw=N close=N)
  udp_entries: N
  icmp_entries: N
  over_limit: N
  total_entries: N

TCP states counted: None, SynSent, SynRecv, Established, FinWait,
TimeWait, Close. Mirrors Linux /proc/net/stat/nf_conntrack.

Exposed via three channels:
- /scheme/netfilter/conntrack/stats  (new dedicated node)
- /scheme/netfilter/stats (existing, now includes per-state)
- /scheme/netcfg/summary (includes conntrack stats block)

All 31 tests pass.
2026-07-09 01:24:16 +03:00
Red Bear OS b27515d583 conntrack: full TCP state machine (RST, FIN, TimeWait, Close)
Complete TCP connection tracking state machine:

NEW TRANSITIONS (mirrors Linux nf_conntrack_proto_tcp.c):
- RST from either direction → Close (10s timeout, ConnState::New)
- Established + FIN (either dir) → FinWait (120s timeout)
- FinWait + FIN (other dir) → TimeWait (120s timeout)
- TimeWait extends timeout on any traffic (125s idle for safe
  delayed-ACK arrival)

PRESERVED TRANSITIONS (from original code):
- None → SynSent (on original SYN) — unchanged
- SynSent → SynRecv (on reply SYN-ACK) — unchanged
- SynRecv → Established (on reply ACK) — unchanged

NEW HELPERS:
- tcp_flags(): extract TCP flags byte from packet
- is_fin(): check FIN bit
- is_rst(): check RST bit

NEW TESTS:
- rst_forces_state_to_new: RST resets conn state to New
  (entry stays 10s for lingering cleanup)
- fin_transitions_established_to_timewait: double-FIN
  transition through FinWait → TimeWait

FIXED BUGS:
- advance_entry_state never processed FIN/RST/TimeWait, so
  connections stayed Established for 5 days after actual close.
  Now: FinWait after FIN, TimeWait after both FINs, Close on RST.

All 31 tests pass.
2026-07-09 01:15:52 +03:00
Red Bear OS bd729751d7 conntrack: complete advance_entry_state with TCP flags helpers
Add the missing tcp_flags(), is_fin(), is_rst() helpers and upgrade
advance_entry_state from a 3-parameter stub to a 4-parameter function
that takes &PacketContext. This completes the WIP conntrack state
machine with proper TCP tracking (SynSent, SynRecv, Established,
FinWait, TimeWait, Close) and RST/session-timeout handling.

Reference: Linux 7.x net/netfilter/nf_conntrack_proto_tcp.c
(tcp_packet, nf_conntrack_tcp_packet state machine).
2026-07-09 01:10:55 +03:00
Red Bear OS 0f5a4f59f4 review: parse_port rejects ranges, document IPv6 ext header limit
parse_port now rejects port ranges ('1024:65535') with a clear
error message instead of silently using only the first number.
FilterRule uses a single u16 field and cannot represent ranges.

infer_context now documents the hardcoded 40-byte IPv6 header
limitation: smoltcp's next_header() chases extension headers to
return the final protocol, but the transport offset is not
computed. Port extraction silently returns None/None for packets
with extension headers, which is safe but means port-based
filter rules won't match for such packets.
2026-07-09 00:52:14 +03:00
Red Bear OS baea0e523b review: 4 critical fixes (ICMP queue, refcount, udp panic, vlan send)
CRITICAL BUGS FIXED:

1. router/mod.rs: ICMP errors for Unreachable/Prohibit went to rx_buffer
   (infinite loop back to input) instead of tx_buffer (sent to source).
   Combined Unreachable/Prohibit arms; both now use tx_buffer.

2. scheme/socket.rs dup(): refcount leak in update_with branch.
   OLD code: new_handle.socket_handle() got +2 when update_with was
   Some, but only decremented once on close. Net: SH1 over-counted (+1),
   SH2 (new listening socket from update_with) never tracked at all.
   FIX: in update_with branch, increment refcount of 'socket_handle'
   (the new SH), not new_handle.socket_handle(). The always-run
   increment at the bottom covers new_handle. Both increments serve
   different purposes and are now distinct.

3. scheme/udp.rs: 4 .expect() panic vectors in bind/send/recv.
   'Can't bind', 'Can't send', 'Can't receive', 'Can't recieve' all
   panicked the daemon. Now return EIO via ? operator.

4. link/vlan.rs (and vxlan/gre/ipip already partially fixed in R42):
   send() pushed tagged packets into self.recv_queue, creating a
   self-loop where packets were never delivered. Now drops packets
   with a debug log since no parent device reference exists.

5. link/qdisc.rs: TokenBucket token_add could overflow u64 on long
   elapsed durations. Changed to saturating_mul.

DOC FIX:
6. filter/table.rs docstring example used --sport 1024:65535 (port
   range) but parse_port only accepts single port. Changed example to
   use single port value. Range support is a future enhancement.

All 29 existing tests still pass.
2026-07-09 00:29:46 +03:00
Red Bear OS 263950aefa review fixes: 2 critical bugs found by comprehensive analysis
CRITICAL BUG #1: is_syn() IPv4-only
conntrack.rs is_syn() hardcoded offset 33 (IPv4: 20+13).
For IPv6, TCP flags are at offset 53 (40+13). IPv6 SYN packets
were never detected as SYNs, so SYN flood rate limiting was
completely broken for IPv6 traffic.
Fix: pass l3num, compute tcp_offset correctly for both families.
Added ipv6_syn_detection_works regression test with IPv6 SYN packet
at offset 53 — verifies the fix.

CRITICAL BUG #2: netfilter writes all broken
open_path stored paths without leading '/' (e.g. 'rule/add')
but commit() compared against '/rule/add' (with leading '/').
Result: ALL write operations silently failed with EINVAL:
  - rule/add  - never added rules
  - nat/add   - never added NAT
  - rule/del  - never deleted
  - nat/del   - never deleted
  - policy/X  - never set policy
  - reset     - never reset
  - counters/reset - never reset
Fix: align commit() paths with the stored convention (no '/').
Removed dead /rule/del/<id> REST-style path (no open_path arm existed).
Updated stored path convention comment.

Tests: 21 total (added ipv6_syn_detection_works), all passing.
2026-07-08 22:07:41 +03:00
Red Bear OS d2e6ea1ba9 nat: add 6 unit tests for IP rewrite + table management
Tests cover:
- rewrite_src_ipv4: source IP changes, dst unchanged
- rewrite_dst_ipv4: destination IP changes, src unchanged
- rewrite_short_packet_returns_false: <20 bytes returns false
- rewrite_recomputes_checksum: checksum updates after rewrite
- nat_table_add_assigns_unique_ids: each rule gets unique ID
- nat_ephemeral_port_allocates_unique: ports are unique across calls

Total tests across filter module: 15 (5 table + 4 conntrack + 6 nat)
All passing.
2026-07-08 21:16:50 +03:00
Red Bear OS aa6bf0f2ea conntrack: per-protocol rate limits + fix ICMP type offset bug + tests
CRITICAL BUG FIX: is_echo_request() and track_icmp() were reading
ctx.packet[0] thinking it was the ICMP type byte. But ctx.packet is
the IP packet, so offset 0 is the IP version/IHL byte (0x45 for IPv4).

Result: ICMP echo detection NEVER matched Type 8 packets.
- ICMP rate limiting (R32) was a no-op — wrong byte read
- ICMP echo tracking in track_icmp() was checking IP version vs 8/128

Fixed: read ICMP type from offset  for IPv4, or offset 40 for IPv6.

ALSO: separate TCP SYN and ICMP echo rate limit maps.
Previously both shared one BTreeMap, so a host doing 100 TCP SYNs
+ 1 ICMP echo would be over-limit. Now each has its own budget.

NEW TESTS (4 conntrack + 5 filter table = 9 total, all passing):
- syn_limit_triggers_after_threshold
- icmp_limit_triggers_after_threshold
- syn_and_icmp_have_independent_budgets
- non_syn_tcp_does_not_count_against_syn_limit

These tests caught the ICMP type bug — failed before fix, pass after.
2026-07-08 19:57:19 +03:00
Red Bear OS 579a512545 filter: add unit tests + chain_summary method
5 new unit tests in filter::table::tests:
- drop_rule_actually_drops (R33 bug regression test)
- accept_rule_actually_accepts (R33 bug regression test)
- rule_matching_other_hook_does_not_apply (hook isolation)
- default_policy_applied_when_no_rules (fallback)
- reset_counters_clears_metrics_keeps_rules (R34 method coverage)

All 5 tests pass — proves the critical verdict bug from R33
is fixed and reset_counters from R34 works correctly.

Also adds FilterTable::chain_summary() returning:
  'input: pkts=12 bytes=5678 policy=ACCEPT' (per-chain line)
for use by future netcfg summary extension.
2026-07-08 19:47:47 +03:00
Red Bear OS ecc0ef33de netfilter: add counters/reset path — preserves rules
Previously '/reset' replaced the entire FilterTable (destructive).
Added '/counters/reset' that clears:
- chain_counters (per-chain packets/bytes)
- rule.match_count (per-rule match counts)
WITHOUT removing rules or resetting policies.

FilterTable gains reset_counters() method.

Usage:
  echo > /scheme/netfilter/reset           # wipe everything
  echo > /scheme/netfilter/counters/reset  # clear metrics only

Mirrors Linux 'iptables -Z' (zero counters) vs full flush.
2026-07-08 19:41:05 +03:00
Red Bear OS 48cb44cb3e filter: critical bug fix — evaluate() was ignoring all rule verdicts!
FilterTable::evaluate() set final_verdict for matched rules but never
returned it — always returned the chain's default_policy instead.
This meant every firewall rule (ACCEPT/DROP/REJECT/LOG) was being
evaluated (correctly) but its verdict was DISCARDED.

Symptoms:
- 'DROP' rules had no effect — packets flowed through
- 'ACCEPT' rules had no effect — packets flowed through
- Only default_policy was ever applied

Fix: return final_verdict.unwrap_or(default_policy).

Now 'iptables-style' rules actually take effect:
- DROP rules block traffic
- ACCEPT rules allow traffic (before default)
- REJECT rules send ICMP unreachable
- LOG rules log and continue

This bug was introduced when the filter evaluation logic was
refactored and the return statement was left pointing at the
default policy instead of the verdict from the rule loop.

Confirmed via cargo build; warning 'value assigned to final_verdict
is never read' is now gone.
2026-07-08 19:36:50 +03:00
Red Bear OS 93f026f292 conntrack: ICMP echo rate limiting (ping flood protection)
Conntrack now rate-limits ICMP/ICMPv6 echo requests per source:
- is_echo_request() detects Type 8 (ICMPv4) / Type 128 (ICMPv6)
- check_icmp_limit() enforces 20 echoes/sec per source IP
- Over-limit returns ConnState::OverLimit, increments over_limit_count

Mirrors existing SYN flood protection (100 SYN/sec per source).
Smaller threshold (20/sec) because ICMP is cheaper to generate.

Reuses same rate_limits map — TCP SYNs and ICMP echoes share the
budget. Side effect: 100 SYN + 20 echo = 120 packets/sec from one
source before any trigger, which is reasonable.
2026-07-08 19:25:07 +03:00
Red Bear OS bb3e36e4e0 restore: networking stack files from reflog (Phases 1-6)
Recovered from reflog commits 1c80937e and d0ecc067 after force-push data loss.
Includes: filter/, icmp_error.rs, slaac.rs, bond.rs, bridge.rs, gre.rs, ipip.rs,
qdisc.rs, tun.rs, vlan.rs, vxlan.rs, netfilter.rs, tun.rs, conntrack.rs, nat.rs,
rule.rs, table.rs, redbear-ufw/, dhcpv6d/, netdiag/ — 39 files total.
2026-07-08 13:27:49 +03:00