diff --git a/src/app/pages/admin/config.vue b/src/app/pages/admin/config.vue
index e408d030..892fde05 100644
--- a/src/app/pages/admin/config.vue
+++ b/src/app/pages/admin/config.vue
@@ -48,14 +48,59 @@
/>
- Amnezia
-
-
-
-
-
-
-
+ AmneziaWG Obfuscation Parameters
+
+
+
+
+
+ * {{ $t('awg.*') }}
+
+
+
+
+
+
{{ $t('form.actions') }}
diff --git a/src/app/pages/admin/interface.vue b/src/app/pages/admin/interface.vue
index fa3b14ce..9a5c896f 100644
--- a/src/app/pages/admin/interface.vue
+++ b/src/app/pages/admin/interface.vue
@@ -22,22 +22,107 @@
/>
- Amnezia
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ AmneziaWG Obfuscation Parameters
+
+
+
+
+
+
+
+ * {{ $t('awg.*') }}
+
+
+
+
+
+
+
+
+
+
+
+
{{ $t('form.actions') }}
diff --git a/src/app/pages/clients/[id].vue b/src/app/pages/clients/[id].vue
index 80957198..0e15de2d 100644
--- a/src/app/pages/clients/[id].vue
+++ b/src/app/pages/clients/[id].vue
@@ -83,14 +83,59 @@
/>
- Amnezia
-
-
-
-
-
-
-
+ AmneziaWG Obfuscation Parameters
+
+
+
+
+
+ * {{ $t('awg.*') }}
+
+
+
+
+
+
diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json
index f76022cc..508621bb 100644
--- a/src/i18n/locales/en.json
+++ b/src/i18n/locales/en.json
@@ -237,5 +237,40 @@
"postUp": "PostUp",
"preDown": "PreDown",
"postDown": "PostDown"
+ },
+ "awg": {
+ "jCLabel": "Junk packet count (Jc)",
+ "jCDescription": "Number of junk packets to send (1-128, recommended: 4-12)",
+ "jMinLabel": "Junk packet min size (Jmin)",
+ "jMinDescription": "Minimum size of junk packets (0-1279*, recommended: 8, must be < Jmax)",
+ "jMaxLabel": "Junk packet max size (Jmax)",
+ "jMaxDescription": "Maximum size of junk packets (1-1280*, recommended: 80, must be > Jmin)",
+ "s1Label": "Init packet junk size (S1)",
+ "s1Description": "Init packet junk size (0-1132[1280* - 148 = 1132], recommended: 15-150, S1+56 ≠ S2)",
+ "s2Label": "Response packet junk size (S2)",
+ "s2Description": "Response packet junk size (0-1188[1280* - 92 = 1188], recommended: 15-150)",
+ "s3Label": "Cookie reply packet junk size (S3)",
+ "s3Description": "Cookie reply packet junk size",
+ "s4Label": "Transport packet junk size (S4)",
+ "s4Description": "Transport packet junk size",
+ "i1Label": "Special junk packet 1 (I1)",
+ "i1Description": "Protocol mimic packet in hex format: ",
+ "i2Label": "Special junk packet 2 (I2)",
+ "i2Description": "Protocol mimic packet in hex format: ",
+ "i3Label": "Special junk packet 3 (I3)",
+ "i3Description": "Protocol mimic packet in hex format: ",
+ "i4Label": "Special junk packet 4 (I4)",
+ "i4Description": "Protocol mimic packet in hex format: ",
+ "i5Label": "Special junk packet 5 (I5)",
+ "i5Description": "Protocol mimic packet in hex format: ",
+ "h1Label": "Init magic header (H1)",
+ "h1Description": "Init packet header value (5-2147483647, must be unique from H2-H4)",
+ "h2Label": "Response magic header (H2)",
+ "h2Description": "Response packet header value (5-2147483647, must be unique from H1, H3, H4)",
+ "h3Label": "Cookie reply magic header (H3)",
+ "h3Description": "Cookie reply packet header value (5-2147483647, must be unique from H1, H2, H4)",
+ "h4Label": "Transport magic header (H4)",
+ "h4Description": "Transport packet header value (5-2147483647, must be unique from H1-H3)",
+ "*": "Values depend on the MTU"
}
}
diff --git a/src/server/database/migrations/0002_optimal_pixie.sql b/src/server/database/migrations/0002_keen_sleepwalker.sql
similarity index 75%
rename from src/server/database/migrations/0002_optimal_pixie.sql
rename to src/server/database/migrations/0002_keen_sleepwalker.sql
index 9344b7b2..d19c0d29 100644
--- a/src/server/database/migrations/0002_optimal_pixie.sql
+++ b/src/server/database/migrations/0002_keen_sleepwalker.sql
@@ -5,6 +5,7 @@ ALTER TABLE `clients_table` ADD `i1` text;--> statement-breakpoint
ALTER TABLE `clients_table` ADD `i2` text;--> statement-breakpoint
ALTER TABLE `clients_table` ADD `i3` text;--> statement-breakpoint
ALTER TABLE `clients_table` ADD `i4` text;--> statement-breakpoint
+ALTER TABLE `clients_table` ADD `i5` text;--> statement-breakpoint
ALTER TABLE `interfaces_table` ADD `j_c` integer DEFAULT 7;--> statement-breakpoint
ALTER TABLE `interfaces_table` ADD `j_min` integer DEFAULT 10;--> statement-breakpoint
ALTER TABLE `interfaces_table` ADD `j_max` integer DEFAULT 1000;--> statement-breakpoint
@@ -16,14 +17,16 @@ ALTER TABLE `interfaces_table` ADD `i1` text;--> statement-breakpoint
ALTER TABLE `interfaces_table` ADD `i2` text;--> statement-breakpoint
ALTER TABLE `interfaces_table` ADD `i3` text;--> statement-breakpoint
ALTER TABLE `interfaces_table` ADD `i4` text;--> statement-breakpoint
-ALTER TABLE `interfaces_table` ADD `h1` integer;--> statement-breakpoint
-ALTER TABLE `interfaces_table` ADD `h2` integer;--> statement-breakpoint
-ALTER TABLE `interfaces_table` ADD `h3` integer;--> statement-breakpoint
-ALTER TABLE `interfaces_table` ADD `h4` integer;--> statement-breakpoint
+ALTER TABLE `interfaces_table` ADD `i5` text;--> statement-breakpoint
+ALTER TABLE `interfaces_table` ADD `h1` integer DEFAULT 0;--> statement-breakpoint
+ALTER TABLE `interfaces_table` ADD `h2` integer DEFAULT 0;--> statement-breakpoint
+ALTER TABLE `interfaces_table` ADD `h3` integer DEFAULT 0;--> statement-breakpoint
+ALTER TABLE `interfaces_table` ADD `h4` integer DEFAULT 0;--> statement-breakpoint
ALTER TABLE `user_configs_table` ADD `default_j_c` integer DEFAULT 7;--> statement-breakpoint
ALTER TABLE `user_configs_table` ADD `default_j_min` integer DEFAULT 10;--> statement-breakpoint
ALTER TABLE `user_configs_table` ADD `default_j_max` integer DEFAULT 1000;--> statement-breakpoint
ALTER TABLE `user_configs_table` ADD `default_i1` text;--> statement-breakpoint
ALTER TABLE `user_configs_table` ADD `default_i2` text;--> statement-breakpoint
ALTER TABLE `user_configs_table` ADD `default_i3` text;--> statement-breakpoint
-ALTER TABLE `user_configs_table` ADD `default_i4` text;
\ No newline at end of file
+ALTER TABLE `user_configs_table` ADD `default_i4` text;--> statement-breakpoint
+ALTER TABLE `user_configs_table` ADD `default_i5` text;
\ No newline at end of file
diff --git a/src/server/database/migrations/meta/0002_snapshot.json b/src/server/database/migrations/meta/0002_snapshot.json
index 1acd28d3..43488542 100644
--- a/src/server/database/migrations/meta/0002_snapshot.json
+++ b/src/server/database/migrations/meta/0002_snapshot.json
@@ -1,7 +1,7 @@
{
"version": "6",
"dialect": "sqlite",
- "id": "56cf26d3-6178-4089-9d94-533d3ea09a26",
+ "id": "e09bc17a-dab6-45a3-a09c-57af222b08fb",
"prevId": "78de2e52-c4a8-4900-86c5-92f34739623a",
"tables": {
"clients_table": {
@@ -186,6 +186,13 @@
"notNull": false,
"autoincrement": false
},
+ "i5": {
+ "name": "i5",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
"dns": {
"name": "dns",
"type": "text",
@@ -564,33 +571,44 @@
"notNull": false,
"autoincrement": false
},
+ "i5": {
+ "name": "i5",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
"h1": {
"name": "h1",
"type": "integer",
"primaryKey": false,
"notNull": false,
- "autoincrement": false
+ "autoincrement": false,
+ "default": 0
},
"h2": {
"name": "h2",
"type": "integer",
"primaryKey": false,
"notNull": false,
- "autoincrement": false
+ "autoincrement": false,
+ "default": 0
},
"h3": {
"name": "h3",
"type": "integer",
"primaryKey": false,
"notNull": false,
- "autoincrement": false
+ "autoincrement": false,
+ "default": 0
},
"h4": {
"name": "h4",
"type": "integer",
"primaryKey": false,
"notNull": false,
- "autoincrement": false
+ "autoincrement": false,
+ "default": 0
},
"enabled": {
"name": "enabled",
@@ -886,6 +904,13 @@
"notNull": false,
"autoincrement": false
},
+ "default_i5": {
+ "name": "default_i5",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
"host": {
"name": "host",
"type": "text",
diff --git a/src/server/database/migrations/meta/_journal.json b/src/server/database/migrations/meta/_journal.json
index a58478f9..9e4a5f4c 100644
--- a/src/server/database/migrations/meta/_journal.json
+++ b/src/server/database/migrations/meta/_journal.json
@@ -19,8 +19,8 @@
{
"idx": 2,
"version": "6",
- "when": 1760948971158,
- "tag": "0002_optimal_pixie",
+ "when": 1761298328460,
+ "tag": "0002_keen_sleepwalker",
"breakpoints": true
}
]
diff --git a/src/server/database/repositories/client/schema.ts b/src/server/database/repositories/client/schema.ts
index 048b0763..64368ef6 100644
--- a/src/server/database/repositories/client/schema.ts
+++ b/src/server/database/repositories/client/schema.ts
@@ -43,6 +43,7 @@ export const client = sqliteTable('clients_table', {
i2: text(),
i3: text(),
i4: text(),
+ i5: text(),
dns: text({ mode: 'json' }).$type(),
serverEndpoint: text('server_endpoint'),
enabled: int({ mode: 'boolean' }).notNull(),
diff --git a/src/server/database/repositories/client/service.ts b/src/server/database/repositories/client/service.ts
index 9218603e..97953cda 100644
--- a/src/server/database/repositories/client/service.ts
+++ b/src/server/database/repositories/client/service.ts
@@ -221,6 +221,7 @@ export class ClientService {
i2: clientConfig.defaultI2,
i3: clientConfig.defaultI3,
i4: clientConfig.defaultI4,
+ i5: clientConfig.defaultI5,
persistentKeepalive: clientConfig.defaultPersistentKeepalive,
serverAllowedIps: [],
enabled: true,
diff --git a/src/server/database/repositories/client/types.ts b/src/server/database/repositories/client/types.ts
index 304c083e..ae2ba852 100644
--- a/src/server/database/repositories/client/types.ts
+++ b/src/server/database/repositories/client/types.ts
@@ -79,6 +79,7 @@ export const ClientUpdateSchema = schemaForType()(
i2: ISchema,
i3: ISchema,
i4: ISchema,
+ i5: ISchema,
persistentKeepalive: PersistentKeepaliveSchema,
serverEndpoint: AddressSchema.nullable(),
dns: DnsSchema.nullable(),
diff --git a/src/server/database/repositories/interface/schema.ts b/src/server/database/repositories/interface/schema.ts
index 0c2992a4..c0ee71c0 100644
--- a/src/server/database/repositories/interface/schema.ts
+++ b/src/server/database/repositories/interface/schema.ts
@@ -3,10 +3,6 @@ import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { userConfig, hooks } from '../../schema';
-// H1/H2/H3/H4 — must be unique among each other; recommended range is from 5 to 2147483647 inclusive
-const generateRandomHeaderValue = () =>
- Math.floor(Math.random() * 2147483642) + 5;
-
// maybe support multiple interfaces in the future
export const wgInterface = sqliteTable('interfaces_table', {
name: text().primaryKey(),
@@ -28,10 +24,11 @@ export const wgInterface = sqliteTable('interfaces_table', {
i2: text(),
i3: text(),
i4: text(),
- h1: int().$defaultFn(generateRandomHeaderValue),
- h2: int().$defaultFn(generateRandomHeaderValue),
- h3: int().$defaultFn(generateRandomHeaderValue),
- h4: int().$defaultFn(generateRandomHeaderValue),
+ i5: text(),
+ h1: int().default(0),
+ h2: int().default(0),
+ h3: int().default(0),
+ h4: int().default(0),
// does nothing yet
enabled: int({ mode: 'boolean' }).notNull(),
createdAt: text('created_at')
diff --git a/src/server/database/repositories/interface/types.ts b/src/server/database/repositories/interface/types.ts
index 02793bf1..3051d3b3 100644
--- a/src/server/database/repositories/interface/types.ts
+++ b/src/server/database/repositories/interface/types.ts
@@ -42,6 +42,7 @@ export const InterfaceUpdateSchema = schemaForType()(
i2: ISchema,
i3: ISchema,
i4: ISchema,
+ i5: ISchema,
h1: HSchema,
h2: HSchema,
h3: HSchema,
diff --git a/src/server/database/repositories/userConfig/schema.ts b/src/server/database/repositories/userConfig/schema.ts
index ba26c822..3e8497a1 100644
--- a/src/server/database/repositories/userConfig/schema.ts
+++ b/src/server/database/repositories/userConfig/schema.ts
@@ -25,6 +25,7 @@ export const userConfig = sqliteTable('user_configs_table', {
defaultI2: text('default_i2'),
defaultI3: text('default_i3'),
defaultI4: text('default_i4'),
+ defaultI5: text('default_i5'),
host: text().notNull(),
port: int().notNull(),
createdAt: text('created_at')
diff --git a/src/server/database/repositories/userConfig/types.ts b/src/server/database/repositories/userConfig/types.ts
index a99af7f1..3043ea14 100644
--- a/src/server/database/repositories/userConfig/types.ts
+++ b/src/server/database/repositories/userConfig/types.ts
@@ -33,6 +33,7 @@ export const UserConfigUpdateSchema = schemaForType()(
defaultI2: ISchema,
defaultI3: ISchema,
defaultI4: ISchema,
+ defaultI5: ISchema,
host: host,
})
);
diff --git a/src/server/utils/WireGuard.ts b/src/server/utils/WireGuard.ts
index b024ebff..0a4a57d8 100644
--- a/src/server/utils/WireGuard.ts
+++ b/src/server/utils/WireGuard.ts
@@ -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();
+
+ 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(() => {});
diff --git a/src/server/utils/wgHelper.ts b/src/server/utils/wgHelper.ts
index 4376e47b..d97baf3d 100644
--- a/src/server/utils/wgHelper.ts
+++ b/src/server/utils/wgHelper.ts
@@ -67,6 +67,7 @@ AllowedIPs = ${allowedIps.join(', ')}${extraLines.length ? `\n${extraLines.join(
i2: wgInterface.i2,
i3: wgInterface.i3,
i4: wgInterface.i4,
+ i5: wgInterface.i5,
H1: wgInterface.h1,
H2: wgInterface.h2,
H3: wgInterface.h3,
@@ -134,6 +135,7 @@ PostDown = ${iptablesTemplate(hooks.postDown, wgInterface)}`;
i2: client.i2,
i3: client.i3,
i4: client.i4,
+ i5: client.i5,
H1: wgInterface.h1,
H2: wgInterface.h2,
H3: wgInterface.h3,