def restart_network_manager(self): try: output = subprocess.run(["systemctl", "restart", "NetworkManager"], stdout=subprocess.PIPE) print("\nRestarted network manager\n") log.info(f"Sucessfully restarted Network Manager: \"{output.stdout.decode()}\"") except: log.warning(f"Unable to restart Network Manager.") print("Cant restart network manager")
def fastest_country(self): if self.check_for_running_ovpn_process(): print("VPN already running.") return False server_feature_filter = [1, 2] server_collection = [] self.server_manager.cache_servers() country = input("Which country to connect to: ").strip().upper() file = country+SERVER_FILE_TYPE #load country configurations try: with open(os.path.join(CACHE_FOLDER, file)) as file: server_list = json.load(file) except TypeError: print("Servers are not cached.") log.warning("Servers are not cached.") return False #load user preferences try: user_pref = self.user_manager.read_user_data() except: print("Profile was not initialized.") log.warning("User profile was not initialized.") return False #filter by features and tier for server in server_list['serverList']: if server_list['serverList'][server]['features'] not in server_feature_filter and server_list['serverList'][server]['tier'] <= user_pref['tier']: server_collection.append(server_list['serverList'][server]) if not len(server_collection): print("Nothing") return False server_id, server_score, server_name, server_load = get_fastest_server(server_collection) user_pref['last_conn_server_id'] = server_id user_pref['last_conn_sever_name'] = server_name user_pref['last_conn_sever_protocol'] = user_pref['protocol'] server_req = req_for_ovpn_file(server_id, user_pref['protocol']) if not server_req: return False if not generate_ovpn_file(server_req): return False if not self.openvpn_connect(protocol=user_pref['protocol']): return False if not edit_file(USER_PREF_FILE, json.dumps(user_pref, indent=2), append=False): log.debug("Did not manage to save last connection preferences.") log.info(f"Updated user last connection data: \"{user_pref}\"")
def req_for_ovpn_file(server_id, user_protocol): """ Makes a request to ProtonVPN servers and returns with a OVPN template "file", returns False otherwise. """ url = f"https://api.protonmail.ch/vpn/config?Platform={OS_PLATFORM}&LogicalID={server_id}&Protocol={user_protocol}" try: log.info("Fetched request from ProtonVPN.") return requests.get(url, headers=(PROTON_HEADERS)) except: log.critical("Unable to fetch request from ProtonVPN.") return False
def manage_dns(action_type, dns_addr=False): resolv_conf_path = walk_to_file("/etc/", "resolv.conf", is_return_bool=False) if not resolv_conf_path: print("The \"resolv.conf\" file was not found on your system.") log.warning("\"resolv.conf\" file was not found.") return False log.info(f"Path to original resolv.conf: \"{resolv_conf_path}\"") print("Modifying dns...") if action_type == "custom": log.info("Applying custom ProtonVPN DNS...") cmd = f"cat > /etc/resolv.conf <<EOF \n# Generated by openvpn-linux-gui for ProtonVPN\nnameserver {dns_addr}\nEOF" try: shutil.copy(resolv_conf_path, RESOLV_BACKUP_FILE) except: print("Unable to backup DNS configurations.") log.warning("Unable to backup DNS configurations.") return False output = subprocess.run(["sudo", "bash", "-c", cmd], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if not output.returncode == 0: print("Unable to update DNS configurations") log.warning("Unable to apply custom ProtonVPN DNS configurations.") print("DNS updated with new configurations.") log.debug(f"...custom ProtonVPN DNS applied: {output}") return True elif action_type == "restore": log.info("Restoring original DNS...") try: with open(RESOLV_BACKUP_FILE) as f: content = f.read() cmd = f"cat > /etc/resolv.conf <<EOF \n{content}\nEOF" subprocess.run(["sudo", "bash", "-c", cmd]) print("...DNS configurations were restored.") delete_file(RESOLV_BACKUP_FILE) log.info( f"Original configurations restored from: \"{RESOLV_BACKUP_FILE}\"" ) return True except: print( "Unable to restore original DNS configurations, try restarting the Network Manager." ) log.warning("Unable to restore original DNS configurations.") return False
def copy_credentials(): cmds = [ f"mkdir /opt/{PROJECT_NAME}/", f"cp {USER_CRED_FILE} /opt/{PROJECT_NAME}/" ] try: if (not os.path.isdir("/opt/" + PROJECT_NAME + "/")): for cmd in cmds: subprocess.run(["sudo", "bash", "-c", cmd]) else: subprocess.run(["sudo", "bash", "-c", cmds[1]]) print("Copied credentials") log.info(f"Credentials were copied to: \"/opt/{PROJECT_NAME}\"") return True except: print("Unable to copy credentials") log.critical(f"Unable to copy credentials to: \"/opt/{PROJECT_NAME}\"") return False
def is_vpn_running(self): openvpn_PID = self.check_for_running_ovpn_process() cmd = "cat /etc/resolv.conf" res = subprocess.run(["sudo", "bash", "-c", cmd], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # log.info(f"PID is: {'NONE' if not openvpn_PID else openvpn_PID}") if openvpn_PID and (res.returncode == 0 and ("10.8.8.1" in res.stdout.decode() or "10.7.7.1" in res.stdout.decode())): print("VPN is running with custom DNS.") log.info(f"VPN is running\nOVPN PID:{openvpn_PID}\nDNF conf:\n{res.stdout.decode()}") return True elif openvpn_PID and not (res.returncode == 0 and ("10.8.8.1" in res.stdout.decode() or "10.7.7.1" in res.stdout.decode())): print("VPN is running, but there might be DNS leaks. Try modifying your DNS configurations.") log.warning(f"Resolv conf has original values, custom ProtonVPN DNS configuration not found: {res.stdout.decode()}") return True else: print("VPN is not running.") log.info("Could not find any OpenVPN processes.") return False
def generate_ovpn_for_boot(server_req): original_req = server_req.text start_index = original_req.find("auth-user-pass") modified_request = original_req[:start_index + 14] + " /opt/" + PROJECT_NAME + "/" + USER_CRED_FILE.split( "/")[-1] + original_req[start_index + 14:] ovpn_file_created = False append_to_file = "cat > /etc/openvpn/client/" + OVPN_FILE.split( "/")[-1].split(".")[0] + ".conf <<EOF " + modified_request + "\nEOF" try: output = subprocess.run(["sudo", "bash", "-c", append_to_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE) log.debug(f"Injection comand output: {output}") ovpn_file_created = True except: print("Unable to create configuration file in /openvpn/client/") log.critical(f"Could not generate/modify openVPN file.") return False print("Created new file in /openvpn/client/") log.info(f"\"Start on boot\" path to credentials injected.") if ovpn_file_created and walk_to_file( "/opt/", USER_CRED_FILE, in_dirs=True): log.critical( f"OVPN file for boot was NOT generated in: \"/etc/openvpn/client/\"" ) return False if not copy_credentials(): return False filename = OVPN_FILE.split("/")[-1].split(".")[0] log.info( f"OVPN file for boot was generated: \"/etc/openvpn/client/{filename}\"" ) return True
def openvpn_disconnect(self): openvpn_PID = self.check_for_running_ovpn_process() is_connected = False print("Disconnecting from vpn server...") log.info(f"PID is: {'NONE' if not openvpn_PID else openvpn_PID}") if not openvpn_PID: print("Unable to disconnect, no OpenVPN process was found.") log.warning("Could not find any OpenVPN processes.") return False try: is_connected = get_ip_info() except: is_connected = False log.info(f"Tested for internet connection: \"{is_connected}\"") if not manage_dns(action_type="restore"): log.critical("Unable to restore DNS prior to disconnecting from VPN, restarting NetworkManager might be needed.") if not manage_ipv6(action_type="restore"): log.warning("Unable to enable IPV6 prior to disconnecting from VPN.") # if not manage_killswitch(action_type="restore"): # return False output = subprocess.run(["sudo","kill", "-9", openvpn_PID], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # SIGTERM - Terminate opevVPN, ref: https://www.poftut.com/what-is-linux-sigterm-signal-and-difference-with-sigkill/ if output.returncode != 0: print("Unable to disconnecto from VPN.") log.critical(f"Unable to disconnecto from VPN, \"{output}\"") return False log.info("Disconnected from VPN.") print("You are disconnected from VPN.") return True
def manage_ipv6(action_type): if action_type == "disable": #check for error default_route = subprocess.run("ip route show | grep default", shell=True, stdout=subprocess.PIPE) if not default_route.returncode == 0: print("Could not find any IPv6 configurations.") log.debug( "Could not find any IPv6 configurations prior to disabling it." ) return False # show all ipv6 interfaces and their status #all_interfaces = subprocess.run(["sudo sysctl --all | grep disable_ipv6"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) default_nic = default_route.stdout.decode().strip().split()[4] ipv6_info = subprocess.run( f"ip addr show dev {default_nic} | grep '\<inet6.*global\>'", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if not ipv6_info.returncode == 0: log.debug(f"Could not find ipv6 {ipv6_info}") return False ipv6_addr = ipv6_info.stdout.decode().strip().split()[1] if walk_to_file(USER_FOLDER, IPV6_BACKUP_FILE.split("/")[-1]): delete_file(IPV6_BACKUP_FILE) log.info(f"Backup file was deleted: \"{IPV6_BACKUP_FILE}\"") ipv6_disable = subprocess.run( f"sudo sysctl -w net.ipv6.conf.{default_nic}.disable_ipv6=1", shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE) if not ipv6_disable.returncode == 0: log.debug(f"Unable to disable ipv6: {ipv6_disable}") return False try: with open(IPV6_BACKUP_FILE, "w") as file: file.write(default_nic + " " + ipv6_addr) except: print("Unable to save to file") return False print("Backup was made") return True elif action_type == "restore": log.info("Start IPV6 restore process.") try: with open(IPV6_BACKUP_FILE, "r") as file: content = file.read().split() default_nic = content[0].strip() ipv6_addr = content[1].strip() except: log.debug("Unable to open file.") return False ipv6_info = subprocess.run( f"ip addr show dev {default_nic} | grep '\<inet6.*global\>'", shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE) if ipv6_info.returncode == 0: log.debug("IPv6 already present.") delete_file(IPV6_BACKUP_FILE) return True ipv6_enable = subprocess.run( f"sudo sysctl -w net.ipv6.conf.{default_nic}.disable_ipv6=0", shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE) if not ipv6_enable.returncode == 0: print( "Unable to restore IPv6 configurations, restarting Network Manager might help." ) log.debug(f"IPv6 configuration restoration error: {ipv6_enable}") return False ipv6_restore_address = subprocess.run( f"sudo ip addr add {ipv6_addr} dev {default_nic}", shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE) if not ipv6_restore_address.returncode == 0: print("Unable to restore IPv6.") log.debug(f"IPv6 restoration error: {ipv6_restore_address}") return False log.debug("Removing IPv6 backup file.") delete_file(IPV6_BACKUP_FILE) log.debug("IPv6 restored") print("IPv6 restored") return True
def start_on_boot_manager(self, action): enabled_on_boot = True #load user preferences try: user_pref = self.user_manager.read_user_data() except: print("Profile was not initialized.") log.warning("User profile was not initialized.") return False if action == "enable": success_msg = "\"Launch on boot\" service enabled." fail_msg = "Cant enable \"launch on boot\" service." self.server_manager.cache_servers() server_collection = [] user_inp_country = input("Which country do you want to start on boot ? ").strip().upper() server_list_file = user_inp_country+SERVER_FILE_TYPE #load country configurations try: with open(os.path.join(CACHE_FOLDER, server_list_file)) as file: server_list = json.load(file) except TypeError: print("Servers are not cached.") log.warning("Servers are not cached.") return False print("Server name|\tServer Load|\tFeatures|\tTier") for server in server_list['serverList']: if server_list['serverList'][server]['tier'] <= user_pref['tier']: server_collection.append(server_list['serverList'][server]) print( server_list['serverList'][server]['name']+"|\t\t\t"+str(server_list['serverList'][server]['load'])+"|\t"+ str(server_list['serverList'][server]['features'])+"|\t\t"+str(server_list['serverList'][server]['tier']) ) if len(server_collection) == 0: print("No servers were found") return False user_selected_server = int(input("Which server to connecto on boot: ")) selected_server = [server for server in server_collection if str(user_selected_server) in server['name']][0] user_pref['on_boot_server_id'] = selected_server['id'] user_pref['on_boot_server_name'] = selected_server['name'] user_pref['on_boot_protocol'] = user_pref['protocol'] server_req = req_for_ovpn_file(selected_server['id'], user_pref['protocol']) if not server_req: return False if not generate_ovpn_for_boot(server_req): return False elif action == "kill": openvpn_PID = self.check_for_running_ovpn_process() if not openvpn_PID: print("Not PID was found") log.debug("Attempted to kill \"openvpn start on boot\" process, none found.") return False output = subprocess.run(["sudo","kill", "-9", openvpn_PID], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # SIGTERM - Terminate opevVPN, ref: https://www.poftut.com/what-is-linux-sigterm-signal-and-difference-with-sigkill/ if output.returncode != 0: print(f"Unable to kill PID {openvpn_PID}.") log.critical(f"Unable to disconnecto from VPN, \"{output}\"") return False self.restart_network_manager() return True elif action == "disable": success_msg = "\"Launch on boot\" service is disabled." fail_msg = "Cant disable service \"launch on boot\"." enabled_on_boot = False #here it should kill all openvpn processes and disable service daemon elif action == "restart": success_msg = "\"Launch on boot\" service was restarted." fail_msg = "Cant restart service \"launch on boot\"." try: output = subprocess.run(["sudo", "systemctl", action, ON_BOOT_PROCESS_NAME], stdout=subprocess.PIPE, stderr=subprocess.PIPE) log.debug(f"Start on boot log: {output}") except: print("\n"+fail_msg+"\n") log.critical("Something went wrong, could not enable \"start on boot\"") return False if not delete_folder_recursive(CACHE_FOLDER): log.debug("Unable to delete cache folder recursively.") print("\n"+success_msg+"\n") user_pref['on_boot_enabled'] = enabled_on_boot if not edit_file(USER_PREF_FILE, json.dumps(user_pref, indent=2), append=False): log.debug("Unable to save on boot preferences.") log.info(f"Start on boot created: \"{output.stdout.decode()}\"")
def openvpn_connect(self, protocol=False): openvpn_PID = self.check_for_running_ovpn_process() pre_vpn_conn_ip = False port_types = {"udp": 1194, "tcp": 443} if openvpn_PID: print("Unable to connect, a OpenVPN process is already running.") log.info("Unable to connect, a OpenVPN process is already running.") return False try: pre_vpn_conn_ip, pre_vpn_conn_isp = get_ip_info() except: pre_vpn_conn_ip = False pre_vpn_conn_isp = False log.info(f"Tested for internet connection: \"{pre_vpn_conn_ip}\"") if not pre_vpn_conn_ip: print("There is no internet connection.") log.warning("Unable to connect, check your internet connection.") print("Connecting to vpn server...") if not protocol: protocol = "udp" # Needs to be worked on, new way to connect to VPN, might help with killswitch with open(OVPN_LOG_FILE, "w+") as log_file: subprocess.Popen( [ "sudo", "openvpn", "--config", OVPN_FILE, "--auth-user-pass", USER_CRED_FILE ], stdout=log_file, stderr=log_file ) with open(OVPN_LOG_FILE, "r") as log_file: while True: content = log_file.read() log_file.seek(0) if "Initialization Sequence Completed" in content: print("VPN established") #change DNS dns_dhcp_regex = re.compile( r"(dhcp-option DNS )" r"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" ) dns_dhcp = dns_dhcp_regex.search(content) log.debug(f"DNS___RESULT: {dns_dhcp}") if dns_dhcp: dns_server = dns_dhcp.group(2) manage_dns(action_type="custom", dns_addr=dns_server) else: print("Could not apply custom DNS.") log.critical(f"Could not apply custom DNS: {dns_dhcp}") if not manage_ipv6(action_type="disable"): return False # if not manage_killswitch(action_type="enable", protocol=protocol, port=port_types[protocol]): # return False # compare old IP with new IP, if they are different the connection has succeded log.debug("Connected to the VPN.") return True elif "AUTH_FAILED" in content: print("Authentication failed") break