From a409db3e0dd856a2ac26ee8312dbee558427ba6b Mon Sep 17 00:00:00 2001 From: lyc <6648049+tooyoungtoosimp@users.noreply.github.com> Date: Tue, 30 Nov 2021 23:58:06 +0800 Subject: [PATCH] server --- .vscode/settings.json | 3 ++ wg-p2p-client.conf | 5 +++ wg-p2p-client.py | 11 +++++++ wg-p2p-server.py | 39 ++++++++++++++++++++++ wgconfig.py | 75 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 133 insertions(+) create mode 100644 .vscode/settings.json create mode 100644 wg-p2p-client.conf create mode 100644 wg-p2p-client.py create mode 100644 wg-p2p-server.py create mode 100644 wgconfig.py diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..1b3cd28 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.pythonPath": "/opt/conda/bin/python" +} \ No newline at end of file diff --git a/wg-p2p-client.conf b/wg-p2p-client.conf new file mode 100644 index 0000000..9f460f7 --- /dev/null +++ b/wg-p2p-client.conf @@ -0,0 +1,5 @@ +url: "http://1.117.146.57:43662" +local_wg: "wg0" +remote_wg: "wg0" +peers: + - "bBSgH68LsCaYceSy6xKhFIIU9J+gNsGhKsUPMsUIUCU=" \ No newline at end of file diff --git a/wg-p2p-client.py b/wg-p2p-client.py new file mode 100644 index 0000000..49ab6bd --- /dev/null +++ b/wg-p2p-client.py @@ -0,0 +1,11 @@ +from time import sleep +import yaml +import requests +with open("wg-p2p-client.conf") as f: + cfg = yaml.safe_load(f) +last_hash = "" +url = f"{cfg['url']}/hash/{cfg['remote_wg']}" +while True: + new_hash = requests.get(url).text + print(new_hash) + sleep(5) \ No newline at end of file diff --git a/wg-p2p-server.py b/wg-p2p-server.py new file mode 100644 index 0000000..8537891 --- /dev/null +++ b/wg-p2p-server.py @@ -0,0 +1,39 @@ +from fastapi import FastAPI, Response +from wgconfig import WireGuardConfig, wg_showconf, wg_syncconf +from dataclasses import dataclass +import hashlib + +app = FastAPI() + + +@app.get("/peers/{ifname}") +def get_all_peer(ifname: str): + c = WireGuardConfig.get_from_interface(ifname) + return Response(c.get_peers_cfg()) + + +@app.get("/peers/{ifname}/{pubkey:path}") +def get_peer(ifname: str, pubkey: str): + print(pubkey) + c = WireGuardConfig.get_from_interface(ifname) + return c.get_peer(pubkey) + + +@dataclass +class EndpointUpdateDTO: + pubkey: str + endpoint: str + + +@app.post("/endpoint/{ifname}") +def update_endpoint(ifname, u: EndpointUpdateDTO): + c = WireGuardConfig.get_from_interface(ifname) + if p := c.get_peer(u.pubkey): + p["Endpoint"] = u.endpoint + wg_syncconf(ifname, str(c)) + + +@app.get("/hash/{ifname}") +def get_config_hash(ifname: str): + c = wg_showconf(ifname).encode() + return hashlib.sha256(c).hexdigest() \ No newline at end of file diff --git a/wgconfig.py b/wgconfig.py new file mode 100644 index 0000000..725ac3c --- /dev/null +++ b/wgconfig.py @@ -0,0 +1,75 @@ +from subprocess import run +import os +import re + +_hdr = re.compile("^\[\w*\]", flags=re.MULTILINE) + + +class WireGuardConfig: + def __init__(self, conf: str = None) -> None: + self.Interface: dict[str, str] = {} + self.Peers: list[dict[str, str]] = [] + if conf: + sp = _hdr.split(conf) + interface = sp[1] + peers = sp[2:] + self.Interface = self._lines2dict(interface.splitlines()) + for peer in peers: + self.Peers.append(self._lines2dict(peer.splitlines())) + + def get_from_interface(ifname: str): + cfg = wg_showconf(ifname) + return WireGuardConfig(cfg) + + def get_peer(self, pubkey: str): + for peer in self.Peers: + if peer["PublicKey"] == pubkey: + return peer + return None + + def _lines2dict(self, lns: list): + d = {} + for l in lns: + if "=" in l: + k, v = l.split("=", 1) + d[k.strip()] = v.strip() + return d + + def _flat_dict(self, d: dict): + return [f"{k} = {v}" for k, v in d.items()] + [""] + + def _flat_peer(self, peer: dict): + return ["[Peer]", *self._flat_dict(peer)] + + def _flat_interface(self): + return ["[Interface]", *self._flat_dict(self.Interface)] + + def _get_peer_lines(self): + return sum([self._flat_peer(p) for p in self.Peers], []) + + def get_peers_cfg(self): + return os.linesep.join(self._get_peer_lines()) + + def __str__(self) -> str: + strs = self._flat_interface() + self._get_peer_lines() + return os.linesep.join(strs) + + +def wg_reload_config(ifname: str): + run( + f"wg syncconf {ifname} <(wg-quick strip {ifname})", + shell=True, + executable="/bin/bash", + ) + + +def wg_showconf(ifname: str): + return run( + f"wg showconf {ifname}", + shell=True, + capture_output=True, + ).stdout.decode() + + +def wg_syncconf(ifname: str, conf: str): + run(f"wg syncconf {ifname} /dev/stdin", shell=True, input=conf)