Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to change IPv4/v6 Prefix from environment variables #7

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bindata.go
42 changes: 39 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Running Subspace on a VPS is designed to be as simple as possible.
**Recommended Specs**

* Type: VPS or dedicated
* Distribution: Ubuntu 16.04 (Xenial)
* Distribution: Ubuntu 16.04 (Xenial) or Ubuntu 18.04 (Bionic)
* Memory: 512MB or greater

### 2. Add a DNS record
Expand All @@ -63,7 +63,7 @@ Subspace runs a TLS ("SSL") https server on port 443/tcp. It also runs a standar
**Requirements**

* Your server must have a publicly resolvable DNS record.
* Your server must be reachable over the internet on ports 80/tcp and 443/tcp and 51820/udp (WireGuard).
* Your server must be reachable over the internet on ports 80/tcp, 443/tcp and 51820/udp (Default WireGuard port, user changeable).

### Usage

Expand Down Expand Up @@ -138,7 +138,19 @@ docker create \
--cap-add NET_ADMIN \
--volume /usr/bin/wg:/usr/bin/wg \
--volume /data:/data \
--env SUBSPACE_HTTP_HOST=subspace.example.com \
--env SUBSPACE_HTTP_HOST="subspace.example.com" \
# Optional variable to change upstream DNS provider
--env SUBSPACE_NAMESERVER="1.1.1.1" \
# Optional variable to change WireGuard Listenport
--env SUBSPACE_LISTENPORT="51820" \
# Optional variables to change IPv4/v6 prefixes
--env SUBSPACE_IPV4_POOL="10.99.97.0/24" \
--env SUBSPACE_IPV6_POOL="fd00::10:97:0/64" \
# Optional variables to change IPv4/v6 Gateway
--env SUBSPACE_IPV4_GW="10.99.97.1" \
--env SUBSPACE_IPV6_GW="fd00::10:97:1" \
# Optional variable to enable or disable IPv6 NAT
--env SUBSPACE_IPV6_NAT_ENABLED=1 \
subspacecloud/subspace:latest

$ sudo docker start subspace
Expand All @@ -149,6 +161,30 @@ $ sudo docker logs subspace

```

#### Docker-Compose Example

```
version: "3.3"
services:
subspace:
image: subspace/subspace:latest
container_name: subspace
volumes:
- /usr/bin/wg:/usr/bin/wg
- /opt/docker/subspace:/data
restart: always
environment:
- SUBSPACE_HTTP_HOST=subspace.example.org
- SUBSPACE_LETSENCRYPT=true
- SUBSPACE_HTTP_INSECURE=false
- SUBSPACE_HTTP_ADDR=":80"
- SUBSPACE_NAMESERVER=1.1.1.1
- SUBSPACE_LISTENPORT=51820
cap_add:
- NET_ADMIN
network_mode: "host"
```

#### Updating the container image

Pull the latest image, remove the container, and re-create the container as explained above.
Expand Down
103 changes: 61 additions & 42 deletions entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,21 @@ if [ -z "${SUBSPACE_HTTP_HOST-}" ] ; then
echo "Environment variable SUBSPACE_HTTP_HOST required. Exiting."
exit 1
fi

# Optional environment variables.
if [ -z "${SUBSPACE_BACKLINK-}" ] ; then
export SUBSPACE_BACKLINK=""
fi

if [ -z "${SUBSPACE_IPV4_POOL-}" ] ; then
export SUBSPACE_IPV4_POOL="10.99.97.0/24"
fi
if [ -z "${SUBSPACE_IPV6_POOL-}" ] ; then
export SUBSPACE_IPV6_POOL="fd00::10:97:0/112"
fi
if [ -z "${SUBSPACE_NAMESERVER-}" ] ; then
export SUBSPACE_NAMESERVER="1.1.1.1"
fi

if [ -z "${SUBSPACE_LETSENCRYPT-}" ] ; then
export SUBSPACE_LETSENCRYPT="true"
fi
Expand All @@ -23,75 +32,82 @@ if [ -z "${SUBSPACE_HTTP_ADDR-}" ] ; then
export SUBSPACE_HTTP_ADDR=":80"
fi

if [ -z "${SUBSPACE_LISTENPORT-}" ] ; then
export SUBSPACE_LISTENPORT="51820"
fi

if [ -z "${SUBSPACE_HTTP_INSECURE-}" ] ; then
export SUBSPACE_HTTP_INSECURE="false"
fi

export NAMESERVER="1.1.1.1"
export DEBIAN_FRONTEND="noninteractive"

if [ -z "${SUBSPACE_IPV4_GW-}" ] ; then
export SUBSPACE_IPV4_PREF=$(echo ${SUBSPACE_IPV4_POOL-} | cut -d '/' -f1 |sed 's/.0$/./g' )
export SUBSPACE_IPV4_GW=$(echo ${SUBSPACE_IPV4_PREF-}1)

fi
if [ -z "${SUBSPACE_IPV6_GW-}" ] ; then
export SUBSPACE_IPV6_PREF=$(echo ${SUBSPACE_IPV6_POOL-} | cut -d '/' -f1 |sed 's/:0$/:/g' )
export SUBSPACE_IPV6_GW=$(echo ${SUBSPACE_IPV6_PREF-}1)
fi

if [ -z "${SUBSPACE_IPV6_NAT_ENABLED-}" ] ; then
export SUBSPACE_IPV6_NAT_ENABLED=1
fi

# Set DNS server
echo "nameserver ${NAMESERVER}" >/etc/resolv.conf
echo "nameserver ${SUBSPACE_NAMESERVER}" >/etc/resolv.conf

# ipv4
if ! /sbin/iptables -t nat --check POSTROUTING -s 10.99.97.0/24 -j MASQUERADE ; then
/sbin/iptables -t nat --append POSTROUTING -s 10.99.97.0/24 -j MASQUERADE
if ! /sbin/iptables -t nat --check POSTROUTING -s ${SUBSPACE_IPV4_POOL} -j MASQUERADE ; then
/sbin/iptables -t nat --append POSTROUTING -s ${SUBSPACE_IPV4_POOL} -j MASQUERADE
fi

if ! /sbin/iptables --check FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT ; then
/sbin/iptables --append FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
fi

if ! /sbin/iptables --check FORWARD -s 10.99.97.0/24 -j ACCEPT ; then
/sbin/iptables --append FORWARD -s 10.99.97.0/24 -j ACCEPT
if ! /sbin/iptables --check FORWARD -s ${SUBSPACE_IPV4_POOL} -j ACCEPT ; then
/sbin/iptables --append FORWARD -s ${SUBSPACE_IPV4_POOL} -j ACCEPT
fi

if [[ ${SUBSPACE_IPV6_NAT_ENABLED-} -gt 0 ]]; then
# ipv6
if ! /sbin/ip6tables -t nat --check POSTROUTING -s fd00::10:97:0/112 -j MASQUERADE ; then
/sbin/ip6tables -t nat --append POSTROUTING -s fd00::10:97:0/112 -j MASQUERADE
fi

if ! /sbin/ip6tables --check FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT ; then
/sbin/ip6tables --append FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
fi

if ! /sbin/ip6tables --check FORWARD -s fd00::10:97:0/112 -j ACCEPT ; then
/sbin/ip6tables --append FORWARD -s fd00::10:97:0/112 -j ACCEPT
if ! /sbin/ip6tables -t nat --check POSTROUTING -s ${SUBSPACE_IPV6_POOL} -j MASQUERADE ; then
/sbin/ip6tables -t nat --append POSTROUTING -s ${SUBSPACE_IPV6_POOL} -j MASQUERADE
fi

if ! /sbin/ip6tables --check FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT ; then
/sbin/ip6tables --append FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
fi

if ! /sbin/ip6tables --check FORWARD -s ${SUBSPACE_IPV6_POOL} -j ACCEPT ; then
/sbin/ip6tables --append FORWARD -s ${SUBSPACE_IPV6_POOL} -j ACCEPT
fi
fi


# ipv4 - DNS Leak Protection
if ! /sbin/iptables -t nat --check OUTPUT -s 10.99.97.0/16 -p udp --dport 53 -j DNAT --to 10.99.97.1:53 ; then
/sbin/iptables -t nat --append OUTPUT -s 10.99.97.0/16 -p udp --dport 53 -j DNAT --to 10.99.97.1:53
if ! /sbin/iptables -t nat --check OUTPUT -s ${SUBSPACE_IPV4_POOL} -p udp --dport 53 -j DNAT --to ${SUBSPACE_IPV4_GW}:53 ; then
/sbin/iptables -t nat --append OUTPUT -s ${SUBSPACE_IPV4_POOL} -p udp --dport 53 -j DNAT --to ${SUBSPACE_IPV4_GW}:53
fi

if ! /sbin/iptables -t nat --check OUTPUT -s 10.99.97.0/16 -p tcp --dport 53 -j DNAT --to 10.99.97.1:53 ; then
/sbin/iptables -t nat --append OUTPUT -s 10.99.97.0/16 -p tcp --dport 53 -j DNAT --to 10.99.97.1:53
if ! /sbin/iptables -t nat --check OUTPUT -s ${SUBSPACE_IPV4_POOL} -p tcp --dport 53 -j DNAT --to ${SUBSPACE_IPV4_GW}:53 ; then
/sbin/iptables -t nat --append OUTPUT -s ${SUBSPACE_IPV4_POOL} -p tcp --dport 53 -j DNAT --to ${SUBSPACE_IPV4_GW}:53
fi

# ipv6 - DNS Leak Protection
if ! /sbin/ip6tables --wait -t nat --check OUTPUT -s fd00::10:97:0/112 -p udp --dport 53 -j DNAT --to fd00::10:97:1 ; then
/sbin/ip6tables --wait -t nat --append OUTPUT -s fd00::10:97:0/112 -p udp --dport 53 -j DNAT --to fd00::10:97:1
if ! /sbin/ip6tables --wait -t nat --check OUTPUT -s ${SUBSPACE_IPV6_POOL} -p udp --dport 53 -j DNAT --to ${SUBSPACE_IPV6_GW} ; then
/sbin/ip6tables --wait -t nat --append OUTPUT -s ${SUBSPACE_IPV6_POOL} -p udp --dport 53 -j DNAT --to ${SUBSPACE_IPV6_GW}
fi

if ! /sbin/ip6tables --wait -t nat --check OUTPUT -s fd00::10:97:0/112 -p tcp --dport 53 -j DNAT --to fd00::10:97:1 ; then
/sbin/ip6tables --wait -t nat --append OUTPUT -s fd00::10:97:0/112 -p tcp --dport 53 -j DNAT --to fd00::10:97:1
if ! /sbin/ip6tables --wait -t nat --check OUTPUT -s ${SUBSPACE_IPV6_POOL} -p tcp --dport 53 -j DNAT --to ${SUBSPACE_IPV6_GW} ; then
/sbin/ip6tables --wait -t nat --append OUTPUT -s ${SUBSPACE_IPV6_POOL} -p tcp --dport 53 -j DNAT --to ${SUBSPACE_IPV6_GW}
fi

# # Delete
# /sbin/iptables -t nat --delete OUTPUT -s 10.99.97.0/16 -p udp --dport 53 -j DNAT --to 10.99.97.1:53
# /sbin/iptables -t nat --delete OUTPUT -s 10.99.97.0/16 -p tcp --dport 53 -j DNAT --to 10.99.97.1:53
# /sbin/ip6tables --wait -t nat --delete OUTPUT -s fd00::10:97:0/112 -p udp --dport 53 -j DNAT --to fd00::10:97:1
# /sbin/ip6tables --wait -t nat --delete OUTPUT -s fd00::10:97:0/112 -p tcp --dport 53 -j DNAT --to fd00::10:97:1
# /sbin/iptables -t nat --delete POSTROUTING -s 10.99.97.0/24 -j MASQUERADE
# /sbin/iptables --delete FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
# /sbin/iptables --delete FORWARD -s 10.99.97.0/24 -j ACCEPT
# /sbin/ip6tables -t nat --delete POSTROUTING -s fd00::10:97:0/112 -j MASQUERADE
# /sbin/ip6tables --delete FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
# /sbin/ip6tables --delete FORWARD -s fd00::10:97:0/112 -j ACCEPT

#
# WireGuard (10.99.97.0/24)
# WireGuard (${SUBSPACE_IPV4_POOL})
#
if ! test -d /data/wireguard ; then
mkdir /data/wireguard
Expand All @@ -109,7 +125,7 @@ fi
cat <<WGSERVER >/data/wireguard/server.conf
[Interface]
PrivateKey = $(cat /data/wireguard/server.private)
ListenPort = 51820
ListenPort = ${SUBSPACE_LISTENPORT}

WGSERVER
cat /data/wireguard/peers/*.conf >>/data/wireguard/server.conf
Expand All @@ -118,16 +134,19 @@ if ip link show wg0 2>/dev/null; then
ip link del wg0
fi
ip link add wg0 type wireguard
ip addr add 10.99.97.1/24 dev wg0
ip addr add fd00::10:97:1/112 dev wg0
export SUBSPACE_IPV4_CIDR=$(echo ${SUBSPACE_IPV4_POOL-} |cut -d '/' -f2)
ip addr add ${SUBSPACE_IPV4_GW}/${SUBSPACE_IPV4_CIDR} dev wg0
export SUBSPACE_IPV6_CIDR=$(echo ${SUBSPACE_IPV6_POOL-} |cut -d '/' -f2)
ip addr add ${SUBSPACE_IPV6_GW}/${SUBSPACE_IPV6_CIDR} dev wg0
wg setconf wg0 /data/wireguard/server.conf
ip link set wg0 up


# dnsmasq service
if ! test -d /etc/sv/dnsmasq ; then
cat <<DNSMASQ >/etc/dnsmasq.conf
# Only listen on necessary addresses.
listen-address=127.0.0.1,10.99.97.1,fd00::10:97:1
listen-address=127.0.0.1,${SUBSPACE_IPV4_GW},${SUBSPACE_IPV6_GW}

# Never forward plain names (without a dot or domain part)
domain-needed
Expand Down
76 changes: 65 additions & 11 deletions handlers.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"os"
"fmt"
"io/ioutil"
"net/http"
Expand All @@ -21,6 +22,13 @@ var (
maxProfilesPerUser = 10
)

func getEnv(key, fallback string) string {
if value, ok := os.LookupEnv(key); ok {
return value
}
return fallback
}

func ssoHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
if token := samlSP.GetAuthorizationToken(r); token != nil {
http.Redirect(w, r, "/", http.StatusFound)
Expand Down Expand Up @@ -365,43 +373,89 @@ func profileAddHandler(w *Web) {
return
}

ipv4Pref := "10.99.97."
if pref := getEnv("SUBSPACE_IPV4_PREF", "nil"); pref != "nil" {
ipv4Pref = pref
}
ipv4Gw := "10.99.97.1"
if gw := getEnv("SUBSPACE_IPV4_GW", "nil"); gw != "nil" {
ipv4Gw = gw
}
ipv4Cidr := "24"
if cidr := getEnv("SUBSPACE_IPV4_CIDR", "nil"); cidr != "nil" {
ipv4Cidr = cidr
}

ipv6Pref := "fd00::10:97:"
if pref := getEnv("SUBSPACE_IPV6_PREF", "nil"); pref != "nil" {
ipv6Pref = pref
}
ipv6Gw := "fd00::10:97:1"
if gw := getEnv("SUBSPACE_IPV6_GW", "nil"); gw != "nil" {
ipv6Gw = gw
}
ipv6Cidr := "64"
if cidr := getEnv("SUBSPACE_IPV6_CIDR", "nil"); cidr != "nil" {
ipv6Cidr = cidr
}
listenport := "51820"
if port := getEnv("SUBSPACE_LISTENPORT", "nil"); port != "nil" {
listenport = port
}

script := `
cd {{$.Datadir}}/wireguard
wg_private_key="$(wg genkey)"
wg_public_key="$(echo $wg_private_key | wg pubkey)"

wg set wg0 peer ${wg_public_key} allowed-ips 10.99.97.{{$.Profile.Number}}/32,fd00::10:97:{{$.Profile.Number}}/128
wg set wg0 peer ${wg_public_key} allowed-ips {{$.IPv4Pref}}{{$.Profile.Number}}/32,{{$.IPv6Pref}}{{$.Profile.Number}}/128

cat <<WGPEER >peers/{{$.Profile.ID}}.conf
[Peer]
PublicKey = ${wg_public_key}
AllowedIPs = 10.99.97.{{$.Profile.Number}}/32,fd00::10:97:{{$.Profile.Number}}/128

AllowedIPs = {{$.IPv4Pref}}{{$.Profile.Number}}/32,{{$.IPv6Pref}}{{$.Profile.Number}}/128
WGPEER

cat <<WGCLIENT >clients/{{$.Profile.ID}}.conf
cat <<WGCLIENT >clients/{{$.Profile.ID}}.conf
[Interface]
PrivateKey = ${wg_private_key}
DNS = 10.99.97.1, fd00::10:97:1
Address = 10.99.97.{{$.Profile.Number}}/22,fd00::10:97:{{$.Profile.Number}}/112
DNS = {{$.IPv4Gw}}, {{$.IPv6Gw}}
Address = {{$.IPv4Pref}}{{$.Profile.Number}}/{{$.IPv4Cidr}},{{$.IPv6Pref}}{{$.Profile.Number}}/{{$.IPv6Cidr}}

[Peer]
PublicKey = $(cat server.public)
Endpoint = {{$.Domain}}:51820
Endpoint = {{$.Domain}}:{{$.Listenport}}
AllowedIPs = 0.0.0.0/0, ::/0
WGCLIENT
`
_, err = bash(script, struct {
Datadir string
Profile Profile
Domain string
Profile Profile
Domain string
Datadir string
IPv4Gw string
IPv6Gw string
IPv4Pref string
IPv6Pref string
IPv4Cidr string
IPv6Cidr string
Listenport string
}{
datadir,
profile,
httpHost,
datadir,
ipv4Gw,
ipv6Gw,
ipv4Pref,
ipv6Pref,
ipv4Cidr,
ipv6Cidr,
listenport,
})
if err != nil {
logger.Warn(err)
f, _ := os.Create("/tmp/error.txt")
errstr := fmt.Sprintln(err)
f.WriteString(errstr)
w.Redirect("/?error=addprofile")
return
}
Expand Down
Binary file modified subspace-linux-amd64
Binary file not shown.