Browse Source

Update backend

Co-authored-by: Peter Lewis <[email protected]>
Co-authored-by: Philip H <[email protected]>
pull/1103/head
Bernd Storath 2 years ago
committed by Philip H
parent
commit
43551d7a48
  1. 32
      src/config.js
  2. 8
      src/lib/Server.js
  3. 7
      src/lib/Util.js
  4. 48
      src/lib/WireGuard.js

32
src/config.js

@ -14,18 +14,36 @@ module.exports.WG_CONFIG_PORT = process.env.WG_CONFIG_PORT || process.env.WG_POR
module.exports.WG_MTU = process.env.WG_MTU || null; module.exports.WG_MTU = process.env.WG_MTU || null;
module.exports.WG_PERSISTENT_KEEPALIVE = process.env.WG_PERSISTENT_KEEPALIVE || '0'; 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 = process.env.WG_DEFAULT_ADDRESS || '10.8.0.x';
module.exports.WG_DEFAULT_ADDRESS6 = process.env.WG_DEFAULT_ADDRESS6 || 'fdcc:ad94:bacf:61a4::cafe:x';
module.exports.WG_DEFAULT_DNS = typeof process.env.WG_DEFAULT_DNS === 'string' module.exports.WG_DEFAULT_DNS = typeof process.env.WG_DEFAULT_DNS === 'string'
? process.env.WG_DEFAULT_DNS ? process.env.WG_DEFAULT_DNS
: '1.1.1.1'; : '1.1.1.1';
module.exports.WG_DEFAULT_DNS6 = typeof process.env.WG_DEFAULT_DNS6 === 'string'
? process.env.WG_DEFAULT_DNS6
: '2606:4700:4700::1111';
module.exports.WG_ALLOWED_IPS = process.env.WG_ALLOWED_IPS || '0.0.0.0/0, ::/0'; module.exports.WG_ALLOWED_IPS = process.env.WG_ALLOWED_IPS || '0.0.0.0/0, ::/0';
module.exports.WG_PRE_UP = process.env.WG_PRE_UP || ''; // Set WG_POST_UP to allow IPv6 NAT and forwarding only if the required kernel module is available
module.exports.WG_POST_UP = process.env.WG_POST_UP || ` const modules = childProcess.execSync('lsmod', {
iptables -t nat -A POSTROUTING -s ${module.exports.WG_DEFAULT_ADDRESS.replace('x', '0')}/24 -o ${module.exports.WG_DEVICE} -j MASQUERADE; shell: 'bash',
iptables -A INPUT -p udp -m udp --dport ${module.exports.WG_PORT} -j ACCEPT; });
iptables -A FORWARD -i wg0 -j ACCEPT; module.exports.WG_POST_UP = process.env.WG_POST_UP;
iptables -A FORWARD -o wg0 -j ACCEPT; if (!process.env.WG_POST_UP) {
`.split('\n').join(' '); module.exports.WG_POST_UP = `
iptables -t nat -A POSTROUTING -s ${module.exports.WG_DEFAULT_ADDRESS.replace('x', '0')}/24 -o eth0 -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;`;
if (modules.includes('ip6table_nat')) {
module.exports.WG_POST_UP += `ip6tables -t nat -A POSTROUTING -s ${module.exports.WG_DEFAULT_ADDRESS6.replace('x', '0')}/64 -o eth0 -j MASQUERADE;
ip6tables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT;
ip6tables -A FORWARD -i wg0 -j ACCEPT;
ip6tables -A FORWARD -o wg0 -j ACCEPT;`;
}
module.exports.WG_POST_UP = module.exports.WG_POST_UP.split('\n').join(' ');
}
module.exports.WG_PRE_DOWN = process.env.WG_PRE_DOWN || ''; module.exports.WG_PRE_DOWN = process.env.WG_PRE_DOWN || '';
module.exports.WG_POST_DOWN = process.env.WG_POST_DOWN || ` module.exports.WG_POST_DOWN = process.env.WG_POST_DOWN || `

8
src/lib/Server.js

@ -210,6 +210,14 @@ module.exports = class Server {
const { address } = await readBody(event); const { address } = await readBody(event);
await WireGuard.updateClientAddress({ clientId, address }); await WireGuard.updateClientAddress({ clientId, address });
return { success: true }; return { success: true };
}))
.put('/api/wireguard/client/:clientId/address6', Util.promisify(async (event) => {
const clientId = getRouterParam(event, 'clientId');
if (clientId === '__proto__' || clientId === 'constructor' || clientId === 'prototype') {
throw createError({ status: 403 });
}
const { address6 } = await readBody(event);
return WireGuard.updateClientAddress6({ clientId, address6 });
})); }));
const safePathJoin = (base, target) => { const safePathJoin = (base, target) => {

7
src/lib/Util.js

@ -17,6 +17,13 @@ module.exports = class Util {
return true; return true;
} }
static isValidIPv6(str) {
// Regex source : https://stackoverflow.com/a/17871737
const regex = new RegExp('^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$');
const matches = str.match(regex);
return !!matches;
}
static promisify(fn) { static promisify(fn) {
// eslint-disable-next-line func-names // eslint-disable-next-line func-names
return function(req, res) { return function(req, res) {

48
src/lib/WireGuard.js

@ -16,7 +16,9 @@ const {
WG_CONFIG_PORT, WG_CONFIG_PORT,
WG_MTU, WG_MTU,
WG_DEFAULT_DNS, WG_DEFAULT_DNS,
WG_DEFAULT_DNS6,
WG_DEFAULT_ADDRESS, WG_DEFAULT_ADDRESS,
WG_DEFAULT_ADDRESS6,
WG_PERSISTENT_KEEPALIVE, WG_PERSISTENT_KEEPALIVE,
WG_ALLOWED_IPS, WG_ALLOWED_IPS,
WG_PRE_UP, WG_PRE_UP,
@ -46,12 +48,14 @@ module.exports = class WireGuard {
log: 'echo ***hidden*** | wg pubkey', log: 'echo ***hidden*** | wg pubkey',
}); });
const address = WG_DEFAULT_ADDRESS.replace('x', '1'); const address = WG_DEFAULT_ADDRESS.replace('x', '1');
const address6 = WG_DEFAULT_ADDRESS6.replace('x', '1');
config = { config = {
server: { server: {
privateKey, privateKey,
publicKey, publicKey,
address, address,
address6,
}, },
clients: {}, clients: {},
}; };
@ -71,6 +75,10 @@ module.exports = class WireGuard {
// await Util.exec('iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT'); // await Util.exec('iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT');
// await Util.exec('iptables -A FORWARD -i wg0 -j ACCEPT'); // await Util.exec('iptables -A FORWARD -i wg0 -j ACCEPT');
// await Util.exec('iptables -A FORWARD -o wg0 -j ACCEPT'); // await Util.exec('iptables -A FORWARD -o wg0 -j ACCEPT');
// await Util.exec(`ip6tables -t nat -A POSTROUTING -s ${WG_DEFAULT_ADDRESS6.replace('x', '')}/120 -o eth0 -j MASQUERADE`);
// await Util.exec('ip6tables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT');
// await Util.exec('ip6tables -A FORWARD -i wg0 -j ACCEPT');
// await Util.exec('ip6tables -A FORWARD -o wg0 -j ACCEPT');
await this.__syncConfig(); await this.__syncConfig();
return config; return config;
@ -94,7 +102,7 @@ module.exports = class WireGuard {
# Server # Server
[Interface] [Interface]
PrivateKey = ${config.server.privateKey} PrivateKey = ${config.server.privateKey}
Address = ${config.server.address}/24 Address = ${config.server.address}/24, ${config.server.address6}/120
ListenPort = ${WG_PORT} ListenPort = ${WG_PORT}
PreUp = ${WG_PRE_UP} PreUp = ${WG_PRE_UP}
PostUp = ${WG_POST_UP} PostUp = ${WG_POST_UP}
@ -111,7 +119,7 @@ PostDown = ${WG_POST_DOWN}
[Peer] [Peer]
PublicKey = ${client.publicKey} PublicKey = ${client.publicKey}
${client.preSharedKey ? `PresharedKey = ${client.preSharedKey}\n` : '' ${client.preSharedKey ? `PresharedKey = ${client.preSharedKey}\n` : ''
}AllowedIPs = ${client.address}/32`; }AllowedIPs = ${client.address}/32, ${client.address6}/128`;
} }
debug('Config saving...'); debug('Config saving...');
@ -195,12 +203,14 @@ ${client.preSharedKey ? `PresharedKey = ${client.preSharedKey}\n` : ''
async getClientConfiguration({ clientId }) { async getClientConfiguration({ clientId }) {
const config = await this.getConfig(); const config = await this.getConfig();
const client = await this.getClient({ clientId }); const client = await this.getClient({ clientId });
const isDnsSet = WG_DEFAULT_DNS || WG_DEFAULT_DNS6;
const dnsServers = [WG_DEFAULT_DNS, WG_DEFAULT_DNS6].filter((item) => !!item).join(', ');
return ` return `
[Interface] [Interface]
PrivateKey = ${client.privateKey ? `${client.privateKey}` : 'REPLACE_ME'} PrivateKey = ${client.privateKey ? `${client.privateKey}` : 'REPLACE_ME'}
Address = ${client.address}/24 Address = ${client.address}/24, ${client.address6}/64
${WG_DEFAULT_DNS ? `DNS = ${WG_DEFAULT_DNS}\n` : ''}\ ${isDnsSet ? `DNS = ${dnsServers}\n` : ''}\
${WG_MTU ? `MTU = ${WG_MTU}\n` : ''}\ ${WG_MTU ? `MTU = ${WG_MTU}\n` : ''}\
[Peer] [Peer]
@ -247,12 +257,29 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`;
throw new Error('Maximum number of clients reached.'); throw new Error('Maximum number of clients reached.');
} }
let address6;
for (let i = 2; i < 255; i++) {
const client = Object.values(config.clients).find((client) => {
return client.address6 === WG_DEFAULT_ADDRESS6.replace('x', i.toString(16));
});
if (!client) {
address6 = WG_DEFAULT_ADDRESS6.replace('x', i.toString(16));
break;
}
}
if (!address6) {
throw new Error('Maximum number of clients reached.');
}
// Create Client // Create Client
const id = crypto.randomUUID(); const id = crypto.randomUUID();
const client = { const client = {
id, id,
name, name,
address, address,
address6,
privateKey, privateKey,
publicKey, publicKey,
preSharedKey, preSharedKey,
@ -319,6 +346,19 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`;
await this.saveConfig(); await this.saveConfig();
} }
async updateClientAddress6({ clientId, address6 }) {
const client = await this.getClient({ clientId });
if (!Util.isValidIPv6(address6)) {
throw new ServerError(`Invalid Address6: ${address6}`, 400);
}
client.address6 = address6;
client.updatedAt = new Date();
await this.saveConfig();
}
// Shutdown wireguard // Shutdown wireguard
async Shutdown() { async Shutdown() {
await Util.exec('wg-quick down wg0').catch(() => { }); await Util.exec('wg-quick down wg0').catch(() => { });

Loading…
Cancel
Save