define icmp_protos = {ipv6-icmp, icmp, igmp}

table arp filter {
  limit lim_arp {
    rate over 50 mbytes/second burst 50 mbytes
  }

  counter arp-rx {}
  counter arp-tx {}

  counter arp-ratelimit-rx {}
  counter arp-ratelimit-tx {}

  chain input {
    type filter hook input priority filter
    policy accept

    limit name lim_arp counter name arp-ratelimit-rx drop

    counter name arp-rx
  }

  chain output {
    type filter hook output priority filter
    policy accept

    limit name lim_arp counter name arp-ratelimit-tx drop

    counter name arp-tx
  }
}

table inet filter {
  limit lim_reject {
    rate over 1000/second burst 1000 packets
  }

  limit lim_icmp {
    rate over 50 mbytes/second burst 50 mbytes
  }

  counter invalid-fw {}
  counter fw-lo {}
  counter fw-vpn {}
  counter fw-upstream {}

  counter icmp-ratelimit-upstream-fw {}
  counter icmp-ratelimit-vpn-fw {}
  counter icmp-ratelimit-established-fw {}

  counter icmp-upstream-fw {}
  counter icmp-vpn-fw {}
  counter icmp-established-fw {}

  counter reject-ratelimit-fw {}
  counter reject-fw {}
  counter reject-tcp-fw {}
  counter reject-icmp-fw {}

  counter drop-fw {}

  counter invalid-rx {}

  counter rx-lo {}
  counter invalid-local4-rx {}
  counter invalid-local6-rx {}

  counter icmp-ratelimit-rx {}
  counter icmp-rx {}

  counter wg-rx {}

  counter established-rx {}

  counter reject-ratelimit-rx {}
  counter reject-rx {}
  counter reject-tcp-rx {}
  counter reject-icmp-rx {}

  counter drop-rx {}

  counter tx-lo {}

  counter icmp-ratelimit-tx {}
  counter icmp-tx {}

  counter wg-tx {}

  counter tx {}

  chain forward {
    type filter hook forward priority filter
    policy drop


    ct state invalid log level debug prefix "vpn: drop invalid forward: " counter name invalid-fw drop


    iifname lo counter name fw-lo accept

    meta l4proto $icmp_protos iifname upstream limit name lim_icmp counter name icmp-ratelimit-upstream-fw drop
    meta l4proto $icmp_protos iifname upstream counter name icmp-upstream-fw accept
    meta l4proto $icmp_protos iifname vpn limit name lim_icmp counter name icmp-ratelimit-vpn-fw drop
    meta l4proto $icmp_protos iifname vpn counter name icmp-vpn-fw accept
    meta l4proto $icmp_protos ct state {established, related} limit name lim_icmp counter name icmp-ratelimit-established-fw drop
    meta l4proto $icmp_protos ct state {established, related} counter name icmp-established-fw accept


    iifname upstream oifname vpn ct state {established, related} counter name fw-vpn accept
    iifname vpn oifname upstream counter name fw-upstream accept


    limit name lim_reject log level debug prefix "vpn: drop forward: " counter name reject-ratelimit-fw drop
    log level debug prefix "vpn: reject forward: " counter name reject-fw
    meta l4proto tcp ct state new counter name reject-tcp-fw reject with tcp reset
    ct state new counter name reject-icmp-fw reject


    counter name drop-fw
  }

  chain input {
    type filter hook input priority filter
    policy drop


    ct state invalid log level debug prefix "vpn: drop invalid input: " counter name invalid-rx drop
    

    iifname lo counter name rx-lo accept
    iif != lo ip daddr 127.0.0.1/8 counter name invalid-local4-rx reject
    iif != lo ip6 daddr ::1/128 counter name invalid-local6-rx reject

    meta l4proto $icmp_protos limit name lim_icmp counter name icmp-ratelimit-rx drop
    meta l4proto $icmp_protos counter name icmp-rx accept

    udp dport 51820 counter name wg-rx accept

    ct state {established, related} counter name established-rx accept


    limit name lim_reject log level debug prefix "vpn: drop input: " counter name reject-ratelimit-rx drop
    log level debug prefix "vpn: reject input: " counter name reject-rx
    meta l4proto tcp ct state new counter name reject-tcp-rx reject with tcp reset
    ct state new counter name reject-icmp-rx reject


    counter name drop-rx
  }

  chain output {
    type filter hook output priority filter
    policy accept


    oifname lo counter name tx-lo accept

    meta l4proto $icmp_protos limit name lim_icmp counter name icmp-ratelimit-tx drop
    meta l4proto $icmp_protos counter name icmp-tx accept


    udp sport 51820 counter name wg-tx
    

    counter name tx
  }
}

table inet nat {
  counter nat {}
  
  chain postrouting {
    type nat hook postrouting priority srcnat
    policy accept

    iifname vpn counter name nat masquerade
  }
}

table ip mss_clamp {
  counter mss-clamp {}

  chain postrouting {
    type filter hook postrouting priority mangle
    policy accept

    iifname vpn oifname upstream tcp flags & (syn|rst) == syn counter name mss-clamp tcp option maxseg size set rt mtu
  }
}