Add public IP field and Network interface to host form
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import type { BUN_SQLITE_WGUI_HOSTS } from "@/db/types/db";
|
||||
import type { BUN_SQLITE_WGUI_HOSTS, BUN_SQLITE_WGUI_VARIABLES } from "@/db/types/db";
|
||||
import BunSQLite from "@moduletrace/bun-sqlite";
|
||||
import type { APIResponseObject } from "@moduletrace/bunext/types";
|
||||
import type { TableType, User } from "@/src/types";
|
||||
@@ -7,6 +7,8 @@ import grabHostPublicIPAddress from "./grab-host-public-ip-address";
|
||||
|
||||
type Params = {
|
||||
wg_ip_address?: string | null;
|
||||
public_ip_address?: string | null;
|
||||
interface?: string | null;
|
||||
user: User;
|
||||
};
|
||||
|
||||
@@ -20,6 +22,8 @@ type Params = {
|
||||
*/
|
||||
export default async function createWireguardHost({
|
||||
wg_ip_address,
|
||||
public_ip_address,
|
||||
interface: iface,
|
||||
user,
|
||||
}: Params): Promise<APIResponseObject> {
|
||||
const wg_ip = (wg_ip_address || "").trim();
|
||||
@@ -31,7 +35,9 @@ export default async function createWireguardHost({
|
||||
};
|
||||
}
|
||||
|
||||
const public_ip_address = await grabHostPublicIPAddress();
|
||||
const detected_public_ip = await grabHostPublicIPAddress();
|
||||
const final_public_ip = public_ip_address?.trim() || detected_public_ip;
|
||||
const final_interface = iface?.trim() || undefined;
|
||||
|
||||
try {
|
||||
const insert_host = await BunSQLite.insert<
|
||||
@@ -43,7 +49,8 @@ export default async function createWireguardHost({
|
||||
{
|
||||
user_id: user.id,
|
||||
wg_ip_address: wg_ip,
|
||||
public_ip_address: public_ip_address || undefined,
|
||||
public_ip_address: final_public_ip || undefined,
|
||||
interface: final_interface,
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -61,9 +68,26 @@ export default async function createWireguardHost({
|
||||
id: host_id,
|
||||
user_id: user.id,
|
||||
wg_ip_address: wg_ip,
|
||||
public_ip_address: public_ip_address || undefined,
|
||||
public_ip_address: final_public_ip || undefined,
|
||||
interface: final_interface,
|
||||
};
|
||||
|
||||
if (host_id === 0 && final_interface) {
|
||||
await BunSQLite.insert<
|
||||
BUN_SQLITE_WGUI_VARIABLES,
|
||||
TableType
|
||||
>({
|
||||
table: "variables",
|
||||
data: [
|
||||
{
|
||||
key: "main_host_public_interface",
|
||||
value: final_interface,
|
||||
},
|
||||
],
|
||||
update_on_duplicate: true,
|
||||
});
|
||||
}
|
||||
|
||||
const setup_res = await setupWireguardHost({
|
||||
host,
|
||||
wg_subnet_ip: wg_ip,
|
||||
@@ -93,4 +117,4 @@ export default async function createWireguardHost({
|
||||
msg: error.message,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import { execSync } from "node:child_process";
|
||||
import os from "node:os";
|
||||
|
||||
const VIRTUAL_INTERFACE_PATTERNS = [
|
||||
/^wg\d+$/,
|
||||
/^docker\d*$/,
|
||||
/^br\d*$/,
|
||||
/^veth.*/,
|
||||
/^tun.*/,
|
||||
/^tap.*/,
|
||||
/^vlan.*/,
|
||||
/^bond\d*$/,
|
||||
/^macvlan.*/,
|
||||
/^ipvlan.*/,
|
||||
/^wgui\d+$/,
|
||||
/^virbr\d*$/,
|
||||
/^vboxnet\d*$/,
|
||||
/^vmnet\d*$/,
|
||||
];
|
||||
|
||||
function isVirtualInterface(name: string): boolean {
|
||||
return VIRTUAL_INTERFACE_PATTERNS.some((pattern) =>
|
||||
pattern.test(name),
|
||||
);
|
||||
}
|
||||
|
||||
function isPhysicalInterface(name: string): boolean {
|
||||
try {
|
||||
const devicePath = `/sys/class/net/${name}/device`;
|
||||
const result = execSync(`test -e ${devicePath} && echo yes || echo no`, {
|
||||
encoding: "utf-8",
|
||||
}).trim();
|
||||
return result === "yes";
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to grab all available physical network interfaces on the machine
|
||||
* @returns Array of interface names (e.g. ["enp2s0", "wlan0"])
|
||||
*/
|
||||
export default async function grabHostNetworkInterfaces(): Promise<string[]> {
|
||||
try {
|
||||
const interfaces = os.networkInterfaces();
|
||||
const names: string[] = [];
|
||||
|
||||
for (const [name, addrs] of Object.entries(interfaces)) {
|
||||
if (!addrs) continue;
|
||||
if (name === "lo") continue;
|
||||
if (isVirtualInterface(name)) continue;
|
||||
for (const addr of addrs) {
|
||||
if (addr.family === "IPv4" && !addr.internal) {
|
||||
if (isPhysicalInterface(name)) {
|
||||
names.push(name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (names.length > 0) {
|
||||
return names.sort();
|
||||
}
|
||||
} catch (error) {}
|
||||
|
||||
try {
|
||||
const route = execSync(`ip -4 addr show`, { encoding: "utf-8" })
|
||||
.trim()
|
||||
.split(/\n/);
|
||||
const names: string[] = [];
|
||||
for (const line of route) {
|
||||
const match = line.match(/^\d+:\s+(\S+):/);
|
||||
if (match && match[1] && match[1] !== "lo") {
|
||||
const iface = match[1];
|
||||
if (!isVirtualInterface(iface) && isPhysicalInterface(iface)) {
|
||||
names.push(iface);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (names.length > 0) return names.sort();
|
||||
} catch (error) {}
|
||||
|
||||
return [`eth0`];
|
||||
}
|
||||
@@ -100,7 +100,7 @@ export default async function setupWireguardHost({
|
||||
rules_by_client_id.set(rule.client_id, existing_rules);
|
||||
}
|
||||
|
||||
const TARGET_INTERFACE = await grabHostNetworkInterface();
|
||||
const TARGET_INTERFACE = host?.interface || await grabHostNetworkInterface();
|
||||
const HOST_WG_IP =
|
||||
host?.wg_ip_address ||
|
||||
variables?.find((v) => v.key == "main_host_wg_ip_address")?.value ||
|
||||
@@ -158,21 +158,29 @@ export default async function setupWireguardHost({
|
||||
}).trim();
|
||||
|
||||
if (HOST_ID == 0 && !is_update_after_client_setup) {
|
||||
const variables_data: Array<{ key: string; value: string }> = [
|
||||
{
|
||||
key: "main_host_wg_ip_address",
|
||||
value: HOST_WG_IP,
|
||||
},
|
||||
{
|
||||
key: "main_host_wg_public_key",
|
||||
value: HOST_PUBLIC_KEY,
|
||||
},
|
||||
];
|
||||
if (host?.interface) {
|
||||
variables_data.push({
|
||||
key: "main_host_public_interface",
|
||||
value: host.interface,
|
||||
});
|
||||
}
|
||||
|
||||
const update_variables = await BunSQLite.insert<
|
||||
BUN_SQLITE_WGUI_VARIABLES,
|
||||
TableType
|
||||
>({
|
||||
table: "variables",
|
||||
data: [
|
||||
{
|
||||
key: "main_host_wg_ip_address",
|
||||
value: HOST_WG_IP,
|
||||
},
|
||||
{
|
||||
key: "main_host_wg_public_key",
|
||||
value: HOST_PUBLIC_KEY,
|
||||
},
|
||||
],
|
||||
data: variables_data as BUN_SQLITE_WGUI_VARIABLES[],
|
||||
update_on_duplicate: true,
|
||||
});
|
||||
|
||||
|
||||
@@ -43,6 +43,10 @@ export default async function syncWireguardHosts() {
|
||||
(v) => v.key == "main_host_public_ip_address",
|
||||
)?.value;
|
||||
|
||||
const main_host_interface = variables.payload?.find(
|
||||
(v) => v.key == "main_host_public_interface",
|
||||
)?.value;
|
||||
|
||||
if (!main_host_ip) {
|
||||
throw new Error(`Main Host not set yet`);
|
||||
}
|
||||
@@ -52,6 +56,7 @@ export default async function syncWireguardHosts() {
|
||||
id: 0,
|
||||
public_ip_address: main_host_public_ip,
|
||||
wg_ip_address: main_host_ip,
|
||||
interface: main_host_interface,
|
||||
},
|
||||
...(hosts.payload || []),
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user