Skip to content

Commit ab5d073

Browse files
2025 07 01
1 parent fea1370 commit ab5d073

File tree

4 files changed

+171
-39
lines changed

4 files changed

+171
-39
lines changed

desktop/l2/README.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,4 +330,32 @@ Internet (enp1s0)
330330
- `monitoring.nix` - Performance monitoring and testing services
331331
- `sysctl.nix` - Kernel network parameters
332332
- `configuration.nix` - Main system configuration
333-
- `CPU_and_IRQ_optimization.md` - Detailed optimization documentation
333+
- `CPU_and_IRQ_optimization.md` - Detailed optimization documentation
334+
335+
336+
## Netlink monitoring
337+
338+
Hostapd communicates with the kernel via Netlink. To monitor the Netlink traffic, follow these instructions:
339+
340+
```
341+
modprobe nlmon
342+
sudo modprobe nlmon
343+
lsmod | grep nlmon
344+
sudo ip link add nlmon0 type nlmon
345+
sudo ip link set dev nlmon0 up
346+
sudo tcpdump -i nlmon0 -w netlink.pcap
347+
sudo chown das:das *.pcap
348+
```
349+
350+
See also: https://jvns.ca/blog/2017/09/03/debugging-netlink-requests/
351+
352+
353+
## ipv6 debugging notes
354+
355+
```
356+
sudo tcpdump -i enp1s0 -n 'icmp6 and (icmp6[0] == 133 or icmp6[0] == 134)'
357+
# triggger router solicitation (nix-shell -p ndisc6)
358+
sudo rdisc6 enp1s0
359+
# another way
360+
sudo ip -6 route flush dev enp1s0
361+
```

desktop/l2/firewall.md

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
This document outlines the design and principles of the `nftables` firewall configuration for the L2 WiFi access point. The primary goals are to provide robust security for the router and its clients, ensure correct network functionality, and maintain a clear, auditable ruleset with maximum performance.
66

7-
The firewall leverages `nftables` for its modern syntax, performance, and ability to handle both IPv4 and IPv6 within a unified `inet` table family where possible. The configuration is optimized for performance through extensive use of nftables sets and strategic rule ordering.
7+
The firewall leverages `nftables` for its modern syntax, performance, and ability to handle both IPv4 and IPv6 within a unified `inet` table family where possible. The configuration is optimized for performance through extensive use of nftables sets and strategic rule ordering, including early processing of trusted traffic like loopback communication.
88

99
### 1.1. Configuration Variables
1010

@@ -49,6 +49,9 @@ The firewall extensively uses nftables sets for optimal performance and maintain
4949
* **`special_purpose_ipv6`**: Contains all RFC 6890 special-purpose IPv6 ranges
5050
* **`loopback_ipv4`**: IPv4 loopback addresses (127.0.0.0/8)
5151
* **`loopback_ipv6`**: IPv6 loopback addresses (::1/128)
52+
* **`link_local_ipv6`**: IPv6 link-local addresses (fe80::/10) - essential for IPv6 operation including Router Advertisements and Neighbor Discovery
53+
* **`internal_ipv4`**: Internal IPv4 subnet (192.168.1.0/24) - our allocated private network
54+
* **`internal_ipv6`**: Internal IPv6 subnet (fd00::/64) - our allocated private network
5255
* **`blacklist`**: Dynamic blacklist for CrowdSec integration (timeout-based, auto-merge)
5356

5457
#### 3.1.2. Service Port Sets
@@ -66,14 +69,18 @@ This chain protects the access point itself with optimized rule ordering:
6669

6770
* **Early Invalid Packet Drops**:
6871
* **Drops** invalid connection states immediately
69-
* **Drops** fragmented packets (potential evasion technique)
72+
* **Allows** fragment reassembly - router reassembles fragments and applies security rules to reassembled packets
73+
* **Loopback Protection** (Early):
74+
* **Accepts** all legitimate traffic on the loopback interface (`lo`) immediately
75+
* **Drops** any packet seen on a physical interface with loopback addresses using optimized set lookups
76+
* **Performance**: Early placement ensures trusted loopback traffic bypasses expensive rule evaluation
77+
* **TCP Flag Validation**:
7078
* **Drops** packets with invalid TCP flag combinations
7179
* **Fast Path for Established Connections**:
7280
* **Accepts** established and related connections early for maximum performance
73-
* **Loopback Protection**:
74-
* **Accepts** all legitimate traffic on the loopback interface (`lo`)
75-
* **Drops** any packet seen on a physical interface with loopback addresses using optimized set lookups
7681
* **Global Anti-Spoofing**:
82+
* **Exception**: Allows essential IPv6 link-local communication (Router Advertisements, Neighbor Discovery) using the `link_local_ipv6` set
83+
* **Allows** legitimate internal traffic from our allocated subnets
7784
* **Drops** any incoming packet with a source address from special-purpose ranges using set-based filtering
7885
* **Service Access Control**:
7986
* **Allows** access to essential network services using set-based port matching
@@ -90,9 +97,14 @@ This chain governs the traffic from WiFi clients to the internet and vice-versa
9097

9198
* **Early Invalid Packet Drops**:
9299
* **Drops** invalid connection states and malformed packets immediately
100+
* **Allows** fragment reassembly for forwarded packets
93101
* **Anti-Spoofing with Set-Based Filtering**:
94102
* **Drops** any packet being forwarded that contains loopback addresses using set lookups
95103
* **Drops** any packet from internal clients with spoofed upstream LAN addresses
104+
* **Drops** any packet from internal clients with spoofed special-purpose addresses
105+
* **Internal Traffic Forwarding**:
106+
* **Allows** legitimate internal traffic from our allocated subnets to external network
107+
* **Special-Purpose Destination Blocking**:
96108
* **Drops** any packet from internal clients destined for special-purpose ranges using set-based filtering
97109
* **Fast Path for Return Traffic**:
98110
* **Allows** return traffic from external to internal for established connections (most common case)
@@ -111,9 +123,13 @@ This chain governs traffic generated by the access point itself with comprehensi
111123

112124
* **Default-Accept Policy**: The policy is `accept`, but hardened with explicit `drop` rules
113125
* **Early Invalid Packet Drops**:
114-
* **Drops** invalid connection states, fragmented packets, and invalid TCP flags
115-
* **Loopback Protection**:
126+
* **Drops** invalid connection states, fragmented packets
127+
* **Allows** fragment reassembly for outgoing packets
128+
* **Loopback Protection** (Early):
116129
* **Drops** any packet with loopback addresses on physical interfaces using set-based filtering
130+
* **Performance**: Early placement ensures loopback spoofing is detected before expensive rule evaluation
131+
* **TCP Flag Validation**:
132+
* **Drops** packets with invalid TCP flag combinations
117133
* **Global Egress Filtering**:
118134
* **Drops** any packet destined for special-purpose ranges using set-based filtering
119135
* **Interface-Specific Egress Filtering**:
@@ -139,6 +155,8 @@ The firewall employs several advanced optimization techniques:
139155

140156
#### 3.6.2. Rule Ordering Optimization
141157
* **Early Drops**: Invalid packets and spoofed traffic are dropped as early as possible
158+
* **Fragment Reassembly**: Fragments are accepted for reassembly before applying security rules
159+
* **Loopback Fast Path**: Loopback traffic is accepted immediately as it's inherently trusted, bypassing expensive rule evaluation and providing maximum performance for localhost communication
142160
* **Fast Path**: Established connections are accepted early to avoid expensive rule evaluation
143161
* **Global Filters**: Non-interface-specific drops (like special-purpose IP blocking) are applied before interface-specific rules
144162
* **Most Common Traffic First**: Return traffic and established connections are prioritized
@@ -253,17 +271,32 @@ The CrowdSec integration makes several deliberate architectural choices:
253271
- Internal clients cannot spoof upstream LAN addresses
254272
- Fragment and TCP flag filtering prevents evasion techniques
255273

256-
### 4.3. Network Segmentation
274+
### 4.3. Fragment Handling Strategy
275+
- **Fragment Reassembly**: Instead of dropping fragments, the router reassembles them and applies security rules to the complete packets
276+
- **Security Benefits**: Prevents fragment-based attacks while maintaining compatibility with legitimate applications
277+
- **Compatibility**: Supports applications that rely on fragmentation (VPNs, streaming, large packet transfers)
278+
- **Performance**: Reassembly happens at the kernel level with minimal overhead
279+
- **Attack Prevention**: Fragment-based evasion techniques are neutralized since security rules are applied to reassembled packets
280+
281+
### 4.4. Network Segmentation
257282
- Clear separation between internal (br0) and external (enp1s0) interfaces
258283
- Service access is restricted to internal interfaces only
259284
- Upstream LAN access is explicitly controlled
260285
- Egress filtering prevents internal network leakage
261286

262-
### 4.4. IPv6 Security
287+
### 4.5. IPv6 Security
263288
- Comprehensive ICMPv6 filtering for proper IPv6 operation
264289
- Neighbor Discovery Protocol protection
265-
- Router Advertisement control
290+
- Router Advertisement control via link-local address set (`link_local_ipv6`)
266291
- Path MTU Discovery support
292+
- Essential link-local communication allowed for IPv6 operation
293+
294+
### 4.6. Performance Considerations
295+
- **Early Loopback Processing**: Loopback traffic is handled immediately to bypass expensive rule evaluation
296+
- **Fragment Reassembly**: Kernel-level reassembly with minimal overhead
297+
- **Set-Based Lookups**: Optimized address and port matching using nftables sets
298+
- **Rule Ordering**: Most common traffic patterns are prioritized for maximum throughput
299+
- **Connection Tracking**: Stateful inspection reduces rule evaluation for established connections
267300

268301
## 5. Monitoring and Logging
269302

@@ -292,6 +325,7 @@ Monitor firewall logs for:
292325
| ------------------------------- | :--------------------: | :-----------------------: | :---------------------: |
293326
| **Default-Deny Policy** ||||
294327
| **Stateful Inspection** ||||
328+
| **Fragment Reassembly** ||||
295329
| **Loopback Anti-Spoofing** ||||
296330
| **Special-Purpose IP Blocking** ||||
297331
| **Service Access Control** || N/A | N/A |
@@ -353,6 +387,9 @@ ping -I 127.0.0.1 8.8.8.8 # Should be blocked
353387
# Test special-purpose IP blocking
354388
ping -I 192.168.1.100 10.0.0.1 # Should be blocked
355389

390+
# Test fragment handling
391+
ping -s 1500 -M do 192.168.1.1 # Test large packets that may fragment
392+
356393
# Test IPv6 functionality
357394
ping6 -c 1 fd00::1 # Should work from internal
358395

desktop/l2/firewall.nix

Lines changed: 74 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,32 @@ in {
111111
}
112112
}
113113
114+
# Define set for link-local IPv6 addresses (essential for IPv6 operation)
115+
set link_local_ipv6 {
116+
type ipv6_addr
117+
flags interval
118+
elements = {
119+
fe80::/10 # Link-Local Addresses
120+
}
121+
}
122+
123+
# Define sets for our internal networks
124+
set internal_ipv4 {
125+
type ipv4_addr
126+
flags interval
127+
elements = {
128+
${internalIPv4Prefix} # Internal IPv4 subnet
129+
}
130+
}
131+
132+
set internal_ipv6 {
133+
type ipv6_addr
134+
flags interval
135+
elements = {
136+
${internalIPv6Prefix} # Internal IPv6 subnet
137+
}
138+
}
139+
114140
# Define sets for common service ports
115141
set ssh_ports {
116142
type inet_service
@@ -181,8 +207,18 @@ in {
181207
# Early drop for invalid packets
182208
ct state invalid drop
183209
184-
# Drop fragmented packets (potential evasion technique)
185-
ip frag-off & 0x1fff != 0 drop
210+
# Allow fragment reassembly - let the router reassemble fragments
211+
# and then apply security rules to the reassembled packets
212+
# This prevents fragment-based attacks while maintaining compatibility
213+
ip frag-off & 0x1fff != 0 accept
214+
215+
# Accept all traffic on the loopback interface, and drop spoofed
216+
# loopback packets on any other interface.
217+
iif lo accept
218+
iif != "lo" ip saddr @loopback_ipv4 drop
219+
iif != "lo" ip daddr @loopback_ipv4 drop
220+
iif != "lo" ip6 saddr @loopback_ipv6 drop
221+
iif != "lo" ip6 daddr @loopback_ipv6 drop
186222
187223
# Drop packets with invalid TCP flag combinations
188224
tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|syn|rst|psh|ack|urg) drop
@@ -196,19 +232,23 @@ in {
196232
# Allow established and related connections
197233
ct state established,related accept
198234
199-
# Accept all traffic on the loopback interface, and drop spoofed
200-
# loopback packets on any other interface.
201-
iif lo accept
202-
iif != "lo" ip saddr @loopback_ipv4 drop
203-
iif != "lo" ip daddr @loopback_ipv4 drop
204-
iif != "lo" ip6 saddr @loopback_ipv6 drop
205-
iif != "lo" ip6 daddr @loopback_ipv6 drop
206-
207235
# Drop incoming traffic from special-purpose/unroutable source addresses (RFC 6890)
208236
# This provides strong anti-spoofing protection for the router itself.
237+
# EXCEPTION: Allow essential IPv6 link-local communication (needed for IPv6 operation)
238+
ip6 saddr @link_local_ipv6 icmpv6 type @icmpv6_allowed accept
239+
240+
# Allow legitimate internal traffic from our networks
241+
iifname "${lanInterface}" ip saddr @internal_ipv4 accept
242+
iifname "${lanInterface}" ip6 saddr @internal_ipv6 accept
243+
244+
# Block spoofed special-purpose addresses from all interfaces
209245
ip saddr @special_purpose_ipv4 drop
210246
ip6 saddr @special_purpose_ipv6 drop
211247
248+
# Block destination special-purpose addresses from all interfaces
249+
ip daddr @special_purpose_ipv4 drop
250+
ip6 daddr @special_purpose_ipv6 drop
251+
212252
# Allow management and network services from the internal interface (${lanInterface})
213253
# Rate limit SSH to prevent brute force attacks
214254
iifname "${lanInterface}" tcp dport @ssh_ports ct state new limit rate 6/minute accept
@@ -247,8 +287,9 @@ in {
247287
# Early drop for invalid packets being forwarded
248288
ct state invalid drop
249289
250-
# Drop fragmented packets being forwarded
251-
ip frag-off & 0x1fff != 0 drop
290+
# Allow fragment reassembly for forwarded packets
291+
# Let the router reassemble fragments and apply security rules to reassembled packets
292+
ip frag-off & 0x1fff != 0 accept
252293
253294
# Drop packets with invalid TCP flag combinations
254295
tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|syn|rst|psh|ack|urg) drop
@@ -265,6 +306,14 @@ in {
265306
# Drop traffic from internal clients pretending to be on the upstream LAN.
266307
iifname "${lanInterface}" ip saddr ${upstreamLanPrefix} drop
267308
309+
# Allow legitimate internal traffic to external network
310+
iifname "${lanInterface}" oifname "${wanInterface}" ip saddr @internal_ipv4 accept
311+
iifname "${lanInterface}" oifname "${wanInterface}" ip6 saddr @internal_ipv6 accept
312+
313+
# Block spoofed special-purpose addresses from internal clients
314+
iifname "${lanInterface}" ip saddr @special_purpose_ipv4 drop
315+
iifname "${lanInterface}" ip6 saddr @special_purpose_ipv6 drop
316+
268317
# Drop traffic from internal clients to private/reserved ranges.
269318
# This prevents traffic from being forwarded to non-routable destinations.
270319
# Based on IANA Special-Purpose Address Registry (RFC 6890)
@@ -300,13 +349,9 @@ in {
300349
# Drop invalid packets originating from the local machine
301350
ct state invalid drop
302351
303-
# Drop fragmented packets from router
304-
ip frag-off & 0x1fff != 0 drop
305-
306-
# Drop packets with invalid TCP flag combinations
307-
tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|syn|rst|psh|ack|urg) drop
308-
tcp flags & (fin|syn) == (fin|syn) drop
309-
tcp flags & (syn|rst) == (syn|rst) drop
352+
# Allow fragment reassembly for outgoing packets
353+
# Let the router reassemble fragments before sending
354+
ip frag-off & 0x1fff != 0 accept
310355
311356
# Drop spoofed loopback packets on non-loopback interfaces.
312357
# Legitimate traffic to/from loopback addresses should only be on the 'lo' interface.
@@ -315,6 +360,11 @@ in {
315360
oif != "lo" ip6 saddr @loopback_ipv6 drop
316361
oif != "lo" ip6 daddr @loopback_ipv6 drop
317362
363+
# Drop packets with invalid TCP flag combinations
364+
tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|syn|rst|psh|ack|urg) drop
365+
tcp flags & (fin|syn) == (fin|syn) drop
366+
tcp flags & (syn|rst) == (syn|rst) drop
367+
318368
# Allow essential ICMPv6 traffic from router (Router Advertisement, Neighbor Advertisement, etc.)
319369
oifname "${lanInterface}" icmpv6 type @icmpv6_allowed accept
320370
oifname "${wanInterface}" icmpv6 type @icmpv6_allowed accept
@@ -328,13 +378,13 @@ in {
328378
329379
# Block allocated subnets from going out the WAN interface (${wanInterface})
330380
# to prevent internal network leakage
331-
oifname "${wanInterface}" ip daddr ${internalIPv4Prefix} drop
332-
oifname "${wanInterface}" ip6 daddr ${internalIPv6Prefix} drop
381+
oifname "${wanInterface}" ip daddr @internal_ipv4 drop
382+
oifname "${wanInterface}" ip6 daddr @internal_ipv6 drop
333383
334384
# Allow allocated subnets to go out the internal interface (${lanInterface})
335385
# for legitimate internal network communication
336-
oifname "${lanInterface}" ip daddr ${internalIPv4Prefix} accept
337-
oifname "${lanInterface}" ip6 daddr ${internalIPv6Prefix} accept
386+
oifname "${lanInterface}" ip daddr @internal_ipv4 accept
387+
oifname "${lanInterface}" ip6 daddr @internal_ipv6 accept
338388
}
339389
}
340390
@@ -357,7 +407,7 @@ in {
357407
358408
chain postrouting {
359409
type nat hook postrouting priority srcnat;
360-
# IPv6 masquerading
410+
# IPv6 masquerading for private fd00::/64 network
361411
oifname "${wanInterface}" masquerade
362412
}
363413
}

0 commit comments

Comments
 (0)