demo-firewall.nix (5683B)
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 forward-ip6 = { 39 type = "filter"; 40 family = "ip6"; 41 policy = "drop"; 42 hook = "forward"; 43 rules = [ 44 (drop "ip6 saddr ::1/128") # loopback address [RFC4291] 45 (drop "ip6 daddr ::1/128") 46 (drop "ip6 saddr ::FFFF:0:0/96")# IPv4-mapped addresses 47 (drop "ip6 daddr ::FFFF:0:0/96") 48 (drop "ip6 saddr fe80::/10") # link-local unicast 49 (drop "ip6 daddr fe80::/10") 50 (drop "ip6 saddr fc00::/7") # unique-local addresses 51 (drop "ip6 daddr fc00::/7") 52 (drop "ip6 saddr 2001:10::/28") # ORCHID [RFC4843]. 53 (drop "ip6 daddr 2001:10::/28") 54 55 (drop "ip6 saddr fc00::/7") # unique local source 56 (drop "ip6 daddr fc00::/7") # and/or dst addresses [RFC4193] 57 58 # multicast with wrong scopes 59 (drop 60 # dest addr first byte 0xff, low nibble of second byte <= scope 61 # https://www.mankier.com/8/nft#Payload_Expressions-Raw_Payload_Expression 62 "@nh,192,8 eq 0xff @nh,204,4 le ${toString mcast-scope}") 63 64 (accept "oifname \"int\" iifname \"ppp0\" meta l4proto udp ct state established,related") 65 (accept "iifname \"int\" oifname \"ppp0\" meta l4proto udp") 66 67 (accept "meta l4proto icmpv6") 68 (accept "meta l4proto ah") 69 (accept "meta l4proto esp") 70 71 # does this ever get used or does the preceding general udp accept 72 # already grab anything that might get here? 73 (accept "oifname \"ppp0\" udp dport 500") # IKE Protocol [RFC5996]. haha zyxel 74 (accept "ip6 nexthdr 139") # Host Identity Protocol 75 76 ## FIXME no support yet for recs 27-30 Mobility Header 77 78 (accept "oifname \"int\" iifname \"ppp0\" meta l4proto tcp ct state established,related") 79 (accept "iifname \"int\" oifname \"ppp0\" meta l4proto tcp") 80 81 (accept "oifname \"int\" iifname \"ppp0\" meta l4proto sctp ct state established,related") 82 (accept "iifname \"int\" oifname \"ppp0\" meta l4proto sctp") 83 84 (accept "oifname \"int\" iifname \"ppp0\" meta l4proto dccp ct state established,related") 85 (accept "iifname \"int\" oifname \"ppp0\" meta l4proto dccp") 86 87 # we can allow all reasonable inbound, or we can use an explicit 88 # allowlist to enumerate the endpoints that are allowed to 89 # accept inbound from the WAN 90 (if allow-incoming 91 then accept "oifname \"int\" iifname \"ppp0\"" 92 else "oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip6" 93 ) 94 # allow all outbound and any inbound that's part of a 95 # recognised (outbound-initiated) flow 96 (accept "oifname \"int\" iifname \"ppp0\" ct state established,related") 97 (accept "iifname \"int\" oifname \"ppp0\" ") 98 ]; 99 }; 100 input-lan = { 101 type = "filter"; 102 family = "ip6"; 103 104 rules = [ 105 (accept "udp dport 547") # dhcp, could restrict to daddr ff02::1:2 106 (accept "tcp dport 22") 107 ]; 108 }; 109 110 input-wan = { 111 type = "filter"; 112 family = "ip6"; 113 114 rules = [ 115 (accept "udp dport 546") # dhcp client, needed for prefix delegation 116 ]; 117 }; 118 119 input-ip6 = { 120 type = "filter"; 121 family = "ip6"; 122 policy = "drop"; 123 hook = "input"; 124 rules = [ 125 (accept "meta l4proto icmpv6") 126 "iifname int jump input-lan" 127 "iifname ppp0 jump input-wan" 128 (if allow-incoming 129 then accept "oifname \"int\" iifname \"ppp0\"" 130 else "oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip6" 131 ) 132 # how does this even make sense in an input chain? 133 (accept "oifname \"int\" iifname \"ppp0\" ct state established,related") 134 (accept "iifname \"int\" oifname \"ppp0\" ") 135 ]; 136 }; 137 138 incoming-allowed-ip6 = { 139 type = "filter"; 140 family = "ip6"; 141 rules = [ 142 # this is where you put permitted incoming connections 143 # "oifname \"int\" ip6 daddr 2001:8b0:de3a:40de::e9d tcp dport 22" 144 ]; 145 }; 146 147 nat-tx = { 148 type = "nat"; 149 hook = "postrouting"; 150 priority = "100"; 151 policy = "accept"; 152 family = "ip"; 153 rules = [ 154 "oifname \"ppp0\" masquerade" 155 ]; 156 }; 157 nat-rx = { 158 type = "nat"; 159 hook = "prerouting"; 160 priority = "-100"; 161 family = "ip"; 162 policy = "accept"; 163 rules = [ 164 # per https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-configuring_nat_using_nftables: 165 # "Even if you do not add a rule to the prerouting chain, the 166 # nftables framework requires this chain to match incoming 167 # packet replies. " 168 ]; 169 }; 170 }