major refactor, replace ovpn.zip file, leverage API instead.
This commit is contained in:
128
nord-checker.py
128
nord-checker.py
@@ -6,17 +6,20 @@ import datetime
|
|||||||
import requests
|
import requests
|
||||||
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, should_skip_file
|
||||||
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
|
||||||
|
from ovpn_template import DEFAULT_OVPN_CONFIG
|
||||||
|
|
||||||
# Variables
|
# Variables
|
||||||
CREDENTIAL_FILE = "nord.creds"
|
CREDENTIAL_FILE = "nord.creds"
|
||||||
OVPN_DIR = "ovpn_configs/ovpn_tcp"
|
TEMP_OVPN_DIR = "/tmp/ovpn_configs" # Directory for temporary OVPN files
|
||||||
LOG_FILE = "openvpn.log" # This is not used anymore
|
LOG_FILE = "openvpn.log" # This is not used anymore
|
||||||
RESULT_FILE = "vpnlist.txt"
|
RESULT_FILE = "vpnlist.txt"
|
||||||
PING_URL = "https://health.ext.ben.io/ping/a1a55915-1051-48ed-bd13-ea3f1717a3ee"
|
PING_URL = "https://health.ext.ben.io/ping/a1a55915-1051-48ed-bd13-ea3f1717a3ee"
|
||||||
|
|
||||||
|
# NordVPN API endpoint (updated to get all servers)
|
||||||
|
NORDVPN_API_URL = "https://api.nordvpn.com/v1/servers?limit=16384"
|
||||||
|
|
||||||
# Define DEBUG_MODE
|
# Define DEBUG_MODE
|
||||||
DEBUG_MODE = False
|
DEBUG_MODE = False
|
||||||
if len(sys.argv) > 1 and sys.argv[1] == "-d":
|
if len(sys.argv) > 1 and sys.argv[1] == "-d":
|
||||||
@@ -27,7 +30,7 @@ def debug_print(message):
|
|||||||
print(f"{datetime.datetime.now()} + [Debug Mode]:{message}")
|
print(f"{datetime.datetime.now()} + [Debug Mode]:{message}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
requests.get(PING_URL, timeout=10)
|
requests.get(PING_URL, auth=('local', 'local'), timeout=10)
|
||||||
print(f"{datetime.datetime.now()} [Main Script]: Ping sent to: %s" % PING_URL)
|
print(f"{datetime.datetime.now()} [Main Script]: Ping sent to: %s" % PING_URL)
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
# Log ping failure here...
|
# Log ping failure here...
|
||||||
@@ -64,7 +67,17 @@ def is_script_running():
|
|||||||
print(f"{datetime.datetime.now()} [Main Script]: Error checking for running instances: {e}")
|
print(f"{datetime.datetime.now()} [Main Script]: Error checking for running instances: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# Function to get a list of all NordVPN servers
|
||||||
|
def get_nordvpn_servers():
|
||||||
|
"""Fetches a list of all NordVPN servers from the API."""
|
||||||
|
try:
|
||||||
|
response = requests.get(NORDVPN_API_URL)
|
||||||
|
response.raise_for_status() # Raise an exception for bad status codes
|
||||||
|
servers = response.json()
|
||||||
|
return servers
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
print(f"{datetime.datetime.now()} [Main Script]: Error fetching NordVPN servers: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
# Get current IP before starting (using get_external_ip)
|
# Get current IP before starting (using get_external_ip)
|
||||||
@@ -91,76 +104,85 @@ except subprocess.CalledProcessError:
|
|||||||
# Connect to PostgreSQL database
|
# Connect to PostgreSQL database
|
||||||
conn, cursor = connect_to_database()
|
conn, cursor = connect_to_database()
|
||||||
|
|
||||||
# Download and extract OVPN configurations, and get the list of files to check
|
# Get the list of recommended NordVPN servers
|
||||||
debug_print(f"{datetime.datetime.now()} [Main Script]: Downloading and extracting OVPN configurations...")
|
servers = get_nordvpn_servers()
|
||||||
ovpn_files_to_check = download_and_extract_ovpn_configs(cursor, conn, debug_print=debug_print)
|
|
||||||
|
|
||||||
total_files = len(ovpn_files_to_check)
|
# Create the temporary directory if it doesn't exist
|
||||||
debug_print(f"{datetime.datetime.now()} [Main Script]: Found {total_files} OVPN files to check.")
|
if not os.path.exists(TEMP_OVPN_DIR):
|
||||||
print(f"{datetime.datetime.now()} [Main Script]: Found {total_files} OVPN files to check.")
|
os.makedirs(TEMP_OVPN_DIR)
|
||||||
|
|
||||||
# Process each OVPN file
|
# Process each server
|
||||||
FILE_NUM = 1
|
server_count = len(servers)
|
||||||
for OVPN_FILE in ovpn_files_to_check:
|
for index, server in enumerate(servers):
|
||||||
OVPN_FILENAME = os.path.basename(OVPN_FILE)
|
# Check if the server uses OpenVPN TCP Dedicated technology
|
||||||
|
technologies = server.get('technologies', [])
|
||||||
|
skip_server = any(tech.get('identifier') == 'openvpn_dedicated_tcp' for tech in technologies)
|
||||||
|
|
||||||
debug_print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Processing OVPN file...")
|
if skip_server:
|
||||||
|
server_name = server.get('hostname')
|
||||||
|
debug_print(f"{datetime.datetime.now()} [{index+1}/{server_count}] [{server_name}]: Skipping OpenVPN TCP Dedicated server.")
|
||||||
|
continue # Skip to the next server
|
||||||
|
|
||||||
# Check if the OVPN file exists, download if needed
|
server_name = server.get('hostname')
|
||||||
file_exists = download_ovpn_if_needed(OVPN_FILENAME, cursor, conn, debug_print=debug_print)
|
server_ip = server.get('station') # Get the server IP address
|
||||||
|
server_load = server.get('load', 'N/A') # Get server load, default to 'N/A' if not available
|
||||||
|
server_status = server.get('status', 'N/A') # Get server status, default to 'N/A' if not available
|
||||||
|
|
||||||
if not file_exists:
|
debug_print(f"{datetime.datetime.now()} [{index+1}/{server_count}] [{server_name}]: Load: {server_load}, Status: {server_status} Processing server... ")
|
||||||
print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Skipping, file not found and removed from database.")
|
|
||||||
FILE_NUM += 1
|
# Construct the temporary OVPN filename
|
||||||
|
ovpn_filename = f"{server_name}.tcp.ovpn"
|
||||||
|
ovpn_filepath = os.path.join(TEMP_OVPN_DIR, ovpn_filename)
|
||||||
|
|
||||||
|
# Check if the server should be skipped based on last check time
|
||||||
|
if should_skip_file(cursor, ovpn_filename, index+1, server_count, debug_print=debug_print):
|
||||||
|
debug_print(f"{datetime.datetime.now()} [{index+1}/{server_count}] [{server_name}]: Skipping server, checked within the last 3 days.")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Establish VPN connection
|
# Create temporary OVPN file from template
|
||||||
connection_successful, connection_message = establish_vpn_connection(f"{OVPN_DIR}/{OVPN_FILE}", CREDENTIAL_FILE, LOG_FILE, debug_print=debug_print)
|
with open(ovpn_filepath, "w") as f:
|
||||||
|
f.write(DEFAULT_OVPN_CONFIG.format(server_ip=server_ip, server_cn=server_name))
|
||||||
|
|
||||||
|
# Establish VPN connection
|
||||||
|
connection_successful, connection_message = establish_vpn_connection(
|
||||||
|
ovpn_filepath, CREDENTIAL_FILE, LOG_FILE, debug_print=debug_print
|
||||||
|
)
|
||||||
if connection_successful:
|
if connection_successful:
|
||||||
print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: {connection_message}")
|
print(f"{datetime.datetime.now()} [{index+1}/{server_count}] [{server_name}]: {connection_message}")
|
||||||
if not connection_successful:
|
|
||||||
print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Error starting OpenVPN connection:{connection_message}")
|
|
||||||
|
|
||||||
# Wait for a random time between 1 and 4 seconds
|
# Check if the VPN connection is active
|
||||||
sleep_time = random.randint(8, 15)
|
try:
|
||||||
print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Waiting for {sleep_time} seconds before the next connection...")
|
subprocess.run(["pgrep", "-f", ovpn_filename], check=True, capture_output=True)
|
||||||
time.sleep(sleep_time)
|
|
||||||
print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Resuming...")
|
|
||||||
|
|
||||||
continue # Skip to the next OVPN file
|
# Check external IP (with validation and retries)
|
||||||
|
external_ip = get_external_ip()
|
||||||
|
|
||||||
# Check if the VPN connection is active (using the function from openvpn_manager.py)
|
if external_ip is None:
|
||||||
try:
|
print(f"{datetime.datetime.now()} [{index+1}/{server_count}] [{server_name}]: Unable to get external IP. Skipping this server.")
|
||||||
subprocess.run(["pgrep", "-f", OVPN_FILENAME], check=True, capture_output=True)
|
continue
|
||||||
|
|
||||||
# Check external IP (with validation and retries)
|
print(f"{datetime.datetime.now()} [{index+1}/{server_count}] [{server_name}]: External IP via VPN: {external_ip}")
|
||||||
external_ip = get_external_ip()
|
|
||||||
|
|
||||||
if external_ip is None:
|
# Update or insert into database
|
||||||
print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: Unable to get external IP. Skipping this OVPN file.")
|
update_or_insert_ip(cursor, conn, ovpn_filename, external_ip)
|
||||||
continue
|
|
||||||
|
|
||||||
print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: External IP via VPN: {external_ip}")
|
except subprocess.CalledProcessError:
|
||||||
|
print(f"{datetime.datetime.now()} [{index+1}/{server_count}] [{server_name}]: VPN connection failed to establish.")
|
||||||
|
else:
|
||||||
|
print(f"{datetime.datetime.now()} [{index+1}/{server_count}] [{server_name}]: Error starting OpenVPN connection: {connection_message}")
|
||||||
|
|
||||||
# Update or insert into database
|
# Disconnect VPN
|
||||||
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()
|
disconnect_vpn()
|
||||||
print(f"{datetime.datetime.now()} [{FILE_NUM}/{total_files}] [{OVPN_FILENAME}]: VPN disconnected.")
|
print(f"{datetime.datetime.now()} [{index+1}/{server_count}] [{server_name}]: VPN disconnected.")
|
||||||
|
|
||||||
# Wait for a random time between 5 and 8 seconds
|
# Wait for a random time between 5 and 8 seconds
|
||||||
sleep_time = random.randint(5, 8)
|
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...")
|
print(f"{datetime.datetime.now()} [{index+1}/{server_count}] [{server_name}]: 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()} [{index+1}/{server_count}] [{server_name}]: Resuming...")
|
||||||
|
|
||||||
# Increment file number
|
# Clean up the temporary OVPN file
|
||||||
FILE_NUM += 1
|
os.remove(ovpn_filepath)
|
||||||
|
|
||||||
# Close the database connection
|
# Close the database connection
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|||||||
83
ovpn_template.py
Normal file
83
ovpn_template.py
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
# ovpn_template.py
|
||||||
|
DEFAULT_OVPN_CONFIG = """
|
||||||
|
client
|
||||||
|
dev tun
|
||||||
|
proto tcp
|
||||||
|
remote {server_ip} 443
|
||||||
|
resolv-retry infinite
|
||||||
|
remote-random
|
||||||
|
nobind
|
||||||
|
tun-mtu 1500
|
||||||
|
tun-mtu-extra 32
|
||||||
|
mssfix 1450
|
||||||
|
persist-key
|
||||||
|
persist-tun
|
||||||
|
ping 15
|
||||||
|
ping-restart 0
|
||||||
|
ping-timer-rem
|
||||||
|
reneg-sec 0
|
||||||
|
comp-lzo no
|
||||||
|
verify-x509-name CN={server_cn}
|
||||||
|
remote-cert-tls server
|
||||||
|
auth-user-pass
|
||||||
|
verb 3
|
||||||
|
pull
|
||||||
|
fast-io
|
||||||
|
cipher AES-256-CBC
|
||||||
|
auth SHA512
|
||||||
|
<ca>
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
</ca>
|
||||||
|
key-direction 1
|
||||||
|
<tls-auth>
|
||||||
|
#
|
||||||
|
# 2048 bit OpenVPN static key
|
||||||
|
#
|
||||||
|
-----BEGIN OpenVPN Static key V1-----
|
||||||
|
e685bdaf659a25a200e2b9e39e51ff03
|
||||||
|
0fc72cf1ce07232bd8b2be5e6c670143
|
||||||
|
f51e937e670eee09d4f2ea5a6e4e6996
|
||||||
|
5db852c275351b86fc4ca892d78ae002
|
||||||
|
d6f70d029bd79c4d1c26cf14e9588033
|
||||||
|
cf639f8a74809f29f72b9d58f9b8f5fe
|
||||||
|
fc7938eade40e9fed6cb92184abb2cc1
|
||||||
|
0eb1a296df243b251df0643d53724cdb
|
||||||
|
5a92a1d6cb817804c4a9319b57d53be5
|
||||||
|
80815bcfcb2df55018cc83fc43bc7ff8
|
||||||
|
2d51f9b88364776ee9d12fc85cc7ea5b
|
||||||
|
9741c4f598c485316db066d52db4540e
|
||||||
|
212e1518a9bd4828219e24b20d88f598
|
||||||
|
a196c9de96012090e333519ae18d3509
|
||||||
|
9427e7b372d348d352dc4c85e18cd4b9
|
||||||
|
3f8a56ddb2e64eb67adfc9b337157ff4
|
||||||
|
-----END OpenVPN Static key V1-----
|
||||||
|
</tls-auth>
|
||||||
|
"""
|
||||||
@@ -23,7 +23,7 @@ def connect_to_database():
|
|||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
return conn, cursor
|
return conn, cursor
|
||||||
|
|
||||||
def should_skip_file(cursor, filename):
|
def should_skip_file(cursor, filename, index, server_count, debug_print):
|
||||||
"""
|
"""
|
||||||
Checks if the given OVPN file should be skipped based on the last check time in the database.
|
Checks if the given OVPN file should be skipped based on the last check time in the database.
|
||||||
Returns True if it should be skipped, False otherwise.
|
Returns True if it should be skipped, False otherwise.
|
||||||
@@ -33,7 +33,7 @@ def should_skip_file(cursor, filename):
|
|||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
|
|
||||||
if row is None:
|
if row is None:
|
||||||
print(f"No record found for {filename} in the database.")
|
debug_print(f"{datetime.datetime.now()} [{index}/{server_count}] [{filename}]: Skipping OpenVPN TCP Dedicated server.")
|
||||||
return False # No record found, so don't skip
|
return False # No record found, so don't skip
|
||||||
|
|
||||||
last_check = row[0]
|
last_check = row[0]
|
||||||
|
|||||||
Reference in New Issue
Block a user