with-wireguard.el provides primitives for managing a wireguard vpn inside a dedicated network namespace, this is useful to e.g. spawn a browser or terminal that requires access to certain network resources, without affecting any routing on main network namespace
Put with-wireguard.el in your load-path
and (require 'with-wireguard)
You can start an application inside a network namespace with a given wireguard
configuration using M-x with-wg-execute RET
To remove the namespace after you’re done with the application you can use the
ip netns list
and ip netns delete
commands, respectively.
Programmatically, you can use the with-wg--deflate-ns
function.
My personal configuration provides an example of a simple application launcher for a wireguard network namespace, as well as a simple fetcher. All use the auto deflate flag which will automatically teardown the namespace when command exits. You’ll note how this usage pattern lets you quickly compose a collection of independently vpn’d applications, such that your system traffic is isolated at the application level rather than sharing traffic patterns and signatures as a whole.
(use-package with-wireguard
:quelpa (with-wireguard :fetcher github :repo "anticomputer/with-wireguard.el")
:ensure t
:demand
:config
;; these use the auto-deflate-ns toggle to automatically teardown on exit
;; chrome, secure core
(defun my/with-wg-proton-secure-chrome ()
(interactive)
(let* ((chrome (executable-find "firejail-google-chrome"))
(namespace
(with-wg-execute
"~/emacs/vpn/protonvpn/wireguard/dolores-secure.conf"
(format "%s --no-first-run --no-default-browser-check --no-crash-upload --incognito --user-data-dir=/tmp/%s"
chrome (make-temp-name "chrome"))
t)))
(message "Spawning chrome in %s" namespace)))
;; xterm, fastest
(defun my/with-wg-proton-xterm ()
(interactive)
(let* ((xterm (executable-find "xterm"))
(namespace
(with-wg-execute
"~/emacs/vpn/protonvpn/wireguard/proton-xterm.conf"
(format "%s" xterm) t)))
(message "Spawning xterm in %s" namespace)))
;; fetcher, fastest
(defun my/with-wg-proton-fetch (uri)
(interactive "MFetch with wireguard (uri): ")
(let* ((curl (executable-find "curl"))
(namespace
(with-wg-execute
"~/emacs/vpn/protonvpn/wireguard/proton-fetch.conf"
;; wait a tiny bit for the link to init
(format "sleep 0.5 && %s -s -O --output-dir /home/bas/Downloads -- %s"
curl
(shell-quote-argument uri))
t)))
(message "Spawning curl in %s" uri namespace))))
You could compose more involved state management on top of the primitives provided by with-wireguard.el but for my personal use I generally just want to spawn a single application within a given vpn, without affecting my main system network routing.
An example of direct use of the with-wg
macro is provided below in the
form of a vterm
wireguard wrapper:
;; vterm with a wireguard namespace
(defun my/with-wg-proton-fast-vterm ()
(interactive)
(let* ((conf "~/emacs/vpn/protonvpn/wireguard/dolores-secure.conf")
(ip (executable-find "ip"))
(namespace (with-wg (conf) ns ns))
(term
;; hehe
(let ((vterm-shell
(format "sudo -E %s netns exec %s sudo -E -u %s zsh"
ip namespace (user-real-login-name))))
(vterm))))
(switch-to-buffer (other-buffer term))
(switch-to-buffer-other-window term)
(with-current-buffer term
(setq-local with-wg--namespace namespace)
(setq-local vterm-exit-functions
(append (list (lambda (proc event)
(with-wg--deflate-ns
with-wg--namespace)))
vterm-exit-functions))
;; set a prompt to designate this shell
(vterm--goto-line -1)
(vterm-send-string
(format "[[ ! -z \"$(sudo wg)\" ]] && export PS1=\"wg-%s> \" || echo \"wireguard not active\\!\""
(file-name-base conf)))
(vterm-send-return))))
This is free and unencumbered software released into the public domain.