initial commit
This commit is contained in:
commit
4d3e204a2d
|
|
@ -0,0 +1,3 @@
|
||||||
|
*.conf
|
||||||
|
*.png
|
||||||
|
*.ini
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": [
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1710146030,
|
||||||
|
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1713537308,
|
||||||
|
"narHash": "sha256-XtTSSIB2DA6tOv+l0FhvfDMiyCmhoRbNB+0SeInZkbk=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "5c24cf2f0a12ad855f444c30b2421d044120c66f",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"systems": "systems"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1680978846,
|
||||||
|
"narHash": "sha256-Gtqg8b/v49BFDpDetjclCYXm8mAnTrUzR0JnE2nv5aw=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "x86_64-linux",
|
||||||
|
"rev": "2ecfcac5e15790ba6ce360ceccddb15ad16d08a8",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "x86_64-linux",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
|
systems.url = "github:nix-systems/x86_64-linux";
|
||||||
|
flake-utils = {
|
||||||
|
url = "github:numtide/flake-utils";
|
||||||
|
inputs.systems.follows = "systems";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
outputs = {
|
||||||
|
nixpkgs,
|
||||||
|
flake-utils,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
flake-utils.lib.eachDefaultSystem (system: let
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
devShells.default = pkgs.mkShellNoCC {
|
||||||
|
name = "wireguard config";
|
||||||
|
packages = with pkgs; [
|
||||||
|
wireguard-tools
|
||||||
|
qrencode
|
||||||
|
python3
|
||||||
|
];
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,166 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import argparse
|
||||||
|
import configparser
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from string import Template
|
||||||
|
from typing import Iterable, TypedDict, NamedTuple
|
||||||
|
|
||||||
|
TEMPLATE_STR = """[Interface]
|
||||||
|
PrivateKey = $private_key
|
||||||
|
Address = $address
|
||||||
|
DNS = $dns
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = $remote_public_key
|
||||||
|
PresharedKey = $psk
|
||||||
|
AllowedIPs = $allowed_ips
|
||||||
|
Endpoint = $endpoint"""
|
||||||
|
TEMPLATE = Template(TEMPLATE_STR)
|
||||||
|
ENDPOINT = "127.0.0.1:51820"
|
||||||
|
PUBLIC_KEY = "REPLACE_WITH_SERVER_PUBLIC_KEY"
|
||||||
|
DNS = "127.0.0.1"
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigArgs(TypedDict):
|
||||||
|
remote_public_key: str
|
||||||
|
public_key: str
|
||||||
|
private_key: str
|
||||||
|
psk: str
|
||||||
|
address: str
|
||||||
|
allowed_ips: str
|
||||||
|
endpoint: str
|
||||||
|
dns: str
|
||||||
|
|
||||||
|
|
||||||
|
class Config(NamedTuple):
|
||||||
|
public_key: str
|
||||||
|
psk: str
|
||||||
|
config: str
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Query for connection info (Public key from server, Address, AllowedIPs, etc...)
|
||||||
|
args = parse_args()
|
||||||
|
config = load_config(args.config)
|
||||||
|
|
||||||
|
if args.outfile and args.outfile.exists():
|
||||||
|
print("The file {args.outfile} already exists. Do you want to overwrite? y/N ", end="")
|
||||||
|
overwrite_input = input()
|
||||||
|
overwrite = overwrite_input.strip()[0].lower() == 'y'
|
||||||
|
if not overwrite:
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
address = args.address
|
||||||
|
allowed_ips = args.allowed_ips
|
||||||
|
public_key = args.public_key or config["wireguard"]["public_key"]
|
||||||
|
endpoint = args.endpoint or config["wireguard"]["endpoint"]
|
||||||
|
dns = args.dns or config["wireguard"]["dns"]
|
||||||
|
psk = args.psk
|
||||||
|
public_key, psk, config = generate_config(
|
||||||
|
address,
|
||||||
|
allowed_ips,
|
||||||
|
public_key,
|
||||||
|
endpoint,
|
||||||
|
dns,
|
||||||
|
psk,
|
||||||
|
)
|
||||||
|
if not args.quiet:
|
||||||
|
print_config(public_key, psk, config)
|
||||||
|
if args.outfile:
|
||||||
|
save_config_file(args.outfile, config)
|
||||||
|
|
||||||
|
|
||||||
|
def print_config(public_key: str, psk: str, config: str):
|
||||||
|
print(f"### Public Key:\n{public_key}", end="\n\n")
|
||||||
|
print(f"### PSK:\n{psk}", end="\n\n")
|
||||||
|
print(f"### Wireguard Config:\n{config}", end="\n\n")
|
||||||
|
|
||||||
|
|
||||||
|
def generate_config(
|
||||||
|
address: str,
|
||||||
|
allowed_ips: Iterable[str],
|
||||||
|
remote_public_key: str,
|
||||||
|
endpoint: str,
|
||||||
|
dns: str,
|
||||||
|
psk: str | None,
|
||||||
|
) -> Config:
|
||||||
|
allowed_ips = ", ".join(allowed_ips)
|
||||||
|
private_key = get_private_key()
|
||||||
|
public_key = get_public_key(private_key)
|
||||||
|
psk = psk or get_psk()
|
||||||
|
config = {
|
||||||
|
"private_key": private_key,
|
||||||
|
"public_key": public_key,
|
||||||
|
"remote_public_key": remote_public_key,
|
||||||
|
"psk": psk,
|
||||||
|
"address": address,
|
||||||
|
"allowed_ips": allowed_ips,
|
||||||
|
"endpoint": endpoint,
|
||||||
|
"dns": dns,
|
||||||
|
}
|
||||||
|
config_string = TEMPLATE.substitute(**config)
|
||||||
|
return Config(public_key, psk, config_string)
|
||||||
|
|
||||||
|
|
||||||
|
def get_private_key() -> str:
|
||||||
|
result = subprocess.run(["wg", "genkey"], stdout=subprocess.PIPE)
|
||||||
|
private_key = result.stdout.strip()
|
||||||
|
return private_key.decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def get_public_key(private_key: str) -> str:
|
||||||
|
process = subprocess.Popen(
|
||||||
|
["wg", "pubkey"], stdin=subprocess.PIPE, stdout=subprocess.PIPE
|
||||||
|
)
|
||||||
|
result = process.communicate(input=private_key.encode("utf-8"))
|
||||||
|
public_key = result[0].strip()
|
||||||
|
return public_key.decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def get_psk() -> str:
|
||||||
|
result = subprocess.run(["wg", "genpsk"], stdout=subprocess.PIPE)
|
||||||
|
psk = result.stdout.strip()
|
||||||
|
return psk.decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def save_config_file(filename: Path, config: str):
|
||||||
|
filename.touch()
|
||||||
|
filename.chmod(0o600)
|
||||||
|
filename.write_text(config)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser(description="WireGuard Config File Generator")
|
||||||
|
parser.add_argument("address", help="The remote wireguard server hostname or address")
|
||||||
|
parser.add_argument("allowed_ips", nargs="+", help="The list of allowed IP ranges for the routed network")
|
||||||
|
parser.add_argument("-c", "--config", default="config.ini", type=Path, help="The config file to use for server configuration")
|
||||||
|
parser.add_argument("-o", "--outfile", type=Path, help="The file to write to")
|
||||||
|
parser.add_argument("-q", "--quiet", default=False, action="store_true", help="Suppress all output")
|
||||||
|
parser.add_argument("-p", "--psk", help="The Pre-Shared Key to use")
|
||||||
|
parser.add_argument("-e", "--endpoint", help="The Wireguard server to use")
|
||||||
|
parser.add_argument("-d", "--dns", help="The DNS server to use")
|
||||||
|
parser.add_argument("-P", "--public-key", help="The Servers public key to use")
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def load_config(filename: Path) -> configparser.ConfigParser:
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
if not filename.exists():
|
||||||
|
config["wireguard"] = {
|
||||||
|
"endpoint": ENDPOINT,
|
||||||
|
"public_key": PUBLIC_KEY,
|
||||||
|
"dns": DNS,
|
||||||
|
}
|
||||||
|
with filename.open("w") as fp:
|
||||||
|
config.write(fp)
|
||||||
|
|
||||||
|
config.read(filename)
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = parse_args()
|
||||||
|
config_file = Path(args.config)
|
||||||
|
config = config_file.read_text().strip()
|
||||||
|
|
||||||
|
if args.outfile and args.outfile.exists():
|
||||||
|
print("The file {args.outfile} already exists. Do you want to overwrite? y/N ", end="")
|
||||||
|
overwrite_input = input()
|
||||||
|
overwrite = overwrite_input.strip()[0].lower() == 'y'
|
||||||
|
if not overwrite:
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if not args.quiet:
|
||||||
|
print_qr_code(config)
|
||||||
|
|
||||||
|
if args.outfile:
|
||||||
|
save_qr_code_image(args.outfile, config)
|
||||||
|
|
||||||
|
|
||||||
|
def print_qr_code(config: str):
|
||||||
|
print("### QR Code:")
|
||||||
|
print(get_qr_code(config))
|
||||||
|
|
||||||
|
def get_qr_code(config: str) -> str:
|
||||||
|
process = subprocess.Popen(
|
||||||
|
["qrencode", "-t", "utf8"], stdin=subprocess.PIPE, stdout=subprocess.PIPE
|
||||||
|
)
|
||||||
|
result = process.communicate(input=config.encode("utf-8"))
|
||||||
|
return result[0].decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def save_qr_code_image(filename: Path, config: str):
|
||||||
|
process = subprocess.Popen(
|
||||||
|
["qrencode", "-t", "png", "-o", filename], stdin=subprocess.PIPE
|
||||||
|
)
|
||||||
|
process.communicate(input=config.encode("utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser(description="WireGuard QR Code Generator")
|
||||||
|
parser.add_argument("config", help="The WireGuard config file to generate a qr code for")
|
||||||
|
parser.add_argument("-o", "--outfile", type=Path, help="The ouput file for the generated PNG image")
|
||||||
|
parser.add_argument("-q", "--quiet", action="store_true", help="Suppress the output of the UTF-8 QR Code")
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Reference in New Issue