def print_version(): """Prints the version of connord along with the copyright.""" printer = Printer() print("connord {}".format(__version__), file=printer) print(__copyright__, file=printer) printer.info("\nConfiguration directory: '{}'".format( resources.get_config_dir()))
def _update_openvpn_conf(force): printer = Printer() try: resources.get_zip_dir(create=False) initial_run = False except resources.ResourceNotFoundError: initial_run = True if force or initial_run: get() unzip() else: update_archives = False for archive in __ARCHIVES.values(): zip_file = resources.get_zip_path(archive) # if one archive needs an update all archives are updated if update_needed(zip_file): update_archives = True break else: raise UpdateError( "Just one update per hour allowed. Use --force to ignore " "the timeout." ) if update_archives: get() for archive in __ARCHIVES.values(): zip_file = resources.get_zip_path(archive) orig_file = resources.get_zip_path(archive + ".orig") if not file_equals(orig_file, zip_file): unzip() break else: printer.info("Configurations are up-to-date.")
def ping(server): """ Ping a server :param dict server: A server as dictionary :returns: copy of server with additional key 'ping' """ server_copy = server.copy() pattern = re.compile(r"rtt .* = ([\d\.]+)/([\d\.]+)/([\d\.]+)/.* ms") ip_address = server["ip_address"] with subprocess.Popen( ["ping", "-q", "-n", "-c", "1", "-l", "1", "-W", "1", ip_address], stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) as ping_: out, _ = ping_.communicate() mat = pattern.search(out.decode()) if mat: server_copy["ping"] = float(mat.group(2)) else: server_copy["ping"] = float("inf") printer = Printer() printer.info( "{:6}: ping: {}".format(server_copy["domain"], server_copy["ping"]) ) return server_copy
def run(self): """High-level command to run openvpn with the assembled command-line. Shuts down openvpn after a timeout. Waits this time for openvpn to startup and writes the environment files from the scripts. As soon as they are present iptables rules are applied. If something goes wrong call the panic method :returns: True if everything went fine or running in daemon mode. """ config_dict = resources.get_config()["openvpn"] self.cleanup() printer = Printer() printer.info("Running openvpn with '{}'".format(self.cmd)) with subprocess.Popen(self.cmd) as ovpn: # give openvpn a maximum of 60 seconds to startup. A lower value is bad if # asked for username/password. # pylint: disable=unused-variable for i in range(300): try: if self.is_running(ovpn): # delay initialization of iptables until resource files are # created. If none are created the delay still applies as normal # timeout time.sleep(0.2) for script in config_dict["scripts"]: stage = script["stage"] if stage in ("up", "always"): resources.get_stats_file( stats_name=script["creates"], create=False ) else: self.panic(ovpn, "Openvpn process stopped unexpected.") if iptables.apply_config_dir(self.server, self.protocol): resources.write_stats(self.server, stats_name="server") stats_dict = resources.get_stats() stats_dict["last_server"] = {} stats_dict["last_server"]["domain"] = self.domain stats_dict["last_server"]["protocol"] = self.protocol resources.write_stats(stats_dict) else: self.panic(ovpn, "Applying iptables failed.") break except resources.ResourceNotFoundError: pass ### for else: self.panic(ovpn, "Timeout reached.") if self.is_running(ovpn): ovpn.wait() return True
def connect( domain, countries_, areas_, features_, categories_, netflix, load_, match, daemon, openvpn, protocol, ): """High-level function to connect to a openvpn server. Filters servers and tries to connect to an openvpn server 'max_retries' times or else raise an exception. :param domain: list of domains. defaults to one value 'best'. :param countries_: list of countries :param areas_: list of areas :param features_: list of features :param categories_: list of categories :param netflix: True to filter netflix optimized servers :param load_: depending on match, filter by max, min or equal load servers :param match: may be 'max', 'min' or 'equal' :param daemon: True if openvpn shall run in daemon mode :param config_: the path to the openvpn configuration file :param openvpn: options to pass-through to openvpn as string :param protocol: may be 'udp' or 'tcp' :returns: True if running openvpn was successful :raises: ConnectError """ if "best" not in domain: return connect_to_specific_server(domain, openvpn, daemon, protocol) servers_ = servers.get_servers() servers_ = filter_servers( servers_, netflix, countries_, areas_, features_, categories_, load_, match ) best_servers = filter_best_servers(servers_) max_retries = 3 printer = Printer() for i, server in enumerate(best_servers): if i == max_retries: raise ConnectError("Maximum retries reached.") if categories.has_category(server, "Obfuscated Servers"): if not printer.yes_no( ( "WARNING: {} is an obfuscated server.\n" "This may fail if not configured properly.\n" "Are you sure you want to continue?" ).format(server["domain"]) ): continue if server["ping"] != inf: printer.info( "Trying to connect to {}: {} ms".format( server["domain"], server["ping"] ) ) printer.print_map(server["location"]["lat"], server["location"]["long"]) if run_openvpn(server, openvpn, daemon, protocol): return True # else give the next server a try else: raise ConnectError("No server left with a valid ping.") raise ConnectError("No server found to establish a connection.")