demo-firewall.nix (7586B)
1 let 2 drop = expr : "${expr} drop"; 3 accept = expr : "${expr} accept"; 4 mcast-scope = 8; 5 allow-incoming = false; 6 in { 7 bogons-ip6 = { 8 type = "filter"; 9 family = "ip6"; 10 policy = "accept"; 11 hook = "prerouting"; 12 rules = [ 13 (drop "ip6 saddr ff00::/8") # multicast saddr is illegal 14 15 (drop "ip6 saddr ::/128") # unspecified address 16 (drop "ip6 daddr ::/128") 17 (drop "ip6 saddr 2001:db8::/32") # documentation addresses 18 (drop "ip6 daddr 2001:db8::/32") 19 20 # I think this means "check FIB for (saddr, iif) to see if we 21 # could route a packet to that address using that interface", 22 # and if we can't then it was an inapproppriate source address 23 # for packets received _from_ said interface 24 (drop "fib saddr . iif oif eq 0") 25 26 (drop "icmpv6 type router-renumbering") 27 (drop "icmpv6 type 139") # Node Information Query 28 (drop "icmpv6 type 140") # Node Information Response 29 (drop "icmpv6 type 100") 30 (drop "icmpv6 type 101") 31 (drop "icmpv6 type 200") 32 (drop "icmpv6 type 201") 33 (drop "icmpv6 type 127") 34 (drop "icmpv6 type 255") 35 (drop "icmpv6 type destination-unreachable ct state invalid,untracked") 36 ]; 37 }; 38 39 forward-ip6 = { 40 type = "filter"; 41 family = "ip6"; 42 policy = "drop"; 43 hook = "forward"; 44 rules = [ 45 (drop "ip6 saddr ::1/128") # loopback address [RFC4291] 46 (drop "ip6 daddr ::1/128") 47 (drop "ip6 saddr ::FFFF:0:0/96")# IPv4-mapped addresses 48 (drop "ip6 daddr ::FFFF:0:0/96") 49 (drop "ip6 saddr fe80::/10") # link-local unicast 50 (drop "ip6 daddr fe80::/10") 51 (drop "ip6 saddr fc00::/7") # unique-local addresses 52 (drop "ip6 daddr fc00::/7") 53 (drop "ip6 saddr 2001:10::/28") # ORCHID [RFC4843]. 54 (drop "ip6 daddr 2001:10::/28") 55 56 (drop "ip6 saddr fc00::/7") # unique local source 57 (drop "ip6 daddr fc00::/7") # and/or dst addresses [RFC4193] 58 59 # multicast with wrong scopes 60 (drop 61 # dest addr first byte 0xff, low nibble of second byte <= scope 62 # https://www.mankier.com/8/nft#Payload_Expressions-Raw_Payload_Expression 63 "@nh,192,8 eq 0xff @nh,204,4 le ${toString mcast-scope}") 64 65 (accept "oifname \"int\" iifname \"ppp0\" meta l4proto udp ct state established,related") 66 (accept "iifname \"int\" oifname \"ppp0\" meta l4proto udp") 67 68 (accept "meta l4proto icmpv6") 69 (accept "meta l4proto ah") 70 (accept "meta l4proto esp") 71 72 # does this ever get used or does the preceding general udp accept 73 # already grab anything that might get here? 74 (accept "oifname \"ppp0\" udp dport 500") # IKE Protocol [RFC5996]. haha zyxel 75 (accept "ip6 nexthdr 139") # Host Identity Protocol 76 77 ## FIXME no support yet for recs 27-30 Mobility Header 78 79 (accept "oifname \"int\" iifname \"ppp0\" meta l4proto tcp ct state established,related") 80 (accept "iifname \"int\" oifname \"ppp0\" meta l4proto tcp") 81 82 (accept "oifname \"int\" iifname \"ppp0\" meta l4proto sctp ct state established,related") 83 (accept "iifname \"int\" oifname \"ppp0\" meta l4proto sctp") 84 85 (accept "oifname \"int\" iifname \"ppp0\" meta l4proto dccp ct state established,related") 86 (accept "iifname \"int\" oifname \"ppp0\" meta l4proto dccp") 87 88 # we can allow all reasonable inbound, or we can use an explicit 89 # allowlist to enumerate the endpoints that are allowed to 90 # accept inbound from the WAN 91 (if allow-incoming 92 then accept "oifname \"int\" iifname \"ppp0\"" 93 else "oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip6" 94 ) 95 # allow all outbound and any inbound that's part of a 96 # recognised (outbound-initiated) flow 97 (accept "oifname \"int\" iifname \"ppp0\" ct state established,related") 98 (accept "iifname \"int\" oifname \"ppp0\" ") 99 100 "log prefix \"DENIED CHAIN=forward-ip6 \"" 101 ]; 102 }; 103 104 input-ip6-lan = { 105 type = "filter"; 106 family = "ip6"; 107 108 rules = [ 109 (accept "udp dport 547") # dhcp, could restrict to daddr ff02::1:2 110 (accept "udp dport 53") # dns 111 (accept "tcp dport 22") 112 ]; 113 }; 114 115 input-ip6-wan = { 116 type = "filter"; 117 family = "ip6"; 118 119 rules = [ 120 (accept "udp dport 546") # dhcp client, needed for prefix delegation 121 ]; 122 }; 123 124 input-ip6 = { 125 type = "filter"; 126 family = "ip6"; 127 policy = "drop"; 128 hook = "input"; 129 rules = [ 130 (accept "meta l4proto icmpv6") 131 "iifname int jump input-ip6-lan" 132 "iifname ppp0 jump input-ip6-wan" 133 (if allow-incoming 134 then accept "oifname \"int\" iifname \"ppp0\"" 135 else "oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip6" 136 ) 137 # how does this even make sense in an input chain? 138 (accept "oifname \"int\" iifname \"ppp0\" ct state established,related") 139 (accept "iifname \"int\" oifname \"ppp0\" ") 140 "log prefix \"DENIED CHAIN=input-ip6 \"" 141 ]; 142 }; 143 144 incoming-allowed-ip6 = { 145 type = "filter"; 146 family = "ip6"; 147 rules = [ 148 # this is where you put permitted incoming connections 149 # "oifname \"int\" ip6 daddr 2001:8b0:de3a:40de::e9d tcp dport 22" 150 ]; 151 }; 152 153 nat-tx = { 154 type = "nat"; 155 hook = "postrouting"; 156 priority = "100"; 157 policy = "accept"; 158 family = "ip"; 159 rules = [ 160 "oifname \"ppp0\" masquerade" 161 ]; 162 }; 163 164 nat-rx = { 165 type = "nat"; 166 hook = "prerouting"; 167 priority = "-100"; 168 family = "ip"; 169 policy = "accept"; 170 rules = [ 171 # per https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-configuring_nat_using_nftables: 172 # "Even if you do not add a rule to the prerouting chain, the 173 # nftables framework requires this chain to match incoming 174 # packet replies. " 175 ]; 176 }; 177 178 # these chains are for rules that have to be present for things to 179 # basically work at all: for example, the router won't issue DHCP 180 # unless it's allowed to receive DHCP requests. For "site policy" 181 # rules you may prefer to use incoming-allowed-ip[46] instead 182 183 input-ip4-lan = { 184 type = "filter"; 185 family = "ip"; 186 187 rules = [ 188 (accept "udp dport 67") # dhcp 189 (accept "udp dport 53") # dns 190 (accept "tcp dport 22") # ssh 191 ]; 192 }; 193 194 input-ip4-wan = { 195 type = "filter"; 196 family = "ip"; 197 198 rules = [ 199 (accept "udp sport 53") 200 ]; 201 }; 202 203 input-ip4 = { 204 type = "filter"; 205 family = "ip"; 206 policy = "drop"; 207 hook = "input"; 208 rules = [ 209 "iifname lo accept" 210 "icmp type { echo-request, echo-reply } accept" 211 "iifname int jump input-ip4-lan" 212 "iifname ppp0 jump input-ip4-wan" 213 "oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip4" 214 "ct state established,related accept" 215 "log prefix \"DENIED CHAIN=input-ip4 \"" 216 ]; 217 }; 218 219 forward-ip4 = { 220 type = "filter"; 221 family = "ip"; 222 policy = "drop"; 223 hook = "forward"; 224 rules = [ 225 "iifname \"int\" accept" 226 "ct state established,related accept" 227 "oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip4" 228 "log prefix \"DENIED CHAIN=forward-ip4 \"" 229 ]; 230 }; 231 232 incoming-allowed-ip4 = { 233 type = "filter"; 234 family = "ip"; 235 rules = [ 236 # This is where you put permitted incoming connections. If 237 # you're using NAT and want to forward a port from outside to 238 # devices on the LAN, then you need a DNAT rule in nat-rx chain 239 # *and* to accept the packet in this chain (specifying the 240 # internal (RFC1918) address). 241 ]; 242 }; 243 244 }