diff --git a/README.md b/README.md index e69de29..99cec33 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,10 @@ +Multiple Openvpn Manager +========= + +Supervise multiple openvpn client connections and provide socks5 proxy with load balancing to achieve bandwidth aggregation from multiple connections. The link isolation is by iptables and ip rules using group id as the identifier. One socks5 server is started for each openvpn connection, and an additional load balancing socks5 server listens for external requests. + +The program also provides link quality monitoring (ping time and speed). The load balancing proxy has the option to dynamically change the rule for load balancing based on the link quality. + +The program has builtin web ui to monitor and control the openvpn connections and load balancing rules. + +The program needs to run as root. diff --git a/o_manager.py b/o_manager.py index 45112f7..8e90618 100644 --- a/o_manager.py +++ b/o_manager.py @@ -10,27 +10,27 @@ class OManager: self.base_folder = base_folder self.base_port = base_port self.ops = [] - self.idx = 0 + self.new_idx = 0 self.running_idx = [] self.run_task = [] - self.PID = None + self.PID = None if loop: self.loop = loop else: self.loop = asyncio.get_event_loop() def new_op(self, cfg_fp, name=None, additional_cfg={}): - folder_path = os.path.join(self.base_folder, f"session{self.idx}") + folder_path = os.path.join(self.base_folder, f"session{self.new_idx}") if not os.path.isdir(folder_path): os.makedirs(folder_path) if not name: - name = f"openvpn-{self.idx}" - os.system(f"groupadd vpn{self.idx}") - op = Openvpn(cfg_fp, self.idx, folder_path, - f"{self.base_port + self.idx}", "script.sh.template", "3proxy.cfg.template", name=name, + name = f"openvpn-{self.new_idx}" + os.system(f"groupadd vpn{self.new_idx}") + op = Openvpn(cfg_fp, self.new_idx, folder_path, + f"{self.base_port + self.new_idx}", "script.sh.template", "3proxy.cfg.template", name=name, additional_cfg=additional_cfg) self.ops.append(op) - self.idx += 1 + self.new_idx += 1 return op def generate_lb_cfg(self): @@ -40,8 +40,7 @@ class OManager: buf = template_f.read() template = Template(buf) items = { - "running_idx": self.running_idx, - "port": f"{1080 + self.idx}" + "running_idx": self.running_idx } lb_cfg = template.generate(**items) with open(lb_cfg_fp, "wb") as lb_cfg_f: @@ -72,9 +71,8 @@ class OManager: self.reset_lb() def stop_all(self): - loop = self.loop for op in self.ops: - loop.create_task(op.stop()) + op.stop() self.running_idx = [] self.reset_lb() @@ -91,7 +89,7 @@ class OManager: lb_cfg_fp = self.generate_lb_cfg() if len(self.running_idx): lb_cmd = ["go-socks-lb/go-socks-lb", "-config", - lb_cfg_fp, "-bind", "0.0.0.0:7000"] + lb_cfg_fp, "-bind", "0.0.0.0:7000"] print("lb_cmd", lb_cmd) self.run_task.append(self.loop.create_task( self.run_cmd(lb_cmd))) @@ -100,7 +98,7 @@ class OManager: while True: print("Manager trying to start go") proc = await asyncio.create_subprocess_exec( - cmd[0], *cmd[1:], + cmd[0], *cmd[1:], stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) print("Manager started", cmd) diff --git a/openvpn.py b/openvpn.py index eecd1e6..dfa9042 100644 --- a/openvpn.py +++ b/openvpn.py @@ -13,6 +13,7 @@ from datetime import datetime import humanize from tornado.template import Template import stat +import shutil def generate_config(in_fp, cfg): @@ -149,10 +150,17 @@ class Openvpn: except: return "" - def clear_log(self): - os.remove(self.log_fp) + def clear_folder(self): + try: + # removing all files in folder path, not removing folders + dirpath = self.folder_path + for filename in os.listdir(dirpath): + filepath = os.path.join(dirpath, filename) + os.remove(filepath) + except Exception as err: + print("cannot remove log file, error:", err) - async def stop(self): + def stop(self, clear_folder=True): if self.status == RUNNING: for pid in self.pids: try: @@ -164,13 +172,11 @@ class Openvpn: task.cancel() self.pids = [] self.run_task = [] - try: - os.remove(self.log_fp) - except Exception as err: - print("cannot remove log file, error:", err) + if clear_folder: + self.clear_folder() - async def restart(self): - await self.stop() + def restart(self): + self.stop() self.start() def get_io_stat(self):