From 99b39a53f8ef9940808d1853d61a28577f4cf1b1 Mon Sep 17 00:00:00 2001 From: b3nw Date: Sat, 7 Sep 2024 17:34:15 -0500 Subject: [PATCH] update ovpn downloader to handle missing files. --- nord-checker.py | 61 +++++++++++++++++++++++++--------------------- ovpn_downloader.py | 38 ++++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 31 deletions(-) diff --git a/nord-checker.py b/nord-checker.py index e3220fe..2082e74 100644 --- a/nord-checker.py +++ b/nord-checker.py @@ -6,7 +6,7 @@ import datetime import re import sys from psql_utils import connect_to_database, update_or_insert_ip -from ovpn_downloader import download_and_extract_ovpn_configs +from ovpn_downloader import download_and_extract_ovpn_configs, download_ovpn_if_needed from openvpn_manager import establish_vpn_connection, is_vpn_active, disconnect_vpn, get_external_ip # Variables @@ -67,7 +67,7 @@ ovpn_files_to_check = download_and_extract_ovpn_configs(cursor, conn) total_files = len(ovpn_files_to_check) debug_print(f"{datetime.datetime.now()} [Main Script]: Found {total_files} OVPN files to check.") -debug_print(ovpn_files_to_check) # Print the list of OVPN files +#debug_print(ovpn_files_to_check) # Print the list of OVPN files # Process each OVPN file FILE_NUM = 1 @@ -76,55 +76,63 @@ for OVPN_FILE in ovpn_files_to_check: debug_print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Processing OVPN file...") + # Check if the OVPN file exists, download if needed + file_exists = download_ovpn_if_needed(OVPN_FILENAME, cursor, conn) + + if not file_exists: + print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Skipping, file not found and removed from database.") + FILE_NUM += 1 + continue + # Read credentials with open(CREDENTIAL_FILE, 'r') as f: username = f.readline().strip() password = f.readline().strip() # Establish VPN connection (capture stdout and stderr) - max_retries = 3 # Maximum number of retries + max_retries = 3 retry_count = 0 while retry_count < max_retries: - openvpn_command = ["openvpn", "--config", f"{OVPN_DIR}/{OVPN_FILE}", - "--auth-user-pass", CREDENTIAL_FILE, "--daemon", + openvpn_command = ["openvpn", "--config", f"{OVPN_DIR}/{OVPN_FILE}", + "--auth-user-pass", CREDENTIAL_FILE, "--daemon", "--log-append", LOG_FILE, "--verb", "3"] debug_print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Executing OpenVPN command: {' '.join(openvpn_command)}") - process = subprocess.Popen(openvpn_command, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, + process = subprocess.Popen(openvpn_command, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate(input=password.encode()) # Check for errors and print output - if process.returncode != 0 or "AUTH_FAILED" in stderr.decode(): + if process.returncode != 0 or "Error opening configuration file" in stderr.decode() or "AUTH_FAILED" in stderr.decode(): print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Error starting OpenVPN connection or authentication failed:") - print(stderr.decode()) - + print(stderr.decode()) + # Explicitly disconnect VPN if there was an error or auth failure disconnect_vpn() print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: VPN disconnected (due to error or auth failure).") - if retry_count < max_retries - 1: # Retry if not the last attempt + if retry_count < max_retries - 1 and "Error opening configuration file" not in stderr.decode(): print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Retrying connection in 10 seconds...") time.sleep(10) retry_count += 1 else: - print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Max retries reached. Skipping this OVPN file.") - break # Exit the retry loop if max retries reached + print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Max retries reached or config file error. Skipping this OVPN file.") + break else: - break # Exit the retry loop if connection is successful + break # Wait for connection to establish (with backoff for auth failure) print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Waiting for VPN connection to establish...") max_attempts = 10 attempt = 0 backoff_time = 0 - with open(LOG_FILE, 'r') as f: + with open(LOG_FILE, 'r') as f: while attempt < max_attempts: line = f.readline() if not line: - time.sleep(1) + time.sleep(1) attempt += 1 continue @@ -135,29 +143,26 @@ for OVPN_FILE in ovpn_files_to_check: backoff_time += 1 if backoff_time >= 30: print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Authentication failed. Skipping this OVPN file.") - break + break - if attempt == max_attempts or backoff_time >= 30: + if attempt == max_attempts or backoff_time >= 30: print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: VPN connection failed to establish (timeout or auth failure).") - # Disconnect VPN + # Disconnect VPN disconnect_vpn() print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: VPN disconnected.") - if not DEBUG_MODE: - log_file.flush() + # Wait for a random time between 1 and 4 seconds - sleep_time = random.randint(1, 4) + sleep_time = random.randint(1, 4) print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Waiting for {sleep_time} seconds before the next connection...") time.sleep(sleep_time) print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Resuming...") - if not DEBUG_MODE: - log_file.flush() + continue # Skip to the next OVPN file -# Check if the VPN connection is active (using the function from openvpn_manager.py) + # Check if the VPN connection is active (using the function from openvpn_manager.py) try: subprocess.run(["pgrep", "-f", OVPN_FILENAME], check=True, capture_output=True) - print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: VPN connection established.") # Check external IP (with validation and retries) external_ip = get_external_ip() @@ -174,7 +179,7 @@ for OVPN_FILE in ovpn_files_to_check: except subprocess.CalledProcessError: print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: VPN connection failed to establish.") - # Disconnect VPN + # Disconnect VPN disconnect_vpn() print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: VPN disconnected.") if not DEBUG_MODE: diff --git a/ovpn_downloader.py b/ovpn_downloader.py index 006ca58..257d2a3 100644 --- a/ovpn_downloader.py +++ b/ovpn_downloader.py @@ -2,13 +2,15 @@ import os import subprocess import random import datetime +import requests -OVPN_DIR = "/root/nordvpn/ovpn_configs/ovpn_tcp" +OVPN_DIR = "ovpn_configs" OVPN_ZIP_URL = "https://downloads.nordcdn.com/configs/archives/servers/ovpn.zip" +OVPN_LEGACY_URL = "https://downloads.nordcdn.com/configs/files/ovpn_legacy/servers/" def download_and_extract_ovpn_configs(cursor, conn): """ - Downloads the OVPN ZIP archive, extracts its contents, + Downloads the OVPN ZIP archive, extracts its contents, adds new entries to the database, and cleans up. Returns a list of OVPN filenames that need to be checked. """ @@ -38,4 +40,34 @@ def download_and_extract_ovpn_configs(cursor, conn): cursor.execute("SELECT file_name FROM ovpn_files WHERE last_exit_ip_check < %s OR last_exit_ip_check IS NULL", (three_days_ago,)) ovpn_files_to_check = [row[0] for row in cursor.fetchall()] - return ovpn_files_to_check \ No newline at end of file + return ovpn_files_to_check + +def download_ovpn_if_needed(filename, cursor, conn): + """ + Downloads the specified OVPN file from the legacy URL if it doesn't exist in the OVPN_DIR. + Removes the entry from the database if the file returns a 404 error. + Returns True if the file was downloaded or already exists, False if it was not found and removed from the database + """ + filepath = os.path.join(OVPN_DIR+"/ovpn_tcp/", filename) + + if os.path.exists(filepath): + print(f"{filename} already exists. Skipping download.") + return True + + url = OVPN_LEGACY_URL + filename + print(f"Attempting to download {filename} from legacy URL...") + response = requests.get(url) + + if response.status_code == 200: + with open(filepath, 'wb') as f: + f.write(response.content) + print(f"Downloaded {filename} from legacy URL.") + return True + elif response.status_code == 404: + print(f"{filename} not found on legacy URL: {filepath}. Removing from database.") # this is the updated line + cursor.execute("DELETE FROM ovpn_files WHERE file_name = %s", (filename,)) + conn.commit() + return False + else: + print(f"Error downloading {filename}: {response.status_code}") + return False