mirror of
https://github.com/wg-easy/wg-easy.git
synced 2025-09-26 19:51:15 +08:00
Add option to disable ipv6 (#1951)
* add option to disable ipv6 * don't add ipv6 address * update docs
This commit is contained in:
@@ -54,6 +54,7 @@ ENV PORT=51821
|
|||||||
ENV HOST=0.0.0.0
|
ENV HOST=0.0.0.0
|
||||||
ENV INSECURE=false
|
ENV INSECURE=false
|
||||||
ENV INIT_ENABLED=false
|
ENV INIT_ENABLED=false
|
||||||
|
ENV DISABLE_IPV6=false
|
||||||
|
|
||||||
LABEL org.opencontainers.image.source=https://github.com/wg-easy/wg-easy
|
LABEL org.opencontainers.image.source=https://github.com/wg-easy/wg-easy
|
||||||
|
|
||||||
|
@@ -28,6 +28,7 @@ ENV PORT=51821
|
|||||||
ENV HOST=0.0.0.0
|
ENV HOST=0.0.0.0
|
||||||
ENV INSECURE=true
|
ENV INSECURE=true
|
||||||
ENV INIT_ENABLED=false
|
ENV INIT_ENABLED=false
|
||||||
|
ENV DISABLE_IPV6=false
|
||||||
|
|
||||||
# Install Dependencies
|
# Install Dependencies
|
||||||
COPY src/package.json src/pnpm-lock.yaml ./
|
COPY src/package.json src/pnpm-lock.yaml ./
|
||||||
|
@@ -4,8 +4,19 @@ title: Optional Configuration
|
|||||||
|
|
||||||
You can set these environment variables to configure the container. They are not required, but can be useful in some cases.
|
You can set these environment variables to configure the container. They are not required, but can be useful in some cases.
|
||||||
|
|
||||||
| Env | Default | Example | Description |
|
| Env | Default | Example | Description |
|
||||||
| ---------- | --------- | ----------- | ------------------------------ |
|
| -------------- | --------- | ----------- | ---------------------------------- |
|
||||||
| `PORT` | `51821` | `6789` | TCP port for Web UI. |
|
| `PORT` | `51821` | `6789` | TCP port for Web UI. |
|
||||||
| `HOST` | `0.0.0.0` | `localhost` | IP address web UI binds to. |
|
| `HOST` | `0.0.0.0` | `localhost` | IP address web UI binds to. |
|
||||||
| `INSECURE` | `false` | `true` | If access over http is allowed |
|
| `INSECURE` | `false` | `true` | If access over http is allowed |
|
||||||
|
| `DISABLE_IPV6` | `false` | `true` | If IPv6 support should be disabled |
|
||||||
|
|
||||||
|
/// note | IPv6 Caveats
|
||||||
|
|
||||||
|
Disabling IPv6 will disable the creation of the default IPv6 firewall rules and won't add a IPv6 address to the interface and clients.
|
||||||
|
|
||||||
|
You will however still see a IPv6 address in the Web UI, but it won't be used.
|
||||||
|
|
||||||
|
This option can be removed in the future, as more devices support IPv6.
|
||||||
|
|
||||||
|
///
|
||||||
|
@@ -2,6 +2,7 @@ import { drizzle } from 'drizzle-orm/libsql';
|
|||||||
import { migrate as drizzleMigrate } from 'drizzle-orm/libsql/migrator';
|
import { migrate as drizzleMigrate } from 'drizzle-orm/libsql/migrator';
|
||||||
import { createClient } from '@libsql/client';
|
import { createClient } from '@libsql/client';
|
||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
|
import { eq } from 'drizzle-orm';
|
||||||
|
|
||||||
import * as schema from './schema';
|
import * as schema from './schema';
|
||||||
import { ClientService } from './repositories/client/service';
|
import { ClientService } from './repositories/client/service';
|
||||||
@@ -25,6 +26,11 @@ export async function connect() {
|
|||||||
await initialSetup(dbService);
|
await initialSetup(dbService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (WG_ENV.DISABLE_IPV6) {
|
||||||
|
DB_DEBUG('Warning: Disabling IPv6...');
|
||||||
|
await disableIpv6(db);
|
||||||
|
}
|
||||||
|
|
||||||
return dbService;
|
return dbService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,3 +114,48 @@ async function initialSetup(db: DBServiceType) {
|
|||||||
await db.general.setSetupStep(0);
|
await db.general.setSetupStep(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function disableIpv6(db: DBType) {
|
||||||
|
// This should match the initial value migration
|
||||||
|
const postUpMatch =
|
||||||
|
' ip6tables -t nat -A POSTROUTING -s {{ipv6Cidr}} -o {{device}} -j MASQUERADE; ip6tables -A INPUT -p udp -m udp --dport {{port}} -j ACCEPT; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -A FORWARD -o wg0 -j ACCEPT;';
|
||||||
|
const postDownMatch =
|
||||||
|
' ip6tables -t nat -D POSTROUTING -s {{ipv6Cidr}} -o {{device}} -j MASQUERADE; ip6tables -D INPUT -p udp -m udp --dport {{port}} -j ACCEPT; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -D FORWARD -o wg0 -j ACCEPT;';
|
||||||
|
|
||||||
|
await db.transaction(async (tx) => {
|
||||||
|
const hooks = await tx.query.hooks.findFirst({
|
||||||
|
where: eq(schema.hooks.id, 'wg0'),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!hooks) {
|
||||||
|
throw new Error('Hooks not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hooks.postUp.includes(postUpMatch)) {
|
||||||
|
DB_DEBUG('Disabling IPv6 in Post Up hooks...');
|
||||||
|
await tx
|
||||||
|
.update(schema.hooks)
|
||||||
|
.set({
|
||||||
|
postUp: hooks.postUp.replace(postUpMatch, ''),
|
||||||
|
postDown: hooks.postDown.replace(postDownMatch, ''),
|
||||||
|
})
|
||||||
|
.where(eq(schema.hooks.id, 'wg0'))
|
||||||
|
.execute();
|
||||||
|
} else {
|
||||||
|
DB_DEBUG('IPv6 Post Up hooks already disabled, skipping...');
|
||||||
|
}
|
||||||
|
if (hooks.postDown.includes(postDownMatch)) {
|
||||||
|
DB_DEBUG('Disabling IPv6 in Post Down hooks...');
|
||||||
|
await tx
|
||||||
|
.update(schema.hooks)
|
||||||
|
.set({
|
||||||
|
postUp: hooks.postUp.replace(postUpMatch, ''),
|
||||||
|
postDown: hooks.postDown.replace(postDownMatch, ''),
|
||||||
|
})
|
||||||
|
.where(eq(schema.hooks.id, 'wg0'))
|
||||||
|
.execute();
|
||||||
|
} else {
|
||||||
|
DB_DEBUG('IPv6 Post Down hooks already disabled, skipping...');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@@ -25,13 +25,21 @@ class WireGuard {
|
|||||||
const hooks = await Database.hooks.get();
|
const hooks = await Database.hooks.get();
|
||||||
|
|
||||||
const result = [];
|
const result = [];
|
||||||
result.push(wg.generateServerInterface(wgInterface, hooks));
|
result.push(
|
||||||
|
wg.generateServerInterface(wgInterface, hooks, {
|
||||||
|
enableIpv6: !WG_ENV.DISABLE_IPV6,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
for (const client of clients) {
|
for (const client of clients) {
|
||||||
if (!client.enabled) {
|
if (!client.enabled) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
result.push(wg.generateServerPeer(client));
|
result.push(
|
||||||
|
wg.generateServerPeer(client, {
|
||||||
|
enableIpv6: !WG_ENV.DISABLE_IPV6,
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
result.push('');
|
result.push('');
|
||||||
@@ -125,7 +133,9 @@ class WireGuard {
|
|||||||
throw new Error('Client not found');
|
throw new Error('Client not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
return wg.generateClientConfig(wgInterface, userConfig, client);
|
return wg.generateClientConfig(wgInterface, userConfig, client, {
|
||||||
|
enableIpv6: !WG_ENV.DISABLE_IPV6,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getClientQRCodeSVG({ clientId }: { clientId: ID }) {
|
async getClientQRCodeSVG({ clientId }: { clientId: ID }) {
|
||||||
|
@@ -17,6 +17,8 @@ export const WG_ENV = {
|
|||||||
INSECURE: process.env.INSECURE === 'true',
|
INSECURE: process.env.INSECURE === 'true',
|
||||||
/** Port the UI is listening on */
|
/** Port the UI is listening on */
|
||||||
PORT: assertEnv('PORT'),
|
PORT: assertEnv('PORT'),
|
||||||
|
/** If IPv6 should be disabled */
|
||||||
|
DISABLE_IPV6: process.env.DISABLE_IPV6 === 'true',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WG_INITIAL_ENV = {
|
export const WG_INITIAL_ENV = {
|
||||||
|
@@ -5,11 +5,20 @@ import type { InterfaceType } from '#db/repositories/interface/types';
|
|||||||
import type { UserConfigType } from '#db/repositories/userConfig/types';
|
import type { UserConfigType } from '#db/repositories/userConfig/types';
|
||||||
import type { HooksType } from '#db/repositories/hooks/types';
|
import type { HooksType } from '#db/repositories/hooks/types';
|
||||||
|
|
||||||
|
type Options = {
|
||||||
|
enableIpv6?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export const wg = {
|
export const wg = {
|
||||||
generateServerPeer: (client: Omit<ClientType, 'createdAt' | 'updatedAt'>) => {
|
generateServerPeer: (
|
||||||
|
client: Omit<ClientType, 'createdAt' | 'updatedAt'>,
|
||||||
|
options: Options = {}
|
||||||
|
) => {
|
||||||
|
const { enableIpv6 = true } = options;
|
||||||
|
|
||||||
const allowedIps = [
|
const allowedIps = [
|
||||||
`${client.ipv4Address}/32`,
|
`${client.ipv4Address}/32`,
|
||||||
`${client.ipv6Address}/128`,
|
...(enableIpv6 ? [`${client.ipv6Address}/128`] : []),
|
||||||
...(client.serverAllowedIps ?? []),
|
...(client.serverAllowedIps ?? []),
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -25,19 +34,29 @@ PresharedKey = ${client.preSharedKey}
|
|||||||
AllowedIPs = ${allowedIps.join(', ')}${extraLines.length ? `\n${extraLines.join('\n')}` : ''}`;
|
AllowedIPs = ${allowedIps.join(', ')}${extraLines.length ? `\n${extraLines.join('\n')}` : ''}`;
|
||||||
},
|
},
|
||||||
|
|
||||||
generateServerInterface: (wgInterface: InterfaceType, hooks: HooksType) => {
|
generateServerInterface: (
|
||||||
|
wgInterface: InterfaceType,
|
||||||
|
hooks: HooksType,
|
||||||
|
options: Options = {}
|
||||||
|
) => {
|
||||||
|
const { enableIpv6 = true } = options;
|
||||||
|
|
||||||
const cidr4 = parseCidr(wgInterface.ipv4Cidr);
|
const cidr4 = parseCidr(wgInterface.ipv4Cidr);
|
||||||
const cidr6 = parseCidr(wgInterface.ipv6Cidr);
|
const cidr6 = parseCidr(wgInterface.ipv6Cidr);
|
||||||
const ipv4Addr = stringifyIp({ number: cidr4.start + 1n, version: 4 });
|
const ipv4Addr = stringifyIp({ number: cidr4.start + 1n, version: 4 });
|
||||||
const ipv6Addr = stringifyIp({ number: cidr6.start + 1n, version: 6 });
|
const ipv6Addr = stringifyIp({ number: cidr6.start + 1n, version: 6 });
|
||||||
|
|
||||||
|
const address =
|
||||||
|
`${ipv4Addr}/${cidr4.prefix}` +
|
||||||
|
(enableIpv6 ? `, ${ipv6Addr}/${cidr6.prefix}` : '');
|
||||||
|
|
||||||
return `# Note: Do not edit this file directly.
|
return `# Note: Do not edit this file directly.
|
||||||
# Your changes will be overwritten!
|
# Your changes will be overwritten!
|
||||||
|
|
||||||
# Server
|
# Server
|
||||||
[Interface]
|
[Interface]
|
||||||
PrivateKey = ${wgInterface.privateKey}
|
PrivateKey = ${wgInterface.privateKey}
|
||||||
Address = ${ipv4Addr}/${cidr4.prefix}, ${ipv6Addr}/${cidr6.prefix}
|
Address = ${address}
|
||||||
ListenPort = ${wgInterface.port}
|
ListenPort = ${wgInterface.port}
|
||||||
MTU = ${wgInterface.mtu}
|
MTU = ${wgInterface.mtu}
|
||||||
PreUp = ${iptablesTemplate(hooks.preUp, wgInterface)}
|
PreUp = ${iptablesTemplate(hooks.preUp, wgInterface)}
|
||||||
@@ -49,11 +68,18 @@ PostDown = ${iptablesTemplate(hooks.postDown, wgInterface)}`;
|
|||||||
generateClientConfig: (
|
generateClientConfig: (
|
||||||
wgInterface: InterfaceType,
|
wgInterface: InterfaceType,
|
||||||
userConfig: UserConfigType,
|
userConfig: UserConfigType,
|
||||||
client: ClientType
|
client: ClientType,
|
||||||
|
options: Options = {}
|
||||||
) => {
|
) => {
|
||||||
|
const { enableIpv6 = true } = options;
|
||||||
|
|
||||||
const cidr4Block = parseCidr(wgInterface.ipv4Cidr).prefix;
|
const cidr4Block = parseCidr(wgInterface.ipv4Cidr).prefix;
|
||||||
const cidr6Block = parseCidr(wgInterface.ipv6Cidr).prefix;
|
const cidr6Block = parseCidr(wgInterface.ipv6Cidr).prefix;
|
||||||
|
|
||||||
|
const address =
|
||||||
|
`${client.ipv4Address}/${cidr4Block}` +
|
||||||
|
(enableIpv6 ? `, ${client.ipv6Address}/${cidr6Block}` : '');
|
||||||
|
|
||||||
const hookLines = [
|
const hookLines = [
|
||||||
client.preUp ? `PreUp = ${client.preUp}` : null,
|
client.preUp ? `PreUp = ${client.preUp}` : null,
|
||||||
client.postUp ? `PostUp = ${client.postUp}` : null,
|
client.postUp ? `PostUp = ${client.postUp}` : null,
|
||||||
@@ -63,7 +89,7 @@ PostDown = ${iptablesTemplate(hooks.postDown, wgInterface)}`;
|
|||||||
|
|
||||||
return `[Interface]
|
return `[Interface]
|
||||||
PrivateKey = ${client.privateKey}
|
PrivateKey = ${client.privateKey}
|
||||||
Address = ${client.ipv4Address}/${cidr4Block}, ${client.ipv6Address}/${cidr6Block}
|
Address = ${address}
|
||||||
DNS = ${(client.dns ?? userConfig.defaultDns).join(', ')}
|
DNS = ${(client.dns ?? userConfig.defaultDns).join(', ')}
|
||||||
MTU = ${client.mtu}
|
MTU = ${client.mtu}
|
||||||
${hookLines.length ? `${hookLines.join('\n')}\n` : ''}
|
${hookLines.length ? `${hookLines.join('\n')}\n` : ''}
|
||||||
|
Reference in New Issue
Block a user