aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/etc/nftables.conf
blob: c1a37c5168d3a2716f0d24854086aa4fa30dc057 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!/usr/bin/nft -f
# vim:set ts=2 sw=2 et:

# IPv4/IPv6 Simple & Safe firewall ruleset.
# More examples in /usr/share/nftables/ and /usr/share/doc/nftables/examples/.

destroy table inet filter
table inet filter {
  chain input {
    type filter hook input priority filter
    policy drop

    ct state invalid drop comment "early drop of invalid connections"
    ct state {established, related} accept comment "allow tracked connections"
    iif lo accept comment "allow from loopback"
    meta l4proto { icmp, icmpv6 } accept comment "allow icmp"

    # libvirt's NAT bridge: let guests reach the host's dnsmasq for DHCP+DNS.
    # libvirt manages its own forward/NAT chains but does NOT touch the input
    # chain, so without this rule guests get no IP (DHCP packets are dropped
    # before dnsmasq sees them).
    iifname "virbr0" udp dport { 53, 67 } accept comment "libvirt: DHCP+DNS from guests"
    iifname "virbr0" tcp dport 53 accept comment "libvirt: DNS over TCP from guests"

    pkttype host limit rate 5/second counter reject with icmpx type admin-prohibited
    counter
  }
  chain forward {
    type filter hook forward priority filter
    policy drop

    # libvirt's NAT bridge: permit guest traffic to be forwarded. libvirt's
    # own table accepts these explicitly at the same hook+priority, but with
    # nftables a packet must be accepted by ALL chains at that priority, so
    # our policy=drop would otherwise block all guest egress and return
    # traffic. Mirror libvirt's accepts here for the default NAT bridge.
    # Use iifname/oifname (string match) instead of iif/oif so the rules
    # load before libvirtd has created virbr0 at boot.
    iifname "virbr0" accept comment "libvirt: guest egress"
    oifname "virbr0" ct state established,related accept comment "libvirt: guest return"

    # Waydroid's NAT bridge: same pattern as libvirt. Unlike libvirt, waydroid
    # does NOT install its own MASQUERADE rule reliably (it tries via the
    # legacy iptables binary which isn't present), so we both forward-accept
    # here AND install MASQUERADE in the ip nat table below.
    iifname "waydroid0" accept comment "waydroid: guest egress"
    oifname "waydroid0" ct state established,related accept comment "waydroid: guest return"
  }
}

# NAT for waydroid's Android container. The waydroid-container service is
# supposed to add this via iptables but ships only the iptables-legacy code
# path; on a pure nftables host (no iptables-nft compat shim active) the rule
# never lands. Declaring it here is deterministic and survives reloads.
destroy table ip nat
table ip nat {
  chain postrouting {
    type nat hook postrouting priority srcnat
    policy accept

    ip saddr 192.168.240.0/24 oifname != "waydroid0" masquerade \
      comment "waydroid: MASQUERADE container egress"
  }
}