liminix

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

default-rules.nix (7680B)


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