2014-04-14 14:26:48 +00:00
|
|
|
|
{ config, lib, pkgs, ... }:
|
2009-05-01 17:57:07 +00:00
|
|
|
|
|
2014-04-14 14:26:48 +00:00
|
|
|
|
with lib;
|
2009-05-01 17:57:07 +00:00
|
|
|
|
|
|
|
|
|
let
|
|
|
|
|
|
|
|
|
|
cfg = config.services.openvpn;
|
|
|
|
|
|
|
|
|
|
inherit (pkgs) openvpn;
|
|
|
|
|
|
2012-02-20 20:10:07 +00:00
|
|
|
|
makeOpenVPNJob = cfg: name:
|
2009-05-01 17:57:07 +00:00
|
|
|
|
let
|
2012-02-20 20:10:07 +00:00
|
|
|
|
|
2013-01-16 11:33:18 +00:00
|
|
|
|
path = (getAttr "openvpn-${name}" config.systemd.services).path;
|
2012-08-31 01:11:36 +00:00
|
|
|
|
|
2009-05-01 17:57:07 +00:00
|
|
|
|
upScript = ''
|
2012-02-20 20:10:07 +00:00
|
|
|
|
#! /bin/sh
|
|
|
|
|
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
|
2012-08-31 01:11:36 +00:00
|
|
|
|
|
2017-04-26 16:32:59 +00:00
|
|
|
|
${cfg.up}
|
2016-06-06 17:17:27 +00:00
|
|
|
|
${optionalString cfg.updateResolvConf
|
|
|
|
|
"${pkgs.update-resolv-conf}/libexec/openvpn/update-resolv-conf"}
|
2009-05-01 17:57:07 +00:00
|
|
|
|
'';
|
2012-08-31 01:11:36 +00:00
|
|
|
|
|
2009-05-01 17:57:07 +00:00
|
|
|
|
downScript = ''
|
2012-02-20 20:10:07 +00:00
|
|
|
|
#! /bin/sh
|
|
|
|
|
export PATH=${path}
|
2016-06-06 17:17:27 +00:00
|
|
|
|
${optionalString cfg.updateResolvConf
|
|
|
|
|
"${pkgs.update-resolv-conf}/libexec/openvpn/update-resolv-conf"}
|
2009-05-01 17:57:07 +00:00
|
|
|
|
${cfg.down}
|
|
|
|
|
'';
|
2012-08-31 01:11:36 +00:00
|
|
|
|
|
2009-10-23 11:30:54 +00:00
|
|
|
|
configFile = pkgs.writeText "openvpn-config-${name}"
|
2009-10-12 16:36:19 +00:00
|
|
|
|
''
|
2013-05-28 12:38:13 +00:00
|
|
|
|
errors-to-stderr
|
2016-06-06 17:17:27 +00:00
|
|
|
|
${optionalString (cfg.up != "" || cfg.down != "" || cfg.updateResolvConf) "script-security 2"}
|
2009-10-12 16:36:19 +00:00
|
|
|
|
${cfg.config}
|
2016-06-06 17:17:27 +00:00
|
|
|
|
${optionalString (cfg.up != "" || cfg.updateResolvConf)
|
|
|
|
|
"up ${pkgs.writeScript "openvpn-${name}-up" upScript}"}
|
|
|
|
|
${optionalString (cfg.down != "" || cfg.updateResolvConf)
|
|
|
|
|
"down ${pkgs.writeScript "openvpn-${name}-down" downScript}"}
|
2018-01-15 07:34:58 +00:00
|
|
|
|
${optionalString (cfg.authUserPass != null)
|
|
|
|
|
"auth-user-pass ${pkgs.writeText "openvpn-credentials-${name}" ''
|
|
|
|
|
${cfg.authUserPass.username}
|
|
|
|
|
${cfg.authUserPass.password}
|
|
|
|
|
''}"}
|
2009-10-12 16:36:19 +00:00
|
|
|
|
'';
|
2012-08-31 01:11:36 +00:00
|
|
|
|
|
2009-05-01 17:57:07 +00:00
|
|
|
|
in {
|
2012-02-20 20:10:07 +00:00
|
|
|
|
description = "OpenVPN instance ‘${name}’";
|
2009-05-01 17:57:07 +00:00
|
|
|
|
|
2013-06-02 08:23:03 +00:00
|
|
|
|
wantedBy = optional cfg.autoStart "multi-user.target";
|
2016-09-12 14:38:49 +00:00
|
|
|
|
after = [ "network.target" ];
|
2009-05-01 17:57:07 +00:00
|
|
|
|
|
2012-02-20 20:10:07 +00:00
|
|
|
|
path = [ pkgs.iptables pkgs.iproute pkgs.nettools ];
|
2009-10-23 11:30:54 +00:00
|
|
|
|
|
2018-04-21 10:51:20 +00:00
|
|
|
|
serviceConfig.ExecStart = "@${openvpn}/sbin/openvpn openvpn --suppress-timestamps --config ${configFile}";
|
2013-05-28 12:38:13 +00:00
|
|
|
|
serviceConfig.Restart = "always";
|
2014-04-22 11:08:00 +00:00
|
|
|
|
serviceConfig.Type = "notify";
|
2009-10-23 11:30:54 +00:00
|
|
|
|
};
|
|
|
|
|
|
2009-05-01 17:57:07 +00:00
|
|
|
|
in
|
2011-09-14 18:20:50 +00:00
|
|
|
|
|
2009-10-12 16:36:19 +00:00
|
|
|
|
{
|
2019-12-10 01:51:19 +00:00
|
|
|
|
imports = [
|
|
|
|
|
(mkRemovedOptionModule [ "services" "openvpn" "enable" ] "")
|
|
|
|
|
];
|
2009-10-12 16:36:19 +00:00
|
|
|
|
|
|
|
|
|
###### interface
|
|
|
|
|
|
|
|
|
|
options = {
|
2011-09-14 18:20:50 +00:00
|
|
|
|
|
2012-02-20 20:10:07 +00:00
|
|
|
|
services.openvpn.servers = mkOption {
|
|
|
|
|
default = {};
|
|
|
|
|
|
2013-10-30 15:19:07 +00:00
|
|
|
|
example = literalExample ''
|
|
|
|
|
{
|
|
|
|
|
server = {
|
|
|
|
|
config = '''
|
2019-06-10 11:02:45 +00:00
|
|
|
|
# Simplest server configuration: https://community.openvpn.net/openvpn/wiki/StaticKeyMiniHowto
|
2013-10-30 15:19:07 +00:00
|
|
|
|
# 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";
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
'';
|
2009-10-12 16:36:19 +00:00
|
|
|
|
|
2012-02-20 20:10:07 +00:00
|
|
|
|
description = ''
|
2013-10-31 12:26:06 +00:00
|
|
|
|
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>,
|
2012-02-20 20:10:07 +00:00
|
|
|
|
where <replaceable>name</replaceable> is the corresponding
|
|
|
|
|
attribute name.
|
|
|
|
|
'';
|
2009-10-23 11:30:54 +00:00
|
|
|
|
|
2016-09-11 09:35:23 +00:00
|
|
|
|
type = with types; attrsOf (submodule {
|
2012-08-31 01:11:36 +00:00
|
|
|
|
|
2016-09-11 09:35:23 +00:00
|
|
|
|
options = {
|
2012-02-20 20:10:07 +00:00
|
|
|
|
|
2016-09-11 09:35:23 +00:00
|
|
|
|
config = mkOption {
|
|
|
|
|
type = types.lines;
|
|
|
|
|
description = ''
|
|
|
|
|
Configuration of this OpenVPN instance. See
|
|
|
|
|
<citerefentry><refentrytitle>openvpn</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
|
|
|
|
for details.
|
2018-07-20 08:30:49 +00:00
|
|
|
|
|
|
|
|
|
To import an external config file, use the following definition:
|
|
|
|
|
<literal>config = "config /path/to/config.ovpn"</literal>
|
2016-09-11 09:35:23 +00:00
|
|
|
|
'';
|
|
|
|
|
};
|
2009-10-23 11:30:54 +00:00
|
|
|
|
|
2016-09-11 09:35:23 +00:00
|
|
|
|
up = mkOption {
|
|
|
|
|
default = "";
|
|
|
|
|
type = types.lines;
|
|
|
|
|
description = ''
|
2017-04-26 16:32:59 +00:00
|
|
|
|
Shell commands executed when the instance is starting.
|
2016-09-11 09:35:23 +00:00
|
|
|
|
'';
|
|
|
|
|
};
|
2009-10-23 11:30:54 +00:00
|
|
|
|
|
2016-09-11 09:35:23 +00:00
|
|
|
|
down = mkOption {
|
|
|
|
|
default = "";
|
|
|
|
|
type = types.lines;
|
|
|
|
|
description = ''
|
2017-04-26 16:32:59 +00:00
|
|
|
|
Shell commands executed when the instance is shutting down.
|
2016-09-11 09:35:23 +00:00
|
|
|
|
'';
|
|
|
|
|
};
|
2009-10-23 11:30:54 +00:00
|
|
|
|
|
2016-09-11 09:35:23 +00:00
|
|
|
|
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.
|
|
|
|
|
'';
|
|
|
|
|
};
|
2013-05-28 12:38:13 +00:00
|
|
|
|
|
2018-01-15 07:34:58 +00:00
|
|
|
|
authUserPass = mkOption {
|
|
|
|
|
default = null;
|
|
|
|
|
description = ''
|
|
|
|
|
This option can be used to store the username / password credentials
|
|
|
|
|
with the "auth-user-pass" authentication method.
|
2018-01-16 04:40:16 +00:00
|
|
|
|
|
|
|
|
|
WARNING: Using this option will put the credentials WORLD-READABLE in the Nix store!
|
2018-01-15 07:34:58 +00:00
|
|
|
|
'';
|
|
|
|
|
type = types.nullOr (types.submodule {
|
|
|
|
|
|
|
|
|
|
options = {
|
|
|
|
|
username = mkOption {
|
|
|
|
|
description = "The username to store inside the credentials file.";
|
2019-08-08 20:48:27 +00:00
|
|
|
|
type = types.str;
|
2018-01-15 07:34:58 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
password = mkOption {
|
|
|
|
|
description = "The password to store inside the credentials file.";
|
2019-08-08 20:48:27 +00:00
|
|
|
|
type = types.str;
|
2018-01-15 07:34:58 +00:00
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
};
|
2016-06-06 17:17:27 +00:00
|
|
|
|
};
|
|
|
|
|
|
2016-09-11 09:35:23 +00:00
|
|
|
|
});
|
2009-10-23 11:30:54 +00:00
|
|
|
|
|
2009-10-12 16:36:19 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
2009-05-01 17:57:07 +00:00
|
|
|
|
|
2009-10-12 16:36:19 +00:00
|
|
|
|
###### implementation
|
2009-05-01 17:57:07 +00:00
|
|
|
|
|
2012-02-20 20:10:07 +00:00
|
|
|
|
config = mkIf (cfg.servers != {}) {
|
2010-10-18 10:40:08 +00:00
|
|
|
|
|
2013-05-28 12:38:13 +00:00
|
|
|
|
systemd.services = listToAttrs (mapAttrsFlatten (name: value: nameValuePair "openvpn-${name}" (makeOpenVPNJob value name)) cfg.servers);
|
2010-10-18 10:40:08 +00:00
|
|
|
|
|
|
|
|
|
environment.systemPackages = [ openvpn ];
|
2012-08-31 01:11:36 +00:00
|
|
|
|
|
2012-02-20 20:10:07 +00:00
|
|
|
|
boot.kernelModules = [ "tun" ];
|
2012-08-31 01:11:36 +00:00
|
|
|
|
|
2009-05-01 17:57:07 +00:00
|
|
|
|
};
|
2011-09-14 18:20:50 +00:00
|
|
|
|
|
2009-05-01 17:57:07 +00:00
|
|
|
|
}
|