def run(self): ip = self.server_dict["ip"] firewall.allow_dest_ip(ip, "-I") self.log.emit(("info", "iptables: created rule for {}".format(ip))) try: if self.server_dict["tunnel"] == "WireGuard": self.wireguard() else: self.openvpn() except KeyError: self.openvpn()
def openvpn(self): self.air_ssl_port = "1413" self.ws_ssl_port = "1194" path = "{}/temp.ovpn".format(ROOTDIR) cwd_ovpn = None provider = self.server_dict["provider"] ip = self.server_dict["ip"] try: port = self.server_dict["port"] protocol = self.server_dict["protocol"] except KeyError: pass if "bypass" in self.server_dict.keys(): path = "{}/bypass.ovpn".format(ROOTDIR) time.sleep(2) else: path = "{}/temp.ovpn".format(ROOTDIR) if provider == "Airvpn": #create temp ssl config if protocol == "SSL": with open("{}/ssl_config".format(ROOTDIR), "r") as ssl_edit: ssl_config = ssl_edit.readlines() for line, value in enumerate(ssl_config): if value.startswith("connect") is True: ssl_config[line] = "connect = {}:{}\n".format(ip, port) elif value.startswith("accept") is True: ssl_config[line] = "accept = 127.0.0.1:{}\n".format(self.air_ssl_port) ssl_config.append("verify = 3\n") ssl_config.append("CAfile = /usr/share/qomui/Airvpn/stunnel.crt") with open("{}/temp.ssl".format(ROOTDIR), "w") as ssl_dump: ssl_dump.writelines(ssl_config) ssl_dump.close() ssl_edit.close() self.write_config(self.server_dict) self.ssl_thread = threading.Thread(target=self.ssl, args=(ip,)) self.ssl_thread.start() self.log.emit(("info", "Started Stunnel process in new thread")) #create temp ssh config elif protocol == "SSH": self.write_config(self.server_dict) self.ssh_thread = threading.Thread(target=self.ssh, args=(ip,port,)) self.ssh_thread.start() self.log.emit(("info", "Started SSH process in new thread")) time.sleep(2) else: self.write_config(self.server_dict) elif provider == "Mullvad": self.write_config(self.server_dict) elif provider == "PIA": self.write_config(self.server_dict) elif provider == "Windscribe": #create temp ssl config if protocol == "SSL": with open("{}/ssl_config".format(ROOTDIR), "r") as ssl_edit: ssl_config = ssl_edit.readlines() for line, value in enumerate(ssl_config): if value.startswith("connect") is True: ssl_config[line] = "connect = {}:{}\n".format(ip, port) elif value.startswith("accept") is True: ssl_config[line] = "accept = 127.0.0.1:{}\n".format(self.ws_ssl_port) with open("{}/temp.ssl".format(ROOTDIR), "w") as ssl_dump: ssl_dump.writelines(ssl_config) ssl_dump.close() ssl_edit.close() self.write_config(self.server_dict) self.ssl_thread = threading.Thread(target=self.ssl, args=(ip,)) self.ssl_thread.start() self.log.emit(("info", "Started Stunnel process in new thread")) self.write_config(self.server_dict) elif provider == "ProtonVPN": self.write_config(self.server_dict) elif provider == "AzireVPN": self.write_config(self.server_dict) else: config_file = "{}/{}".format(ROOTDIR, self.server_dict["path"]) try: edit = "{}/temp".format(provider) self.write_config(self.server_dict, edit=edit, path=config_file) path = "{}/{}/temp.ovpn".format(ROOTDIR, provider) except UnboundLocalError: path = config_file #setting cwd for OpenVPN is important if certifacte/key files separate from config file cwd_ovpn = os.path.dirname(config_file) if self.hop == "2": firewall.allow_dest_ip(self.hop_dict["ip"], "-I") if self.hop_dict["provider"] in SUPPORTED_PROVIDERS: hop_path = "{}/hop.ovpn".format(ROOTDIR) self.write_config(self.hop_dict, edit="hop") else: config_file = "{}/{}".format(ROOTDIR, self.hop_dict["path"]) try: edit = "{}/hop".format(self.hop_dict["provider"]) self.write_config(self.hop_dict, edit=edit, path=config_file) hop_path = "{}/{}/temp.ovpn".format(ROOTDIR, self.hop_dict["provider"]) except (UnboundLocalError, KeyError): hop_path = config_file cwd_ovpn = os.path.dirname(config_file) self.hop_thread = threading.Thread(target=self.ovpn, args=(hop_path, "1", cwd_ovpn,)) self.hop_thread.start() #wait until first hop is connected while self.connect_status == 0: time.sleep(1) self.ovpn(path, self.hop, cwd_ovpn)
def ovpn(self, ovpn_file, h, cwd_ovpn): self.log.emit(("info", "Establishing new OpenVPN tunnel")) name = self.server_dict["name"] last_ip = self.server_dict["ip"] add = "" if "bypass" not in self.server_dict and h != 1: exe_custom_scripts("pre", self.server_dict["provider"], self.config) #if doublehop is selected additional arguments are needed for OpenVPN if h == "1": add = "_hop" name = self.hop_dict["name"] self.log.emit(("info", "Establishing connection to {} - first hop".format(name))) last_ip = self.hop_dict["ip"] cmd_ovpn = ['openvpn', '--config', '{}'.format(ovpn_file), '--route-nopull', '--script-security', '2', '--up', '{}/scripts/hop.sh -f {} {}'.format( ROOTDIR, self.hop_dict["ip"], self.server_dict["ip"] ), '--down', '{}/scripts/hop_down.sh {}'.format(ROOTDIR, self.hop_dict["ip"]) ] elif h == "2": self.log.emit(("info", "Establishing connection to {} - second hop".format(name))) cmd_ovpn = ['openvpn', '--config', '{}'.format(ovpn_file), '--route-nopull', '--script-security', '2', '--up', '{}/hop.sh -s'.format(ROOTDIR) ] else: self.log.emit(("info", "Establishing connection to {}".format(name))) cmd_ovpn = ['openvpn', '{}'.format(ovpn_file)] if "bypass" in self.server_dict: add = "_bypass" self.dns_bypass = self.config["alt_dns1"] self.dns_2_bypass = self.config["alt_dns2"] else: self.dns = self.config["alt_dns1"] self.dns_2 = self.config["alt_dns2"] ovpn_exe = Popen(cmd_ovpn, stdout=PIPE, stderr=STDOUT, cwd=cwd_ovpn, bufsize=1, universal_newlines=True ) self.log.emit(("debug", "OpenVPN pid: {}".format(ovpn_exe.pid))) self.pid.emit((ovpn_exe.pid, "OpenVPN{}".format(add))) line = ovpn_exe.stdout.readline() self.status.emit("starting_timer{}".format(add)) #keep this thread as long as openvpn process has not been terminated #disconnection from gui will kill the openvpn process and break the loop while line.find("SIGTERM[hard,] received, process exiting") == -1: time_measure = time.time() line_format = ("OpenVPN:" + line.replace('{}'.format(time.asctime()), '').replace('\n', '')) self.log.emit(("info", line_format)) #signals that tunnel has been successfully established if line.find("Initialization Sequence Completed") != -1: if "bypass" not in self.server_dict and h != 1: exe_custom_scripts("up", self.server_dict["provider"], self.config) self.connect_status = 1 self.bypass.emit() self.status.emit("connection_established{}".format(add)) self.log.emit(("info", "Successfully connected to {}".format(name))) elif line.find('TUN/TAP device') != -1: setattr(self, "tun{}".format(add), line_format.split(" ")[3]) self.dev.emit(("tun{}".format(add), getattr(self, "tun{}".format(add)))) #read dns servers pushed by OpenVPN server #if not found: fallback to alternatives ones from config file elif line.find('PUSH: Received control message:') != -1: dns_option_1 = line_format.find('dhcp-option') if dns_option_1 != -1 and self.config["alt_dns"] == 0: option = line_format[dns_option_1:].split(",")[0] setattr(self, "dns{}".format(add), option.split(" ")[2]) dns_option_2 = line_format.find('dhcp-option', dns_option_1+20) if dns_option_2 != -1: option = line_format[dns_option_2:].split(",")[0] setattr(self, "dns_2{}".format(add), option.split(" ")[2]) else: setattr(self, "dns_2{}".format(add), None) dns_manager.set_dns(getattr(self, "dns{}".format(add)), getattr(self, "dns_2{}".format(add))) self.dnsserver.emit((add, getattr(self, "dns{}".format(add)), getattr(self, "dns_2{}".format(add)))) #might be redundant as gui checks for timeout anyway elif line.find("Restart pause, 10 second(s)") != -1: self.status.emit("conn_attempt_failed{}".format(add)) self.log.emit(("info" ,"Connection attempt failed")) elif line.find('SIGTERM[soft,auth-failure]') != -1: self.status.emit("conn_attempt_failed{}".format(add)) self.log.emit(("info", "Authentication error while trying to connect")) #bugfix for double-hop #sometimes whitelisting servers via iptables fails so we retry #need to investigate further elif line.find('write UDP: Operation not permitted') != -1: ips = [] try: hop_ip = self.hop_dict["ip"] ips.append(hop_ip) except: pass remote_ip = self.server_dict["ip"] ips.append(remote_ip) for ip in ips: firewall.allow_dest_ip(ip, "-I") elif line.find("Exiting due to fatal error") != -1: self.status.emit("conn_attempt_failed{}".format(add)) self.log.emit(("info", "Connection attempt failed due to fatal error")) #break if openvpn emits empty lines to avoid clogging log elif line == '': break line = ovpn_exe.stdout.readline() if "bypass" not in self.server_dict and h != 1: exe_custom_scripts("down", self.server_dict["provider"], self.config) self.log.emit(("info", "OpenVPN:" + line.replace('{}'.format(time.asctime()), '').replace('\n', ''))) ovpn_exe.stdout.close() self.status.emit("tunnel_terminated{}".format(add)) self.log.emit(("info", "OpenVPN - process killed")) #delete outbound rule for this server firewall.allow_dest_ip(last_ip, "-D") #reset bypass so it can work without second OpenVPN tunnel if add == "_bypass": setattr(self, "dns{}".format(add), self.config["alt_dns1"]) setattr(self, "dns{}_2".format(add), self.config["alt_dns2"]) setattr(self, "tun{}".format(add), None) self.dnsserver.emit((add, self.config["alt_dns1"], self.config["alt_dns2"])) self.dev.emit(("tun{}".format(add), getattr(self, "tun{}".format(add)))) self.bypass.emit() else: setattr(self, "tun{}".format(add), None) self.dev.emit(("tun{}".format(add), getattr(self, "tun{}".format(add))))