openvpn: add riseup in net namespace
authorJulien Moutinho <julm@sourcephile.fr>
Mon, 16 Nov 2020 03:39:37 +0000 (04:39 +0100)
committerJulien Moutinho <julm@sourcephile.fr>
Mon, 16 Nov 2020 05:26:58 +0000 (06:26 +0100)
12 files changed:
machines/losurdo/networking.nix
machines/losurdo/networking/nftables.nix
machines/losurdo/networking/openvpn.nix [new file with mode: 0644]
machines/losurdo/networking/openvpn/riseup.nix [new file with mode: 0644]
machines/losurdo/networking/openvpn/riseup/cacert.pem [new file with mode: 0644]
machines/losurdo/networking/openvpn/riseup/client.pem [new file with mode: 0644]
machines/losurdo/transmission.nix
machines/mermet/networking/nftables.nix
nixos/modules.nix
nixos/modules/services/networking/netns.nix [new file with mode: 0644]
nixos/modules/services/networking/openvpn.nix [new file with mode: 0644]
var/nftables/filter.txt [new file with mode: 0644]

index 1c235cf9a70dc14d89baef9514acd57d85586a33..7f2bb678b559ef989295d2b0bdca980f02e2e7a4 100644 (file)
@@ -17,6 +17,7 @@ imports = [
   networking/nsupdate.nix
   networking/upnpc.nix
   networking/wireless.nix
+  networking/openvpn.nix
 ];
 
 boot.initrd.network = {
index f5cfff7b7258c0285b82b82790cf56be3ff47d47..3b931212be5988b563f257f5fb70afc5c0cf73c9 100644 (file)
@@ -14,58 +14,7 @@ networking.nftables = {
   enable = true;
   ruleset = lib.mkBefore ''
     table inet filter {
-      # A set containing the udp port(s) to which SSDP replies are allowed.
-      set ssdp_out {
-        type inet_service
-        timeout 5s
-      }
-      set lograte4 { type ipv4_addr; size 65535; flags dynamic; }
-      set lograte6 { type ipv6_addr; size 65535; flags dynamic; }
-      chain block {
-        add @lograte4 { ip  saddr limit rate 1/minute } log level warn prefix "block: "
-        add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "block: "
-        counter drop
-      }
-      chain ping-flood {
-        add @lograte4 { ip  saddr limit rate 1/minute } log level warn prefix "ping-flood: "
-        add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "ping-flood: "
-        counter drop
-      }
-      chain smurf {
-        add @lograte4 { ip  saddr limit rate 1/minute } log level warn prefix "smurf: "
-        add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "smurf: "
-        counter drop
-      }
-      chain bogus-tcp {
-        add @lograte4 { ip  saddr limit rate 1/minute } log level warn prefix "bogus-tcp: "
-        add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "bogus-tcp: "
-        counter drop
-      }
-      chain syn-flood {
-        add @lograte4 { ip  saddr limit rate 1/minute } log level warn prefix "syn-flood: "
-        add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "syn-flood: "
-        counter drop
-      }
-      chain check-tcp {
-        tcp flags syn tcp option maxseg size != 536-65535 counter goto bogus-tcp
-        tcp flags & (ack|fin) == fin counter goto bogus-tcp
-        tcp flags & (ack|psh) == psh counter goto bogus-tcp
-        tcp flags & (ack|urg) == urg counter goto bogus-tcp
-        tcp flags & (fin|ack) == fin counter goto bogus-tcp
-        tcp flags & (fin|rst) == (fin|rst) counter goto bogus-tcp
-        tcp flags & (fin|psh|ack) == (fin|psh) counter goto bogus-tcp
-        tcp flags & (syn|fin) == (syn|fin) counter goto bogus-tcp comment "SYN-FIN scan"
-        tcp flags & (syn|rst) == (syn|rst) counter goto bogus-tcp comment "SYN-RST scan"
-        tcp flags == (fin|syn|rst|psh|ack|urg) counter goto bogus-tcp comment "XMAS scan"
-        tcp flags == 0x0 counter goto bogus-tcp comment "NULL scan"
-        tcp flags == (fin|urg|psh) counter goto bogus-tcp
-        tcp flags == (fin|urg|psh|syn) counter goto bogus-tcp comment "NMAP-ID"
-        tcp flags == (fin|urg|syn|rst|ack) counter goto bogus-tcp
-
-        ct state new tcp flags != syn counter goto bogus-tcp
-        tcp sport 0 tcp flags & (fin|syn|rst|ack) == syn counter goto bogus-tcp
-        tcp flags & (fin|syn|rst|ack) == syn counter limit rate over 30/second burst 60 packets goto syn-flood
-      }
+      include "${../../../var/nftables/filter.txt}"
       chain net2fw {
         #udp dport mdns ip6 daddr ff02::fb counter accept comment "Accept mDNS"
         #udp dport mdns ip daddr 224.0.0.251 counter accept comment "Accept mDNS"
@@ -104,43 +53,6 @@ networking.nftables = {
       chain extra2fw {
         # Some .nix append rules here with: add rule inet filter extra2fw ...
       }
-      chain accept-icmpv6 {
-        # Traffic That Must Not Be Dropped
-        # https://tools.ietf.org/html/rfc4890#section-4.4.1
-        icmpv6 type destination-unreachable counter accept
-        icmpv6 type packet-too-big counter accept
-        icmpv6 type time-exceeded counter accept
-        icmpv6 type parameter-problem counter accept
-
-        # Address Configuration and Router Selection messages
-        # (must be received with hop limit = 255)
-        icmpv6 type nd-router-solicit ip6 hoplimit 255 counter accept
-        ip6 nexthdr ipv6-icmp icmpv6 type nd-router-advert ip6 hoplimit 255 counter accept
-        icmpv6 type nd-neighbor-solicit ip6 hoplimit 255 counter accept
-        icmpv6 type nd-neighbor-advert ip6 hoplimit 255 counter accept
-        icmpv6 type nd-redirect ip6 hoplimit 255 log level warn prefix "icmpv6: nd-redirect: " counter drop
-        icmpv6 type ind-neighbor-solicit ip6 hoplimit 255 counter accept
-        icmpv6 type ind-neighbor-advert ip6 hoplimit 255 counter accept
-
-        # Link-local multicast receiver notification messages
-        # (must have link-local source address)
-        icmpv6 type mld-listener-query ip6 saddr fe80::/10 counter accept
-        icmpv6 type mld-listener-report ip6 saddr fe80::/10 counter accept
-        icmpv6 type mld-listener-done ip6 saddr fe80::/10 counter accept
-        # https://tools.ietf.org/html/rfc3810 Multicast Listener Discovery Version 2 (MLDv2) for IPv6
-        icmpv6 type mld2-listener-report ip6 saddr fe80::/10 counter accept
-
-        # SEND Certificate Path notification messages
-        # (must be received with hop limit = 255)
-        icmpv6 type 148 ip6 hoplimit 255 counter accept comment "certificate-path-solicitation"
-        icmpv6 type 149 ip6 hoplimit 255 counter accept comment "certificate-path-advertisement"
-
-        # Multicast Router Discovery messages
-        # (must have link-local source address and hop limit = 1)
-        icmpv6 type 151 ip6 saddr fe80::/10 ip6 hoplimit 1 counter accept comment "multicast-router-advertisement"
-        icmpv6 type 152 ip6 saddr fe80::/10 ip6 hoplimit 1 counter accept comment "multicast-router-solicitation"
-        icmpv6 type 153 ip6 saddr fe80::/10 ip6 hoplimit 1 counter accept comment "multicast-router-termination"
-      }
 
       chain input {
         type filter hook input priority filter
@@ -149,54 +61,10 @@ networking.nftables = {
         iifname lo accept
 
         jump check-tcp
-
         ct state { established, related } accept
-
-        # Connectivity checking messages
-        # (multicast) ping
-        ip protocol icmp icmp type echo-reply counter accept
-
-        ${lib.optionalString networking.enableIPv6 ''
-        # drop packets with rh0 headers
-        rt type 0 jump block
-        rt type 0 jump block
-        rt type 0 jump block
-
-        # (multicast) ping
-        ip6 nexthdr ipv6-icmp icmpv6 type echo-reply counter accept
-
-        #ip6 daddr fe80::/64 udp dport 546 counter accept comment "DHCPv6"
-        ''}
-
+        jump accept-connectivity-input
         ct state invalid counter drop
 
-        ip protocol icmp icmp type destination-unreachable counter accept
-        ip protocol icmp icmp type time-exceeded counter accept
-        ip protocol icmp icmp type parameter-problem counter accept
-        ip protocol icmp icmp type echo-request limit rate over 10/second burst 20 packets goto ping-flood
-        ip protocol icmp icmp type echo-request counter accept
-        # echo-reply is handled before invalid packets to allow multicast ping
-        # which do not have an associated connection.
-
-        #ip daddr 224.0.0.251 udp dport 5353 counter accept comment "mDNS"
-        #ip saddr 0.0.0.0/32 counter accept comment "DHCP"
-        #ip udp sport 67 udp dport 68 counter accept comment "DHCP"
-
-        ${lib.optionalString networking.enableIPv6 ''
-        ip6 nexthdr ipv6-icmp jump accept-icmpv6
-
-        # Connectivity checking messages
-        icmpv6 type echo-request counter accept
-        # echo-reply is handled before invalid because of multicast
-
-        ip6 nexthdr ipv6-icmp log level err prefix "net2fw: icmpv6: catch all: " counter reject
-
-        ip6 daddr ff02::fb udp dport 5353 counter accept comment "mDNS"
-        ''}
-
-        ip saddr 224.0.0.0/4 counter goto smurf
-        fib saddr type broadcast counter goto smurf
-
         # admin services
         tcp dport 22 counter accept comment "SSH"
         udp dport 60000-61000 counter accept comment "Mosh"
@@ -208,31 +76,7 @@ networking.nftables = {
         policy drop
 
         ct state { related, established } accept
-
-        ip protocol icmp icmp type destination-unreachable counter accept
-        ip protocol icmp icmp type time-exceeded counter accept
-        ip protocol icmp icmp type parameter-problem counter accept
-        ip protocol icmp icmp type echo-request counter accept
-
-        ${lib.optionalString networking.enableIPv6 ''
-        # Traffic That Must Not Be Dropped
-        # https://tools.ietf.org/html/rfc4890#section-4.3.1
-        ip6 nexthdr ipv6-icmp icmpv6 type destination-unreachable counter accept
-        ip6 nexthdr ipv6-icmp icmpv6 type packet-too-big counter accept
-        ip6 nexthdr ipv6-icmp icmpv6 type time-exceeded counter accept
-        ip6 nexthdr ipv6-icmp icmpv6 type parameter-problem counter accept
-
-        # Connectivity checking messages
-        ip6 nexthdr ipv6-icmp icmpv6 type echo-request counter accept
-        ip6 nexthdr ipv6-icmp icmpv6 type echo-reply counter accept
-
-        # Traffic That Normally Should Not Be Dropped
-        # https://tools.ietf.org/html/rfc4890#section-4.3.2
-        ip6 nexthdr ipv6-icmp icmpv6 type 144 counter accept comment "home-agent-address-discovery-request"
-        ip6 nexthdr ipv6-icmp icmpv6 type 145 counter accept comment "home-agent-address-discovery-reply"
-        ip6 nexthdr ipv6-icmp icmpv6 type 146 counter accept comment "mobile-prefix-solicitation"
-        ip6 nexthdr ipv6-icmp icmpv6 type 147 counter accept comment "mobile-prefix-advertisement"
-        ''}
+        jump accept-connectivity-forward
       }
       chain output {
         type filter hook output priority filter
@@ -241,22 +85,7 @@ networking.nftables = {
         oifname lo accept
 
         ct state { related, established } accept
-
-        ip protocol icmp counter accept
-        meta skuid 0 udp dport 33434-33523 counter accept comment "traceroute"
-
-        ${lib.optionalString networking.enableIPv6 ''
-        ip6 nexthdr ipv6-icmp jump accept-icmpv6
-
-        # Connectivity checking messages
-        ip6 nexthdr ipv6-icmp icmpv6 type echo-request counter accept
-        ip6 nexthdr ipv6-icmp icmpv6 type echo-reply counter accept
-        ip6 nexthdr ipv6-icmp log level err prefix "fw2net: icmpv6: catch all: " counter reject
-
-        ip6 daddr ff02::1:2/64 udp dport 547 counter accept comment "DHCPv6"
-        ''}
-
-        ct state invalid log level warn prefix "fw2net: invalid: " counter drop
+        jump accept-connectivity-output
 
         tcp dport 22 counter accept comment "SSH"
 
diff --git a/machines/losurdo/networking/openvpn.nix b/machines/losurdo/networking/openvpn.nix
new file mode 100644 (file)
index 0000000..19c65b6
--- /dev/null
@@ -0,0 +1,5 @@
+{
+imports = [
+  openvpn/riseup.nix
+];
+}
diff --git a/machines/losurdo/networking/openvpn/riseup.nix b/machines/losurdo/networking/openvpn/riseup.nix
new file mode 100644 (file)
index 0000000..01f4733
--- /dev/null
@@ -0,0 +1,194 @@
+{ pkgs, lib, config, ... }:
+let
+  ns = "riseup";
+  dev = "ov-${ns}";
+  inherit (config.services) openvpn;
+in
+{
+networking.nftables.ruleset = ''
+  add rule inet filter fw2net tcp dport {443,1194} counter accept comment "OpenVPN"
+'';
+systemd.services."openvpn-${ns}" = {
+  bindsTo = [ "netns@${ns}.service" ];
+  requires = [ "netns@${ns}.service" ];
+};
+services.openvpn.servers = {
+  "${ns}" = {
+    config = ''
+      verb 3
+      ca ${riseup/cacert.pem}
+      cert ${riseup/client.pem}
+      client
+      dev ov-${ns}
+      dev-type tun
+      persist-tun
+      nobind
+      # Useless to setup the interface
+      # because moving it to ${ns} will reset it
+      ifconfig-noexec
+      route-noexec
+      persist-key
+      key ${riseup/client.pem}
+      tls-client
+      remote-cert-tls server
+      remote 37.218.241.7 1194 tcp4
+      remote 37.218.241.106 443 tcp4
+      remote 163.172.126.44 443 tcp4
+      remote 198.252.153.28 443 tcp4
+      remote 199.58.81.143 443 tcp4
+      remote 199.58.81.145 443 tcp4
+      remote 212.83.143.67 443 tcp4
+      remote 212.83.144.12 443 tcp4
+      remote 212.83.146.228 443 tcp4
+      remote 212.83.165.160 443 tcp4
+      remote 212.83.182.127 443 tcp4
+      remote 212.129.62.247 443 tcp4
+      reneg-sec 0
+      script-security 2
+      up-restart
+    '';
+    up = let dev = "ov-${ns}"; in ''
+      set -eux
+      PATH=${lib.makeBinPath [pkgs.iproute]}
+      ip link set dev "${dev}" up netns "${ns}" mtu "$tun_mtu"
+      ip netns exec "${ns}" ${pkgs.writeShellScript "route-up.sh" ''
+        set -eux
+        PATH=${lib.makeBinPath [pkgs.iproute pkgs.coreutils]}
+
+        ip link set dev lo up
+
+        mkdir -p /etc/netns/"${ns}"
+        foreign_opt_domains=
+        process_foreign_option () {
+          case "$1:$2" in
+            dhcp-option:DNS) echo "nameserver $3" >>/etc/netns/"${ns}"/resolv.conf ;;
+            dhcp-option:DOMAIN) foreign_opt_domains="$foreign_opt_domains $3" ;;
+          esac
+        }
+        if test ! -e /etc/netns/"${ns}"/resolv.conf; then
+          # add DNS settings if given in foreign options
+          i=1
+          while
+            eval opt=\"\''${foreign_option_$i-}\"
+            [ -n "$opt" ]
+          do
+            process_foreign_option $opt
+            i=$(( i + 1 ))
+          done
+          for d in $foreign_opt_domains; do
+            printf '%s\n' "domain $1" "search $*" \
+              >>/etc/netns/"${ns}"/resolv.conf
+          done
+        fi
+
+        netmask4="''${ifconfig_netmask:-30}"
+        netbits6="''${ifconfig_ipv6_netbits:-112}"
+        if [ -n "''${ifconfig_local-}" ]; then
+          if [ -n "''${ifconfig_remote-}" ]; then
+            ip -4 addr replace \
+              local "$ifconfig_local" \
+              peer "$ifconfig_remote/$netmask4" \
+              ''${ifconfig_broadcast:+broadcast "$ifconfig_broadcast"} \
+              dev "${dev}"
+          else
+            ip -4 addr replace \
+              local "$ifconfig_local/$netmask4" \
+              ''${ifconfig_broadcast:+broadcast "$ifconfig_broadcast"} \
+              dev "${dev}"
+          fi
+        fi
+        if [ -n "''${ifconfig_ipv6_local-}" ]; then
+          if [ -n "''${ifconfig_ipv6_remote-}" ]; then
+            ip -6 addr replace \
+              local "$ifconfig_ipv6_local" \
+              peer "$ifconfig_ipv6_remote/$netbits6" \
+              dev "${dev}"
+          else
+            ip -6 addr replace \
+              local "$ifconfig_ipv6_local/$netbits6" \
+              dev "${dev}"
+          fi
+        fi
+
+        ${pkgs.writeScript "ruleset" openvpn.servers.${ns}.nftables}
+      ''}
+    '';
+    routeUp = ''
+      set -eux
+      PATH=${lib.makeBinPath [pkgs.iproute]}
+      ${pkgs.coreutils}/bin/env
+      ip netns exec "${ns}" ${pkgs.writeShellScript "route-up.sh" ''
+        set -eux
+        PATH=${lib.makeBinPath [pkgs.iproute]}
+        i=1
+        while
+          eval net=\"\''${route_network_$i-}\"
+          eval mask=\"\''${route_netmask_$i-}\"
+          eval gw=\"\''${route_gateway_$i-}\"
+          eval mtr=\"\''${route_metric_$i-}\"
+          [ -n "$net" ]
+        do
+          ip -4 route replace "$net/$mask" via "$gw" ''${mtr:+metric "$mtr"}
+          i=$(( i + 1 ))
+        done
+
+        if [ -n "''${route_vpn_gateway-}" ]; then
+          ip -4 route replace default via "$route_vpn_gateway"
+        fi
+
+        i=1
+        while
+          # There doesn't seem to be $route_ipv6_metric_<n>
+          # according to the manpage.
+          eval net=\"\''${route_ipv6_network_$i-}\"
+          eval gw=\"\''${route_ipv6_gateway_$i-}\"
+          [ -n "$net" ]
+        do
+          ip -6 route replace  "$net"  via "$gw"  metric 100
+          i=$(( i + 1 ))
+        done
+
+        # There's no $route_vpn_gateway for IPv6. It's not
+        # documented if OpenVPN includes default route in
+        # $route_ipv6_*. Set default route to remote VPN
+        # endpoint address if there is one. Use higher metric
+        # than $route_ipv6_* routes to give preference to a
+        # possible default route in them.
+        if [ -n "''${ifconfig_ipv6_remote-}" ]; then
+          ip -6 route replace default \
+            via "$ifconfig_ipv6_remote" metric 200
+        fi
+      ''}
+    '';
+    nftables = lib.mkBefore ''
+      #!${pkgs.nftables}/bin/nft -f
+      flush ruleset
+      table inet filter {
+        include "${../../../../var/nftables/filter.txt}"
+        chain input {
+          type filter hook input priority filter
+          policy drop
+          iifname lo accept
+          jump check-tcp
+          ct state { established, related } accept
+          jump accept-connectivity-input
+          jump check-broadcast
+          ct state invalid drop
+        }
+        chain forward {
+          type filter hook forward priority filter
+          policy drop
+          jump accept-connectivity-forward
+        }
+        chain output {
+          type filter hook output priority filter
+          policy drop
+          oifname lo accept
+          ct state { related, established } accept
+          jump accept-connectivity-output
+        }
+      }
+    '';
+  };
+};
+}
diff --git a/machines/losurdo/networking/openvpn/riseup/cacert.pem b/machines/losurdo/networking/openvpn/riseup/cacert.pem
new file mode 100644 (file)
index 0000000..cbec39c
--- /dev/null
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFjTCCA3WgAwIBAgIBATANBgkqhkiG9w0BAQ0FADBZMRgwFgYDVQQKDA9SaXNl
+dXAgTmV0d29ya3MxGzAZBgNVBAsMEmh0dHBzOi8vcmlzZXVwLm5ldDEgMB4GA1UE
+AwwXUmlzZXVwIE5ldHdvcmtzIFJvb3QgQ0EwHhcNMTQwNDI4MDAwMDAwWhcNMjQw
+NDI4MDAwMDAwWjBZMRgwFgYDVQQKDA9SaXNldXAgTmV0d29ya3MxGzAZBgNVBAsM
+Emh0dHBzOi8vcmlzZXVwLm5ldDEgMB4GA1UEAwwXUmlzZXVwIE5ldHdvcmtzIFJv
+b3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC76J4ciMJ8Sg0m
+TP7DF2DT9zNe0Csk4myoMFC57rfJeqsAlJCv1XMzBmXrw8wq/9z7XHv6n/0sWU7a
+7cF2hLR33ktjwODlx7vorU39/lXLndo492ZBhXQtG1INMShyv+nlmzO6GT7ESfNE
+LliFitEzwIegpMqxCIHXFuobGSCWF4N0qLHkq/SYUMoOJ96O3hmPSl1kFDRMtWXY
+iw1SEKjUvpyDJpVs3NGxeLCaA7bAWhDY5s5Yb2fA1o8ICAqhowurowJpW7n5ZuLK
+5VNTlNy6nZpkjt1QycYvNycffyPOFm/Q/RKDlvnorJIrihPkyniV3YY5cGgP+Qkx
+HUOT0uLA6LHtzfiyaOqkXwc4b0ZcQD5Vbf6Prd20Ppt6ei0zazkUPwxld3hgyw58
+m/4UIjG3PInWTNf293GngK2Bnz8Qx9e/6TueMSAn/3JBLem56E0WtmbLVjvko+LF
+PM5xA+m0BmuSJtrD1MUCXMhqYTtiOvgLBlUm5zkNxALzG+cXB28k6XikXt6MRG7q
+hzIPG38zwkooM55yy5i1YfcIi5NjMH6A+t4IJxxwb67MSb6UFOwg5kFokdONZcwj
+shczHdG9gLKSBIvrKa03Nd3W2dF9hMbRu//STcQxOailDBQCnXXfAATj9pYzdY4k
+ha8VCAREGAKTDAex9oXf1yRuktES4QIDAQABo2AwXjAdBgNVHQ4EFgQUC4tdmLVu
+f9hwfK4AGliaet5KkcgwDgYDVR0PAQH/BAQDAgIEMAwGA1UdEwQFMAMBAf8wHwYD
+VR0jBBgwFoAUC4tdmLVuf9hwfK4AGliaet5KkcgwDQYJKoZIhvcNAQENBQADggIB
+AGzL+GRnYu99zFoy0bXJKOGCF5XUXP/3gIXPRDqQf5g7Cu/jYMID9dB3No4Zmf7v
+qHjiSXiS8jx1j/6/Luk6PpFbT7QYm4QLs1f4BlfZOti2KE8r7KRDPIecUsUXW6P/
+3GJAVYH/+7OjA39za9AieM7+H5BELGccGrM5wfl7JeEz8in+V2ZWDzHQO4hMkiTQ
+4ZckuaL201F68YpiItBNnJ9N5nHr1MRiGyApHmLXY/wvlrOpclh95qn+lG6/2jk7
+3AmihLOKYMlPwPakJg4PYczm3icFLgTpjV5sq2md9bRyAg3oPGfAuWHmKj2Ikqch
+Td5CHKGxEEWbGUWEMP0s1A/JHWiCbDigc4Cfxhy56CWG4q0tYtnc2GMw8OAUO6Wf
+Xu5pYKNkzKSEtT/MrNJt44tTZWbKV/Pi/N2Fx36my7TgTUj7g3xcE9eF4JV2H/sg
+tsK3pwE0FEqGnT4qMFbixQmc8bGyuakr23wjMvfO7eZUxBuWYR2SkcP26sozF9PF
+tGhbZHQVGZUTVPyvwahMUEhbPGVerOW0IYpxkm0x/eaWdTc4vPpf/rIlgbAjarnJ
+UN9SaWRlWKSdP4haujnzCoJbM7dU9bjvlGZNyXEekgeT0W2qFeGGp+yyUWw8tNsp
+0BuC1b7uW/bBn/xKm319wXVDvBgZgcktMolak39V7DVO
+-----END CERTIFICATE-----
diff --git a/machines/losurdo/networking/openvpn/riseup/client.pem b/machines/losurdo/networking/openvpn/riseup/client.pem
new file mode 100644 (file)
index 0000000..cb391bb
--- /dev/null
@@ -0,0 +1,54 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAs4V9VZQSh1xSjk0tIUc3B6nEu8uLht/WDp+LU/RzPdjLDMXc
+irpRKzBAuhqJwWB0SBw8LoaNp1DnIVetEa1RmuWkD+VVTtDwaPwst36T64BHrKzP
+yiK/vXs5mzhm4KbLKFlcwOYGysNrORVrMJtSsK6TD9TpoPEeELTJt8gJ1mFGZBjY
+HHRMGvYOvZwFhtsMDNSj5b48KwxIIiiPfrkYElNRU35NQcZfT8ETvRCM+R98E+3E
+YFY017Lhfzdgak5LWttYB/AVruOMbmSv50WKT6rhZFeG6llelEcPaRb1aT6IR3uq
+nhQLn/xXsUKEO+pAvOUb6p+GyOwcQMMAHDLkOQIDAQABAoIBAB31hBIZEPKIBLr8
+xDBOiy97NHrGoDVU+4sbMwxCukyy9kfeaUy5hTw45ERqk1yzNRSnqZ92EwO+K6RT
+1m0hyIGaG0QP2Km7krNiii/hLtxZXxzBBjhMjkUX4Gg4BGsvSq4kI6eJe86wyB8R
+pP7KnQUhTSeSN58FPig5k4RZHNMqxwIjWLBWoz3qy82CtICcJLWDd0ro/rNZFW8h
+LAteXA7DuOlbyFHcC0SG8kctB9ZRPkasdwrF6swyBOTTtwabsMXfat8f+mqM6Efo
+VZ3Xp2wN0UXEFVjJXMEDDeQH+q0kGE7H6MQE/0FiOt98wLuC5bBYQC0HxMSlWdz1
+USbPDVUCgYEA4vlA29mvSffe4iqDC83VtawMt4lC5m2Zqs8+D4BV1kUnnA9OO1zu
+ZPmof4eWj6K17k7YXO8Xd8je794s4iTmZvO5Ig76bZk43N8aXSr0M+WmMMLRKAbC
+EsJlVOwwwwmu2sQLHBEeS+9vsnA1tlslvtqsq5/fEBOFXGMvMrS9be8CgYEAynq6
+hTKodj7BpvwipGXLa+uaPN8ttCesOUc+yKK9nuMnpJNPU1MCyTEtskijsz823Tzi
+ti1dyTQSiBFtFgh8D1dUYKdd98u3ljzoToSsaDvIyMvn/2pxvTGMvZ9VaMSRHlZI
+bMC9xtfchuDzVR3APh2I4CV9UHnCEiIVtRrd+FcCgYEA0wdWI1KI5Kf+ZZ+LCf2N
+toTJqheHyQCcADEBjZ4PsNHJWxLr9MuZpu5smG3zMYbhyjkqd3WhBzEO/kw+xN/0
+DEKMnbr5Yc81DD6un3Mha+MYGnv3xVRLOu/dEREs4Rnupd3iSm0sEwQCgRBNEEg8
+lu9v3X4eAi90LgrVxjo/aacCgYEAqCOeO/nDNt4KRbZethHqCKZPIHlcJJxFQhNN
+qaKqwAR16Q6C8vid+aCjB8eWWMUHtFRZF1s45FofgWqnIYLOMpccdF7Hg3xh6ZqO
+dpVp7eynYUciUlF8PdWlv9lOPX/t2jlgTx8G+NZMRJ0MtAPOnkY8YZYAKBHT/Obd
+C9VRumUCgYB5njH4P8PNeBA/H/vYF17a9F6ulDYHB5/BZnFcPfuxiov/aNepVyvt
+Z+QY6SmFdmak00YLh3qOGT5ek6iMODfKBe625VIr4p3akwzr/bu/LWHWNpfffaET
+bvJ4nzplqyYkMV9nLr+9N/iUjtRXQ0yHJp+cBRu2cS032TDyzplc7A==
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIEmzCCAoOgAwIBAgIQT9fuPod6b6yND5zUoXK38TANBgkqhkiG9w0BAQsFADB1
+MRgwFgYDVQQKDA9SaXNldXAgTmV0d29ya3MxGzAZBgNVBAsMEmh0dHBzOi8vcmlz
+ZXVwLm5ldDE8MDoGA1UEAwwzUmlzZXVwIE5ldHdvcmtzIFJvb3QgQ0EgKGNsaWVu
+dCBjZXJ0aWZpY2F0ZXMgb25seSEpMB4XDTIwMDgyMjAwMDAwMFoXDTIwMTEyMjAw
+MDAwMFowLTErMCkGA1UEAwwiVU5MSU1JVEVEODE5a3Rxa3ZhNGkyeDEzbW5wNnJ2
+MmswYzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALOFfVWUEodcUo5N
+LSFHNwepxLvLi4bf1g6fi1P0cz3YywzF3Iq6USswQLoaicFgdEgcPC6GjadQ5yFX
+rRGtUZrlpA/lVU7Q8Gj8LLd+k+uAR6ysz8oiv717OZs4ZuCmyyhZXMDmBsrDazkV
+azCbUrCukw/U6aDxHhC0ybfICdZhRmQY2Bx0TBr2Dr2cBYbbDAzUo+W+PCsMSCIo
+j365GBJTUVN+TUHGX0/BE70QjPkffBPtxGBWNNey4X83YGpOS1rbWAfwFa7jjG5k
+r+dFik+q4WRXhupZXpRHD2kW9Wk+iEd7qp4UC5/8V7FChDvqQLzlG+qfhsjsHEDD
+ABwy5DkCAwEAAaNvMG0wHQYDVR0OBBYEFCRYWXXaTEtq6EbvKXTDkTNTOf70MAsG
+A1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAjAJBgNVHRMEAjAAMB8GA1Ud
+IwQYMBaAFBf0G9XlKgEBTWuiXTYKKQmWZYBGMA0GCSqGSIb3DQEBCwUAA4ICAQCV
+sL/zmlK0f8conYDz2d5uZ0qIcJjtsb1DtE3vHULrei0cVgFuAX/y7XT4ddzj64r6
+PzkoHSZ5FhVbg/ZN0olpEed25kt6bp4m2QvfRNd/qctcYmnqsSZdC5vb7NByBWQE
+a7by2zvG281W0J+PRrXcnbPB2dTUMw7/mEJ9MIh5KfHWoPQl+KKYJorOgkoUACMS
+L1k+0xxKGOE7DDwALGa/Uh8KSEZ2tF3OrYTNfweaOmdjn6UBzii1Jn54aU4dhwea
+I5WFWDQ3TxOdtSrOWHuyVLNGE61iwMAhqLmPlBl3tqci/BHe5/bAKWx4FkS6GcZ6
++i6mCqJG93rT+XLmePqFd9WQKd5Ff9kG104X3Fv5qnVRxR+eYRqZjDg6kySFyj3G
+ZM9SXYH0dMl3oxMjroIBlIKIW3A+VFjWpM2W49eib+wVL0YL5wMTCNpK7ZM84amz
+b1Q1A9jKgPMmbIL9HFWDjJigMBC6SYu3vfNUsXQzimrRvho6HBpQ63X3FcOOAlZ3
+5z/3OFWwwRvI/S7SENgRj7QB6mTc0z18BdwYKB7UZX8xhoZWYr9UaKeo/OGoSi1K
+LqEe6R30A8PYGYgnXxeOe0adZHiIIElE9ypZccy2qAcak1BYdoHjQqoY96Amqi37
+J24ftvwhm5GUwYFRecUP7Ll/NI6AjcgxxDxU5v2viA==
+-----END CERTIFICATE-----
index 81eb9e2d08a8c64d69ebe63d97d4abe7142a6528..b8a93cbeee89f6d577c91290f1fc2f7cec69cbc2 100644 (file)
@@ -3,23 +3,31 @@ let
   inherit (config.services) transmission;
   inherit (config.users) users;
   inherit (config.security) gnupg;
+  netns = "riseup";
 in
 {
 users.groups.transmission.members = [
   users."julm".name
 ];
-networking.nftables.ruleset = ''
-  add rule inet filter net2fw tcp dport ${toString transmission.settings.peer-port} counter accept comment "Transmission"
-  add rule inet filter net2fw udp dport ${toString transmission.settings.peer-port} counter accept comment "Transmission"
-  add rule inet filter fw2net meta skuid ${transmission.user}                       counter accept comment "Transmission"
+services.openvpn.servers.${netns}.nftables = ''
+  add rule inet filter input tcp dport ${toString transmission.settings.peer-port} counter accept comment "Transmission"
+  add rule inet filter input udp dport ${toString transmission.settings.peer-port} counter accept comment "Transmission"
+  add rule inet filter output meta skuid ${transmission.user} counter accept comment "Transmission"
 '';
 #users.groups.keys.members = [ transmission.user ];
 security.gnupg.secrets."transmission/settings.json" = {
   user = transmission.user;
 };
 systemd.services.transmission = {
-  after = [ gnupg.secrets."transmission/settings.json".service ];
-  requires = [ gnupg.secrets."transmission/settings.json".service ];
+  after = [
+    gnupg.secrets."transmission/settings.json".service
+    "netns@${netns}.service"
+  ];
+  requires = [
+    gnupg.secrets."transmission/settings.json".service
+    "netns@${netns}.service"
+  ];
+  serviceConfig.NetworkNamespacePath = "/var/run/netns/${netns}";
 };
 services.transmission = {
   enable = true;
@@ -51,12 +59,12 @@ services.transmission = {
     queue-stalled-enabled = true;
     queue-stalled-minutes = 30;
     speed-limit-down-enabled = false;
-    speed-limit-up = 500;
+    speed-limit-up = 50;
     speed-limit-up-enabled = true;
     alt-speed-enabled = true;
     alt-speed-time-enabled = true;
-    alt-speed-down = 5000;
-    alt-speed-up = 50;
+    alt-speed-down = 1000;
+    alt-speed-up = 0;
     alt-speed-time-day = 127; # all days. 65; # weekend only
     alt-speed-time-begin = 360; # 06h00 local time
     alt-speed-time-end = 1320; # 22h00 local time
index b0b2cb2d9db30e4f030b3a1d06656379f7dde11a..1c440111d34290257c760ca5eb8f2d56df8a2c52 100644 (file)
@@ -14,72 +14,7 @@ networking.nftables = {
   enable = true;
   ruleset = lib.mkBefore ''
     table inet filter {
-      set lograte4 { type ipv4_addr; size 65535; flags dynamic; }
-      #set lograte6 { type ipv6_addr; size 65535; flags dynamic; }
-      chain ping-flood {
-        add @lograte4 { ip  saddr limit rate 1/minute } log level warn prefix "ping-flood: "
-        #add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "ping-flood: "
-        counter drop
-      }
-      chain check-ping {
-        ip protocol icmp   icmp   type echo-request limit rate over 10/second burst 20 packets goto ping-flood
-        #ip6 nexthdr ipv6-icmp icmpv6 type echo-request limit rate over 10/second burst 20 packets goto ping-flood
-      }
-      chain smurf {
-        add @lograte4 { ip  saddr limit rate 1/minute } log level warn prefix "smurf: "
-        #add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "smurf: "
-        counter drop
-      }
-      chain check-broadcast {
-        #ip saddr 0.0.0.0/32 counter accept comment "DHCP broadcast"
-        fib saddr type broadcast counter goto smurf
-        ip saddr 224.0.0.0/4     counter goto smurf
-      }
-      chain bogus-tcp {
-        add @lograte4 { ip  saddr limit rate 1/minute } log level warn prefix "bogus-tcp: "
-        #add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "bogus-tcp: "
-        counter drop
-      }
-      chain syn-flood {
-        add @lograte4 { ip  saddr limit rate 1/minute } log level warn prefix "syn-flood: "
-        #add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "syn-flood: "
-        counter drop
-      }
-      chain check-tcp {
-        tcp flags syn tcp option maxseg size != 536-65535 counter goto bogus-tcp
-        tcp flags & (ack|fin) == fin counter goto bogus-tcp
-        tcp flags & (ack|psh) == psh counter goto bogus-tcp
-        tcp flags & (ack|urg) == urg counter goto bogus-tcp
-        tcp flags & (fin|ack) == fin counter goto bogus-tcp
-        tcp flags & (fin|rst) == (fin|rst) counter goto bogus-tcp
-        tcp flags & (fin|psh|ack) == (fin|psh) counter goto bogus-tcp
-        tcp flags & (syn|fin) == (syn|fin) counter goto bogus-tcp comment "SYN-FIN scan"
-        tcp flags & (syn|rst) == (syn|rst) counter goto bogus-tcp comment "SYN-RST scan"
-        tcp flags == (fin|syn|rst|psh|ack|urg) counter goto bogus-tcp comment "XMAS scan"
-        tcp flags == 0x0 counter goto bogus-tcp comment "NULL scan"
-        tcp flags == (fin|urg|psh) counter goto bogus-tcp
-        tcp flags == (fin|urg|psh|syn) counter goto bogus-tcp comment "NMAP-ID"
-        tcp flags == (fin|urg|syn|rst|ack) counter goto bogus-tcp
-
-        ct state new tcp flags != syn counter goto bogus-tcp
-        tcp sport 0 tcp flags & (fin|syn|rst|ack) == syn counter goto bogus-tcp
-        tcp flags & (fin|syn|rst|ack) == syn counter limit rate over 30/second burst 60 packets goto syn-flood
-      }
-      chain spoofing {
-        add @lograte4 { ip  saddr limit rate 1/minute } log level warn prefix "spoofing: "
-        counter drop
-      }
-      chain check-public {
-        ip saddr 0.0.0.0/8 counter goto spoofing
-        ip saddr 10.0.0.0/8 counter goto spoofing
-        ip saddr 127.0.0.0/8 counter goto spoofing
-        ip saddr 169.254.0.0/16 counter goto spoofing
-        ip saddr 172.16.0.0/12 counter goto spoofing
-        ip saddr 192.0.2.0/24 counter goto spoofing
-        ip saddr 192.168.0.0/16 counter goto spoofing
-        ip saddr 224.0.0.0/3 counter goto spoofing
-        ip saddr 240.0.0.0/5 counter goto spoofing
-      }
+      include "${../../../var/nftables/filter.txt}"
       chain net2fw {
         jump check-public
         # Some .nix append rules here with: add rule inet filter net2fw ...
@@ -118,44 +53,14 @@ networking.nftables = {
 
         # accept traffic already established
         ct state { established, related } accept
+        jump accept-connectivity-input
+        jump check-broadcast
         ct state invalid drop
 
         # admin services
         tcp dport 22 counter accept comment "SSH"
         udp dport 60000-61000 counter accept comment "Mosh"
 
-        # ICMP
-        ip protocol icmp icmp type echo-request counter accept
-        ip protocol icmp icmp type destination-unreachable counter accept
-        ip protocol icmp icmp type router-solicitation counter accept
-        ip protocol icmp icmp type router-advertisement counter accept
-        ip protocol icmp icmp type time-exceeded counter accept
-        ip protocol icmp icmp type parameter-problem counter accept
-        ip protocol icmp log level warn prefix "net2fw: icmpv: " counter accept
-        #ip protocol icmp icmp type { echo-request, destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem } counter accept
-
-        #ip6 nexthdr ipv6-icmp icmpv6 type echo-request counter accept
-        #ip6 nexthdr ipv6-icmp icmpv6 type nd-neighbor-solicit counter accept
-        #ip6 nexthdr ipv6-icmp icmpv6 type nd-neighbor-advert counter accept
-        #ip6 nexthdr ipv6-icmp icmpv6 type nd-router-solicit counter accept
-        #ip6 nexthdr ipv6-icmp icmpv6 type nd-router-advert counter accept
-        #ip6 nexthdr ipv6-icmp icmpv6 type mld-listener-query counter accept
-        #ip6 nexthdr ipv6-icmp icmpv6 type mld-listener-report counter accept
-        #ip6 nexthdr ipv6-icmp icmpv6 type mld-listener-reduction counter accept
-        #ip6 nexthdr ipv6-icmp icmpv6 type destination-unreachable counter accept
-        #ip6 nexthdr ipv6-icmp icmpv6 type packet-too-big counter accept
-        #ip6 nexthdr ipv6-icmp icmpv6 type time-exceeded counter accept
-        #ip6 nexthdr ipv6-icmp icmpv6 type parameter-problem counter accept
-        #ip6 nexthdr ipv6-icmp icmpv6 type ind-neighbor-solicit counter accept
-        #ip6 nexthdr ipv6-icmp icmpv6 type ind-neighbor-advert counter accept
-        #ip6 nexthdr ipv6-icmp icmpv6 type mld2-listener-report counter accept
-        #ip6 nexthdr ipv6-icmp log level warn prefix "net2fw: icmpv6: " counter accept
-        #ip6 nexthdr ipv6-icmp icmpv6 type { echo-request, nd-neighbor-solicit, nd-neighbor-advert, nd-router-solicit, nd-router-advert, mld-listener-query, mld-listener-report, mld-listener-reduction, destination-unreachable, packet-too-big, time-exceeded, parameter-problem, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } counter accept
-
-        # ICMP
-        ip protocol icmp   icmp   type echo-request accept
-        #ip6 nexthdr ipv6-icmp icmpv6 type echo-request accept
-
         # Some .nix append gotos here with: add rule inet filter input iffname ... goto ...
       }
       chain output {
@@ -165,9 +70,8 @@ networking.nftables = {
         oifname lo accept
 
         ct state { established, related } accept
-        ct state invalid drop
+        jump accept-connectivity-output
 
-        icmp type echo-request counter accept comment "Ping"
         tcp dport 22 counter accept comment "SSH"
 
         # Some .nix append gotos here with: add rule inet filter output oifname ... goto ...
index c5eaa90afd77f4cdeabd6ef149bfe18c07eb4736..d743e23ecde49bce47b52b86c6002901bb8591ce 100644 (file)
@@ -11,6 +11,8 @@ imports = [
   #modules/security/gnupg.nix
   #modules/services/networking/biboumi.nix
   #modules/services/networking/croc.nix
+  modules/services/networking/netns.nix
+  modules/services/networking/openvpn.nix
   #/home/julm/src/nix/nixpkgs/.git-worktree/transmission/nixos/modules/services/torrent/transmission.nix
   #/home/julm/src/nix/nixpkgs/nixos/modules/services/torrent/transmission.nix
   #modules/services/mail/mlmmj.nix
@@ -24,6 +26,8 @@ disabledModules = [
   #"security/gnupg.nix"
   #"services/networking/biboumi.nix"
   #"services/networking/croc.nix"
+  "services/networking/netns.nix"
+  "services/networking/openvpn.nix"
   #"services/torrent/transmission.nix"
   "services/freeciv.nix"
 ];
diff --git a/nixos/modules/services/networking/netns.nix b/nixos/modules/services/networking/netns.nix
new file mode 100644 (file)
index 0000000..cefcc43
--- /dev/null
@@ -0,0 +1,14 @@
+{ pkgs, lib, config, ... }:
+{
+systemd.services."netns@" = {
+  description = "%I network namespace";
+  before = [ "network.target" ];
+  serviceConfig = {
+    Type = "oneshot";
+    RemainAfterExit = true;
+    PrivateNetwork = true;
+    ExecStart = "${pkgs.iproute}/bin/ip netns add %i";
+    ExecStop = "${pkgs.iproute}/bin/ip netns del %i";
+  };
+};
+}
diff --git a/nixos/modules/services/networking/openvpn.nix b/nixos/modules/services/networking/openvpn.nix
new file mode 100644 (file)
index 0000000..8b9cdd7
--- /dev/null
@@ -0,0 +1,233 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.openvpn;
+
+  inherit (pkgs) openvpn;
+
+  makeOpenVPNJob = cfg: name:
+    let
+
+      path = makeBinPath (getAttr "openvpn-${name}" config.systemd.services).path;
+
+      upScript = ''
+        export PATH=${path}
+
+        # For convenience in client scripts, extract the remote domain
+        # name and name server.
+        for var in ''${!foreign_option_*}; do
+          x=(''${!var})
+          if [ "''${x[0]}" = dhcp-option ]; then
+            if [ "''${x[1]}" = DOMAIN ]; then domain="''${x[2]}"
+            elif [ "''${x[1]}" = DNS ]; then nameserver="''${x[2]}"
+            fi
+          fi
+        done
+
+        ${cfg.up}
+        ${optionalString cfg.updateResolvConf
+           "${pkgs.update-resolv-conf}/libexec/openvpn/update-resolv-conf"}
+      '';
+
+      downScript = ''
+        export PATH=${path}
+        ${optionalString cfg.updateResolvConf
+           "${pkgs.update-resolv-conf}/libexec/openvpn/update-resolv-conf"}
+        ${cfg.down}
+      '';
+
+      configFile = pkgs.writeText "openvpn-config-${name}"
+        ''
+          errors-to-stderr
+          ${optionalString (cfg.up != "" || cfg.down != "" || cfg.updateResolvConf) "script-security 2"}
+          ${cfg.config}
+          ${optionalString (cfg.up != "" || cfg.updateResolvConf)
+              "up ${pkgs.writeShellScript "openvpn-${name}-up" upScript}"}
+          ${optionalString (cfg.routeUp != "")
+              "route-up ${pkgs.writeShellScript "openvpn-${name}-up" cfg.routeUp}"}
+          ${optionalString (cfg.down != "" || cfg.updateResolvConf)
+              "down ${pkgs.writeShellScript "openvpn-${name}-down" downScript}"}
+          ${optionalString (cfg.authUserPass != null)
+              "auth-user-pass ${pkgs.writeText "openvpn-credentials-${name}" ''
+                ${cfg.authUserPass.username}
+                ${cfg.authUserPass.password}
+              ''}"}
+        '';
+
+    in {
+      description = "OpenVPN instance ‘${name}’";
+
+      wantedBy = optional cfg.autoStart "multi-user.target";
+      after = [ "network.target" ];
+
+      path = [ pkgs.iptables pkgs.iproute pkgs.nettools ];
+
+      serviceConfig.ExecStart = "@${openvpn}/sbin/openvpn openvpn --suppress-timestamps --config ${configFile}";
+      serviceConfig.Restart = "always";
+      serviceConfig.Type = "notify";
+    };
+
+in
+
+{
+  imports = [
+    (mkRemovedOptionModule [ "services" "openvpn" "enable" ] "")
+  ];
+
+  ###### interface
+
+  options = {
+
+    services.openvpn.servers = mkOption {
+      default = {};
+
+      example = literalExample ''
+        {
+          server = {
+            config = '''
+              # Simplest server configuration: https://community.openvpn.net/openvpn/wiki/StaticKeyMiniHowto
+              # server :
+              dev tun
+              ifconfig 10.8.0.1 10.8.0.2
+              secret /root/static.key
+            ''';
+            up = "ip route add ...";
+            down = "ip route del ...";
+          };
+
+          client = {
+            config = '''
+              client
+              remote vpn.example.org
+              dev tun
+              proto tcp-client
+              port 8080
+              ca /root/.vpn/ca.crt
+              cert /root/.vpn/alice.crt
+              key /root/.vpn/alice.key
+            ''';
+            up = "echo nameserver $nameserver | ''${pkgs.openresolv}/sbin/resolvconf -m 0 -a $dev";
+            down = "''${pkgs.openresolv}/sbin/resolvconf -d $dev";
+          };
+        }
+      '';
+
+      description = ''
+        Each attribute of this option defines a systemd service that
+        runs an OpenVPN instance.  These can be OpenVPN servers or
+        clients.  The name of each systemd service is
+        <literal>openvpn-<replaceable>name</replaceable>.service</literal>,
+        where <replaceable>name</replaceable> is the corresponding
+        attribute name.
+      '';
+
+      type = with types; attrsOf (submodule {
+
+        options = {
+
+          config = mkOption {
+            type = types.lines;
+            description = ''
+              Configuration of this OpenVPN instance.  See
+              <citerefentry><refentrytitle>openvpn</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+              for details.
+
+              To import an external config file, use the following definition:
+              <literal>config = "config /path/to/config.ovpn"</literal>
+            '';
+          };
+
+          up = mkOption {
+            default = "";
+            type = types.lines;
+            description = ''
+              Shell commands executed when the instance is starting.
+            '';
+          };
+
+          routeUp = mkOption {
+            default = "";
+            type = types.lines;
+            description = ''
+            '';
+          };
+
+          down = mkOption {
+            default = "";
+            type = types.lines;
+            description = ''
+              Shell commands executed when the instance is shutting down.
+            '';
+          };
+
+          nftables = mkOption {
+            default = "";
+            type = types.lines;
+            description = ''
+            '';
+          };
+
+          autoStart = mkOption {
+            default = true;
+            type = types.bool;
+            description = "Whether this OpenVPN instance should be started automatically.";
+          };
+
+          updateResolvConf = mkOption {
+            default = false;
+            type = types.bool;
+            description = ''
+              Use the script from the update-resolv-conf package to automatically
+              update resolv.conf with the DNS information provided by openvpn. The
+              script will be run after the "up" commands and before the "down" commands.
+            '';
+          };
+
+          authUserPass = mkOption {
+            default = null;
+            description = ''
+              This option can be used to store the username / password credentials
+              with the "auth-user-pass" authentication method.
+
+              WARNING: Using this option will put the credentials WORLD-READABLE in the Nix store!
+            '';
+            type = types.nullOr (types.submodule {
+
+              options = {
+                username = mkOption {
+                  description = "The username to store inside the credentials file.";
+                  type = types.str;
+                };
+
+                password = mkOption {
+                  description = "The password to store inside the credentials file.";
+                  type = types.str;
+                };
+              };
+            });
+          };
+        };
+
+      });
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf (cfg.servers != {}) {
+
+    systemd.services = listToAttrs (mapAttrsFlatten (name: value: nameValuePair "openvpn-${name}" (makeOpenVPNJob value name)) cfg.servers);
+
+    environment.systemPackages = [ openvpn ];
+
+    boot.kernelModules = [ "tun" ];
+
+  };
+
+}
diff --git a/var/nftables/filter.txt b/var/nftables/filter.txt
new file mode 100644 (file)
index 0000000..a96e9c4
--- /dev/null
@@ -0,0 +1,175 @@
+# A set containing the udp port(s) to which SSDP replies are allowed.
+set ssdp_out {
+  type inet_service
+  timeout 5s
+}
+set lograte4 { type ipv4_addr; size 65535; flags dynamic; }
+set lograte6 { type ipv6_addr; size 65535; flags dynamic; }
+chain block {
+  add @lograte4 { ip  saddr limit rate 1/minute } log level warn prefix "block: "
+  add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "block: "
+  counter drop
+}
+chain ping-flood {
+  add @lograte4 { ip  saddr limit rate 1/minute } log level warn prefix "ping-flood: "
+  add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "ping-flood: "
+  counter drop
+}
+chain smurf {
+  add @lograte4 { ip  saddr limit rate 1/minute } log level warn prefix "smurf: "
+  add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "smurf: "
+  counter drop
+}
+chain bogus-tcp {
+  add @lograte4 { ip  saddr limit rate 1/minute } log level warn prefix "bogus-tcp: "
+  add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "bogus-tcp: "
+  counter drop
+}
+chain syn-flood {
+  add @lograte4 { ip  saddr limit rate 1/minute } log level warn prefix "syn-flood: "
+  add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "syn-flood: "
+  counter drop
+}
+chain check-tcp {
+  tcp flags syn tcp option maxseg size != 536-65535 counter goto bogus-tcp
+  tcp flags & (ack|fin) == fin counter goto bogus-tcp
+  tcp flags & (ack|psh) == psh counter goto bogus-tcp
+  tcp flags & (ack|urg) == urg counter goto bogus-tcp
+  tcp flags & (fin|ack) == fin counter goto bogus-tcp
+  tcp flags & (fin|rst) == (fin|rst) counter goto bogus-tcp
+  tcp flags & (fin|psh|ack) == (fin|psh) counter goto bogus-tcp
+  tcp flags & (syn|fin) == (syn|fin) counter goto bogus-tcp comment "SYN-FIN scan"
+  tcp flags & (syn|rst) == (syn|rst) counter goto bogus-tcp comment "SYN-RST scan"
+  tcp flags == (fin|syn|rst|psh|ack|urg) counter goto bogus-tcp comment "XMAS scan"
+  tcp flags == 0x0 counter goto bogus-tcp comment "NULL scan"
+  tcp flags == (fin|urg|psh) counter goto bogus-tcp
+  tcp flags == (fin|urg|psh|syn) counter goto bogus-tcp comment "NMAP-ID"
+  tcp flags == (fin|urg|syn|rst|ack) counter goto bogus-tcp
+
+  ct state new tcp flags != syn counter goto bogus-tcp
+  tcp sport 0 tcp flags & (fin|syn|rst|ack) == syn counter goto bogus-tcp
+  tcp flags & (fin|syn|rst|ack) == syn counter limit rate over 30/second burst 60 packets goto syn-flood
+}
+chain spoofing {
+  add @lograte4 { ip  saddr limit rate 1/minute } log level warn prefix "spoofing: "
+  counter drop
+}
+chain check-broadcast {
+  #ip saddr 0.0.0.0/32 counter accept comment "DHCP broadcast"
+  fib saddr type broadcast counter goto smurf
+  #ip saddr 224.0.0.0/4     counter goto smurf
+}
+chain check-ping {
+  ip protocol icmp icmp type echo-request limit rate over 10/second burst 20 packets goto ping-flood
+  ip6 nexthdr ipv6-icmp icmpv6 type echo-request limit rate over 10/second burst 20 packets goto ping-flood
+}
+chain check-public {
+  ip saddr 0.0.0.0/8 counter goto spoofing
+  ip saddr 10.0.0.0/8 counter goto spoofing
+  ip saddr 127.0.0.0/8 counter goto spoofing
+  ip saddr 169.254.0.0/16 counter goto spoofing
+  ip saddr 172.16.0.0/12 counter goto spoofing
+  ip saddr 192.0.2.0/24 counter goto spoofing
+  ip saddr 192.168.0.0/16 counter goto spoofing
+  ip saddr 224.0.0.0/3 counter goto spoofing
+  ip saddr 240.0.0.0/5 counter goto spoofing
+}
+chain accept-icmpv6 {
+  # Traffic That Must Not Be Dropped
+  # https://tools.ietf.org/html/rfc4890#section-4.4.1
+  icmpv6 type destination-unreachable counter accept
+  icmpv6 type packet-too-big counter accept
+  icmpv6 type time-exceeded counter accept
+  icmpv6 type parameter-problem counter accept
+
+  # Address Configuration and Router Selection messages
+  # (must be received with hop limit = 255)
+  icmpv6 type nd-router-solicit ip6 hoplimit 255 counter accept
+  ip6 nexthdr ipv6-icmp icmpv6 type nd-router-advert ip6 hoplimit 255 counter accept
+  icmpv6 type nd-neighbor-solicit ip6 hoplimit 255 counter accept
+  icmpv6 type nd-neighbor-advert ip6 hoplimit 255 counter accept
+  icmpv6 type nd-redirect ip6 hoplimit 255 log level warn prefix "icmpv6: nd-redirect: " counter drop
+  icmpv6 type ind-neighbor-solicit ip6 hoplimit 255 counter accept
+  icmpv6 type ind-neighbor-advert ip6 hoplimit 255 counter accept
+
+  # Link-local multicast receiver notification messages
+  # (must have link-local source address)
+  icmpv6 type mld-listener-query ip6 saddr fe80::/10 counter accept
+  icmpv6 type mld-listener-report ip6 saddr fe80::/10 counter accept
+  icmpv6 type mld-listener-done ip6 saddr fe80::/10 counter accept
+  # https://tools.ietf.org/html/rfc3810 Multicast Listener Discovery Version 2 (MLDv2) for IPv6
+  icmpv6 type mld2-listener-report ip6 saddr fe80::/10 counter accept
+
+  # SEND Certificate Path notification messages
+  # (must be received with hop limit = 255)
+  icmpv6 type 148 ip6 hoplimit 255 counter accept comment "certificate-path-solicitation"
+  icmpv6 type 149 ip6 hoplimit 255 counter accept comment "certificate-path-advertisement"
+
+  # Multicast Router Discovery messages
+  # (must have link-local source address and hop limit = 1)
+  icmpv6 type 151 ip6 saddr fe80::/10 ip6 hoplimit 1 counter accept comment "multicast-router-advertisement"
+  icmpv6 type 152 ip6 saddr fe80::/10 ip6 hoplimit 1 counter accept comment "multicast-router-solicitation"
+  icmpv6 type 153 ip6 saddr fe80::/10 ip6 hoplimit 1 counter accept comment "multicast-router-termination"
+}
+chain accept-connectivity-input {
+  # Connectivity checking messages
+  # (multicast) ping
+  ip protocol icmp icmp type echo-reply counter accept
+
+  # drop packets with rh0 headers
+  rt type 0 jump block
+  rt type 0 jump block
+  rt type 0 jump block
+
+  # (multicast) ping
+  ip6 nexthdr ipv6-icmp icmpv6 type echo-reply counter accept
+  #ct state invalid counter drop
+
+  ip protocol icmp icmp type destination-unreachable counter accept
+  ip protocol icmp icmp type time-exceeded counter accept
+  ip protocol icmp icmp type parameter-problem counter accept
+  ip protocol icmp icmp type echo-request limit rate over 10/second burst 20 packets goto ping-flood
+  ip protocol icmp icmp type echo-request counter accept
+  # echo-reply is handled before invalid packets to allow multicast ping
+  # which do not have an associated connection.
+
+  ip6 nexthdr ipv6-icmp jump accept-icmpv6
+
+  # Connectivity checking messages
+  icmpv6 type echo-request counter accept
+  # echo-reply is handled before invalid because of multicast
+}
+chain accept-connectivity-output {
+  ip protocol icmp counter accept
+  meta skuid 0 udp dport 33434-33523 counter accept comment "traceroute"
+
+  ip6 nexthdr ipv6-icmp jump accept-icmpv6
+
+  # Connectivity checking messages
+  ip6 nexthdr ipv6-icmp icmpv6 type echo-request counter accept
+  ip6 nexthdr ipv6-icmp icmpv6 type echo-reply counter accept
+}
+chain accept-connectivity-forward {
+  ip protocol icmp icmp type destination-unreachable counter accept
+  ip protocol icmp icmp type time-exceeded counter accept
+  ip protocol icmp icmp type parameter-problem counter accept
+  ip protocol icmp icmp type echo-request counter accept
+
+  # Traffic That Must Not Be Dropped
+  # https://tools.ietf.org/html/rfc4890#section-4.3.1
+  ip6 nexthdr ipv6-icmp icmpv6 type destination-unreachable counter accept
+  ip6 nexthdr ipv6-icmp icmpv6 type packet-too-big counter accept
+  ip6 nexthdr ipv6-icmp icmpv6 type time-exceeded counter accept
+  ip6 nexthdr ipv6-icmp icmpv6 type parameter-problem counter accept
+
+  # Connectivity checking messages
+  ip6 nexthdr ipv6-icmp icmpv6 type echo-request counter accept
+  ip6 nexthdr ipv6-icmp icmpv6 type echo-reply counter accept
+
+  # Traffic That Normally Should Not Be Dropped
+  # https://tools.ietf.org/html/rfc4890#section-4.3.2
+  ip6 nexthdr ipv6-icmp icmpv6 type 144 counter accept comment "home-agent-address-discovery-request"
+  ip6 nexthdr ipv6-icmp icmpv6 type 145 counter accept comment "home-agent-address-discovery-reply"
+  ip6 nexthdr ipv6-icmp icmpv6 type 146 counter accept comment "mobile-prefix-solicitation"
+  ip6 nexthdr ipv6-icmp icmpv6 type 147 counter accept comment "mobile-prefix-advertisement"
+}