summary refs log tree commit diff
diff options
context:
space:
mode:
authorDomagoj Stolfa <ds815@gmx.com>2021-06-13 16:08:53 +0100
committerTobias Geerinckx-Rice <me@tobias.gr>2021-06-25 00:39:32 +0200
commit66be80fabb9af0a570aee4c2e96886267a613e8e (patch)
treee56be781fd031d24d3da987f06f9977ceb1317b8
parent1baaf599a4000451a54dcf30098a998f1b5bc70f (diff)
downloadguix-66be80fabb9af0a570aee4c2e96886267a613e8e.tar.gz
gnu: Add strongswan service.
* gnu/services/vpn.scm (<strongswan-configuration>): New record type.
(charon-plugins, strongswan-configuration-file)
(strongswan-shepherd-service, strongswan-service-type): New variables.
* doc/guix.tex (VPN Services): Document them all.
-rw-r--r--doc/guix.texi39
-rw-r--r--gnu/services/vpn.scm140
2 files changed, 178 insertions, 1 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index 560d7af83f..4456f9a055 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -92,6 +92,7 @@ Copyright @copyright{} 2021 Maxime Devos@*
 Copyright @copyright{} 2021 B. Wilson@*
 Copyright @copyright{} 2021 Xinglu Chen@*
 Copyright @copyright{} 2021 Raghav Gururajan@*
+Copyright @copyright{} 2021 Domagoj Stolfa@*
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -27107,9 +27108,45 @@ Defaults to @samp{#f}.
 
 @end deftypevr
 
-
 @c %end of automatic openvpn-server documentation
 
+@subheading strongSwan
+
+Currently, the strongSwan service only provides legacy-style configuration with
+@file{ipsec.conf} and @file{ipsec.secrets} files.
+
+@defvr {Scheme Variable} strongswan-service-type
+A service type for configuring strongSwan for IPsec @acronym{VPN,
+Virtual Private Networking}.  Its value must be a
+@code{strongswan-configuration} record as in this example:
+
+@lisp
+(service strongswan-service-type
+         (strongswan-configuration
+          (ipsec-conf "/etc/ipsec.conf")
+          (ipsec-secrets "/etc/ipsec.secrets")))
+@end lisp
+
+@end defvr
+
+@deftp {Data Type} strongswan-configuration
+Data type representing the configuration of the StrongSwan service.
+
+@table @asis
+@item @code{strongswan}
+The strongSwan package to use for this service.
+
+@item @code{ipsec-conf} (default: @code{#f})
+The file name of your @file{ipsec.conf}.  If not @code{#f}, then this and
+@code{ipsec-secrets} must both be strings.
+
+@item @code{ipsec-secrets} (default @code{#f})
+The file name of your @file{ipsec.secrets}.  If not @code{#f}, then this and
+@code{ipsec-conf} must both be strings.
+
+@end table
+@end deftp
+
 @subsubheading Wireguard
 
 @defvr {Scheme Variable} wireguard-service-type
diff --git a/gnu/services/vpn.scm b/gnu/services/vpn.scm
index 2bcbf76727..6804e3ff9c 100644
--- a/gnu/services/vpn.scm
+++ b/gnu/services/vpn.scm
@@ -4,6 +4,8 @@
 ;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
 ;;; Copyright © 2021 Guillaume Le Vaillant <glv@posteo.net>
 ;;; Copyright © 2021 Solene Rapenne <solene@perso.pw>
+;;; Copyright © 2021 Domagoj Stolfa <ds815@gmx.com>
+;;; Copyright © 2021 Tobias Geerinckx-Rice <me@tobias.gr>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -26,10 +28,13 @@
   #:use-module (gnu services shepherd)
   #:use-module (gnu system shadow)
   #:use-module (gnu packages admin)
+  #:use-module (gnu packages networking)
   #:use-module (gnu packages vpn)
   #:use-module (guix packages)
   #:use-module (guix records)
   #:use-module (guix gexp)
+  #:use-module (guix i18n)
+  #:use-module (guix utils)
   #:use-module (srfi srfi-1)
   #:use-module (ice-9 match)
   #:use-module (ice-9 regex)
@@ -44,6 +49,9 @@
             generate-openvpn-client-documentation
             generate-openvpn-server-documentation
 
+            strongswan-configuration
+            strongswan-service-type
+
             wireguard-peer
             wireguard-peer?
             wireguard-peer-name
@@ -530,6 +538,138 @@ is truncated and rewritten every minute.")
    'openvpn-client-configuration))
 
 ;;;
+;;; Strongswan.
+;;;
+
+(define-record-type* <strongswan-configuration>
+  strongswan-configuration make-strongswan-configuration
+  strongswan-configuration?
+  (strongswan      strongswan-configuration-strongswan ;<package>
+                   (default strongswan))
+  (ipsec-conf      strongswan-configuration-ipsec-conf ;string|#f
+                   (default #f))
+  (ipsec-secrets   strongswan-configuration-ipsec-secrets ;string|#f
+                   (default #f)))
+
+;; In the future, it might be worth implementing a record type to configure
+;; all of the plugins, but for *most* basic use cases, simply creating the
+;; files will be sufficient. Same is true of charon-plugins.
+(define strongswand-configuration-files
+  (list "charon" "charon-logging" "pki" "pool" "scepclient"
+        "swanctl" "tnc"))
+
+;; Plugins to load. All of these plugins end up as configuration files in
+;; strongswan.d/charon/.
+(define charon-plugins
+  (list "aes" "aesni" "attr" "attr-sql" "chapoly" "cmac" "constraints"
+        "counters" "curl" "curve25519" "dhcp" "dnskey" "drbg" "eap-aka-3gpp"
+        "eap-aka" "eap-dynamic" "eap-identity" "eap-md5" "eap-mschapv2"
+        "eap-peap" "eap-radius" "eap-simaka-pseudonym" "eap-simaka-reauth"
+        "eap-simaka-sql" "eap-sim" "eap-sim-file" "eap-tls" "eap-tnc"
+        "eap-ttls" "ext-auth" "farp" "fips-prf" "gmp" "ha" "hmac"
+        "kernel-netlink" "led" "md4" "md5" "mgf1" "nonce" "openssl" "pem"
+        "pgp" "pkcs12" "pkcs1" "pkcs7" "pkcs8" "pubkey" "random" "rc2"
+        "resolve" "revocation" "sha1" "sha2" "socket-default" "soup" "sql"
+        "sqlite" "sshkey" "tnc-tnccs" "vici" "x509" "xauth-eap" "xauth-generic"
+        "xauth-noauth" "xauth-pam" "xcbc"))
+
+(define (strongswan-configuration-file config)
+  (match-record config <strongswan-configuration>
+    (strongswan ipsec-conf ipsec-secrets)
+    (if (eq? (string? ipsec-conf) (string? ipsec-secrets))
+        (let* ((strongswan-dir
+                (computed-file
+                 "strongswan.d"
+                 #~(begin
+                     (mkdir #$output)
+                     ;; Create all of the configuration files strongswan.d/.
+                     (map (lambda (conf-file)
+                            (let* ((filename (string-append
+                                              #$output "/"
+                                              conf-file ".conf")))
+                              (call-with-output-file filename
+                                (lambda (port)
+                                  (display
+                                   "# Created by 'strongswan-service'\n"
+                                   port)))))
+                          (list #$@strongswand-configuration-files))
+                     (mkdir (string-append #$output "/charon"))
+                     ;; Create all of the plugin configuration files.
+                     (map (lambda (plugin)
+                            (let* ((filename (string-append
+                                              #$output "/charon/"
+                                              plugin ".conf")))
+                              (call-with-output-file filename
+                                (lambda (port)
+                                  (format port "~a {
+  load = yes
+}"
+                                          plugin)))))
+                          (list #$@charon-plugins))))))
+          ;; Generate our strongswan.conf to reflect the user configuration.
+          (computed-file
+           "strongswan.conf"
+           #~(begin
+               (call-with-output-file #$output
+                 (lambda (port)
+                   (display "# Generated by 'strongswan-service'.\n" port)
+                   (format port "charon {
+  load_modular = yes
+  plugins {
+    include ~a/charon/*.conf"
+                           #$strongswan-dir)
+                   (if #$ipsec-conf
+                       (format port "
+    stroke {
+      load = yes
+      secrets_file = ~a
+    }
+  }
+}
+
+starter {
+  config_file = ~a
+}
+
+include ~a/*.conf"
+                               #$ipsec-secrets
+                               #$ipsec-conf
+                               #$strongswan-dir)
+                       (format port "
+  }
+}
+include ~a/*.conf"
+                               #$strongswan-dir)))))))
+        (throw 'error
+               (G_ "strongSwan ipsec-conf and ipsec-secrets must both be (un)set")))))
+
+(define (strongswan-shepherd-service config)
+  (let* ((ipsec (file-append strongswan "/sbin/ipsec"))
+        (strongswan-conf-path (strongswan-configuration-file config)))
+    (list (shepherd-service
+           (requirement '(networking))
+           (provision '(ipsec))
+           (start #~(make-forkexec-constructor
+                     (list #$ipsec "start" "--nofork")
+                     #:environment-variables
+                     (list (string-append "STRONGSWAN_CONF="
+                                          #$strongswan-conf-path))))
+           (stop #~(make-kill-destructor))
+           (documentation
+            "strongSwan's charon IKE keying daemon for IPsec VPN.")))))
+
+(define strongswan-service-type
+  (service-type
+   (name 'strongswan)
+   (extensions
+    (list (service-extension shepherd-root-service-type
+                             strongswan-shepherd-service)))
+   (default-value (strongswan-configuration))
+   (description
+    "Connect to an IPsec @acronym{VPN, Virtual Private Network} with
+strongSwan.")))
+
+;;;
 ;;; Wireguard.
 ;;;