def delete_cgroup(interface): cgroup_iptables_del = [ ["-t", "mangle", "-D", "OUTPUT", "-m", "cgroup", "--cgroup", "0x00110011", "-j", "MARK", "--set-mark", "11"], ["-t", "nat", "-D", "POSTROUTING", "-m", "cgroup", "--cgroup", "0x00110011", "-o", "{}".format(interface), "-j", "MASQUERADE"], ["-D", "OUTPUT", "-m", "cgroup", "--cgroup", "0x00110011", "-j", "ACCEPT"], ["-D", "INPUT", "-m", "cgroup", "--cgroup", "0x00110011", "-j", "ACCEPT"], ["-t", "nat", "-D", "OUTPUT", "-m", "cgroup", "--cgroup", "0x00110011", "-p", "tcp", "--dport", "53", "-j", "REDIRECT", "--to-ports", "5354"], ["-t", "nat", "-D", "OUTPUT", "-m", "cgroup", "--cgroup", "0x00110011", "-p", "udp", "--dport", "53", "-j", "REDIRECT", "--to-ports", "5354"] ] try: check_call(["ip", "rule", "del", "fwmark", "11", "table", "bypass_qomui"]) except CalledProcessError: pass firewall.batch_rule(cgroup_iptables_del) firewall.batch_rule_6(cgroup_iptables_del) try: os.rmdir(cgroup_path) except (OSError, FileNotFoundError): logging.debug("Bypass: Could not delete {} - resource does not exist or is busy".format(cgroup_path)) logging.info("Deleted cgroup")
def disconnect(self, env): if env == "main": self.restore_default_dns() self.tun is None for i in self.pid_list: if i[1] != "OpenVPN_bypass": self.kill_pid(i) if self.wg_connect == 1: try: wg_down = Popen(["wg-quick", "down", "{}/wg_qomui.conf".format(config.ROOTDIR)], stdout=PIPE, stderr=STDOUT) for line in wg_down.stdout: self.logger.info("WireGuard: " + line.decode("utf-8").replace("\n", "")) except CalledProcessError: pass #as WireGuard is down we can remove those rules wg_rules = [ ["-D", "INPUT", "-i", "wg_qomui", "-j", "ACCEPT"], ["-D", "OUTPUT", "-o", "wg_qomui", "-j", "ACCEPT"] ] firewall.batch_rule_6(wg_rules) firewall.batch_rule(wg_rules) tunnel.exe_custom_scripts("down", self.wg_provider, config.settings) self.wg_connect = 0 elif env == "bypass": for i in self.pid_list: if i[1] == "OpenVPN_bypass": self.kill_pid(i)
def set_bypass_vpn(interface, interface_cmd, tun, tun_cmd): postroutes = [[ "-t", "nat", tun_cmd, "POSTROUTING", "-m", "cgroup", "--cgroup", "0x00110011", "-o", tun, "-j", "MASQUERADE" ], [ "-t", "nat", interface_cmd, "POSTROUTING", "-m", "cgroup", "--cgroup", "0x00110011", "-o", interface, "-j", "MASQUERADE" ]] firewall.batch_rule(postroutes) firewall.batch_rule_6(postroutes)
def create_cgroup(user, group, interface, gw=None, gw_6=None, default_int=None, no_dnsmasq=0): print("nodnsmasq={}".format(no_dnsmasq)) logging.info("Creating bypass for {}".format(interface)) delete_cgroup(default_int) cgroup_iptables = [[ "-t", "mangle", "-A", "OUTPUT", "-m", "cgroup", "--cgroup", "0x00110011", "-j", "MARK", "--set-mark", "11" ], [ "-t", "nat", "-A", "POSTROUTING", "-m", "cgroup", "--cgroup", "0x00110011", "-o", "{}".format(interface), "-j", "MASQUERADE" ], [ "-I", "OUTPUT", "1", "-m", "cgroup", "--cgroup", "0x00110011", "-j", "ACCEPT" ], [ "-I", "INPUT", "1", "-m", "cgroup", "--cgroup", "0x00110011", "-j", "ACCEPT" ]] if no_dnsmasq == 0: cgroup_iptables.append([ "-t", "nat", "-A", "OUTPUT", "-m", "cgroup", "--cgroup", "0x00110011", "-p", "tcp", "--dport", "53", "-j", "REDIRECT", "--to-ports", "5354" ]) cgroup_iptables.append([ "-t", "nat", "-A", "OUTPUT", "-m", "cgroup", "--cgroup", "0x00110011", "-p", "udp", "--dport", "53", "-j", "REDIRECT", "--to-ports", "5354" ]) if not os.path.exists(cgroup_path): os.makedirs(cgroup_path) with open("{}/net_cls.classid".format(cgroup_path), 'w') as setcid: setcid.write(cls_id) setcid.close() logging.debug("Bypass: Created cgroup 'net_cls:bypass_qomui'") try: check_call(["ip", "route", "show", "table", "bypass_qomui"]) logging.debug( "Bypass: No routing table added - table bypass_qomui already exists" ) except CalledProcessError: with open("/etc/iproute2/rt_tables", "a") as rt_tables: rt_tables.write("11 bypass_qomui\n") logging.debug("Bypass: Created new routing table") firewall.batch_rule(cgroup_iptables) if gw_6 != "None" and default_int == interface: firewall.batch_rule_6(cgroup_iptables) else: logging.debug("Blocking ipv6 via bypass_qomui") cgroup_iptables.pop(1) cgroup_iptables.insert(1, [ "-t", "nat", "-A", "POSTROUTING", "-m", "cgroup", "--cgroup", "0x00110011", "-o", "{}".format(interface), "-j", "MASQUERADE" ]) cgroup_iptables.pop(2) cgroup_iptables.insert(2, [ "-I", "OUTPUT", "1", "-m", "cgroup", "--cgroup", "0x00110011", "-j", "DROP" ]) cgroup_iptables.pop(3) cgroup_iptables.insert(3, [ "-I", "INPUT", "1", "-m", "cgroup", "--cgroup", "0x00110011", "-j", "DROP" ]) firewall.batch_rule_6(cgroup_iptables) try: check_call( ["ip", "rule", "add", "fwmark", "11", "table", "bypass_qomui"]) if interface == default_int: check_call(["ip", "route", "flush", "table", "bypass_qomui"]) check_call( ["ip", "rule", "add", "fwmark", "11", "table", "bypass_qomui"]) check_call([ "ip", "route", "add", "default", "via", "{}".format(gw), "dev", "{}".format(interface), "table", "bypass_qomui" ]) logging.debug( "Bypass: Set ipv4 route 'default via {} dev {}'".format( gw, interface)) except CalledProcessError: logging.error( "Bypass: Setting ipv4 route 'default via {} dev {}'".format( gw, interface)) try: check_call([ "ip", "-6", "rule", "add", "fwmark", "11", "table", "bypass_qomui" ]) if interface == default_int: check_call(["ip", "-6", "route", "flush", "table", "bypass_qomui"]) check_call([ "ip", "-6", "route", "add", "default", "via", "{}".format(gw_6), "dev", "{}".format(interface), "table", "bypass_qomui" ]) logging.debug( "Bypass: Set ipv6 route 'default via {} dev {}'".format( gw_6, interface)) except CalledProcessError: logging.error( "Bypass: Setting ipv6 route 'default via {} dev {}' failed".format( gw, interface)) with open("/proc/sys/net/ipv4/conf/all/rp_filter", 'w') as rp_edit_all: rp_edit_all.write("2") try: with open("/proc/sys/net/ipv4/conf/{}/rp_filter".format(interface), 'w') as rp_edit_int: rp_edit_int.write("2") logging.debug( "Disabled reverse path filtering for {}".format(interface)) except FileNotFoundError: logging.error("Failed to disable reverse path filtering for {}".format( interface)) try: check_call([ "cgcreate", "-t", "{}:{}".format(user, group), "-a" "{}:{}".format(user, group), "-g", "net_cls:bypass_qomui" ]) logging.debug("Bypass: Configured cgroup access for {}".format(user)) logging.info("Successfully created cgroup for {}".format(interface)) except (CalledProcessError, FileNotFoundError) as e: logging.error("Creating cgroup failed - is libcgroup installed?")
def wg(self, wg_file): exe_custom_scripts("pre", self.server_dict["provider"], self.config) name = self.server_dict["name"] self.log.emit(("info", "Establishing connection to {}".format(name))) #allow traffic via wg interface wg_rules = [["-I", "INPUT", "2", "-i", "wg_qomui", "-j", "ACCEPT"], ["-I", "OUTPUT", "2", "-o", "wg_qomui", "-j", "ACCEPT"] ] firewall.batch_rule_6(wg_rules) firewall.batch_rule(wg_rules) time.sleep(1) try: self.dev.emit(("tun", "wg_qomui")) cmd_wg = Popen(['wg-quick', 'up', '{}'.format(wg_file)], stdout=PIPE, stderr=STDOUT) for line in cmd_wg.stdout: self.log.emit(("info", "WireGuard: " + line.decode("utf-8").replace("\n", ""))) with open("{}/wg_qomui.conf".format(ROOTDIR), "r") as dns_check: lines = dns_check.readlines() for line in lines: if line.startswith("DNS ="): dns_servers = line.split("=")[1].replace(" ", "").split(",") self.dns = dns_servers[0].split("\n")[0] try: self.dns_2 = dns_servers[1].split("\n")[0] except IndexError: self.dns_2 = None dns_manager.set_dns(self.dns, self.dns_2) self.dnsserver.emit(("", self.dns, self.dns_2)) #Necessary, otherwise bypass mode breaks - need to investigate if self.config["bypass"] == 1: try: check_call(["ip", "rule", "del", "fwmark", "11", "table", "bypass_qomui"]) check_call(["ip", "-6", "rule", "del", "fwmark", "11", "table", "bypass_qomui"]) except CalledProcessError: pass try: check_call(["ip", "rule", "add", "fwmark", "11", "table", "bypass_qomui"]) check_call(["ip", "-6", "rule", "add", "fwmark", "11", "table", "bypass_qomui"]) self.log.emit(("debug", "Packet classification for bypass table reset")) except CalledProcessError: self.log.emit(("warning", "Could not reset packet classification for bypass table")) self.bypass.emit() #we can't be sure of that exe_custom_scripts("up", self.server_dict["provider"], self.config) self.status.emit("connection_established") except (CalledProcessError, FileNotFoundError): self.status.emit("fail")