update ovpn downloader to handle missing files.

This commit is contained in:
2024-09-07 17:34:15 -05:00
parent 6dd4e6f755
commit 99b39a53f8
2 changed files with 68 additions and 31 deletions

View File

@@ -6,7 +6,7 @@ import datetime
import re import re
import sys import sys
from psql_utils import connect_to_database, update_or_insert_ip 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 from openvpn_manager import establish_vpn_connection, is_vpn_active, disconnect_vpn, get_external_ip
# Variables # Variables
@@ -67,7 +67,7 @@ ovpn_files_to_check = download_and_extract_ovpn_configs(cursor, conn)
total_files = len(ovpn_files_to_check) total_files = len(ovpn_files_to_check)
debug_print(f"{datetime.datetime.now()} [Main Script]: Found {total_files} 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 # Process each OVPN file
FILE_NUM = 1 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...") 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 # Read credentials
with open(CREDENTIAL_FILE, 'r') as f: with open(CREDENTIAL_FILE, 'r') as f:
username = f.readline().strip() username = f.readline().strip()
password = f.readline().strip() password = f.readline().strip()
# Establish VPN connection (capture stdout and stderr) # Establish VPN connection (capture stdout and stderr)
max_retries = 3 # Maximum number of retries max_retries = 3
retry_count = 0 retry_count = 0
while retry_count < max_retries: while retry_count < max_retries:
openvpn_command = ["openvpn", "--config", f"{OVPN_DIR}/{OVPN_FILE}", openvpn_command = ["openvpn", "--config", f"{OVPN_DIR}/{OVPN_FILE}",
"--auth-user-pass", CREDENTIAL_FILE, "--daemon", "--auth-user-pass", CREDENTIAL_FILE, "--daemon",
"--log-append", LOG_FILE, "--verb", "3"] "--log-append", LOG_FILE, "--verb", "3"]
debug_print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Executing OpenVPN command: {' '.join(openvpn_command)}") debug_print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Executing OpenVPN command: {' '.join(openvpn_command)}")
process = subprocess.Popen(openvpn_command, process = subprocess.Popen(openvpn_command,
stdin=subprocess.PIPE, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE) stderr=subprocess.PIPE)
stdout, stderr = process.communicate(input=password.encode()) stdout, stderr = process.communicate(input=password.encode())
# Check for errors and print output # 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(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 # Explicitly disconnect VPN if there was an error or auth failure
disconnect_vpn() disconnect_vpn()
print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: VPN disconnected (due to error or auth failure).") 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...") print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Retrying connection in 10 seconds...")
time.sleep(10) time.sleep(10)
retry_count += 1 retry_count += 1
else: else:
print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Max retries reached. Skipping this OVPN file.") print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Max retries reached or config file error. Skipping this OVPN file.")
break # Exit the retry loop if max retries reached break
else: else:
break # Exit the retry loop if connection is successful break
# Wait for connection to establish (with backoff for auth failure) # 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...") print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Waiting for VPN connection to establish...")
max_attempts = 10 max_attempts = 10
attempt = 0 attempt = 0
backoff_time = 0 backoff_time = 0
with open(LOG_FILE, 'r') as f: with open(LOG_FILE, 'r') as f:
while attempt < max_attempts: while attempt < max_attempts:
line = f.readline() line = f.readline()
if not line: if not line:
time.sleep(1) time.sleep(1)
attempt += 1 attempt += 1
continue continue
@@ -135,29 +143,26 @@ for OVPN_FILE in ovpn_files_to_check:
backoff_time += 1 backoff_time += 1
if backoff_time >= 30: if backoff_time >= 30:
print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Authentication failed. Skipping this OVPN file.") 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).") 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() disconnect_vpn()
print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: VPN disconnected.") 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 # 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...") print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Waiting for {sleep_time} seconds before the next connection...")
time.sleep(sleep_time) time.sleep(sleep_time)
print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Resuming...") 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 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: try:
subprocess.run(["pgrep", "-f", OVPN_FILENAME], check=True, capture_output=True) 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) # Check external IP (with validation and retries)
external_ip = get_external_ip() external_ip = get_external_ip()
@@ -174,7 +179,7 @@ for OVPN_FILE in ovpn_files_to_check:
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: VPN connection failed to establish.") print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: VPN connection failed to establish.")
# Disconnect VPN # Disconnect VPN
disconnect_vpn() disconnect_vpn()
print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: VPN disconnected.") print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: VPN disconnected.")
if not DEBUG_MODE: if not DEBUG_MODE:

View File

@@ -2,13 +2,15 @@ import os
import subprocess import subprocess
import random import random
import datetime 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_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): 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. adds new entries to the database, and cleans up.
Returns a list of OVPN filenames that need to be checked. 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,)) 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()] ovpn_files_to_check = [row[0] for row in cursor.fetchall()]
return ovpn_files_to_check 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