Subject: [bug#41803] [PATCH] Yggdrasil package and accompanying shepherd service (mesh network)

From: raingloom <[email-masked]>
Date: Thu, 3 Sep 2020 19:59:47 +0200

On Mon, 13 Jul 2020 16:23:30 +0200
raingloom <[email-masked]> wrote:

> On Sun, 12 Jul 2020 00:12:06 +0200
> Julien Lepiller <[email-masked]> wrote:
> > As you noted, could you add something about it to the manual?  
> 
> On it, but I've never used texinfo, so this might take a while. Gonna
> send it in a later mail.
> 

Finally got around to documenting it.
Also exported all the accessors for the service.

Is it mergeable in this form?

ps.: i'm not sure if i should include all patches or only the ones i
changed. to be safe i rebased it again on the current main branch and
attached all patches.
>From 0fe7ec1dec27c206b1a6d854067a4319d67ea1e7 Mon Sep 17 00:00:00 2001
From: raingloom <[email-masked]>
Date: Sat, 30 May 2020 12:52:00 +0200
Subject: [PATCH 01/11] gnu: go-golang-org-x-sys: update to
 05986578812163b26672dabd9b425240ae2bb0ad

---
 gnu/packages/golang.scm | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/gnu/packages/golang.scm b/gnu/packages/golang.scm
index 78bf4fff87..91f0db02a9 100644
--- a/gnu/packages/golang.scm
+++ b/gnu/packages/golang.scm
@@ -741,8 +741,8 @@ processing.")
       (license license:bsd-3))))
 
 (define-public go-golang-org-x-sys
-  (let ((commit "c709ea063b76879dc9915358f55d4d77c16ab6d5")
-        (revision "6"))
+  (let ((commit "05986578812163b26672dabd9b425240ae2bb0ad")
+        (revision "7"))
     (package
       (name "go-golang-org-x-sys")
       (version (git-version "0.0.0" revision commit))
@@ -754,7 +754,7 @@ processing.")
                 (file-name (git-file-name name version))
                 (sha256
                  (base32
-                  "15nq53a6kcqchng4j0d1pjw0m6hny6126nhjdwqw5n9dzh6a226d"))))
+                  "1q2rxb6z5l6pmlckjsz2l0b8lw7bqgk6frhzbmi1dv0y5irb2ka7"))))
       (build-system go-build-system)
       (arguments
        `(#:import-path "golang.org/x/sys"
-- 
2.28.0

>From 7a93c6168e69fddeafcdf237bb66eb6a121b7ffe Mon Sep 17 00:00:00 2001
From: raingloom <[email-masked]>
Date: Mon, 13 Jul 2020 04:15:28 +0200
Subject: [PATCH 02/11] gnu: Add go-github-com-arceliar-phony

* gnu/packages/golang.scm (go-github-com-arceliar-phony): New variable.
---
 gnu/packages/golang.scm | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/gnu/packages/golang.scm b/gnu/packages/golang.scm
index 91f0db02a9..b843652459 100644
--- a/gnu/packages/golang.scm
+++ b/gnu/packages/golang.scm
@@ -5631,3 +5631,27 @@ Included are the following:
 except that it adds convenience functions that use the fmt package to format
 error messages.")
     (license license:bsd-3)))
+
+(define-public go-github-com-arceliar-phony
+  (let ((commit "d0c68492aca0bd4b5c5c8e0452c9b4c8af923eaf")
+        (revision "0"))
+    (package
+      (name "go-github-com-arceliar-phony")
+      (version (git-version "0.0.0" revision commit))
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://github.com/Arceliar/phony")
+               (commit commit)))
+         (sha256
+          (base32
+           "0876y0hlb1zh8hn0pxrb5zfdadvaqmqwlr66p19yl2a76galz992"))))
+      (arguments
+       '(#:import-path "github.com/Arceliar/phony"))
+      (build-system go-build-system)
+      (home-page "https://github.com/Arceliar/phony")
+      (synopsis "A very minimal actor model library")
+      (description "Phony is a very minimal actor model library for Go,
+inspired by the causal messaging system in the Pony programming language")
+      (license license:expat))))
-- 
2.28.0

>From 48c9c437d18e6c3d5f4dd82cc93f3331c23f7ce4 Mon Sep 17 00:00:00 2001
From: raingloom <[email-masked]>
Date: Mon, 13 Jul 2020 04:21:11 +0200
Subject: [PATCH 03/11] gnu: Add go-github-com-cheggaaa-pb at version 3.0.4

* gnu/packages/golang.scm (go-github-com-cheggaaa-pb): New variable.
---
 gnu/packages/golang.scm | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/gnu/packages/golang.scm b/gnu/packages/golang.scm
index b843652459..7aacaa7bc1 100644
--- a/gnu/packages/golang.scm
+++ b/gnu/packages/golang.scm
@@ -5655,3 +5655,31 @@ error messages.")
       (description "Phony is a very minimal actor model library for Go,
 inspired by the causal messaging system in the Pony programming language")
       (license license:expat))))
+
+(define-public go-github-com-cheggaaa-pb
+  (package
+    (name "go-github-com-cheggaaa-pb")
+    (version "3.0.4")
+    (source
+      (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/cheggaaa/pb/")
+             (commit (string-append "v" version))))
+       (sha256
+        (base32
+         "0xhsv9yf3fz918ay6w0d87jnb3hk9vxvi16jk172kqq26x7jixd0"))))
+    (build-system go-build-system)
+    (arguments
+     '(#:import-path "github.com/cheggaaa/pb/"))
+    (propagated-inputs
+     `(("go-github-com-fatih-color" ,go-github-com-fatih-color)
+       ("go-github-com-mattn-go-colorable" ,go-github-com-mattn-go-colorable)
+       ("go-github.com-mattn-go-runewidth" ,go-github.com-mattn-go-runewidth)
+       ("go-golang-org-x-sys" ,go-golang-org-x-sys)))
+    (native-inputs
+     `(("go-github-com-mattn-go-isatty" ,go-github-com-mattn-go-isatty)))
+    (home-page "https://github.com/cheggaaa/pb/")
+    (synopsis "Console progress bar for Golang")
+    (description "")
+    (license license:bsd-3)))
-- 
2.28.0

>From d9e586f4548ed85b0a557e9f527cf59e180f877f Mon Sep 17 00:00:00 2001
From: raingloom <[email-masked]>
Date: Mon, 13 Jul 2020 04:22:46 +0200
Subject: [PATCH 04/11] gnu: Add go-github-com-gologme-log at version 1.2.0

* gnu/packages/golang.scm (go-github-com-gologme-log): New variable.
  See comment about license.
---
 gnu/packages/golang.scm | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/gnu/packages/golang.scm b/gnu/packages/golang.scm
index 7aacaa7bc1..38654de97a 100644
--- a/gnu/packages/golang.scm
+++ b/gnu/packages/golang.scm
@@ -5683,3 +5683,30 @@ inspired by the causal messaging system in the Pony programming language")
     (synopsis "Console progress bar for Golang")
     (description "")
     (license license:bsd-3)))
+
+(define-public go-github-com-gologme-log
+  ;; this is the same as v1.2.0, only the LICENSE file changed
+  (let ((commit "720ba0b3ccf0a91bc6018c9967a2479f93f56a55"))
+    (package
+      (name "go-github-com-gologme-log")
+      (version "1.2.0")
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://github.com/gologme/log")
+               (commit commit)))
+         (sha256
+          (base32
+           "0z3gs5ngv2jszp42ypp3ai0pn410v3b2m674g73ma7vsbn2yjk1n"))))
+      (build-system go-build-system)
+      (arguments
+       '(#:import-path "github.com/gologme/log"))
+      (home-page "https://github.com/gologme/log/")
+      (synopsis
+       "A fork of the golang built in log package to add support for levels")
+      (description "This package is a drop in replacement for the built-in Go log
+package. All the functionality of the built-in package still exists and is
+unchanged. In addition, this package contains a series of small enhancements
+and additions.")
+      (license license:bsd-3))))
-- 
2.28.0

>From f0915d5917399a4ed0549c7b346738c759653531 Mon Sep 17 00:00:00 2001
From: raingloom <[email-masked]>
Date: Mon, 13 Jul 2020 16:14:35 +0200
Subject: [PATCH 05/11] gnu: Add go-github-com-hashicorp-go-syslog at version
 1.0.0

* gnu/packages/golang.scm (go-github-com-hashicorp-go-syslog): New variable.
---
 gnu/packages/golang.scm | 71 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/gnu/packages/golang.scm b/gnu/packages/golang.scm
index 38654de97a..97db5c7b7b 100644
--- a/gnu/packages/golang.scm
+++ b/gnu/packages/golang.scm
@@ -5710,3 +5710,74 @@ package. All the functionality of the built-in package still exists and is
 unchanged. In addition, this package contains a series of small enhancements
 and additions.")
       (license license:bsd-3))))
+
+(define-public go-github-com-hashicorp-go-syslog
+  (package
+    (name "go-github-com-hashicorp-go-syslog")
+    (version "1.0.0")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/hashicorp/go-syslog")
+             (commit (string-append "v" version))))
+       (sha256
+        (base32
+         "09vccqggz212cg0jir6vv708d6mx0f9w5bxrcdah3h6chgmal6v1"))))
+    (build-system go-build-system)
+    (arguments
+     '(#:import-path "github.com/hashicorp/go-syslog"))
+    (home-page "https://github.com/hashicorp/go-syslog")
+    (synopsis "Golang syslog wrapper, cross-compile friendly")
+    (description "A very simple wrapper around log/syslog")
+    (license license:expat)))
+
+(define-public go-github-com-hjson-hjson-go
+  (package
+    (name "go-github-com-hjson-hjson-go")
+    (version "3.0.1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/hjson/hjson-go")
+             (commit (string-append "v" version))))
+       (sha256
+        (base32
+         "0q340mddapq0lxrdrzkjnw7xdwdn1lzifcf564wrmj8rggh7rl81"))))
+    (build-system go-build-system)
+    (arguments
+     '(#:import-path "github.com/hjson/hjson-go"))
+    (home-page "https://hjson.org/")
+    (synopsis "Human JSON implementation for Go")
+    (description "Hjson is a syntax extension to JSON.
+It's intended to be used like a user interface for humans, to read and edit
+before passing the JSON data to the machine.")
+    (license license:expat)))
+
+(define-public go-github-com-mitchellh-mapstructure
+  (package
+    (name "go-github-com-mitchellh-mapstructure")
+    (version "1.3.1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/mitchellh/mapstructure")
+             (commit (string-append "v" version))))
+       (sha256
+        (base32
+         "0l3qyskfx9bwh0b17zv8yk15rrdhjmj482jsp09f9bp0d4g9k87j"))))
+    (build-system go-build-system)
+    (arguments
+     '(#:import-path "github.com/mitchellh/mapstructure"))
+    (home-page "https://github.com/mitchellh/mapstructure/")
+    (synopsis
+     "Go library for decoding generic map values to and from native Go structures")
+    (description
+     "Mapstructure is a Go library for decoding generic map values to structures
+and vice versa, while providing helpful error handling.
+This library is most useful when decoding values from some data stream
+(JSON, Gob, etc.) where you don't quite know the structure of the underlying
+data until you read a part of it.")
+    (license license:expat)))
-- 
2.28.0

>From 713cb77af81843dd3d582363177b68091a1d8310 Mon Sep 17 00:00:00 2001
From: raingloom <[email-masked]>
Date: Mon, 13 Jul 2020 04:27:01 +0200
Subject: [PATCH 06/11] gnu: Add go-golang-zx2c4-com-wireguard at version
 0.0.20200320

* gnu/packages/golang.scm (go-golang-zx2c4-com-wireguard): New variable.
---
 gnu/packages/golang.scm | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/gnu/packages/golang.scm b/gnu/packages/golang.scm
index 97db5c7b7b..961600ad8f 100644
--- a/gnu/packages/golang.scm
+++ b/gnu/packages/golang.scm
@@ -5781,3 +5781,32 @@ This library is most useful when decoding values from some data stream
 (JSON, Gob, etc.) where you don't quite know the structure of the underlying
 data until you read a part of it.")
     (license license:expat)))
+
+(define-public go-golang-zx2c4-com-wireguard
+  (package
+    (name "go-golang-zx2c4-com-wireguard")
+    (version "0.0.20200320")
+    (source
+     (origin
+       (method git-fetch)
+       ;; NOTE: module URL is a redirect
+       ;; target: git.zx2c4.com/wireguard-go
+       ;; source: golang.zx2c4.com/wireguard
+       (uri (git-reference
+             (url "https://git.zx2c4.com/wireguard-go/")
+             (commit (string-append "v" version))))
+       (sha256
+        (base32
+         "0fy4qsss3i3pkq1rpgjds4aipbwlh1dr9hbbf7jn2a1c63kfks0r"))))
+    (build-system go-build-system)
+    (arguments
+     '(#:import-path "golang.zx2c4.com/wireguard"))
+    (propagated-inputs
+     `(("go-golang-org-x-crypto" ,go-golang-org-x-crypto)
+       ("go-golang-org-x-net" ,go-golang-org-x-net)
+       ("go-golang-org-x-sys" ,go-golang-org-x-sys)
+       ("go-golang-org-x-text" ,go-golang-org-x-text)))
+    (home-page "https://git.zx2c4.com/wireguard")
+    (synopsis "This is an implementation of WireGuard in Go")
+    (description "Go Implementation of [WireGuard](https://www.wireguard.com/)")
+    (license license:expat)))
-- 
2.28.0

>From 63cf4ec66588027516b9d69e989f29daefb3176b Mon Sep 17 00:00:00 2001
From: raingloom <[email-masked]>
Date: Mon, 13 Jul 2020 04:28:15 +0200
Subject: [PATCH 07/11] gnu: Add go-github-com-kardianos-minwinsvc.

* gnu/packages/golang.scm (go-github-com-kardianos-minwinsvc): New variable.
---
 gnu/packages/golang.scm | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/gnu/packages/golang.scm b/gnu/packages/golang.scm
index 961600ad8f..744ddadaa1 100644
--- a/gnu/packages/golang.scm
+++ b/gnu/packages/golang.scm
@@ -5810,3 +5810,30 @@ data until you read a part of it.")
     (synopsis "This is an implementation of WireGuard in Go")
     (description "Go Implementation of [WireGuard](https://www.wireguard.com/)")
     (license license:expat)))
+
+(define-public go-github-com-kardianos-minwinsvc
+  (let ((commit "cad6b2b879b0970e4245a20ebf1a81a756e2bb70")
+        (revision "0"))
+    (package
+      (name "go-github-com-kardianos-minwinsvc")
+      (version (git-version "0.0.0" revision commit))
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://github.com/kardianos/minwinsvc")
+               (commit commit)))
+         (sha256
+          (base32
+           "000fk0b1ff7m6dd2n3am1l39hzl6nsl1a9p7zmq78qn6h3glabdl"))))
+      (build-system go-build-system)
+      (arguments
+       '(#:import-path "github.com/kardianos/minwinsvc"))
+      (home-page "https://github.com/kardianos/minwinsvc/")
+      ;; some packages (Yggdrasil) need it to compile
+      ;; it's a tiny package and it's easier to bundle it than to patch it out
+      (synopsis "A minimal windows only service stub for Go")
+      (description "Go programs designed to run from most *nix style operating
+systems can import this package to enable running programs as services without
+modifying them.")
+      (license license:zlib))))
-- 
2.28.0

>From 30422b88c3a0a9add8bf073d5d5d3501cd34a17b Mon Sep 17 00:00:00 2001
From: raingloom <[email-masked]>
Date: Mon, 13 Jul 2020 03:52:56 +0200
Subject: [PATCH 08/11] gnu: Add yggdrasil at version 0.3.14 (plus patch)

* gnu/packages/networking.scm: (yggdrasil): New variable.
  (gnu packages golang): New dependency.
* gnu/packages/patches/yggdrasil-extra-config.patch: New file.
* gnu/local.mk: (yggdrasil-extra-config.patch): Add to patches.
---
 gnu/local.mk                                  |  1 +
 gnu/packages/networking.scm                   | 90 +++++++++++++++++++
 .../patches/yggdrasil-extra-config.patch      | 86 ++++++++++++++++++
 3 files changed, 177 insertions(+)
 create mode 100644 gnu/packages/patches/yggdrasil-extra-config.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index d2753f52ae..2aca0c7a17 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1687,6 +1687,7 @@ dist_patch_DATA =						\
   %D%/packages/patches/xsane-fix-snprintf-buffer-length.patch	\
   %D%/packages/patches/xsane-support-ipv6.patch			\
   %D%/packages/patches/xsane-tighten-default-umask.patch	\
+  %D%/packages/patches/yggdrasil-extra-config.patch	\
   %D%/packages/patches/zziplib-CVE-2018-16548.patch
 
 MISC_DISTRO_FILES =				\
diff --git a/gnu/packages/networking.scm b/gnu/packages/networking.scm
index 8b18de6121..4ba59762a4 100644
--- a/gnu/packages/networking.scm
+++ b/gnu/packages/networking.scm
@@ -95,6 +95,7 @@
   #:use-module (gnu packages glib)
   #:use-module (gnu packages gnome)
   #:use-module (gnu packages gnupg)
+  #:use-module (gnu packages golang)
   #:use-module (gnu packages graphviz)
   #:use-module (gnu packages gstreamer)
   #:use-module (gnu packages gtk)
@@ -3762,3 +3763,92 @@ hashcash stamps efficiently.
 This package contains a command-line tool for computing and verifying hashcash
 stamps.")
     (license license:public-domain)))
+
+(define-public yggdrasil
+  (package
+    (name "yggdrasil")
+    (version "0.3.14")
+    (source
+     (origin
+       (method git-fetch)
+       (uri
+        (git-reference
+         (url "https://github.com/yggdrasil-network/yggdrasil-go")
+         (commit (string-append "v" version))
+         (recursive? #t)))
+       (sha256
+        (base32
+         "0vncf39gqr5hzjn948jlchppf7451a6rcvr962ng97sjdy8mplrw"))
+       (patches (search-patches "yggdrasil-extra-config.patch"))))
+    (build-system go-build-system)
+    (arguments
+     '(#:import-path "github.com/yggdrasil-network/yggdrasil-go"
+       ;; TODO: figure out how tests are run
+       #:tests? #f
+       #:install-source? #f
+       #:phases (modify-phases %standard-phases
+                  (replace 'build
+                    (lambda _
+                      (for-each
+                       (lambda (c)
+                         (invoke "go" "build" "-v" "-ldflags=-s -w"
+                                 (string-append
+                                  "github.com/yggdrasil-network/yggdrasil-go/cmd/"
+                                  c)))
+                       (list "yggdrasil" "yggdrasilctl"))
+                      #t))
+                  (replace 'install
+                    (lambda* (#:key outputs #:allow-other-keys)
+                      (let* ((out (assoc-ref outputs "out"))
+                             (bin (string-append out "/bin/"))
+                             (doc (string-append out "/share/doc/yggdrasil/")))
+                        (mkdir-p bin)
+                        (for-each
+                         (lambda (f)
+                           (install-file f bin))
+                         (list "yggdrasil" "yggdrasilctl"))
+                        (mkdir-p doc)
+                        (copy-recursively
+                         (string-append
+                          "src/github.com/yggdrasil-network/yggdrasil-go/"
+                          "doc/yggdrasil-network.github.io")
+                         doc)))))))
+    ;; https://github.com/kardianos/minwinsvc is windows only
+    (propagated-inputs
+     `(("go-github-com-arceliar-phony" ,go-github-com-arceliar-phony)
+       ("go-github-com-cheggaaa-pb" ,go-github-com-cheggaaa-pb)
+       ("go-github-com-gologme-log" ,go-github-com-gologme-log)
+       ("go-github-com-hashicorp-go-syslog" ,go-github-com-hashicorp-go-syslog)
+       ("go-github-com-hjson-hjson-go" ,go-github-com-hjson-hjson-go)
+       ("go-github-com-kardianos-minwinsvc" ,go-github-com-kardianos-minwinsvc)
+       ("go-github-com-mitchellh-mapstructure"
+        ,go-github-com-mitchellh-mapstructure)
+       ("go-golang-org-x-crypto" ,go-golang-org-x-crypto)
+       ("go-golang-org-x-net" ,go-golang-org-x-net)
+       ("go-golang-org-x-text" ,go-golang-org-x-text)
+       ("go-golang-zx2c4-com-wireguard" ,go-golang-zx2c4-com-wireguard)
+       ("go-netlink" ,go-netlink)
+       ("go-netns" ,go-netns)))
+    (home-page "https://yggdrasil-network.github.io/blog.html")
+    (synopsis "An experiment in scalable routing as an encrypted IPv6 overlay network")
+    (description "Yggdrasil is an early-stage implementation of a fully end-to-end encrypted
+IPv6 network. It is lightweight, self-arranging, supported on multiple platforms and allows
+pretty much any IPv6-capable application to communicate securely with other Yggdrasil nodes.
+Yggdrasil does not require you to have IPv6 Internet connectivity - it also works over IPv4.")
+    (license
+     ;; As a special exception to the GNU Lesser General Public License version 3
+     ;; ("LGPL3"), the copyright holders of this Library give you permission to
+     ;; convey to a third party a Combined Work that links statically or dynamically
+     ;; to this Library without providing any Minimal Corresponding Source or
+     ;; Minimal Application Code as set out in 4d or providing the installation
+     ;; information set out in section 4e, provided that you comply with the other
+     ;; provisions of LGPL3 and provided that you meet, for the Application the
+     ;; terms and conditions of the license(s) which apply to the Application.
+     ;; Except as stated in this special exception, the provisions of LGPL3 will
+     ;; continue to comply in full to this Library. If you modify this Library, you
+     ;; may apply this exception to your version of this Library, but you are not
+     ;; obliged to do so. If you do not wish to do so, delete this exception
+     ;; statement from your version. This exception does not (and cannot) modify any
+     ;; license terms which apply to the Application, with which you must still
+     ;; comply
+     license:lgpl3)))
diff --git a/gnu/packages/patches/yggdrasil-extra-config.patch b/gnu/packages/patches/yggdrasil-extra-config.patch
new file mode 100644
index 0000000000..e3502eb644
--- /dev/null
+++ b/gnu/packages/patches/yggdrasil-extra-config.patch
@@ -0,0 +1,86 @@
+diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go
+index 813e950..08d35cc 100644
+--- a/cmd/yggdrasil/main.go
++++ b/cmd/yggdrasil/main.go
+@@ -40,11 +40,12 @@ type node struct {
+ 	admin     module.Module // admin.AdminSocket
+ }
+ 
+-func readConfig(useconf *bool, useconffile *string, normaliseconf *bool) *config.NodeConfig {
++func readConfig(useconf *bool, useconffile *string, extraconffile *string, normaliseconf *bool) *config.NodeConfig {
+ 	// Use a configuration file. If -useconf, the configuration will be read
+ 	// from stdin. If -useconffile, the configuration will be read from the
+ 	// filesystem.
+ 	var conf []byte
++	var extraconf []byte
+ 	var err error
+ 	if *useconffile != "" {
+ 		// Read the file from the filesystem
+@@ -56,6 +57,21 @@ func readConfig(useconf *bool, useconffile *string, normaliseconf *bool) *config
+ 	if err != nil {
+ 		panic(err)
+ 	}
++	if *extraconffile != "" {
++		extraconf, err = ioutil.ReadFile(*extraconffile);
++	}
++	if err != nil {
++		panic(err)
++	}
++	// Generate a new configuration - this gives us a set of sane defaults -
++	// then parse the configuration we loaded above on top of it. The effect
++	// of this is that any configuration item that is missing from the provided
++	// configuration will use a sane default.
++	cfg := config.GenerateConfig()
++	var confs [2][]byte
++	confs[0]=conf
++	confs[1]=extraconf
++	for _, conf := range confs {
+ 	// If there's a byte order mark - which Windows 10 is now incredibly fond of
+ 	// throwing everywhere when it's converting things into UTF-16 for the hell
+ 	// of it - remove it and decode back down into UTF-8. This is necessary
+@@ -69,11 +85,6 @@ func readConfig(useconf *bool, useconffile *string, normaliseconf *bool) *config
+ 			panic(err)
+ 		}
+ 	}
+-	// Generate a new configuration - this gives us a set of sane defaults -
+-	// then parse the configuration we loaded above on top of it. The effect
+-	// of this is that any configuration item that is missing from the provided
+-	// configuration will use a sane default.
+-	cfg := config.GenerateConfig()
+ 	var dat map[string]interface{}
+ 	if err := hjson.Unmarshal(conf, &dat); err != nil {
+ 		panic(err)
+@@ -112,6 +123,7 @@ func readConfig(useconf *bool, useconffile *string, normaliseconf *bool) *config
+ 	if err = mapstructure.Decode(dat, &cfg); err != nil {
+ 		panic(err)
+ 	}
++	}
+ 	return cfg
+ }
+ 
+@@ -164,6 +176,7 @@ func main() {
+ 	genconf := flag.Bool("genconf", false, "print a new config to stdout")
+ 	useconf := flag.Bool("useconf", false, "read HJSON/JSON config from stdin")
+ 	useconffile := flag.String("useconffile", "", "read HJSON/JSON config from specified file path")
++	extraconffile := flag.String("extraconffile", "", "extra (usually private) HJSON/JSON config from specified file path")
+ 	normaliseconf := flag.Bool("normaliseconf", false, "use in combination with either -useconf or -useconffile, outputs your configuration normalised")
+ 	confjson := flag.Bool("json", false, "print configuration from -genconf or -normaliseconf as JSON instead of HJSON")
+ 	autoconf := flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)")
+@@ -187,7 +200,7 @@ func main() {
+ 		cfg = config.GenerateConfig()
+ 	case *useconffile != "" || *useconf:
+ 		// Read the configuration from either stdin or from the filesystem
+-		cfg = readConfig(useconf, useconffile, normaliseconf)
++		cfg = readConfig(useconf, useconffile, extraconffile, normaliseconf)
+ 		// If the -normaliseconf option was specified then remarshal the above
+ 		// configuration and print it back to stdout. This lets the user update
+ 		// their configuration file with newly mapped names (like above) or to
+@@ -332,7 +345,7 @@ func main() {
+ 			goto exit
+ 		case _ = <-r:
+ 			if *useconffile != "" {
+-				cfg = readConfig(useconf, useconffile, normaliseconf)
++				cfg = readConfig(useconf, useconffile, extraconffile, normaliseconf)
+ 				logger.Infoln("Reloading configuration from", *useconffile)
+ 				n.core.UpdateConfig(cfg)
+ 				n.tuntap.UpdateConfig(cfg)
-- 
2.28.0

>From 3d345ae585338e087db0cb106e2c2d8af44cf78f Mon Sep 17 00:00:00 2001
From: raingloom <[email-masked]>
Date: Thu, 11 Jun 2020 14:09:57 +0200
Subject: [PATCH 09/11] gnu: services: Add new service for yggdrasil network.

* gnu/services/networking.scm:
  (yggdrasil-service-type
  yggdrasil-configuration
  yggdrasil-configuration?
  yggdrasil-configuration-package
  yggdrasil-configuration-auto-conf
  yggdrasil-configuration-log-level
  yggdrasil-configuration-log-to): New variables.
---
 gnu/services/networking.scm | 117 +++++++++++++++++++++++++++++++++++-
 1 file changed, 116 insertions(+), 1 deletion(-)

diff --git a/gnu/services/networking.scm b/gnu/services/networking.scm
index e45b116218..c37f6449d5 100644
--- a/gnu/services/networking.scm
+++ b/gnu/services/networking.scm
@@ -61,7 +61,9 @@
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-9)
   #:use-module (srfi srfi-26)
+  #:use-module (srfi srfi-43)
   #:use-module (ice-9 match)
+  #:use-module (json)
   #:re-export (static-networking-service
                static-networking-service-type)
   #:export (%facebook-host-aliases
@@ -180,7 +182,17 @@
             pagekite-configuration-kitesecret
             pagekite-configuration-frontend
             pagekite-configuration-kites
-            pagekite-configuration-extra-file))
+            pagekite-configuration-extra-file
+
+            yggdrasil-service-type
+            yggdrasil-configuration
+            yggdrasil-configuration?
+            yggdrasil-configuration-autoconf?
+            yggdrasil-configuration-config-file
+            yggdrasil-configuration-log-level
+            yggdrasil-configuration-log-to
+            yggdrasil-configuration-json-config
+            yggdrasil-configuration-package))
 
 ;;; Commentary:
 ;;;
@@ -1748,4 +1760,107 @@ table inet filter {
     "Run @url{https://pagekite.net/,PageKite}, a tunneling solution to make
 local servers publicly accessible on the web, even behind NATs and firewalls.")))
 
+
+;;;
+;;; Yggdrasil
+;;;
+
+(define-record-type* <yggdrasil-configuration>
+  yggdrasil-configuration
+  make-yggdrasil-configuration
+  yggdrasil-configuration?
+  (package yggdrasil-configuration-package
+           (default yggdrasil))
+  (json-config yggdrasil-configuration-json-config
+               (default '()))
+  (config-file yggdrasil-config-file
+               (default "/etc/yggdrasil-private.conf"))
+  (autoconf? yggdrasil-configuration-autoconf?
+             (default #f))
+  (log-level yggdrasil-configuration-log-level
+             (default 'info))
+  (log-to yggdrasil-configuration-log-to
+          (default 'stdout)))
+
+(define (yggdrasil-configuration-file config)
+  (define (scm->yggdrasil-json x)
+    (define key-value?
+      dotted-list?)
+    (define (param->camel str)
+      (string-concatenate
+       (map
+	string-capitalize
+	(string-split str (cut eqv? <> #\-)))))
+    (cond
+     ((key-value? x)
+      (let ((k (car x))
+	    (v (cdr x)))
+	(cons
+	 (if (symbol? k)
+	     (param->camel (symbol->string k))
+	     k)
+	 v)))
+     ((list? x) (map scm->yggdrasil-json x))
+     ((vector? x) (vector-map scm->yggdrasil-json x))
+     (else x)))
+  (computed-file
+   "yggdrasil.conf"
+   #~(call-with-output-file #$output
+       (lambda (port)
+         ;; it's HJSON, so comments are a-okay
+         (display "# Generated by yggdrasil-service\n" port)
+         (display #$(scm->json-string
+                     (scm->yggdrasil-json
+                      (yggdrasil-configuration-json-config config)))
+                  port)))))
+
+(define (yggdrasil-shepherd-service config)
+  "Return a <shepherd-service> for yggdrasil with CONFIG."
+  (define yggdrasil-command
+    #~(append
+       (list (string-append
+              #$(yggdrasil-configuration-package config)
+              "/bin/yggdrasil")
+             "-useconffile"
+             #$(yggdrasil-configuration-file config))
+       (if #$(yggdrasil-configuration-autoconf? config)
+           '("-autoconf")
+           '())
+       (let ((extraconf #$(yggdrasil-config-file config)))
+         (if extraconf
+             (list "-extraconffile" extraconf)
+             '()))
+       (list "-loglevel"
+             #$(symbol->string
+		(yggdrasil-configuration-log-level config))
+             "-logto"
+             #$(symbol->string
+		(yggdrasil-configuration-log-to config)))))
+  (list (shepherd-service
+         (documentation "Connect to the Yggdrasil mesh network")
+         (provision '(yggdrasil))
+         (requirement '(networking))
+         (start #~(make-forkexec-constructor
+                   #$yggdrasil-command
+                   #:log-file "/var/log/yggdrasil.log"))
+         (stop #~(make-kill-destructor)))))
+
+;; TODO: somehow chown the socket. might be better to fix upstream?
+(define %yggdrasil-accounts
+  (list (user-group (name "yggdrasil") (system? #t))))
+
+(define yggdrasil-service-type
+  (service-type
+   (name 'yggdrasil)
+   (description
+    "Connect to the Yggdrasil mesh network.
+See yggdrasil -genconf for config options.")
+   (extensions
+    (list (service-extension shepherd-root-service-type
+                             yggdrasil-shepherd-service)
+          (service-extension account-service-type
+                             (const %yggdrasil-accounts))
+          (service-extension profile-service-type
+                             (compose list yggdrasil-configuration-package))))))
+
 ;;; networking.scm ends here
-- 
2.28.0

>From 26a591e6a1483acd713b44bed6b0cd53ab50c4c5 Mon Sep 17 00:00:00 2001
From: raingloom <[email-masked]>
Date: Thu, 11 Jun 2020 14:16:42 +0200
Subject: [PATCH 10/11] gnu: system: add example with yggdrasil

* gnu/system/examples/yggdrasil.tmpl: New file.
---
 gnu/system/examples/yggdrasil.tmpl | 61 ++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 gnu/system/examples/yggdrasil.tmpl

diff --git a/gnu/system/examples/yggdrasil.tmpl b/gnu/system/examples/yggdrasil.tmpl
new file mode 100644
index 0000000000..be222e9223
--- /dev/null
+++ b/gnu/system/examples/yggdrasil.tmpl
@@ -0,0 +1,61 @@
+;; This is an operating system configuration template
+;; for a "bare bones" setup, with no X11 display server.
+
+(use-modules (gnu))
+(use-service-modules networking ssh)
+(use-package-modules admin networking screen)
+
+(operating-system
+  (host-name "ruby-guard-5545")
+  (timezone "Europe/Budapest")
+  (locale "en_US.utf8")
+
+  ;; Boot in "legacy" BIOS mode, assuming /dev/sdX is the
+  ;; target hard disk, and "my-root" is the label of the target
+  ;; root file system.
+  (bootloader (bootloader-configuration
+                (bootloader grub-bootloader)
+                (target "/dev/sdX")))
+  (file-systems (cons (file-system
+                        (device (file-system-label "my-root"))
+                        (mount-point "/")
+                        (type "ext4"))
+                      %base-file-systems))
+
+  ;; This is where user accounts are specified.  The "root"
+  ;; account is implicit, and is initially created with the
+  ;; empty password.
+  (users (cons (user-account
+                (name "alice")
+                (comment "Bob's sister")
+                (group "users")
+
+                ;; Adding the account to the "wheel" group
+                ;; makes it a sudoer.  Adding it to "audio"
+                ;; and "video" allows the user to play sound
+                ;; and access the webcam.
+                (supplementary-groups '("wheel"
+                                        "audio" "video")))
+               %base-user-accounts))
+
+  ;; Globally-installed packages.
+  (packages (cons* screen %base-packages))
+
+  ;; Add services to the baseline: a DHCP client and
+  ;; an SSH server.
+  (services
+   (append
+    (list
+     (service dhcp-client-service-type)
+     (service yggdrasil-service-type
+              (yggdrasil-configuration
+               (log-to 'stdout)
+               (log-level 'debug)
+               (autoconf? #f)
+               (json-config
+               ;; choose one from https://github.com/yggdrasil-network/public-peers
+                '((peers . #("tcp://1.2.3.4:1337"))))))
+     (service openssh-service-type
+              (openssh-configuration
+               (port-number 2222))))
+    %base-services)))
-- 
2.28.0

>From f9bf4bd3af7ef114b54d67155bc3a568194d8f5e Mon Sep 17 00:00:00 2001
From: your friendly localhost admin <[email-masked]>
Date: Thu, 3 Sep 2020 19:43:44 +0200
Subject: [PATCH 11/11] doc: document Yggdrasil service

* doc/guix.texi
  (yggdrasil-service-type, yggdrasil-configuration): Newly documented.
---
 doc/guix.texi | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/doc/guix.texi b/doc/guix.texi
index d3f0f729ec..308dedfcb3 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -80,6 +80,7 @@ Copyright @copyright{} 2020 Brice Waegeneire@*
 Copyright @copyright{} 2020 R Veera Kumar@*
 Copyright @copyright{} 2020 Pierre Langlois@*
 Copyright @copyright{} 2020 pinoaffe@*
+Copyright @copyright{} 2020 raingloom@*
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -15324,6 +15325,59 @@ Use this to add additional options and manage shared secrets out-of-band.
 @end table
 @end deftp
 
+@defvr {Scheme Variable} yggdrasil-service-type
+The service type for connecting to the @uref{https://yggdrasil-network.github.io/, Yggdrasil network}, an early-stage implementation of a fully end-to-end encrypted IPv6 network.
+Pass it a value of @code{yggdrasil-configuration} to connect it to public peers and/or local peers.
+
+Here is an example using public peers and private configuration from @file{/etc/yggdrasil-private.conf} (the default value for @code{config-file}).
+See below for which options should go to @code{json-config} and which to @code{config-file}.
+
+@lisp
+(service yggdrasil-service-type
+              (yggdrasil-configuration
+               (autoconf? #f)
+               (json-config
+               ;; choose one from https://github.com/yggdrasil-network/public-peers
+                '((peers . #("tcp://1.2.3.4:1337"))))))
+@end lisp
+@end defvr
+
+@deftp {Data Type} yggdrasil-configuration
+Data type representing the configuration of Yggdrasil. Note that these settings are stored in the Guix store, which is readable to all users.
+
+@table @asis
+@item @code{package} (default: @code{yggdrasil})
+Package object of Yggdrasil.
+
+@item @code{json-config} (default: @code{'()})
+Contents of @file{/etc/yggdrasil.conf}. Will be merged with @file{/etc/yggdrasil-private.conf}.
+Do not store sensitive data (like private keys) in this.
+See the output of @code{yggdrasil -genconf} for a quick overview of valid keys and their default values.
+
+@item @code{autoconf?} (default: @code{#f})
+Whether to automatically configure an address and join through local peers.
+
+@item @code{log-level} (default: @code{'info})
+How much detail to include in logs. Use @code{'debug} for more detail.
+
+@item @code{log-to} (default: @code{'stdout})
+Where to send logs. By default, the service logs standard output to @file{/var/log/yggdrasil.log}.
+The alternative is @code{'syslog}.
+
+@item @code{config-file} (default: @code{"/etc/yggdrasil-private.conf"})
+What HJSON file to load sensitive data from. This is where private keys should be stored, which are necessary to specify if you don't want a randomized address after each restart.
+Use @code{"/dev/null"} if you don't need it.
+Options defined in this file take precedence over @code{json-config}.
+Use the output of @code{yggdrasil -genconf} as a starting point. You most likely only need these keys:
+@itemize
+@item @code{EncryptionPublicKey}
+@item @code{EncryptionPrivateKey}
+@item @code{SigningPublicKey}
+@item @code{SigningPrivateKey}
+@end itemize
+@end table
+@end deftp
+
 @node Unattended Upgrades
 @subsection Unattended Upgrades
 
-- 
2.28.0