190 lines
5.6 KiB
JavaScript
190 lines
5.6 KiB
JavaScript
|
#!node
|
||
|
const fs = require("fs");
|
||
|
const p = require("path");
|
||
|
const qrimage = require("./qr/qr");
|
||
|
const crypto = require("crypto");
|
||
|
|
||
|
|
||
|
const deleteRec = (path) => {
|
||
|
path = p.resolve(path);
|
||
|
if (fs.existsSync(path)) {
|
||
|
if (fs.statSync(path).isDirectory()) {
|
||
|
fs.readdirSync(path).forEach(entry => deleteRec(p.join(path, entry)));
|
||
|
fs.rmdirSync(path);
|
||
|
} else {
|
||
|
fs.unlinkSync(path);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const config = fs.existsSync("config.json") ? JSON.parse(fs.readFileSync("config.json").toString()) : {};
|
||
|
|
||
|
const child = require("child_process");
|
||
|
const getPrivate = () => {
|
||
|
return child.execSync("wg genkey").toString().replace("\n", "").replace("\r", "").trim();
|
||
|
}
|
||
|
|
||
|
const getPublic = (private) => {
|
||
|
return child.execSync(`echo ${private} | wg pubkey`).toString().replace("\n", "").replace("\r", "").trim();
|
||
|
}
|
||
|
|
||
|
const keyPair = () => {
|
||
|
const private = getPrivate();
|
||
|
const public = getPublic(private);
|
||
|
return { private, public };
|
||
|
}
|
||
|
|
||
|
const clientArray = (clients) => Object.keys(clients).map(key => ({ ...clients[key], name: key }))
|
||
|
|
||
|
const ipTablesPostUP = [
|
||
|
"iptables -A FORWARD -i %i -j ACCEPT",
|
||
|
"iptables -A FORWARD -o %i -j ACCEPT",
|
||
|
"iptables -t nat -A POSTROUTING -o %i -j MASQUERADE",
|
||
|
"iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE",
|
||
|
"iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE"
|
||
|
].join("; ");
|
||
|
|
||
|
const ipTablesPostDOWN = [
|
||
|
"iptables -D FORWARD -i %i -j ACCEPT",
|
||
|
"iptables -D FORWARD -o %i -j ACCEPT",
|
||
|
"iptables -t nat -D POSTROUTING -o %i -j MASQUERADE",
|
||
|
"iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE",
|
||
|
"iptables -t nat -D POSTROUTING -o wg0 -j MASQUERADE"
|
||
|
].join("; ");
|
||
|
|
||
|
function makeServer({ port, subnet, subnet6, server, clients }) {
|
||
|
const base = `[Interface] #Server
|
||
|
ListenPort = ${port}
|
||
|
Address = ${subnet}1/32,${subnet6}1/48
|
||
|
PrivateKey = ${server.private}
|
||
|
PostUp = ${ipTablesPostUP}
|
||
|
PostDown = ${ipTablesPostDOWN}
|
||
|
# ---------------------------
|
||
|
|
||
|
`
|
||
|
|
||
|
let peers = clientArray(clients).map(client => {
|
||
|
return `[Peer] #${client.name}
|
||
|
PublicKey = ${client.public}
|
||
|
AllowedIPs = ${subnet}${client.ip}/32,${subnet6}${client.ip}/128
|
||
|
` + (client.endpoint ? "\nEndpoint = " + client.endpoint + ":" + port : "");
|
||
|
}).join("\n\n");
|
||
|
|
||
|
fs.writeFileSync("out/server/server.conf", base + peers);
|
||
|
fs.writeFileSync("out/server/server.public", server.public);
|
||
|
}
|
||
|
|
||
|
function makeClients({ port, subnet, subnet6, server, clients }) {
|
||
|
clientArray(clients).map(client => {
|
||
|
const config = `[Interface]
|
||
|
ListenPort = ${port}
|
||
|
Address = ${subnet}${client.ip}/32, ${subnet6}${client.ip}/128
|
||
|
PrivateKey = ${client.private}
|
||
|
DNS = 1.1.1.1
|
||
|
|
||
|
[Peer] #Server
|
||
|
PublicKey = ${server.public}
|
||
|
AllowedIPs = 0.0.0.0/0, ::0/0
|
||
|
Endpoint = ${server.endpoint}:${port}
|
||
|
`
|
||
|
|
||
|
fs.writeFileSync(`out/clients/${client.name}.conf`, config);
|
||
|
fs.writeFileSync(`out/clients/${client.name}.public`, client.public);
|
||
|
var qr_svg = qrimage.image(config, { type: 'png' });
|
||
|
qr_svg.pipe(require('fs').createWriteStream(`out/clients/${client.name}.png`));
|
||
|
})
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
if (!config.subnet6) {
|
||
|
let sn = crypto.randomBytes(5).toString("hex");
|
||
|
let s1 = sn.substr(0, 2);
|
||
|
let s23 = sn.substr(2, 4);
|
||
|
let s45 = sn.substr(6, 4);
|
||
|
config.subnet6 = `fd${s1}:${s23}:${s45}::`;
|
||
|
}
|
||
|
|
||
|
switch (process.argv[2]) {
|
||
|
case "init": {
|
||
|
const hostname = process.argv[3];
|
||
|
let subnet = process.argv[4];
|
||
|
const port = Number(process.argv[5]) | 51823;
|
||
|
|
||
|
if (!hostname)
|
||
|
throw new Error("Hostname required");
|
||
|
|
||
|
if (!subnet) {
|
||
|
let randomIP1 = Math.floor(Math.random() * 256);
|
||
|
let randomIP2 = Math.floor(Math.random() * 256);
|
||
|
subnet = `10.${randomIP1}.${randomIP2}.`;
|
||
|
} else {
|
||
|
if (!subnet.endsWith("."))
|
||
|
subnet += ".";
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
config.subnet = subnet;
|
||
|
config.port = port;
|
||
|
config.server = {
|
||
|
endpoint: hostname,
|
||
|
...keyPair()
|
||
|
}
|
||
|
config.clients = {};
|
||
|
console.log("Created new configuration");
|
||
|
console.log("Server Hostname:", hostname);
|
||
|
console.log(" Port:", port);
|
||
|
console.log(" Subnet:", subnet + "0/24");
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case "generate": {
|
||
|
deleteRec("./out");
|
||
|
fs.mkdirSync("./out")
|
||
|
fs.mkdirSync("./out/server")
|
||
|
fs.mkdirSync("./out/clients")
|
||
|
makeServer(config)
|
||
|
makeClients(config)
|
||
|
break;
|
||
|
}
|
||
|
case "add": {
|
||
|
const name = process.argv[3];
|
||
|
const endpoint = process.argv[4];
|
||
|
if (!name)
|
||
|
throw new Error("No name!");
|
||
|
if (config.clients[name]) {
|
||
|
throw new Error("A device with this name exists already!\n Remove with 'remove <name>'");
|
||
|
}
|
||
|
|
||
|
let freeIP = 2;
|
||
|
clientArray(config.clients).forEach(c => c.ip >= freeIP ? freeIP = c.ip + 1 : undefined);
|
||
|
config.clients[name] = {
|
||
|
ip: freeIP,
|
||
|
endpoint,
|
||
|
...keyPair()
|
||
|
}
|
||
|
console.log("Peer added:")
|
||
|
console.log(`IP: ${config.subnet}${freeIP}`)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case "remove": {
|
||
|
const name = process.argv[3];
|
||
|
if (!name)
|
||
|
throw new Error("No name!");
|
||
|
delete config.clients[name];
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default: {
|
||
|
console.log("Wireguard VPN Config generator v0.1");
|
||
|
console.log("Usage:")
|
||
|
console.log("generate, add, remove")
|
||
|
}
|
||
|
}
|
||
|
} catch (err) {
|
||
|
console.error(err);
|
||
|
console.error(err.message);
|
||
|
}
|
||
|
|
||
|
fs.writeFileSync("config.json", JSON.stringify(config, undefined, " "));
|