Browse Source

Feat: Cidr Support (#1347)

* cidr support

* add cidr

* fix some errors

fix server config

missing cidr block in server config
pull/1648/head
Bernd Storath 7 months ago
committed by Bernd Storath
parent
commit
a0e4fbcccc
  1. 2
      src/package.json
  2. 18
      src/pnpm-lock.yaml
  3. 33
      src/server/utils/WireGuard.ts
  4. 12
      src/server/utils/ip.ts
  5. 14
      src/services/database/migrations/1.ts

2
src/package.json

@ -29,6 +29,7 @@
"bcryptjs": "^2.4.3",
"crc-32": "^1.2.2",
"debug": "^4.3.7",
"ip": "^2.0.1",
"js-sha256": "^0.11.0",
"lowdb": "^7.0.1",
"nuxt": "^3.13.0",
@ -44,6 +45,7 @@
"@nuxt/eslint-config": "^0.5.5",
"@types/bcryptjs": "^2.4.6",
"@types/debug": "^4.1.12",
"@types/ip": "^1.1.3",
"@types/qrcode": "^1.5.5",
"eslint": "^9.9.1",
"eslint-config-prettier": "^9.1.0",

18
src/pnpm-lock.yaml

@ -38,6 +38,9 @@ importers:
debug:
specifier: ^4.3.7
version: 4.3.7
ip:
specifier: ^2.0.1
version: 2.0.1
js-sha256:
specifier: ^0.11.0
version: 0.11.0
@ -78,6 +81,9 @@ importers:
'@types/debug':
specifier: ^4.1.12
version: 4.1.12
'@types/ip':
specifier: ^1.1.3
version: 1.1.3
'@types/qrcode':
specifier: ^1.5.5
version: 1.5.5
@ -1217,6 +1223,9 @@ packages:
'@types/[email protected]':
resolution: {integrity: sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==}
'@types/[email protected]':
resolution: {integrity: sha512-64waoJgkXFTYnCYDUWgSATJ/dXEBanVkaP5d4Sbk7P6U7cTTMhxVyROTckc6JKdwCrgnAjZMn0k3177aQxtDEA==}
'@types/[email protected]':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
@ -2546,6 +2555,9 @@ packages:
resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==}
engines: {node: '>=12.22.0'}
[email protected]:
resolution: {integrity: sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==}
[email protected]:
resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==}
@ -5619,6 +5631,10 @@ snapshots:
dependencies:
'@types/node': 22.5.2
'@types/[email protected]':
dependencies:
'@types/node': 22.5.2
'@types/[email protected]': {}
'@types/[email protected]': {}
@ -7171,6 +7187,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
[email protected]: {}
[email protected]: {}
[email protected]: {}

33
src/server/utils/WireGuard.ts

@ -6,6 +6,7 @@ import QRCode from 'qrcode';
import CRC32 from 'crc-32';
import type { NewClient } from '~~/services/database/repositories/client';
import ip from 'ip';
const DEBUG = debug('WireGuard');
@ -18,6 +19,9 @@ class WireGuard {
async #saveWireguardConfig() {
const system = await Database.getSystem();
const clients = await Database.getClients();
const cidrBlock = ip.cidrSubnet(
system.userConfig.addressRange
).subnetMaskLength;
let result = `
# Note: Do not edit this file directly.
# Your changes will be overwritten!
@ -25,7 +29,7 @@ class WireGuard {
# Server
[Interface]
PrivateKey = ${system.interface.privateKey}
Address = ${system.interface.address}/24
Address = ${system.interface.address}/${cidrBlock}
ListenPort = ${system.wgPort}
PreUp = ${system.iptables.PreUp}
PostUp = ${system.iptables.PostUp}
@ -41,9 +45,8 @@ PostDown = ${system.iptables.PostDown}
# Client: ${client.name} (${clientId})
[Peer]
PublicKey = ${client.publicKey}
${
client.preSharedKey ? `PresharedKey = ${client.preSharedKey}\n` : ''
}AllowedIPs = ${client.address}/32`;
PresharedKey = ${client.preSharedKey}
AllowedIPs = ${client.address}/32`;
}
DEBUG('Config saving...');
@ -134,8 +137,8 @@ ${
return `
[Interface]
PrivateKey = ${client.privateKey ? `${client.privateKey}` : 'REPLACE_ME'}
Address = ${client.address}/24
PrivateKey = ${client.privateKey}
Address = ${client.address}
DNS = ${system.userConfig.defaultDns.join(',')}
MTU = ${system.userConfig.mtu}
@ -175,19 +178,21 @@ Endpoint = ${system.wgHost}:${system.wgConfigPort}`;
});
const preSharedKey = await exec('wg genpsk');
// TODO: cidr
// Calculate next IP
const cidr = ip.cidrSubnet(system.userConfig.addressRange);
let address;
for (let i = 2; i < 255; i++) {
for (
let i = ip.toLong(cidr.firstAddress) + 1;
i <= ip.toLong(cidr.lastAddress) - 1;
i++
) {
const currentIp = ip.fromLong(i);
const client = Object.values(clients).find((client) => {
return (
client.address ===
system.userConfig.addressRange.replace('x', i.toString())
);
return client.address === currentIp;
});
if (!client) {
address = system.userConfig.addressRange.replace('x', i.toString());
address = currentIp;
break;
}
}
@ -281,7 +286,7 @@ Endpoint = ${system.wgHost}:${system.wgConfigPort}`;
clientId: string;
address: string;
}) {
if (!isValidIPv4(address)) {
if (!ip.isV4Format(address)) {
throw createError({
statusCode: 400,
statusMessage: `Invalid Address: ${address}`,

12
src/server/utils/ip.ts

@ -1,12 +0,0 @@
export function isValidIPv4(str: string) {
const blocks = str.split('.');
if (blocks.length !== 4) return false;
for (const value of blocks) {
const num = parseInt(value, 10);
if (Number.isNaN(value)) return false;
if (num < 0 || num > 255) return false;
}
return true;
}

14
src/services/database/migrations/1.ts

@ -2,13 +2,15 @@ import type { Low } from 'lowdb';
import type { Database } from '../repositories/database';
import packageJson from '@@/package.json';
import { ChartType } from '../repositories/system';
import ip from 'ip';
export async function run1(db: Low<Database>) {
const privateKey = await exec('wg genkey');
const publicKey = await exec(`echo ${privateKey} | wg pubkey`, {
log: 'echo ***hidden*** | wg pubkey',
});
const addressRange = '10.8.0.x';
const addressRange = '10.8.0.0/24';
const cidr = ip.cidrSubnet(addressRange);
const database: Database = {
migrations: [],
system: {
@ -17,20 +19,18 @@ export async function run1(db: Low<Database>) {
interface: {
privateKey: privateKey,
publicKey: publicKey,
address: addressRange.replace('x', '1'),
address: cidr.firstAddress,
},
sessionTimeout: 3600, // 1 hour
lang: 'en',
userConfig: {
mtu: 1420,
persistentKeepalive: 0,
// TODO: handle CIDR to compute next ip in WireGuard
//addressRange: '10.8.0.0/24',
addressRange: addressRange,
defaultDns: ['1.1.1.1'],
allowedIps: ['0.0.0.0/0', '::/0'],
},
wgDevice: 'wg0',
wgDevice: 'eth0',
// TODO: wgHost has to be configured when onboarding
wgHost: '',
wgPort: 51820,
@ -71,7 +71,7 @@ export async function run1(db: Low<Database>) {
// TODO: use variables inside up/down script
database.system.iptables.PostUp = `
iptables -t nat -A POSTROUTING -s ${database.system.userConfig.addressRange.replace('x', '0')}/24 -o ${database.system.wgDevice} -j MASQUERADE;
iptables -t nat -A POSTROUTING -s ${database.system.userConfig.addressRange} -o ${database.system.wgDevice} -j MASQUERADE;
iptables -A INPUT -p udp -m udp --dport ${database.system.wgPort} -j ACCEPT;
iptables -A FORWARD -i wg0 -j ACCEPT;
iptables -A FORWARD -o wg0 -j ACCEPT;
@ -79,7 +79,7 @@ iptables -A FORWARD -o wg0 -j ACCEPT;
.split('\n')
.join(' ');
database.system.iptables.PostDown = `
iptables -t nat -D POSTROUTING -s ${database.system.userConfig.addressRange.replace('x', '0')}/24 -o ${database.system.wgDevice} -j MASQUERADE;
iptables -t nat -D POSTROUTING -s ${database.system.userConfig.addressRange} -o ${database.system.wgDevice} -j MASQUERADE;
iptables -D INPUT -p udp -m udp --dport ${database.system.wgPort} -j ACCEPT;
iptables -D FORWARD -i wg0 -j ACCEPT;
iptables -D FORWARD -o wg0 -j ACCEPT;

Loading…
Cancel
Save