AmneziaWG 2.0 (#2226)
* feat!: awg * feat: add description to fields, add I5 * fix: awg i18n * fix: types * minor fixes * Remove TODO comment from types.ts Removed TODO comment for more validation. --------- Co-authored-by: Bernd Storath <999999bst@gmail.com>
This commit is contained in:
committed by
GitHub
parent
a8ba7f7247
commit
6a282e6ab9
@@ -5,6 +5,9 @@ import type { InterfaceType } from '#db/repositories/interface/types';
|
||||
|
||||
const WG_DEBUG = debug('WireGuard');
|
||||
|
||||
const generateRandomHeaderValue = () =>
|
||||
Math.floor(Math.random() * 2147483642) + 5;
|
||||
|
||||
class WireGuard {
|
||||
/**
|
||||
* Save and sync config
|
||||
@@ -196,6 +199,24 @@ class WireGuard {
|
||||
wgInterface = await Database.interfaces.get();
|
||||
WG_DEBUG('New Wireguard Keys generated successfully.');
|
||||
}
|
||||
|
||||
if (WG_ENV.WG_EXECUTABLE === 'awg' && wgInterface.h1 === 0) {
|
||||
WG_DEBUG('Generating random AmneziaWG obfuscation parameters...');
|
||||
const headers = new Set<number>();
|
||||
|
||||
while (headers.size < 4) {
|
||||
headers.add(generateRandomHeaderValue());
|
||||
}
|
||||
const [h1, h2, h3, h4] = Array.from(headers);
|
||||
|
||||
wgInterface.h1 = h1!;
|
||||
wgInterface.h2 = h2!;
|
||||
wgInterface.h3 = h3!;
|
||||
wgInterface.h4 = h4!;
|
||||
|
||||
Database.interfaces.update(wgInterface);
|
||||
}
|
||||
|
||||
WG_DEBUG(`Starting Wireguard Interface ${wgInterface.name}...`);
|
||||
await this.#saveWireguardConfig(wgInterface);
|
||||
await wg.down(wgInterface.name).catch(() => {});
|
||||
|
||||
@@ -12,7 +12,23 @@ export const OLD_ENV = {
|
||||
PASSWORD_HASH: process.env.PASSWORD_HASH,
|
||||
};
|
||||
|
||||
const OVERRIDE_AUTO_AWG = process.env.OVERRIDE_AUTO_AWG?.toLowerCase();
|
||||
const detectAwg = async (): Promise<'awg' | 'wg'> => {
|
||||
/** TODO: delete on next major version */
|
||||
if (process.env.EXPERIMENTAL_AWG === 'true') {
|
||||
const OVERRIDE_AUTO_AWG = process.env.OVERRIDE_AUTO_AWG?.toLowerCase();
|
||||
|
||||
if (
|
||||
OVERRIDE_AUTO_AWG === ('wg' as const) ||
|
||||
OVERRIDE_AUTO_AWG === ('awg' as const)
|
||||
) {
|
||||
return OVERRIDE_AUTO_AWG;
|
||||
} else {
|
||||
return await exec('modinfo amneziawg')
|
||||
.then(() => 'awg' as const)
|
||||
.catch(() => 'wg' as const);
|
||||
}
|
||||
} else return 'wg';
|
||||
};
|
||||
|
||||
export const WG_ENV = {
|
||||
/** UI is hosted on HTTP instead of HTTPS */
|
||||
@@ -21,14 +37,7 @@ export const WG_ENV = {
|
||||
PORT: assertEnv('PORT'),
|
||||
/** If IPv6 should be disabled */
|
||||
DISABLE_IPV6: process.env.DISABLE_IPV6 === 'true',
|
||||
/** Override automatic detection */
|
||||
OVERRIDE_AUTO_AWG:
|
||||
OVERRIDE_AUTO_AWG === ('wg' as const) ||
|
||||
OVERRIDE_AUTO_AWG === ('awg' as const)
|
||||
? OVERRIDE_AUTO_AWG
|
||||
: undefined,
|
||||
/** TODO: delete on next major version */
|
||||
EXPERIMENTAL_AWG: process.env.EXPERIMENTAL_AWG === 'true',
|
||||
WG_EXECUTABLE: await detectAwg(),
|
||||
};
|
||||
|
||||
export const WG_INITIAL_ENV = {
|
||||
|
||||
@@ -26,6 +26,18 @@ export const MtuSchema = z
|
||||
.min(1024, { message: t('zod.mtu') })
|
||||
.max(9000, { message: t('zod.mtu') });
|
||||
|
||||
export const JcSchema = z.number().min(1).max(128).nullable();
|
||||
|
||||
export const JminSchema = z.number().max(1279).nullable();
|
||||
|
||||
export const JmaxSchema = z.number().max(1280).nullable();
|
||||
|
||||
export const SSchema = z.number().max(1132).nullable();
|
||||
|
||||
export const HSchema = z.number().min(5).max(2147483647).nullable();
|
||||
|
||||
export const ISchema = z.string().nullable();
|
||||
|
||||
export const PortSchema = z
|
||||
.number({ message: t('zod.port') })
|
||||
.min(1, { message: t('zod.port') })
|
||||
|
||||
@@ -9,17 +9,7 @@ type Options = {
|
||||
enableIpv6?: boolean;
|
||||
};
|
||||
|
||||
let wgExecutable: 'awg' | 'wg' = 'wg';
|
||||
|
||||
if (WG_ENV.EXPERIMENTAL_AWG) {
|
||||
if (WG_ENV.OVERRIDE_AUTO_AWG !== undefined) {
|
||||
wgExecutable = WG_ENV.OVERRIDE_AUTO_AWG;
|
||||
} else {
|
||||
wgExecutable = await exec('modinfo amneziawg')
|
||||
.then(() => 'awg' as const)
|
||||
.catch(() => 'wg' as const);
|
||||
}
|
||||
}
|
||||
const wgExecutable = WG_ENV.WG_EXECUTABLE;
|
||||
|
||||
export const wg = {
|
||||
generateServerPeer: (
|
||||
@@ -62,6 +52,35 @@ AllowedIPs = ${allowedIps.join(', ')}${extraLines.length ? `\n${extraLines.join(
|
||||
`${ipv4Addr}/${cidr4.prefix}` +
|
||||
(enableIpv6 ? `, ${ipv6Addr}/${cidr6.prefix}` : '');
|
||||
|
||||
let awgLines: string[] = [];
|
||||
|
||||
if (wgExecutable === 'awg') {
|
||||
const parameters = {
|
||||
Jc: wgInterface.jC,
|
||||
Jmin: wgInterface.jMin,
|
||||
Jmax: wgInterface.jMax,
|
||||
S1: wgInterface.s1,
|
||||
S2: wgInterface.s2,
|
||||
S3: wgInterface.s3,
|
||||
S4: wgInterface.s4,
|
||||
i1: wgInterface.i1,
|
||||
i2: wgInterface.i2,
|
||||
i3: wgInterface.i3,
|
||||
i4: wgInterface.i4,
|
||||
i5: wgInterface.i5,
|
||||
H1: wgInterface.h1,
|
||||
H2: wgInterface.h2,
|
||||
H3: wgInterface.h3,
|
||||
H4: wgInterface.h4,
|
||||
} as const;
|
||||
|
||||
awgLines = Object.entries(parameters)
|
||||
.filter(([_, value]) => !!value)
|
||||
.map(([key, value]) => `${key} = ${value}`);
|
||||
}
|
||||
|
||||
const extraLines = [...awgLines].filter((v) => v !== null);
|
||||
|
||||
return `# Note: Do not edit this file directly.
|
||||
# Your changes will be overwritten!
|
||||
|
||||
@@ -71,6 +90,7 @@ PrivateKey = ${wgInterface.privateKey}
|
||||
Address = ${address}
|
||||
ListenPort = ${wgInterface.port}
|
||||
MTU = ${wgInterface.mtu}
|
||||
${extraLines.length ? `${extraLines.join('\n')}\n` : ''}
|
||||
PreUp = ${iptablesTemplate(hooks.preUp, wgInterface)}
|
||||
PostUp = ${iptablesTemplate(hooks.postUp, wgInterface)}
|
||||
PreDown = ${iptablesTemplate(hooks.preDown, wgInterface)}
|
||||
@@ -100,7 +120,36 @@ PostDown = ${iptablesTemplate(hooks.postDown, wgInterface)}`;
|
||||
const dnsLine =
|
||||
dnsServers.length > 0 ? `DNS = ${dnsServers.join(', ')}` : null;
|
||||
|
||||
const extraLines = [dnsLine, ...hookLines].filter((v) => v !== null);
|
||||
let awgLines: string[] = [];
|
||||
|
||||
if (wgExecutable === 'awg') {
|
||||
const parameters = {
|
||||
Jc: client.jC,
|
||||
Jmin: client.jMin,
|
||||
Jmax: client.jMax,
|
||||
S1: wgInterface.s1,
|
||||
S2: wgInterface.s2,
|
||||
S3: wgInterface.s3,
|
||||
S4: wgInterface.s4,
|
||||
i1: client.i1,
|
||||
i2: client.i2,
|
||||
i3: client.i3,
|
||||
i4: client.i4,
|
||||
i5: client.i5,
|
||||
H1: wgInterface.h1,
|
||||
H2: wgInterface.h2,
|
||||
H3: wgInterface.h3,
|
||||
H4: wgInterface.h4,
|
||||
} as const;
|
||||
|
||||
awgLines = Object.entries(parameters)
|
||||
.filter(([_, value]) => !!value)
|
||||
.map(([key, value]) => `${key} = ${value}`);
|
||||
}
|
||||
|
||||
const extraLines = [dnsLine, ...hookLines, ...awgLines].filter(
|
||||
(v) => v !== null
|
||||
);
|
||||
|
||||
return `[Interface]
|
||||
PrivateKey = ${client.privateKey}
|
||||
|
||||
Reference in New Issue
Block a user