diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 4635bc7..4c3177c 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -15,14 +15,13 @@ if [ ! -d "/data" ]; then chmod 700 /data fi -# Starting Redis server in detached mode -screen -dmS redis bash -c "redis-server --port 6479 --daemonize no --dir /data --appendonly yes" +mkdir -p /var/vlogs # Start Tor in the background -screen -dmS tor bash -c "sleep 1; tor -f /etc/tor/torrc" +screen -L -Logfile /var/vlogs/tor -dmS tor bash -c "tor" -# If WG_HOST exists, again export it as NEXT_PUBLIC_WG_HOST -export NEXT_PUBLIC_WG_HOST="$WG_HOST" +# Starting Redis server in detached mode +screen -L -Logfile /var/vlogs/redis -dmS redis bash -c "redis-server --port 6479 --daemonize no --dir /data --appendonly yes" # After 5 seconds, export the database to the WireGuard config file screen -dm bash -c "sleep 5; curl -s -o /dev/null http://127.0.0.1:3000/api/wireguard/regen" diff --git a/src/lib/network.ts b/src/lib/network.ts new file mode 100644 index 0000000..c2fa105 --- /dev/null +++ b/src/lib/network.ts @@ -0,0 +1,33 @@ +import Shell from "@lib/shell"; + +export default class Network { + + public static async createInterface(inet: string, address: string): Promise { + // First, check if the interface already exists. + const interfaces = await Shell.exec(`ip link show | grep ${inet}`, true) + if (interfaces.includes(`${inet}`)) { + console.error(`failed to create interface, ${inet} already exists!`) + return false + } + + const o2 = await Shell.exec(`ip address add dev ${inet} ${address}`) + // check if it has any error + if (o2 !== '') { + console.error(`failed to assign ip to interface, ${o2}`) + console.log(`removing interface ${inet} due to errors`) + await Shell.exec(`ip link delete dev ${inet}`, true) + return false + } + + return true + } + + public static async dropInterface(inet: string) { + await Shell.exec(`ip link delete dev ${inet}`, true) + } + + public static async defaultInterface(): Promise { + return await Shell.exec(`ip route list default | awk '{print $5}'`) + } + +}; diff --git a/src/lib/wireguard-utils.ts b/src/lib/wireguard-utils.ts index ed9b3a3..ea54572 100644 --- a/src/lib/wireguard-utils.ts +++ b/src/lib/wireguard-utils.ts @@ -36,7 +36,13 @@ interface GenPeerConParams extends Peer, Pick { port: number } -export function getPeerConf(params: GenPeerConParams): string { + +export async function getServerIP(): Promise { + const resp = await fetch('/api/host') + return resp.text() +} + +export async function getPeerConf(params: GenPeerConParams): Promise { const lines = [ '# Autogenerated by WireGuard UI (WireAdmin)', '[Interface]', diff --git a/src/lib/wireguard.ts b/src/lib/wireguard.ts index 46bd984..0b03285 100644 --- a/src/lib/wireguard.ts +++ b/src/lib/wireguard.ts @@ -7,6 +7,7 @@ import { client, WG_SEVER_PATH } from "@lib/redis"; import { dynaJoin, isJson } from "@lib/utils"; import deepmerge from "deepmerge"; import { getPeerConf, getServerConf } from "@lib/wireguard-utils"; +import Network from "@lib/network"; export class WGServer { @@ -18,7 +19,6 @@ export class WGServer { } await Shell.exec(`wg-quick down wg${server.confId}`, true) - await dropInterface(server.confId) await this.update(id, { status: 'down' }) return true @@ -46,9 +46,7 @@ export class WGServer { } await this.stop(id) - await dropInterface(server.confId) - await fs.unlink(path.join(WG_PATH, `wg${server.confId}.conf`)) - .catch(() => null) + await fs.unlink(path.join(WG_PATH, `wg${server.confId}.conf`)).catch(() => null) const index = await findServerIndex(id) if (typeof index !== 'number') { @@ -194,7 +192,7 @@ export class WGServer { console.error('generatePeerConfig: peer not found') return undefined } - return getPeerConf({ + return await getPeerConf({ ...peer, serverPublicKey: server.publicKey, port: server.listen, @@ -413,10 +411,6 @@ export async function generateWgServer(config: { // to ensure interface does not exists await Shell.exec(`wg-quick down wg${confId}`, true) - await dropInterface(confId) - - // create a interface - // await createInterface(confId, config.address) // restart WireGuard await Shell.exec(`wg-quick up wg${confId}`) @@ -425,47 +419,6 @@ export async function generateWgServer(config: { return uuid } -/** - * # ip link add dev wg0 type wireguard - * # ip address add dev wg0 10.0.0.1/24 - * - * @param configId - * @param address - */ -export async function createInterface(configId: number, address: string): Promise { - - // first checking for the interface is already exists - const interfaces = await Shell.exec(`ip link show | grep wg${configId}`, true) - if (interfaces.includes(`wg${configId}`)) { - console.error(`failed to create interface, wg${configId} already exists!`) - return false - } - - // create interface - const o1 = await Shell.exec(`ip link add dev wg${configId} type wireguard`) - // check if it has error - if (o1 !== '') { - console.error(`failed to create interface, ${o1}`) - return false - } - - const o2 = await Shell.exec(`ip address add dev wg${configId} ${address}/24`) - // check if it has error - if (o2 !== '') { - console.error(`failed to assign ip to interface, ${o2}`) - console.log(`removing interface wg${configId} due to errors`) - await Shell.exec(`ip link delete dev wg${configId}`, true) - return false - } - - return true - -} - -export async function dropInterface(configId: number) { - await Shell.exec(`ip link delete dev wg${configId}`, true) -} - export async function maxConfId(): Promise { // get files in /etc/wireguard const files = await fs.readdir(WG_PATH) @@ -506,17 +459,14 @@ export async function findServer(id: string | undefined, hash?: string): Promise undefined } -async function makeWgIptables(s: WgServer): Promise<{ - up: string - down: string -}> { - const inet = await Shell.exec('ip route list default | awk \'{print $5}\'') - const wgAddress = `${s.address}/24` +async function makeWgIptables(s: WgServer): Promise<{ up: string, down: string }> { + const inet = await Network.defaultInterface() + const source = `${s.address}/24` const wgInet = `wg${s.confId}` if (s.type === 'direct') { const up = dynaJoin([ - `iptables -t nat -A POSTROUTING -s ${wgAddress} -o ${inet} -j MASQUERADE`, + `iptables -t nat -A POSTROUTING -s ${source} -o ${inet} -j MASQUERADE`, `iptables -A INPUT -p udp -m udp --dport ${s.listen} -j ACCEPT`, `iptables -A INPUT -p tcp -m tcp --dport ${s.listen} -j ACCEPT`, `iptables -A FORWARD -i ${wgInet} -j ACCEPT`, @@ -528,10 +478,10 @@ async function makeWgIptables(s: WgServer): Promise<{ if (s.type === 'tor') { const up = dynaJoin([ `iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT`, - `iptables -A INPUT -i ${wgInet} -m state --state NEW -j ACCEPT`, - `iptables -t nat -A PREROUTING -i ${wgInet} -p udp --dport 53 -j DNAT --to-destination 127.0.0.1:53530`, - `iptables -t nat -A PREROUTING -i ${wgInet} -p tcp -j DNAT --to-destination 127.0.0.1:9040`, - `iptables -t nat -A PREROUTING -i ${wgInet} -p udp -j DNAT --to-destination 127.0.0.1:9040`, + `iptables -A INPUT -i ${wgInet} -s ${source} -m state --state NEW -j ACCEPT`, + `iptables -t nat -A PREROUTING -i ${wgInet} -p udp -s ${source} --dport 53 -j DNAT --to-destination 10.8.0.1:53530`, + `iptables -t nat -A PREROUTING -i ${wgInet} -p tcp -s ${source} -j DNAT --to-destination 10.8.0.1:9040`, + `iptables -t nat -A PREROUTING -i ${wgInet} -p udp -s ${source} -j DNAT --to-destination 10.8.0.1:9040`, `iptables -t nat -A OUTPUT -o lo -j RETURN`, `iptables -A OUTPUT -m conntrack --ctstate INVALID -j DROP`, `iptables -A OUTPUT -m state --state INVALID -j DROP`, diff --git a/src/pages/[serverId]/index.tsx b/src/pages/[serverId]/index.tsx index e5dde60..a804da6 100644 --- a/src/pages/[serverId]/index.tsx +++ b/src/pages/[serverId]/index.tsx @@ -230,12 +230,14 @@ function Client(props: ClientProps) { const [ conf, setConf ] = React.useState(null) React.useEffect(() => { - setConf(getPeerConf({ + getPeerConf({ ...props, serverPublicKey: props.serverPublicKey, port: props.listenPort, dns: props.dns, - })) + }) + .then((s) => setConf(s)) + console.log('conf', conf) }, [ props ]) diff --git a/src/pages/api/host.ts b/src/pages/api/host.ts new file mode 100644 index 0000000..20c21f5 --- /dev/null +++ b/src/pages/api/host.ts @@ -0,0 +1,31 @@ +import type { NextApiRequest, NextApiResponse } from 'next' +import safeServe from "@lib/safe-serve"; +import Shell from "@lib/shell"; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + return safeServe(res, async () => { + + let { WG_HOST } = process.env + + // if the host is not set, then we are using the server's public IP + if (!WG_HOST) { + const resp = await Shell.exec('curl -s ifconfig.me', true) + WG_HOST = resp.trim() + } + + // check if WG_HOST is still not set + if (!WG_HOST) { + console.error('WG_HOST is not set') + return res + .status(500) + .setHeader('Content-Type', 'text/plain') + .end('NOT_SET') + } + + return res + .status(200) + .setHeader('Content-Type', 'text/plain') + .end(WG_HOST) + + }) +}