This commit is contained in:
Shahrad Elahi 2023-09-26 07:28:15 +03:30
parent 440a6189bd
commit c521faf7df
10 changed files with 57 additions and 36 deletions

View File

@ -4,9 +4,6 @@ services:
image: wireadmin
volumes:
- ./src/:/app/
ports:
- "4040:4040/udp" # Direct
- "4050:4050/udp" # Tor
environment:
- UI_PASSWORD=password
- WG_HOST=127.0.0.1
- WG_HOST=192.168.1.102

View File

@ -19,12 +19,10 @@ fi
screen -dmS redis bash -c "redis-server --port 6479 --daemonize no --dir /data --appendonly yes"
# Start Tor in the background
screen -dmS tor bash -c "tor -f /etc/tor/torrc"
screen -dmS tor bash -c "sleep 1; tor -f /etc/tor/torrc"
# If WG_HOST exists, again export it as NEXT_PUBLIC_WG_HOST
if [ ! -z "$WG_HOST" ]; then
export NEXT_PUBLIC_WG_HOST=$WG_HOST
fi
export NEXT_PUBLIC_WG_HOST="$WG_HOST"
# 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"

View File

@ -29,7 +29,7 @@ export const PortSchema = z
message: 'Port must be a valid port number'
})
export const TypeSchema = z.enum([ 'default', 'tor' ])
export const TypeSchema = z.enum([ 'direct', 'tor' ])
export const DnsSchema = z
.string()

View File

@ -30,8 +30,9 @@ export function getServerConf(server: WgServer): string {
type Peer = WgServer['peers'][0]
interface GenPeerConParams extends Peer {
interface GenPeerConParams extends Peer, Pick<WgServer, 'dns'> {
serverAddress?: string
serverPublicKey: string
port: number
}
@ -40,12 +41,13 @@ export function getPeerConf(params: GenPeerConParams): string {
'# Autogenerated by WireGuard UI (WireAdmin)',
'[Interface]',
`PrivateKey = ${params.privateKey}`,
`Address = ${params.allowedIps}/32`,
`Address = ${params.allowedIps}/24`,
`${params.dns ? `DNS = ${params.dns}` : 'OMIT'}`,
'',
'[Peer]',
`PublicKey = ${params.publicKey}`,
`PublicKey = ${params.serverPublicKey}`,
`${params.preSharedKey ? `PresharedKey = ${params.preSharedKey}` : 'OMIT'}`,
`AllowedIPs = ${params.allowedIps}/32`,
`AllowedIPs = 0.0.0.0/0, ::/0`,
`PersistentKeepalive = ${params.persistentKeepalive}`,
`Endpoint = ${params.serverAddress || process.env.NEXT_PUBLIC_WG_HOST}:${params.port}`,
]

View File

@ -16,7 +16,10 @@ export class WGServer {
console.error('server could not be updated (reason: not exists)')
return false
}
await Shell.exec(`ip link set down dev wg${server.confId}`, true)
await Shell.exec(`wg-quick down wg${server.confId}`, true)
await dropInterface(server.confId)
await this.update(id, { status: 'down' })
return true
}
@ -27,8 +30,10 @@ export class WGServer {
console.error('server could not be updated (reason: not exists)')
return false
}
await createInterface(server.confId, server.address)
await Shell.exec(`ip link set up dev wg${server.confId}`)
await Shell.exec(`wg-quick down wg${server.confId}`, true)
await Shell.exec(`wg-quick up wg${server.confId}`)
await this.update(id, { status: 'up' })
return true
}
@ -189,7 +194,12 @@ export class WGServer {
console.error('generatePeerConfig: peer not found')
return undefined
}
return getPeerConf({ ...peer, port: server.listen })
return getPeerConf({
...peer,
serverPublicKey: server.publicKey,
port: server.listen,
dns: server.dns
})
}
}
@ -402,16 +412,14 @@ export async function generateWgServer(config: {
})
// to ensure interface does not exists
await Shell.exec(`wg-quick down wg${confId}`, true)
await dropInterface(confId)
await Shell.exec(`ip link set down dev wg${confId}`, true)
// create a interface
await createInterface(confId, config.address)
// await createInterface(confId, config.address)
// restart WireGuard
await Shell.exec(`wg setconf wg${confId} ${CONFIG_PATH}`)
await Shell.exec(`ip link set up dev wg${confId}`)
await Shell.exec(`wg-quick up wg${confId}`)
// return server id
return uuid
@ -502,7 +510,7 @@ async function makeWgIptables(s: WgServer): Promise<{
up: string
down: string
}> {
const inet = Shell.exec('ip route | grep default | grep -oP "(?<=dev )[^ ]+"')
const inet = await Shell.exec('ip route list default | awk \'{print $5}\'')
const wgAddress = `${s.address}/24`
const wgInet = `wg${s.confId}`

View File

@ -9,7 +9,9 @@ function publicENV(ex = {}) {
const nextConfig = {
reactStrictMode: true,
transpilePackages: [],
env: publicENV()
env: publicENV({
NEXT_PUBLIC_WG_HOST: process.env.WG_HOST
})
}
module.exports = nextConfig;

View File

@ -190,6 +190,8 @@ export default function ServerPage(props: PageProps) {
key={s.id}
{...s}
serverId={props.serverId}
serverPublicKey={data?.publicKey}
dns={data?.dns}
listenPort={data?.listen}
refreshTrigger={() => refresh()}
/>
@ -214,8 +216,9 @@ export default function ServerPage(props: PageProps) {
type Peer = WgServer['peers'][0]
interface ClientProps extends Peer {
interface ClientProps extends Peer, Pick<WgServer, 'dns'> {
serverId: string
serverPublicKey: string
listenPort: number
refreshTrigger: () => void
}
@ -229,7 +232,9 @@ function Client(props: ClientProps) {
React.useEffect(() => {
setConf(getPeerConf({
...props,
port: props.listenPort
serverPublicKey: props.serverPublicKey,
port: props.listenPort,
dns: props.dns,
}))
console.log('conf', conf)
}, [ props ])
@ -254,12 +259,18 @@ function Client(props: ClientProps) {
return (
<List.Item key={props.id} className={'flex items-center justify-between p-4'}>
<QRCodeModal ref={qrcodeRef} content={conf?.trim() || 'null'} />
<div className={'w-full grid grid-cols-12 items-center gap-x-2'}>
<div className={'col-span-12 md:col-span-4'}>
<span className={'inline-block font-medium'}> {props.name} </span>
<div className={'w-full flex flex-row items-center gap-x-2'}>
<div className={'w-12 aspect-square flex items-center justify-center mr-4 rounded-full bg-gray-200'}>
{/* User Icon */}
<i className={'fas fa-user text-gray-400 text-lg'} />
</div>
<div className={'col-span-12 md:col-span-4'}>
<span className={'font-mono text-gray-400 text-sm'}> {props.allowedIps} </span>
<div className={'col-span-12 md:col-span-4'}>
<span className={'inline-block font-medium'}> {props.name} </span>
</div>
<div className={'col-span-12 md:col-span-4'}>
<span className={'font-mono text-gray-400 text-xs'}> {props.allowedIps} </span>
</div>
</div>
</div>
<div className={'flex items-center justify-center gap-x-3'}>
@ -310,7 +321,7 @@ function ClientBaseButton(props: {
<div
className={twMerge(
'group flex items-center justify-center w-10 aspect-square rounded-md',
'bg-gray-200/80 hover:bg-gray-100',
'bg-gray-200/80 hover:bg-gray-100/50',
'border border-transparent hover:border-primary',
'transition-colors duration-200 ease-in-out',
'cursor-pointer',

View File

@ -50,7 +50,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
publicKey: peerKeys.publicKey,
privateKey: peerKeys.privateKey,
preSharedKey: peerKeys.preSharedKey,
persistentKeepalive: 25,
persistentKeepalive: 0,
})
if (!addedPeer) {
return res

View File

@ -1,6 +1,6 @@
import type { NextApiRequest, NextApiResponse } from 'next'
import safeServe from "@lib/safe-serve";
import { getServers } from "@lib/wireguard";
import { getServers, WGServer } from "@lib/wireguard";
import { getServerConf } from "@lib/wireguard-utils";
import fs from "fs";
import path from "path";
@ -17,10 +17,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const servers = await getServers()
servers.forEach((s) => {
for (const s of servers) {
const CONFIG_PATH = path.join(WG_PATH, `wg${s.confId}.conf`)
fs.writeFileSync(CONFIG_PATH, getServerConf(s), { mode: 0o600 })
})
await WGServer.start(s.id)
}
return res
.status(200)

View File

@ -24,7 +24,7 @@ const CreateServerModal = React.forwardRef<
const innerRef = React.useRef<SmartModalRef | null>(null)
const [ form ] = Form.useForm()
const [ type, setType ] = React.useState<'default' | 'tor'>('default')
const [ type, setType ] = React.useState<ServerType>('direct')
React.useImperativeHandle(ref, () => innerRef.current as SmartModalRef)
@ -206,4 +206,6 @@ const FormSchema = z.object({
mtu: MtuSchema
})
type ServerType = z.infer<typeof TypeSchema>
type FormValues = z.infer<typeof FormSchema>