396 lines
12 KiB
Python
Executable File
396 lines
12 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
FREEDNS API MANAGER
|
|
Gère les domaines FreeDNS:
|
|
- Récupère liste des domaines disponibles
|
|
- Ajoute des sous-domaines
|
|
- Configure DNS (A, MX, TXT/SPF)
|
|
- Valide et teste
|
|
|
|
FreeDNS: https://freedns.afraid.org
|
|
"""
|
|
|
|
import psycopg2
|
|
import requests
|
|
import re
|
|
import hashlib
|
|
from bs4 import BeautifulSoup
|
|
from datetime import datetime
|
|
import time
|
|
|
|
DB_CONFIG = {
|
|
'host': 'localhost',
|
|
'database': 'adx_system',
|
|
'user': 'admin',
|
|
'password': 'admin123'
|
|
}
|
|
|
|
# FreeDNS Configuration
|
|
FREEDNS_CONFIG = {
|
|
'base_url': 'https://freedns.afraid.org',
|
|
'login_url': 'https://freedns.afraid.org/zc.php?from=L2R5bmFtaWMv',
|
|
'subdomain_url': 'https://freedns.afraid.org/subdomain/',
|
|
'registry_url': 'https://freedns.afraid.org/domain/registry/',
|
|
# Credentials - à configurer
|
|
'username': '',
|
|
'password': '',
|
|
'cookie': '', # Session cookie if logged in
|
|
}
|
|
|
|
def get_db():
|
|
return psycopg2.connect(**DB_CONFIG)
|
|
|
|
class FreeDNSClient:
|
|
def __init__(self, username=None, password=None, cookie=None):
|
|
self.session = requests.Session()
|
|
self.session.headers.update({
|
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
|
})
|
|
self.logged_in = False
|
|
|
|
if cookie:
|
|
self.session.cookies.set('dns_cookie', cookie)
|
|
self.logged_in = True
|
|
elif username and password:
|
|
self.login(username, password)
|
|
|
|
def login(self, username, password):
|
|
"""Login to FreeDNS"""
|
|
try:
|
|
# Get login page for any tokens
|
|
self.session.get(FREEDNS_CONFIG['base_url'])
|
|
|
|
# Login
|
|
data = {
|
|
'username': username,
|
|
'password': password,
|
|
'submit': 'Login',
|
|
'action': 'auth'
|
|
}
|
|
|
|
response = self.session.post(FREEDNS_CONFIG['login_url'], data=data)
|
|
|
|
if 'logout' in response.text.lower() or 'my account' in response.text.lower():
|
|
self.logged_in = True
|
|
print("✅ FreeDNS login successful")
|
|
return True
|
|
else:
|
|
print("❌ FreeDNS login failed")
|
|
return False
|
|
except Exception as e:
|
|
print(f"Login error: {e}")
|
|
return False
|
|
|
|
def get_available_domains(self, limit=50):
|
|
"""Get list of available public domains"""
|
|
try:
|
|
response = self.session.get(FREEDNS_CONFIG['registry_url'])
|
|
soup = BeautifulSoup(response.text, 'html.parser')
|
|
|
|
domains = []
|
|
|
|
# Parse domain list
|
|
for row in soup.find_all('tr'):
|
|
cells = row.find_all('td')
|
|
if len(cells) >= 3:
|
|
domain_link = cells[0].find('a')
|
|
if domain_link:
|
|
domain = domain_link.text.strip()
|
|
if '.' in domain and not domain.startswith('.'):
|
|
# Get domain info
|
|
hosts = cells[1].text.strip() if len(cells) > 1 else '0'
|
|
status = cells[2].text.strip() if len(cells) > 2 else 'unknown'
|
|
|
|
domains.append({
|
|
'domain': domain,
|
|
'hosts': hosts,
|
|
'status': status
|
|
})
|
|
|
|
if len(domains) >= limit:
|
|
break
|
|
|
|
return domains
|
|
except Exception as e:
|
|
print(f"Error fetching domains: {e}")
|
|
return []
|
|
|
|
def get_my_subdomains(self):
|
|
"""Get list of my subdomains"""
|
|
if not self.logged_in:
|
|
print("Not logged in")
|
|
return []
|
|
|
|
try:
|
|
response = self.session.get(FREEDNS_CONFIG['subdomain_url'])
|
|
soup = BeautifulSoup(response.text, 'html.parser')
|
|
|
|
subdomains = []
|
|
|
|
# Parse subdomain table
|
|
for row in soup.find_all('tr'):
|
|
cells = row.find_all('td')
|
|
if len(cells) >= 4:
|
|
subdomain = cells[0].text.strip()
|
|
record_type = cells[1].text.strip()
|
|
destination = cells[2].text.strip()
|
|
|
|
if subdomain and '.' in subdomain:
|
|
subdomains.append({
|
|
'subdomain': subdomain,
|
|
'type': record_type,
|
|
'destination': destination
|
|
})
|
|
|
|
return subdomains
|
|
except Exception as e:
|
|
print(f"Error fetching subdomains: {e}")
|
|
return []
|
|
|
|
def add_subdomain(self, subdomain, domain, record_type='A', destination=''):
|
|
"""Add a new subdomain"""
|
|
if not self.logged_in:
|
|
print("Not logged in")
|
|
return False
|
|
|
|
try:
|
|
# Get domain ID from registry
|
|
response = self.session.get(f"{FREEDNS_CONFIG['registry_url']}?q={domain}")
|
|
|
|
# Find domain ID in response
|
|
match = re.search(rf'domain_id=(\d+).*?{re.escape(domain)}', response.text)
|
|
if not match:
|
|
print(f"Domain {domain} not found in registry")
|
|
return False
|
|
|
|
domain_id = match.group(1)
|
|
|
|
# Add subdomain
|
|
data = {
|
|
'type': record_type,
|
|
'subdomain': subdomain,
|
|
'domain_id': domain_id,
|
|
'address': destination,
|
|
'submit': 'Save!'
|
|
}
|
|
|
|
response = self.session.post(
|
|
f"{FREEDNS_CONFIG['subdomain_url']}save.php",
|
|
data=data
|
|
)
|
|
|
|
if 'successfully' in response.text.lower() or subdomain in response.text:
|
|
print(f"✅ Added {subdomain}.{domain}")
|
|
return True
|
|
else:
|
|
print(f"❌ Failed to add subdomain")
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f"Error adding subdomain: {e}")
|
|
return False
|
|
|
|
def add_txt_record(self, subdomain, domain, txt_value):
|
|
"""Add TXT record (for SPF)"""
|
|
return self.add_subdomain(subdomain, domain, 'TXT', txt_value)
|
|
|
|
|
|
def save_domain_to_pool(domain, source='freedns'):
|
|
"""Save domain to database pool"""
|
|
conn = get_db()
|
|
cur = conn.cursor()
|
|
|
|
try:
|
|
cur.execute("""
|
|
INSERT INTO admin.domain_pool (domain, source, dns_provider, status)
|
|
VALUES (%s, %s, 'freedns', 'pending')
|
|
ON CONFLICT (domain) DO UPDATE SET
|
|
last_check = NOW()
|
|
RETURNING id
|
|
""", (domain, source))
|
|
conn.commit()
|
|
return cur.fetchone()[0]
|
|
except Exception as e:
|
|
print(f"Error saving domain: {e}")
|
|
return None
|
|
finally:
|
|
conn.close()
|
|
|
|
def fetch_and_save_domains(limit=100):
|
|
"""Fetch domains from FreeDNS and save to database"""
|
|
client = FreeDNSClient()
|
|
|
|
print("=" * 60)
|
|
print("📥 FETCHING FREEDNS DOMAINS")
|
|
print("=" * 60)
|
|
|
|
domains = client.get_available_domains(limit)
|
|
|
|
print(f"\nFound {len(domains)} domains")
|
|
|
|
saved = 0
|
|
for d in domains:
|
|
domain = d['domain']
|
|
if save_domain_to_pool(domain, 'freedns_registry'):
|
|
saved += 1
|
|
print(f" ✅ {domain}")
|
|
|
|
print(f"\n✅ Saved {saved} domains to pool")
|
|
return saved
|
|
|
|
def configure_freedns_credentials():
|
|
"""Interactive configuration of FreeDNS credentials"""
|
|
print("=" * 60)
|
|
print("🔧 FREEDNS CONFIGURATION")
|
|
print("=" * 60)
|
|
print("\nFreeDNS requires an account at https://freedns.afraid.org")
|
|
print("Create a free account and enter your credentials below.\n")
|
|
|
|
conn = get_db()
|
|
cur = conn.cursor()
|
|
|
|
# Check if already configured
|
|
cur.execute("""
|
|
SELECT config_value FROM admin.system_config
|
|
WHERE config_key = 'freedns_username'
|
|
""")
|
|
|
|
existing = cur.fetchone()
|
|
if existing:
|
|
print(f"Current username: {existing[0]}")
|
|
change = input("Change credentials? (y/n): ")
|
|
if change.lower() != 'y':
|
|
conn.close()
|
|
return
|
|
|
|
username = input("FreeDNS Username: ")
|
|
password = input("FreeDNS Password: ")
|
|
|
|
# Test login
|
|
client = FreeDNSClient(username=username, password=password)
|
|
|
|
if client.logged_in:
|
|
# Save to database
|
|
cur.execute("""
|
|
INSERT INTO admin.system_config (config_key, config_value)
|
|
VALUES ('freedns_username', %s)
|
|
ON CONFLICT (config_key) DO UPDATE SET config_value = EXCLUDED.config_value
|
|
""", (username,))
|
|
|
|
cur.execute("""
|
|
INSERT INTO admin.system_config (config_key, config_value)
|
|
VALUES ('freedns_password', %s)
|
|
ON CONFLICT (config_key) DO UPDATE SET config_value = EXCLUDED.config_value
|
|
""", (password,))
|
|
|
|
conn.commit()
|
|
print("\n✅ Credentials saved!")
|
|
else:
|
|
print("\n❌ Login failed, credentials not saved")
|
|
|
|
conn.close()
|
|
|
|
def get_stored_credentials():
|
|
"""Get stored FreeDNS credentials"""
|
|
conn = get_db()
|
|
cur = conn.cursor()
|
|
|
|
cur.execute("""
|
|
SELECT config_key, config_value FROM admin.system_config
|
|
WHERE config_key IN ('freedns_username', 'freedns_password')
|
|
""")
|
|
|
|
creds = dict(cur.fetchall())
|
|
conn.close()
|
|
|
|
return creds.get('freedns_username'), creds.get('freedns_password')
|
|
|
|
def show_status():
|
|
"""Show FreeDNS status"""
|
|
conn = get_db()
|
|
cur = conn.cursor()
|
|
|
|
print("=" * 60)
|
|
print("📊 FREEDNS STATUS")
|
|
print("=" * 60)
|
|
|
|
# Check credentials
|
|
username, password = get_stored_credentials()
|
|
print(f"\nCredentials: {'✅ Configured' if username else '❌ Not configured'}")
|
|
|
|
# Domain pool stats
|
|
cur.execute("""
|
|
SELECT source, status, COUNT(*)
|
|
FROM admin.domain_pool
|
|
WHERE source LIKE 'freedns%'
|
|
GROUP BY source, status
|
|
""")
|
|
|
|
print("\nDomain Pool:")
|
|
for source, status, count in cur.fetchall():
|
|
print(f" {source} / {status}: {count}")
|
|
|
|
conn.close()
|
|
|
|
def main():
|
|
import sys
|
|
|
|
# Ensure system_config table exists
|
|
conn = get_db()
|
|
cur = conn.cursor()
|
|
cur.execute("""
|
|
CREATE TABLE IF NOT EXISTS admin.system_config (
|
|
config_key VARCHAR(100) PRIMARY KEY,
|
|
config_value TEXT,
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
updated_at TIMESTAMP DEFAULT NOW()
|
|
)
|
|
""")
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
if len(sys.argv) < 2:
|
|
show_status()
|
|
print("\nUsage:")
|
|
print(" freedns-api.py status - Show status")
|
|
print(" freedns-api.py configure - Configure credentials")
|
|
print(" freedns-api.py fetch - Fetch available domains")
|
|
print(" freedns-api.py list - List my subdomains")
|
|
print(" freedns-api.py add <sub> <domain> <ip> - Add subdomain")
|
|
return
|
|
|
|
cmd = sys.argv[1]
|
|
|
|
if cmd == 'status':
|
|
show_status()
|
|
elif cmd == 'configure':
|
|
configure_freedns_credentials()
|
|
elif cmd == 'fetch':
|
|
fetch_and_save_domains()
|
|
elif cmd == 'list':
|
|
username, password = get_stored_credentials()
|
|
if username:
|
|
client = FreeDNSClient(username=username, password=password)
|
|
subdomains = client.get_my_subdomains()
|
|
print(f"\nMy Subdomains ({len(subdomains)}):")
|
|
for s in subdomains:
|
|
print(f" {s['subdomain']} ({s['type']}) → {s['destination']}")
|
|
else:
|
|
print("❌ Credentials not configured. Run: freedns-api.py configure")
|
|
elif cmd == 'add':
|
|
if len(sys.argv) < 5:
|
|
print("Usage: freedns-api.py add <subdomain> <domain> <ip>")
|
|
return
|
|
subdomain, domain, ip = sys.argv[2], sys.argv[3], sys.argv[4]
|
|
username, password = get_stored_credentials()
|
|
if username:
|
|
client = FreeDNSClient(username=username, password=password)
|
|
client.add_subdomain(subdomain, domain, 'A', ip)
|
|
else:
|
|
print("❌ Credentials not configured")
|
|
else:
|
|
print(f"Unknown command: {cmd}")
|
|
|
|
if __name__ == '__main__':
|
|
main()
|