at 24.11-pre 4.5 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.services.libreswan; 8 9 libexec = "${pkgs.libreswan}/libexec/ipsec"; 10 ipsec = "${pkgs.libreswan}/sbin/ipsec"; 11 12 trim = chars: str: 13 let 14 nonchars = filter (x : !(elem x.value chars)) 15 (imap0 (i: v: {ind = i; value = v;}) (stringToCharacters str)); 16 in 17 lib.optionalString (nonchars != [ ]) 18 (substring (head nonchars).ind (add 1 (sub (last nonchars).ind (head nonchars).ind)) str); 19 indent = str: concatStrings (concatMap (s: [" " (trim [" " "\t"] s) "\n"]) (splitString "\n" str)); 20 configText = indent (toString cfg.configSetup); 21 connectionText = concatStrings (mapAttrsToList (n: v: 22 '' 23 conn ${n} 24 ${indent v} 25 '') cfg.connections); 26 27 configFile = pkgs.writeText "ipsec-nixos.conf" 28 '' 29 config setup 30 ${configText} 31 32 ${connectionText} 33 ''; 34 35 policyFiles = mapAttrs' (name: text: 36 { name = "ipsec.d/policies/${name}"; 37 value.source = pkgs.writeText "ipsec-policy-${name}" text; 38 }) cfg.policies; 39 40in 41 42{ 43 44 ###### interface 45 46 options = { 47 48 services.libreswan = { 49 50 enable = mkEnableOption "Libreswan IPsec service"; 51 52 configSetup = mkOption { 53 type = types.lines; 54 default = '' 55 protostack=netkey 56 virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:25.0.0.0/8,%v4:100.64.0.0/10,%v6:fd00::/8,%v6:fe80::/10 57 ''; 58 example = '' 59 secretsfile=/root/ipsec.secrets 60 protostack=netkey 61 virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:25.0.0.0/8,%v4:100.64.0.0/10,%v6:fd00::/8,%v6:fe80::/10 62 ''; 63 description = "Options to go in the 'config setup' section of the Libreswan IPsec configuration"; 64 }; 65 66 connections = mkOption { 67 type = types.attrsOf types.lines; 68 default = {}; 69 example = literalExpression '' 70 { myconnection = ''' 71 auto=add 72 left=%defaultroute 73 leftid=@user 74 75 right=my.vpn.com 76 77 ikev2=no 78 ikelifetime=8h 79 '''; 80 } 81 ''; 82 description = "A set of connections to define for the Libreswan IPsec service"; 83 }; 84 85 policies = mkOption { 86 type = types.attrsOf types.lines; 87 default = {}; 88 example = literalExpression '' 89 { private-or-clear = ''' 90 # Attempt opportunistic IPsec for the entire Internet 91 0.0.0.0/0 92 ::/0 93 '''; 94 } 95 ''; 96 description = '' 97 A set of policies to apply to the IPsec connections. 98 99 ::: {.note} 100 The policy name must match the one of connection it needs to apply to. 101 ::: 102 ''; 103 }; 104 105 disableRedirects = mkOption { 106 type = types.bool; 107 default = true; 108 description = '' 109 Whether to disable send and accept redirects for all network interfaces. 110 See the Libreswan [ 111 FAQ](https://libreswan.org/wiki/FAQ#Why_is_it_recommended_to_disable_send_redirects_in_.2Fproc.2Fsys.2Fnet_.3F) page for why this is recommended. 112 ''; 113 }; 114 115 }; 116 117 }; 118 119 120 ###### implementation 121 122 config = mkIf cfg.enable { 123 124 # Install package, systemd units, etc. 125 environment.systemPackages = [ pkgs.libreswan pkgs.iproute2 ]; 126 systemd.packages = [ pkgs.libreswan ]; 127 systemd.tmpfiles.packages = [ pkgs.libreswan ]; 128 129 # Install configuration files 130 environment.etc = { 131 "ipsec.secrets".source = "${pkgs.libreswan}/etc/ipsec.secrets"; 132 "ipsec.conf".source = "${pkgs.libreswan}/etc/ipsec.conf"; 133 "ipsec.d/01-nixos.conf".source = configFile; 134 } // policyFiles; 135 136 systemd.services.ipsec = { 137 description = "Internet Key Exchange (IKE) Protocol Daemon for IPsec"; 138 wantedBy = [ "multi-user.target" ]; 139 restartTriggers = [ configFile ] ++ mapAttrsToList (n: v: v.source) policyFiles; 140 path = with pkgs; [ 141 libreswan 142 iproute2 143 procps 144 nssTools 145 iptables 146 nettools 147 ]; 148 preStart = optionalString cfg.disableRedirects '' 149 # Disable send/receive redirects 150 echo 0 | tee /proc/sys/net/ipv4/conf/*/send_redirects 151 echo 0 | tee /proc/sys/net/ipv{4,6}/conf/*/accept_redirects 152 ''; 153 serviceConfig = { 154 StateDirectory = "ipsec/nss"; 155 StateDirectoryMode = 0700; 156 }; 157 }; 158 159 }; 160 161}