import os import subprocess import random import time 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 openvpn_manager import establish_vpn_connection, is_vpn_active, disconnect_vpn, get_external_ip # Variables CREDENTIAL_FILE = "nord.creds" OVPN_DIR = "ovpn_configs/ovpn_tcp" LOG_FILE = "openvpn.log" RESULT_FILE = "vpnlist.txt" # Check for debug flag DEBUG_MODE = False if len(sys.argv) > 1 and sys.argv[1] == "-d": DEBUG_MODE = True def debug_print(message): if DEBUG_MODE: print(message) # Open the log file in append mode if not in debug mode log_file = None # Define log_file in the global scope if not DEBUG_MODE: log_file = open('nord-checker.log', 'a') # Redirect stdout and stderr to the log file sys.stdout = log_file sys.stderr = log_file # Get current IP before starting (using get_external_ip) CURRENT_IP = get_external_ip() if CURRENT_IP is None: print(f"{datetime.datetime.now()} [Main Script]: Unable to get current IP. Exiting.") if not DEBUG_MODE: log_file.close() # Close the log file if it was opened sys.exit(1) # Exit if unable to get current IP else: print(f"{datetime.datetime.now()} [Main Script]: Current IP before VPN connections: {CURRENT_IP}") if not DEBUG_MODE: log_file.flush() # Terminate any existing OpenVPN connections try: result = subprocess.run(["pgrep", "openvpn"], check=True, capture_output=True) pids = result.stdout.decode().strip().split('\n') # Get PIDs as a list for pid in pids: subprocess.run(["kill", pid]) print(f"{datetime.datetime.now()} [Main Script]: Existing OpenVPN connections terminated.") if not DEBUG_MODE: log_file.flush() except subprocess.CalledProcessError: pass # No openvpn process found # Connect to PostgreSQL database conn, cursor = connect_to_database() # Download and extract OVPN configurations, and get the list of files to check debug_print(f"{datetime.datetime.now()} [Main Script]: Downloading and extracting OVPN configurations...") 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 # Process each OVPN file FILE_NUM = 1 for OVPN_FILE in ovpn_files_to_check: OVPN_FILENAME = os.path.basename(OVPN_FILE) debug_print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Processing OVPN file...") # 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 retry_count = 0 while retry_count < max_retries: 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, 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(): print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Error starting OpenVPN connection or authentication failed:") 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 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 else: break # Exit the retry loop if connection is successful # 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: while attempt < max_attempts: line = f.readline() if not line: time.sleep(1) attempt += 1 continue if "Initialization Sequence Completed" in line: print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: VPN connection established.") break elif "AUTH: Received control message: AUTH_FAILED" in line: 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 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() 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) 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) 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() if external_ip is None: print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Unable to get external IP. Skipping this OVPN file.") continue print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: External IP via VPN: {external_ip}") # Update or insert into database update_or_insert_ip(cursor, conn, OVPN_FILENAME, external_ip) except subprocess.CalledProcessError: print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: VPN connection failed to establish.") # 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 5 and 8 seconds sleep_time = random.randint(5, 8) 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() # Increment file number FILE_NUM += 1 # Close the database connection cursor.close() conn.close() # Close the log file if it was opened if not DEBUG_MODE: log_file.close()