Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisbouchard committed Mar 14, 2021
0 parents commit d094a6b
Show file tree
Hide file tree
Showing 12 changed files with 278 additions and 0 deletions.
20 changes: 20 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Copyright (c) 2021 Chris Bouchard

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Empty file added README.md
Empty file.
33 changes: 33 additions & 0 deletions conf/namespaced-wireguard-vpn.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Name of the VPN network namespace
NETNS_NAME=vpn

# Name of the VPN WireGuard interface
WIREGUARD_NAME=wg-vpn

# Endpoint of the VPN WireGuard server
WIREGUARD_ENDPOINT=1.2.3.4

# Public key of the VPN WireGuard peer
WIREGUARD_VPN_PUBLIC_KEY=abcdFAKEefghFAKEijklFAKEmnopFAKEqrstFAKEuvw=

# Comma-separated list of allowed IP addresses for the VPN WireGuard interface
WIREGUARD_ALLOWED_IPS=0.0.0.0/0,::0/0

# Comma-separated list of static IP addresses to assign to the VPN WireGuard
# interface
WIREGUARD_IP_ADDRESSES=10.0.0.1/32,fd12:3456:789a:1::1/128

# Name of the init-facing tunnel interface
TUNNEL_INIT_NAME=veth-vpn0

# Comma-separated list of static IP addresses to assign to the init-facing
# (public) tunnel interface
TUNNEL_INIT_IP_ADDRESSES=10.127.0.1/24

# Name of the VPN-facing tunnel interface
TUNNEL_VPN_NAME=veth-vpn1

# Comma-separated list of static IP addresses to assign to the VPN-facing
# tunnel interface
TUNNEL_VPN_IP_ADDRESSES=10.127.0.2/24

5 changes: 5 additions & 0 deletions lib/base.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
die() {
[[ -n "$1" ]] && echo $1 >&2
exit 1
}

34 changes: 34 additions & 0 deletions lib/interface.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/usr/bin/env bash

source base.sh

case "$1"
up)
ip link add "$WIREGUARD_NAME" type wireguard || die

wg set \
private-key <(echo "$WIREGUARD_PRIVATE_KEY") \
peer "$WIREGUARD_VPN_PUBLIC_KEY" \
endpoint "$WIREGUARD_ENDPOINT" \
allowed-ips "$WIREGUARD_ALLOWED_IPS" || die

ip link set "$WIREGUARD_NAME" netns "$NETNS_NAME" || die

# Addresses are comma-separated, so to split them.
xargs -d ',' -I '{}' \
ip -n "$NETNS_NAME" address add '{}' dev "$VPN_WIREGUARD_NAME" \
<<<"$WIREGUARD_IP_ADDRESSES" || die

ip -n "$NETNS_NAME" link set "$WIREGUARD_NAME" up || die
ip -n "$NETNS_NAME" route add default dev "$WIREGUARD_NAME" || die
;;

down)
# We need to delete the WireGuard interface. It's initially created in
# the init network namespace, then moved to the VPN namespace.
# Depending how well the "up" operation went, it might be in either.
ip -n "$NETNS_NAME" link delete "$WIREGUARD_NAME" ||
ip link delete "$WIREGUARD_NAME" || die
;;
esac

22 changes: 22 additions & 0 deletions lib/netns.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash

source base.sh

case "$1"
up)
ip netns add "$NETNS_NAME" || die

if [[ -n "$PRIVATE_NETNS_BIND_MOUNT" ]]
then
umount "/var/run/netns/$NETNS_NAME" || die
mount --bind "$PRIVATE_NETNS_BIND_MOUNT" "/var/run/netns/$NETNS_NAME" || die
fi

ip -n "$NETNS_NAME" link set lo up || die
;;

down)
ip netns delete "$NETNS_NAME" || die
;;
esac

29 changes: 29 additions & 0 deletions lib/tunnel.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash

source base.sh

case "$1"
up)
ip link add "$TUNNEL_INIT_NAME" type veth \
peer "$TUNNEL_VPN_NAME" netns "$NETNS_NAME" || die

# Addresses are comma-separated, so to split them.
xargs -d ',' -I '{}' \
ip address add '{}' dev "$TUNNEL_INIT_NAME" \
<<<"$TUNNEL_INIT_IP_ADDRESSES" || die
xargs -d ',' -I '{}' \
ip -n "$NETNS_NAME" address add '{}' dev "$TUNNEL_VPN_NAME" \
<<<"$TUNNEL_VPN_IP_ADDRESSES" || die

ip link set "$TUNNEL_INIT_NAME" up || die
ip -n "$NETNS_NAME" link set "$TUNNEL_VPN_NAME" up || die
;;

down)
EXIT_CODE=0
ip link delete "$TUNNEL_INIT_NAME" || EXIT_CODE=$?
ip -n "$NETNS_NAME" link delete "$TUNNEL_VPN_NAME" || EXIT_CODE=$?
[[ EXIT_CODE -eq 0 ]] || die
;;
esac

60 changes: 60 additions & 0 deletions namespaced-wireguard-vpn.spec.rpkg
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
Name: {{{ git_dir_name }}}
Version: {{{ git_dir_version }}}
Release: 1%{?dist}
Summary: Systemd configuration for a network namespace containing a WireGuard VPN connection

License: MIT
VCS: {{{ git_dir_vcs }}}

Source: {{{ git_dir_pack }}}

BuildRequires: systemd-rpm-macros
Requires: bash, iproute2, systemd, xargs, wireguard-tools

BuildArch: noarch

%description
This package contains configuration for Systemd to create and manage a network
namespace containing a WireGuard VPN connection.

namespaced-wireguard-vpn.target:
namespaced-wireguard-vpn-netns.service:
Creates the network namespace
namespaced-wireguard-vpn-interface.service:
Creates the WireGuard connection and moves it into the namespace
namespaced-wireguard-vpn-tunnel.service:
Creates a Veth tunnel into the namespace

%prep
{{{ git_dir_setup_macro }}}

%install
install --mode=755 --directory=%{buildroot}%{_libdir}/%{name}
install --mode=755 --target-directory=%{buildroot}%{_libdir}/%{name} lib/*

install --mode=700 --directory %{buildroot}%{_sysconfdir}/%{name}
install --mode=600 --target-directory=%{buildroot}%{_sysconfdir}/%{name} conf/*

install --mode=755 --directory=%{buildroot}%{_unitdir}
install --mode=644 --target-directory=%{buildroot}%{_unitdir} systemd/*

%post
%systemd_post namespaced-wireguard-vpn.target

%preun
%systemd_preun namespaced-wireguard-vpn.target

%postun
%systemd_postun namespaced-wireguard-vpn.target

%files
%license LICENSE
%{_libdir}/%{name}/*
%dir %{_sysconfdir}/%{name}
%config(noreplace) %{_sysconfdir}/%{name}/*
%{_unitdir}/*

%changelog
{{{ git_dir_changelog }}}

# vim: syntax=spec
19 changes: 19 additions & 0 deletions systemd/namespaced-wireguard-vpn-interface.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Based on:
# https://cloudnull.io/2019/04/running-services-in-network-name-spaces-with-systemd/

[Unit]
Description=VPN Wireguard Interface
PartOf=namespaced-wireguard-vpn.target
Requires=namespaced-wireguard-vpn-netns.service
After=namespaced-wireguard-vpn-netns.service
After=network-online.target nss-lookup.target

[Service]
Type=oneshot
RemainAfterExit=yes

EnvironmentFile=/etc/namespaced-wireguard-vpn/namespaced-wireguard-vpn.conf

ExecStart=/usr/lib/namespaced-wireguard-vpn/interface.sh up
ExecStopPost=/usr/lib/namespaced-wireguard-vpn/interface.sh down

19 changes: 19 additions & 0 deletions systemd/namespaced-wireguard-vpn-netns.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Based on:
# https://cloudnull.io/2019/04/running-services-in-network-name-spaces-with-systemd/

[Unit]
Description=VPN Network Namespace
PartOf=namespaced-wireguard-vpn.target
After=network.target

[Service]
Type=oneshot
RemainAfterExit=yes
PrivateNetwork=yes

Environment=PRIVATE_NETNS_BIND_MOUNT=/proc/self/ns/net
EnvironmentFile=/etc/namespaced-wireguard-vpn/namespaced-wireguard-vpn.conf

ExecStart=/usr/lib/namespaced-wireguard-vpn/netns.sh up
ExecStopPost=/usr/lib/namespaced-wireguard-vpn/netns.sh down

28 changes: 28 additions & 0 deletions systemd/namespaced-wireguard-vpn-tunnel.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[Unit]
Description=VPN Tunnel Veth Interface
PartOf=namespaced-wireguard-vpn.target
Requires=namespaced-wireguard-vpn-netns.service
After=vpn-netns.service

[Service]
Type=oneshot
RemainAfterExit=yes

EnvironmentFile=/etc/namespaced-wireguard-vpn/namespaced-wireguard-vpn.conf

ExecStart=/usr/lib/namespaced-wireguard-vpn/netns.sh up
ExecStopPost=/usr/lib/namespaced-wireguard-vpn/netns.sh down

ExecStart=/sbin/ip link add veth-vpn0 type veth peer name veth-vpn1 netns vpn
# TODO: Extract these to configuration
ExecStart=/sbin/ip address add 10.127.0.1/24 dev veth-vpn0
ExecStart=/sbin/ip -n vpn address add 10.127.0.2/24 dev veth-vpn1
ExecStart=/sbin/ip link set veth-vpn0 up
ExecStart=/sbin/ip -n vpn link set veth-vpn1 up

# TODO: What to do if the first one fails?
ExecStop=/sbin/ip -n vpn link set veth-vpn1 down
ExecStop=/sbin/ip link set veth-vpn0 down
ExecStopPost=-/sbin/ip -n vpn link delete veth-vpn1
ExecStopPost=-/sbin/ip link delete veth-vpn0

9 changes: 9 additions & 0 deletions systemd/namespaced-wireguard-vpn.target
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[Unit]
Description=VPN Network Configuration Target
Requires=namespaced-wireguard-vpn-interface.service
Requires=namespaced-wireguard-vpn-netns.service
Requires=namespaced-wireguard-vpn-tunnel.service

[Install]
WantedBy=multi-user.target

0 comments on commit d094a6b

Please sign in to comment.