<feed xmlns='http://www.w3.org/2005/Atom'>
<title>dotfiles/etc/nftables.conf, branch master</title>
<subtitle>My linux config and rc files</subtitle>
<id>https://git.sommerfeld.dev/dotfiles/atom/etc/nftables.conf?h=master</id>
<link rel='self' href='https://git.sommerfeld.dev/dotfiles/atom/etc/nftables.conf?h=master'/>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/'/>
<updated>2026-05-22T13:28:18Z</updated>
<entry>
<title>fix(nftables): waydroid DHCP/DNS ingress, drop manual NAT table</title>
<updated>2026-05-22T13:28:18Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-22T13:28:18Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=115c508c0ecfa4b255de854d433ba02eaf029b29'/>
<id>urn:sha1:115c508c0ecfa4b255de854d433ba02eaf029b29</id>
<content type='text'>
Mirror the libvirt pattern by accepting DHCP+DNS on waydroid0 so the
Android container's DhcpClient can lease an IP from dnsmasq.

Remove the manual ip nat MASQUERADE table: waydroid-container installs
its own MASQUERADE rule via iptables-nft compat, so the explicit table
is redundant (and was clobbering anything else in ip nat via the
destroy table).
</content>
</entry>
<entry>
<title>fix(nftables): add MASQUERADE for waydroid0</title>
<updated>2026-05-22T13:28:18Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-22T13:28:18Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=9e9781b7f5b70893acefd50817d8bfa233d7362a'/>
<id>urn:sha1:9e9781b7f5b70893acefd50817d8bfa233d7362a</id>
<content type='text'>
waydroid-container ships only the iptables-legacy code path for adding
its POSTROUTING MASQUERADE; on a host with pure nftables the rule
never lands and the Android container has no outbound NAT. Declare it
explicitly in our nftables.conf for determinism.
</content>
</entry>
<entry>
<title>fix(net): keep waydroid0 out of bond0, allow it through nftables</title>
<updated>2026-05-22T13:28:17Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-22T13:28:17Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=18277fc1ec921dfcfa61c0b2f0b40fb62cfa070f'/>
<id>urn:sha1:18277fc1ec921dfcfa61c0b2f0b40fb62cfa070f</id>
<content type='text'>
systemd-networkd's Type=ether matcher was enslaving waydroid0 into
bond0 the moment 'waydroid session start' ran, taking down the host's
default route. Mirror the libvirt/docker negation pattern.

Also mirror the existing virbr0 forward accepts for waydroid0 so the
Android container can actually reach the internet through MASQUERADE.
</content>
</entry>
<entry>
<title>fix(nftables): use iifname/oifname for virbr0 so rules load before libvirtd</title>
<updated>2026-05-13T12:43:41Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-13T12:43:41Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=a831d12291f40832bc3da4a927cbc31cae8e06eb'/>
<id>urn:sha1:a831d12291f40832bc3da4a927cbc31cae8e06eb</id>
<content type='text'>
nftables.service starts at boot before libvirtd creates the virbr0 NAT
bridge. 'iif'/'oif' resolve to a kernel ifindex at rule-load time and
fail with 'Interface does not exist' when virbr0 isn't up yet.
'iifname'/'oifname' do a string match per packet and tolerate a missing
interface, so the ruleset loads cleanly at boot and starts matching
once libvirtd brings virbr0 up.
</content>
</entry>
<entry>
<title>fix(nftables): allow DHCP/DNS and forwarding for libvirt virbr0</title>
<updated>2026-05-13T12:43:41Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-13T12:43:41Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=fa081c7a7dbe0ab3660f6f6d7860b5a815370c5d'/>
<id>urn:sha1:fa081c7a7dbe0ab3660f6f6d7860b5a815370c5d</id>
<content type='text'>
The host firewall has policy=drop on both input and forward chains.
libvirt creates its own nftables table for virbr0 NAT, but:

  1. It does not touch the input chain at all, so DHCP packets from
     guests (UDP/67) are dropped before reaching dnsmasq. Result:
     Windows guest stuck on 169.254.x APIPA forever.

  2. Its forward-chain accepts have the same hook+priority as ours.
     In nftables, all chains at a hook+priority must accept (any drop
     wins), so our policy=drop would block guest egress and return
     traffic even though libvirt's chain explicitly accepts.

Add minimal carve-outs for virbr0: DHCP+DNS in input, guest egress
and return traffic in forward.
</content>
</entry>
<entry>
<title>refactor(nftables): minimize diff against upstream pristine</title>
<updated>2026-05-13T12:43:36Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-13T12:43:36Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=fd06e5313c257648b10a56b9c4151d701fba7d43'/>
<id>urn:sha1:fd06e5313c257648b10a56b9c4151d701fba7d43</id>
<content type='text'>
The previous custom config rewrote the file to 4-space indentation,
added an explicit accept-policy output chain, and expanded the icmp
section into per-type whitelists. None of that changed observable
behaviour vs the stock arch nftables.conf:

  * Stock already uses scoped `destroy table inet filter` (so podman
    and netavark tables survive a reload).
  * `meta l4proto { icmp, icmpv6 } accept` already covers NDP, MLD,
    PMTUD, and echo — the explicit per-type list was equivalent.
  * Without an output chain, outbound traffic is unfiltered, which is
    identical to `policy accept` on an explicit output chain.
  * DHCPv6 client (UDP/546) is only needed on networks that hand out
    DHCPv6 leases; my home/work LANs use SLAAC + RDNSS, and the rare
    DHCPv6 case can be added back in one line if it ever bites.

The only laptop-specific deviation is dropping the
`tcp dport ssh accept` line — no inbound SSH on a portable machine.
Net diff against pristine is now a single deletion, which makes
`just etc-upstream-diff` actually useful for spotting upstream
ruleset improvements on package updates.
</content>
</entry>
<entry>
<title>feat(net): nftables laptop firewall</title>
<updated>2026-05-13T12:43:22Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-13T12:43:22Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=ac0654daf06a9d01fd264d96c00c8ab47b90cb73'/>
<id>urn:sha1:ac0654daf06a9d01fd264d96c00c8ab47b90cb73</id>
<content type='text'>
Default-deny inbound, allow outbound. Scoped to 'inet filter' with
'destroy table' on reload so podman/netavark tables are preserved.

- meta/base.txt: add nftables
- systemd-units/system/base.txt: enable nftables.service
- etc/nftables.conf: laptop ruleset (loopback, ct state, ICMP/ICMPv6
  essentials, DHCPv6 client, default-drop input/forward, accept output)
- etc/sysctl.d/99-sysctl.conf: rp_filter=2, no redirects, no source-route,
  log_martians
- README.md: firewall section with reload caveat
</content>
</entry>
</feed>
