From ea490f9882f5dc9ea659d82a83c247c7f4d8cf34 Mon Sep 17 00:00:00 2001 From: Bernd Storath <999999bst@gmail.com> Date: Thu, 5 Sep 2024 10:23:38 +0200 Subject: [PATCH] start supporting ipv6 --- Dockerfile | 2 + Dockerfile.dev | 2 + docker-compose.yml | 3 + src/package.json | 3 + src/pnpm-lock.yaml | 82 ++++++++++++++++++++ src/server/api/release.get.ts | 3 +- src/server/api/session.post.ts | 2 +- src/server/utils/WireGuard.ts | 20 ++--- src/server/utils/config.ts | 3 + src/services/database/migrations/1.ts | 17 ++-- src/services/database/repositories/system.ts | 4 +- 11 files changed, 116 insertions(+), 25 deletions(-) diff --git a/Dockerfile b/Dockerfile index 966632b0..8b09d381 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,11 +27,13 @@ RUN apk add --no-cache \ dpkg \ dumb-init \ iptables \ + ip6tables \ iptables-legacy \ wireguard-tools # Use iptables-legacy RUN update-alternatives --install /sbin/iptables iptables /sbin/iptables-legacy 10 --slave /sbin/iptables-restore iptables-restore /sbin/iptables-legacy-restore --slave /sbin/iptables-save iptables-save /sbin/iptables-legacy-save +RUN update-alternatives --install /sbin/ip6tables ip6tables /sbin/ip6tables-legacy 10 --slave /sbin/ip6tables-restore ip6tables-restore /sbin/ip6tables-legacy-restore --slave /sbin/ip6tables-save ip6tables-save /sbin/ip6tables-legacy-save # Set Environment ENV DEBUG=Server,WireGuard,LowDB diff --git a/Dockerfile.dev b/Dockerfile.dev index fed4ec47..9be2832b 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -17,11 +17,13 @@ RUN apk add --no-cache \ dpkg \ dumb-init \ iptables \ + ip6tables \ iptables-legacy \ wireguard-tools # Use iptables-legacy RUN update-alternatives --install /sbin/iptables iptables /sbin/iptables-legacy 10 --slave /sbin/iptables-restore iptables-restore /sbin/iptables-legacy-restore --slave /sbin/iptables-save iptables-save /sbin/iptables-legacy-save +RUN update-alternatives --install /sbin/ip6tables ip6tables /sbin/ip6tables-legacy 10 --slave /sbin/ip6tables-restore ip6tables-restore /sbin/ip6tables-legacy-restore --slave /sbin/ip6tables-save ip6tables-save /sbin/ip6tables-legacy-save # Set Environment ENV DEBUG=Server,WireGuard,LowDB diff --git a/docker-compose.yml b/docker-compose.yml index f607837b..c5a6b346 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,3 +24,6 @@ services: sysctls: - net.ipv4.ip_forward=1 - net.ipv4.conf.all.src_valid_mark=1 + - net.ipv6.conf.all.disable_ipv6=0 + - net.ipv6.conf.all.forwarding=1 + - net.ipv6.conf.default.forwarding=1 diff --git a/src/package.json b/src/package.json index 4d8ba686..bf4c80bd 100644 --- a/src/package.json +++ b/src/package.json @@ -27,9 +27,12 @@ "apexcharts": "^3.53.0", "basic-auth": "^2.0.1", "bcryptjs": "^2.4.3", + "cidr-tools": "^11.0.2", "crc-32": "^1.2.2", "debug": "^4.3.6", "ip": "^2.0.1", + "ip-bigint": "^8.2.0", + "is-ip": "^5.0.1", "js-sha256": "^0.11.0", "lowdb": "^7.0.1", "nuxt": "^3.13.0", diff --git a/src/pnpm-lock.yaml b/src/pnpm-lock.yaml index 095ecea0..c9f052f1 100644 --- a/src/pnpm-lock.yaml +++ b/src/pnpm-lock.yaml @@ -32,6 +32,9 @@ importers: bcryptjs: specifier: ^2.4.3 version: 2.4.3 + cidr-tools: + specifier: ^11.0.2 + version: 11.0.2 crc-32: specifier: ^1.2.2 version: 1.2.2 @@ -41,6 +44,12 @@ importers: ip: specifier: ^2.0.1 version: 2.0.1 + ip-bigint: + specifier: ^8.2.0 + version: 8.2.0 + is-ip: + specifier: ^5.0.1 + version: 5.0.1 js-sha256: specifier: ^0.11.0 version: 0.11.0 @@ -1678,6 +1687,10 @@ packages: resolution: {integrity: sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==} engines: {node: '>=8'} + cidr-tools@11.0.2: + resolution: {integrity: sha512-OLeM9EOXybbhMsGGBNRLCMjn8e+wFOXARIShF/sZwmJLsxWywqfE0By4BMftT6BFWpbcETWpW7TfM2KGCtrZDg==} + engines: {node: '>=18'} + citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} @@ -1699,6 +1712,10 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + clone-regexp@3.0.0: + resolution: {integrity: sha512-ujdnoq2Kxb8s3ItNBtnYeXdm07FcU0u8ARAT1lQ2YdMwQC+cdiXX8KoqMVuglztILivceTtp4ivqGSmEmhBUJw==} + engines: {node: '>=12'} + cluster-key-slot@1.1.2: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} @@ -1784,6 +1801,10 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} + convert-hrtime@5.0.0: + resolution: {integrity: sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==} + engines: {node: '>=12'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -2338,6 +2359,10 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + function-timeout@0.1.1: + resolution: {integrity: sha512-0NVVC0TaP7dSTvn1yMiy6d6Q8gifzbvQafO46RtLG/kHJUBNd+pVRGOBoK44wNBvtSPUJRfdVvkFdD3p0xvyZg==} + engines: {node: '>=14.16'} + gauge@3.0.2: resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} engines: {node: '>=10'} @@ -2555,6 +2580,14 @@ packages: resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==} engines: {node: '>=12.22.0'} + ip-bigint@8.2.0: + resolution: {integrity: sha512-46EAEKzGNxojH5JaGEeCix49tL4h1W8ia5mhogZ68HroVAfyLj1E+SFFid4GuyK0mdIKjwcAITLqwg1wlkx2iQ==} + engines: {node: '>=18'} + + ip-regex@5.0.0: + resolution: {integrity: sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + ip@2.0.1: resolution: {integrity: sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==} @@ -2614,6 +2647,10 @@ packages: resolution: {integrity: sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==} engines: {node: '>=18'} + is-ip@5.0.1: + resolution: {integrity: sha512-FCsGHdlrOnZQcp0+XT5a+pYowf33itBalCl+7ovNXC/7o5BhIpG14M3OrpPPdBSIQJCm+0M5+9mO7S9VVTTCFw==} + engines: {node: '>=14.16'} + is-module@1.0.0: resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} @@ -2632,6 +2669,10 @@ packages: is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} + is-regexp@3.1.0: + resolution: {integrity: sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==} + engines: {node: '>=12'} + is-ssh@1.4.0: resolution: {integrity: sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==} @@ -3843,6 +3884,10 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + super-regex@0.2.0: + resolution: {integrity: sha512-WZzIx3rC1CvbMDloLsVw0lkZVKJWbrkJ0k1ghKFmcnPrW1+jWbgTkTEWVtD9lMdmI4jZEz40+naBxl1dCUhXXw==} + engines: {node: '>=14.16'} + superjson@2.2.1: resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==} engines: {node: '>=16'} @@ -3951,6 +3996,10 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + time-span@5.1.0: + resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==} + engines: {node: '>=12'} + timeago.js@4.0.2: resolution: {integrity: sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w==} @@ -6214,6 +6263,10 @@ snapshots: ci-info@4.0.0: {} + cidr-tools@11.0.2: + dependencies: + ip-bigint: 8.2.0 + citty@0.1.6: dependencies: consola: 3.2.3 @@ -6242,6 +6295,10 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + clone-regexp@3.0.0: + dependencies: + is-regexp: 3.1.0 + cluster-key-slot@1.1.2: {} co@4.6.0: {} @@ -6302,6 +6359,8 @@ snapshots: content-type@1.0.5: {} + convert-hrtime@5.0.0: {} + convert-source-map@2.0.0: {} cookie-es@1.2.2: {} @@ -6951,6 +7010,8 @@ snapshots: function-bind@1.1.2: {} + function-timeout@0.1.1: {} + gauge@3.0.2: dependencies: aproba: 2.0.0 @@ -7190,6 +7251,10 @@ snapshots: transitivePeerDependencies: - supports-color + ip-bigint@8.2.0: {} + + ip-regex@5.0.0: {} + ip@2.0.1: {} iron-webcrypto@1.2.1: {} @@ -7235,6 +7300,11 @@ snapshots: global-directory: 4.0.1 is-path-inside: 4.0.0 + is-ip@5.0.1: + dependencies: + ip-regex: 5.0.0 + super-regex: 0.2.0 + is-module@1.0.0: {} is-number@7.0.0: {} @@ -7247,6 +7317,8 @@ snapshots: dependencies: '@types/estree': 1.0.5 + is-regexp@3.1.0: {} + is-ssh@1.4.0: dependencies: protocols: 2.0.1 @@ -8598,6 +8670,12 @@ snapshots: pirates: 4.0.6 ts-interface-checker: 0.1.13 + super-regex@0.2.0: + dependencies: + clone-regexp: 3.0.0 + function-timeout: 0.1.1 + time-span: 5.1.0 + superjson@2.2.1: dependencies: copy-anything: 3.0.5 @@ -8743,6 +8821,10 @@ snapshots: dependencies: any-promise: 1.3.0 + time-span@5.1.0: + dependencies: + convert-hrtime: 5.0.0 + timeago.js@4.0.2: {} tiny-invariant@1.3.3: {} diff --git a/src/server/api/release.get.ts b/src/server/api/release.get.ts index ebca8838..a7c3f02f 100644 --- a/src/server/api/release.get.ts +++ b/src/server/api/release.get.ts @@ -1,8 +1,7 @@ export default defineEventHandler(async () => { - const system = await Database.getSystem(); const latestRelease = await fetchLatestRelease(); return { - currentRelease: system.release, + currentRelease: RELEASE, latestRelease: latestRelease, }; }); diff --git a/src/server/api/session.post.ts b/src/server/api/session.post.ts index c4a9b7e3..0eb77690 100644 --- a/src/server/api/session.post.ts +++ b/src/server/api/session.post.ts @@ -29,7 +29,7 @@ export default defineEventHandler(async (event) => { if (remember) { conf.cookie = { ...(system.sessionConfig.cookie ?? {}), - maxAge: system.cookieMaxAge * 60, + maxAge: system.sessionTimeout, }; } diff --git a/src/server/utils/WireGuard.ts b/src/server/utils/WireGuard.ts index 85f6462f..e2636bd8 100644 --- a/src/server/utils/WireGuard.ts +++ b/src/server/utils/WireGuard.ts @@ -6,7 +6,9 @@ import QRCode from 'qrcode'; import CRC32 from 'crc-32'; import type { NewClient } from '~~/services/database/repositories/client'; -import ip from 'ip'; +import { parseCidr } from 'cidr-tools'; +import { stringifyIp } from 'ip-bigint'; +import { isIPv4 } from 'is-ip'; const DEBUG = debug('WireGuard'); @@ -19,9 +21,7 @@ class WireGuard { async #saveWireguardConfig() { const system = await Database.getSystem(); const clients = await Database.getClients(); - const cidrBlock = ip.cidrSubnet( - system.userConfig.addressRange - ).subnetMaskLength; + const cidrBlock = parseCidr(system.userConfig.addressRange).prefix; let result = ` # Note: Do not edit this file directly. # Your changes will be overwritten! @@ -179,14 +179,10 @@ Endpoint = ${system.wgHost}:${system.wgConfigPort}`; const preSharedKey = await exec('wg genpsk'); // Calculate next IP - const cidr = ip.cidrSubnet(system.userConfig.addressRange); + const cidr = parseCidr(system.userConfig.addressRange); let address; - for ( - let i = ip.toLong(cidr.firstAddress) + 1; - i <= ip.toLong(cidr.lastAddress) - 1; - i++ - ) { - const currentIp = ip.fromLong(i); + for (let i = cidr.start + 2n; i <= cidr.end - 2n; i++) { + const currentIp = stringifyIp({ number: i, version: 4 }); const client = Object.values(clients).find((client) => { return client.address === currentIp; }); @@ -286,7 +282,7 @@ Endpoint = ${system.wgHost}:${system.wgConfigPort}`; clientId: string; address: string; }) { - if (!ip.isV4Format(address)) { + if (!isIPv4(address)) { throw createError({ statusCode: 400, statusMessage: `Invalid Address: ${address}`, diff --git a/src/server/utils/config.ts b/src/server/utils/config.ts index f9fba02f..31498076 100644 --- a/src/server/utils/config.ts +++ b/src/server/utils/config.ts @@ -1,5 +1,8 @@ import debug from 'debug'; +import packageJson from '@@/package.json'; export const WG_PATH = process.env.WG_PATH || '/etc/wireguard/'; +export const RELEASE = packageJson.release.version; + export const SERVER_DEBUG = debug('Server'); diff --git a/src/services/database/migrations/1.ts b/src/services/database/migrations/1.ts index 7f4f5aef..281d9b09 100644 --- a/src/services/database/migrations/1.ts +++ b/src/services/database/migrations/1.ts @@ -1,8 +1,8 @@ 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'; +import { parseCidr } from 'cidr-tools'; +import { stringifyIp } from 'ip-bigint'; export async function run1(db: Low) { const privateKey = await exec('wg genkey'); @@ -10,16 +10,17 @@ export async function run1(db: Low) { log: 'echo ***hidden*** | wg pubkey', }); const addressRange = '10.8.0.0/24'; - const cidr = ip.cidrSubnet(addressRange); + const addressRange6 = 'fdcc:ad94:bacf:61a4::cafe:0/112'; + const cidr = parseCidr(addressRange); + const cidr6 = parseCidr(addressRange6); const database: Database = { migrations: [], system: { - // TODO: move to var, no need for database - release: packageJson.release.version, interface: { privateKey: privateKey, publicKey: publicKey, - address: cidr.firstAddress, + address: stringifyIp({ number: cidr.start, version: 4 }), + address6: stringifyIp({ number: cidr6.start, version: 6 }), }, sessionTimeout: 3600, // 1 hour lang: 'en', @@ -27,7 +28,8 @@ export async function run1(db: Low) { mtu: 1420, persistentKeepalive: 0, addressRange: addressRange, - defaultDns: ['1.1.1.1'], + addressRange6: addressRange6, + defaultDns: ['1.1.1.1', '2606:4700:4700::1111'], allowedIps: ['0.0.0.0/0', '::/0'], }, wgDevice: 'eth0', @@ -63,7 +65,6 @@ export async function run1(db: Low) { name: 'wg-easy', cookie: {}, }, - cookieMaxAge: 24 * 60, }, users: [], clients: {}, diff --git a/src/services/database/repositories/system.ts b/src/services/database/repositories/system.ts index 6ba9cfac..e1990a90 100644 --- a/src/services/database/repositories/system.ts +++ b/src/services/database/repositories/system.ts @@ -13,12 +13,14 @@ export type WGInterface = { privateKey: string; publicKey: string; address: string; + address6: string; }; export type WGConfig = { mtu: number; persistentKeepalive: number; addressRange: string; + addressRange6: string; defaultDns: string[]; allowedIps: string[]; }; @@ -50,7 +52,6 @@ export type Feature = { export type System = { interface: WGInterface; - release: string; // maxAge sessionTimeout: number; lang: Lang; @@ -71,7 +72,6 @@ export type System = { prometheus: Prometheus; sessionConfig: SessionConfig; - cookieMaxAge: number; }; /**