From 577af9947d77232082d45a456e3df252c3e151dd Mon Sep 17 00:00:00 2001 From: Thomas Willems Date: Mon, 29 Jan 2024 12:51:44 +0100 Subject: [PATCH] introduce WG_DEFAULT_ADDRESS_RANGE (CIDR notation) This PR allows the use of Address Ranges using the CIDR notation. To make it backward compatible, i introduced a new env variable WG_DEFAULT_ADDRESS_RANGE (defaults to the previous default of 24). This allows the usage of smaller subnets (or possibly larger; but i didn't test that due to restrictions on my network). Client IPs will be calculated with correct IP addresses instead of making assumptions of the address space. --- README.md | 1 + docker-compose.yml | 1 + src/config.js | 10 +++++++++- src/lib/WireGuard.js | 21 ++++++++++++++------- src/package-lock.json | 6 ++++++ src/package.json | 1 + wg-easy.service | 1 + 7 files changed, 33 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 95810441..49fc42ff 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ These options can be configured by setting environment variables using `-e KEY=" | `WG_MTU` | `null` | `1420` | The MTU the clients will use. Server uses default WG MTU. | | `WG_PERSISTENT_KEEPALIVE` | `0` | `25` | Value in seconds to keep the "connection" open. If this value is 0, then connections won't be kept alive. | | `WG_DEFAULT_ADDRESS` | `10.8.0.x` | `10.6.0.x` | Clients IP address range. | +| `WG_DEFAULT_ADDRESS_RANGE` | `24` | `28` | CIDR notation block of range. Default equals `10.8.0.1/24` | | `WG_DEFAULT_DNS` | `1.1.1.1` | `8.8.8.8, 8.8.4.4` | DNS server clients will use. If set to blank value, clients will not use any DNS. | | `WG_ALLOWED_IPS` | `0.0.0.0/0, ::/0` | `192.168.15.0/24, 10.0.1.0/24` | Allowed IPs clients will use. | | `WG_PRE_UP` | `...` | - | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L19) for the default value. | diff --git a/docker-compose.yml b/docker-compose.yml index a6738832..22e73cdb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,6 +16,7 @@ services: # - PASSWORD=foobar123 # - WG_PORT=51820 # - WG_DEFAULT_ADDRESS=10.8.0.x + # - WG_DEFAULT_ADDRESS_RANGE=24 # - WG_DEFAULT_DNS=1.1.1.1 # - WG_MTU=1420 # - WG_ALLOWED_IPS=192.168.15.0/24, 10.0.1.0/24 diff --git a/src/config.js b/src/config.js index 33ff7832..5245a348 100644 --- a/src/config.js +++ b/src/config.js @@ -1,5 +1,7 @@ 'use strict'; +const ip = require('ip'); + const { release } = require('./package.json'); module.exports.RELEASE = release; @@ -13,14 +15,20 @@ module.exports.WG_PORT = process.env.WG_PORT || 51820; module.exports.WG_MTU = process.env.WG_MTU || null; module.exports.WG_PERSISTENT_KEEPALIVE = process.env.WG_PERSISTENT_KEEPALIVE || 0; module.exports.WG_DEFAULT_ADDRESS = process.env.WG_DEFAULT_ADDRESS || '10.8.0.x'; +module.exports.WG_DEFAULT_ADDRESS_RANGE = process.env.WG_DEFAULT_ADDRESS_RANGE || 24; module.exports.WG_DEFAULT_DNS = typeof process.env.WG_DEFAULT_DNS === 'string' ? process.env.WG_DEFAULT_DNS : '1.1.1.1'; module.exports.WG_ALLOWED_IPS = process.env.WG_ALLOWED_IPS || '0.0.0.0/0, ::/0'; +module.exports.WG_SUBNET = ip.subnet(module.exports.WG_DEFAULT_ADDRESS.replace('x', '1'), `255.255.255.${256 - 2 ** (32 - module.exports.WG_DEFAULT_ADDRESS_RANGE)}`); +module.exports.WG_SERVER_ADDRESS = module.exports.WG_SUBNET.firstAddress; +module.exports.WG_CLIENT_FIRST_ADDRESS = ip.toLong(module.exports.WG_SERVER_ADDRESS) + 1; +module.exports.WG_CLIENT_LAST_ADDRESS = ip.toLong(module.exports.WG_SUBNET.lastAddress) - 1; // Exclude the broadcast address + module.exports.WG_PRE_UP = process.env.WG_PRE_UP || ''; module.exports.WG_POST_UP = process.env.WG_POST_UP || ` -iptables -t nat -A POSTROUTING -s ${module.exports.WG_DEFAULT_ADDRESS.replace('x', '0')}/24 -o ${module.exports.WG_DEVICE} -j MASQUERADE; +iptables -t nat -A POSTROUTING -s ${module.exports.WG_SERVER_ADDRESS}/${module.exports.WG_DEFAULT_ADDRESS_RANGE} -o ${module.exports.WG_DEVICE} -j MASQUERADE; iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT; iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; diff --git a/src/lib/WireGuard.js b/src/lib/WireGuard.js index 89246a73..a0beddeb 100644 --- a/src/lib/WireGuard.js +++ b/src/lib/WireGuard.js @@ -4,6 +4,7 @@ const fs = require('fs').promises; const path = require('path'); const debug = require('debug')('WireGuard'); +const ip = require('ip'); const uuid = require('uuid'); const QRCode = require('qrcode'); @@ -16,9 +17,12 @@ const { WG_PORT, WG_MTU, WG_DEFAULT_DNS, - WG_DEFAULT_ADDRESS, + WG_DEFAULT_ADDRESS_RANGE, WG_PERSISTENT_KEEPALIVE, WG_ALLOWED_IPS, + WG_SERVER_ADDRESS, + WG_CLIENT_FIRST_ADDRESS, + WG_CLIENT_LAST_ADDRESS, WG_PRE_UP, WG_POST_UP, WG_PRE_DOWN, @@ -45,13 +49,15 @@ module.exports = class WireGuard { const publicKey = await Util.exec(`echo ${privateKey} | wg pubkey`, { log: 'echo ***hidden*** | wg pubkey', }); - const address = WG_DEFAULT_ADDRESS.replace('x', '1'); + const address = WG_SERVER_ADDRESS; + const cidrBlock = WG_DEFAULT_ADDRESS_RANGE; config = { server: { privateKey, publicKey, address, + cidrBlock, }, clients: {}, }; @@ -94,7 +100,7 @@ module.exports = class WireGuard { # Server [Interface] PrivateKey = ${config.server.privateKey} -Address = ${config.server.address}/24 +Address = ${config.server.address}/${config.server.cidrBlock} ListenPort = 51820 PreUp = ${WG_PRE_UP} PostUp = ${WG_POST_UP} @@ -229,15 +235,16 @@ Endpoint = ${WG_HOST}:${WG_PORT}`; const publicKey = await Util.exec(`echo ${privateKey} | wg pubkey`); const preSharedKey = await Util.exec('wg genpsk'); - // Calculate next IP + // find next IP let address; - for (let i = 2; i < 255; i++) { + for (let i = WG_CLIENT_FIRST_ADDRESS; i <= WG_CLIENT_LAST_ADDRESS; i++) { + const currentIp = ip.fromLong(i); const client = Object.values(config.clients).find((client) => { - return client.address === WG_DEFAULT_ADDRESS.replace('x', i); + return client.address === currentIp; }); if (!client) { - address = WG_DEFAULT_ADDRESS.replace('x', i); + address = currentIp; break; } } diff --git a/src/package-lock.json b/src/package-lock.json index 532fa5bb..85d8420b 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -13,6 +13,7 @@ "debug": "^4.3.4", "express": "^4.18.3", "express-session": "^1.18.0", + "ip": "^1.1.8", "qrcode": "^1.5.3", "uuid": "^9.0.1" }, @@ -2793,6 +2794,11 @@ "node": ">= 0.4" } }, + "node_modules/ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", diff --git a/src/package.json b/src/package.json index 14cf5183..fe676ce3 100644 --- a/src/package.json +++ b/src/package.json @@ -17,6 +17,7 @@ "debug": "^4.3.4", "express": "^4.18.3", "express-session": "^1.18.0", + "ip": "^1.1.8", "qrcode": "^1.5.3", "uuid": "^9.0.1" }, diff --git a/wg-easy.service b/wg-easy.service index bcdf72fd..9b842b39 100644 --- a/wg-easy.service +++ b/wg-easy.service @@ -6,6 +6,7 @@ After=network-online.target nss-lookup.target Environment="WG_HOST=raspberrypi.local" # Change this to your host's public address or static public ip. Environment="PASSWORD=REPLACEME" # When set, requires a password when logging in to the Web UI, to disable add a hashtag #Environment="WG_DEFAULT_ADDRESS=10.0.8.x" #Clients IP address range. +#Environment="WG_DEFAULT_ADDRESS_RANGE=24" #Clients IP address range block. #Environment="WG_DEFAULT_DNS=10.0.8.1, 1.1.1.1" #DNS server clients will use. If set to blank value, clients will not use any DNS. #Environment="WG_ALLOWED_IPS=0.0.0.0/0,::/0" #Allowed IPs clients will use. #Environment="WG_DEVICE=ens1" #Ethernet device the wireguard traffic should be forwarded through.