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