geoip_shop_manager.py aktualisiert

This commit is contained in:
2025-12-09 10:37:27 +01:00
parent 4e0960ccff
commit 6a253ad01d

View File

@@ -1,8 +1,10 @@
#!/usr/bin/env python3
"""
GeoIP Shop Blocker Manager - DACH Version
GeoIP Shop Blocker Manager - DACH & Eurozone Version
2-Component System: PHP blocking + Python watcher (systemd service)
Blocks all IPs outside Germany, Austria, and Switzerland (DACH region)
Supports two geo regions:
- DACH: Germany, Austria, Switzerland (3 countries)
- Eurozone+GB: All Eurozone countries + GB + CH (22 countries)
"""
import os
@@ -20,6 +22,7 @@ from pathlib import Path
COLOR_GREEN = "\033[92m"
COLOR_RED = "\033[91m"
COLOR_YELLOW = "\033[93m"
COLOR_BLUE = "\033[94m"
COLOR_RESET = "\033[0m"
COLOR_BOLD = "\033[1m"
@@ -33,13 +36,56 @@ DNS_CACHE = {}
VHOSTS_DIR = "/var/www/vhosts"
BACKUP_SUFFIX = ".geoip_backup"
BLOCKING_FILE = "geoip_blocking.php"
CACHE_FILE = "dach_ip_ranges.cache"
CACHE_FILE = "geoip_ip_ranges.cache"
LOG_FILE = "geoip_blocked.log"
CROWDSEC_QUEUE_FILE = "geoip_crowdsec_queue.log"
WATCHER_SCRIPT = "/usr/local/bin/geoip_crowdsec_watcher.py"
SYSTEMD_SERVICE = "/etc/systemd/system/geoip-crowdsec-watcher.service"
ACTIVE_SHOPS_FILE = "/var/lib/crowdsec/geoip_active_shops.json"
# =============================================================================
# GEO REGIONS
# =============================================================================
GEO_REGIONS = {
"dach": {
"name": "DACH",
"countries": ["de", "at", "ch"],
"description": "Deutschland, Österreich, Schweiz",
"icon": "🇩🇪🇦🇹🇨🇭",
"short": "DACH"
},
"eurozone": {
"name": "Eurozone + GB",
"countries": [
"de", # Deutschland
"at", # Österreich
"ch", # Schweiz
"be", # Belgien
"cy", # Zypern
"ee", # Estland
"es", # Spanien
"fi", # Finnland
"fr", # Frankreich
"gb", # Großbritannien
"gr", # Griechenland
"hr", # Kroatien
"ie", # Irland
"it", # Italien
"lt", # Litauen
"lu", # Luxemburg
"lv", # Lettland
"mt", # Malta
"nl", # Niederlande
"pt", # Portugal
"si", # Slowenien
"sk", # Slowakei
],
"description": "22 Länder: DE, AT, CH, BE, CY, EE, ES, FI, FR, GB, GR, HR, IE, IT, LT, LU, LV, MT, NL, PT, SI, SK",
"icon": "🇪🇺",
"short": "EU+"
}
}
# =============================================================================
# BOT DETECTION - Comprehensive list of known bots/crawlers
# =============================================================================
@@ -221,11 +267,23 @@ def format_shop_with_link11(shop, prefix="", show_index=None):
return f"{prefix}{color}{shop}{suffix}{COLOR_RESET}"
# PHP GeoIP blocking script (no exec, just logging)
GEOIP_SCRIPT = '''<?php
def get_geo_region_info(geo_region):
"""Get info for a geo region"""
return GEO_REGIONS.get(geo_region, GEO_REGIONS["dach"])
def generate_php_countries_array(geo_region):
"""Generate PHP array string for countries"""
region_info = get_geo_region_info(geo_region)
countries = region_info["countries"]
return ", ".join([f"'{c}'" for c in countries])
# PHP GeoIP blocking script template (with CrowdSec)
GEOIP_SCRIPT_TEMPLATE = '''<?php
/**
* GeoIP Blocking Script - Blocks all non-DACH IPs
* DACH = Germany (DE), Austria (AT), Switzerland (CH)
* GeoIP Blocking Script - Blocks all IPs outside allowed region
* Region: {region_name} ({region_description})
* Logs blocked IPs for CrowdSec watcher to process
* Valid until: {expiry_date}
*/
@@ -253,10 +311,12 @@ $cache_duration = 86400; // 24 hours
$log_file = __DIR__ . '/{log_file}';
$crowdsec_queue = __DIR__ . '/{crowdsec_queue}';
// Function to download DACH IP ranges (Germany, Austria, Switzerland)
function download_dach_ranges() {{
// Allowed countries
$allowed_countries = [{countries_array}];
// Function to download IP ranges for allowed countries
function download_allowed_ranges($countries) {{
$ranges = [];
$countries = ['de', 'at', 'ch']; // Germany, Austria, Switzerland
foreach ($countries as $country) {{
$url = "https://www.ipdeny.com/ipblocks/data/aggregated/$country-aggregated.zone";
@@ -286,27 +346,27 @@ function ip_in_range($ip, $cidr) {{
}}
// Load or download IP ranges
$dach_ranges = [];
$allowed_ranges = [];
if (file_exists($cache_file) && (time() - filemtime($cache_file)) < $cache_duration) {{
$dach_ranges = unserialize(file_get_contents($cache_file));
$allowed_ranges = unserialize(file_get_contents($cache_file));
}} else {{
$dach_ranges = download_dach_ranges();
if (!empty($dach_ranges)) {{
@file_put_contents($cache_file, serialize($dach_ranges));
$allowed_ranges = download_allowed_ranges($allowed_countries);
if (!empty($allowed_ranges)) {{
@file_put_contents($cache_file, serialize($allowed_ranges));
}}
}}
// Check if visitor IP is from DACH region
$is_dach = false;
foreach ($dach_ranges as $range) {{
// Check if visitor IP is from allowed region
$is_allowed = false;
foreach ($allowed_ranges as $range) {{
if (ip_in_range($visitor_ip, $range)) {{
$is_dach = true;
$is_allowed = true;
break;
}}
}}
// Block non-DACH IPs
if (!$is_dach) {{
// Block non-allowed IPs
if (!$is_allowed) {{
$timestamp = date('Y-m-d H:i:s');
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? 'Unknown';
$request_uri = $_SERVER['REQUEST_URI'] ?? '/';
@@ -324,11 +384,11 @@ if (!$is_dach) {{
}}
'''
# PHP GeoIP blocking script - PHP ONLY (no CrowdSec queue)
GEOIP_SCRIPT_PHP_ONLY = '''<?php
# PHP GeoIP blocking script template - PHP ONLY (no CrowdSec queue)
GEOIP_SCRIPT_TEMPLATE_PHP_ONLY = '''<?php
/**
* GeoIP Blocking Script - Blocks all non-DACH IPs (PHP-only mode)
* DACH = Germany (DE), Austria (AT), Switzerland (CH)
* GeoIP Blocking Script - Blocks all IPs outside allowed region (PHP-only mode)
* Region: {region_name} ({region_description})
* Logs blocked IPs (no CrowdSec synchronisation)
* Valid until: {expiry_date}
*/
@@ -355,10 +415,12 @@ $cache_file = __DIR__ . '/{cache_file}';
$cache_duration = 86400; // 24 hours
$log_file = __DIR__ . '/{log_file}';
// Function to download DACH IP ranges (Germany, Austria, Switzerland)
function download_dach_ranges() {{
// Allowed countries
$allowed_countries = [{countries_array}];
// Function to download IP ranges for allowed countries
function download_allowed_ranges($countries) {{
$ranges = [];
$countries = ['de', 'at', 'ch']; // Germany, Austria, Switzerland
foreach ($countries as $country) {{
$url = "https://www.ipdeny.com/ipblocks/data/aggregated/$country-aggregated.zone";
@@ -388,27 +450,27 @@ function ip_in_range($ip, $cidr) {{
}}
// Load or download IP ranges
$dach_ranges = [];
$allowed_ranges = [];
if (file_exists($cache_file) && (time() - filemtime($cache_file)) < $cache_duration) {{
$dach_ranges = unserialize(file_get_contents($cache_file));
$allowed_ranges = unserialize(file_get_contents($cache_file));
}} else {{
$dach_ranges = download_dach_ranges();
if (!empty($dach_ranges)) {{
@file_put_contents($cache_file, serialize($dach_ranges));
$allowed_ranges = download_allowed_ranges($allowed_countries);
if (!empty($allowed_ranges)) {{
@file_put_contents($cache_file, serialize($allowed_ranges));
}}
}}
// Check if visitor IP is from DACH region
$is_dach = false;
foreach ($dach_ranges as $range) {{
// Check if visitor IP is from allowed region
$is_allowed = false;
foreach ($allowed_ranges as $range) {{
if (ip_in_range($visitor_ip, $range)) {{
$is_dach = true;
$is_allowed = true;
break;
}}
}}
// Block non-DACH IPs
if (!$is_dach) {{
// Block non-allowed IPs
if (!$is_allowed) {{
$timestamp = date('Y-m-d H:i:s');
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? 'Unknown';
$request_uri = $_SERVER['REQUEST_URI'] ?? '/';
@@ -468,7 +530,7 @@ def add_to_crowdsec(ip, shop):
'--ip', ip,
'--duration', '72h',
'--type', 'ban',
'--reason', f'GeoIP: Non-DACH IP blocked by {shop}'
'--reason', f'GeoIP: Non-allowed IP blocked by {shop}'
]
try:
@@ -528,7 +590,7 @@ def process_queue_file(shop_path, shop):
return processed
def main():
log("🚀 GeoIP CrowdSec Watcher started (DACH mode)")
log("🚀 GeoIP CrowdSec Watcher started")
while True:
try:
@@ -564,7 +626,7 @@ if __name__ == "__main__":
# Systemd service file
SYSTEMD_SERVICE_CONTENT = '''[Unit]
Description=GeoIP CrowdSec Watcher Service (DACH)
Description=GeoIP CrowdSec Watcher Service
After=network.target crowdsec.service
Wants=crowdsec.service
@@ -652,8 +714,8 @@ def uninstall_watcher_service():
print(" ✅ Service deinstalliert")
def add_shop_to_active(shop, mode="php+crowdsec"):
"""Add shop to active shops tracking with mode"""
def add_shop_to_active(shop, mode="php+crowdsec", geo_region="dach"):
"""Add shop to active shops tracking with mode and geo region"""
os.makedirs(os.path.dirname(ACTIVE_SHOPS_FILE), exist_ok=True)
shops = {}
@@ -664,7 +726,8 @@ def add_shop_to_active(shop, mode="php+crowdsec"):
shops[shop] = {
"activated": datetime.now().isoformat(),
"expiry": (datetime.now() + timedelta(hours=72)).isoformat(),
"mode": mode # "php+crowdsec" or "php-only"
"mode": mode, # "php+crowdsec" or "php-only"
"geo_region": geo_region # "dach" or "eurozone"
}
with open(ACTIVE_SHOPS_FILE, 'w') as f:
@@ -684,6 +747,19 @@ def get_shop_mode(shop):
return "php+crowdsec"
def get_shop_geo_region(shop):
"""Get the geo region for a shop"""
if not os.path.isfile(ACTIVE_SHOPS_FILE):
return "dach"
try:
with open(ACTIVE_SHOPS_FILE, 'r') as f:
shops = json.load(f)
return shops.get(shop, {}).get("geo_region", "dach")
except:
return "dach"
def get_shop_activation_time(shop):
"""Get the activation timestamp for a shop"""
if not os.path.isfile(ACTIVE_SHOPS_FILE):
@@ -819,13 +895,43 @@ def get_active_shops():
return active
def activate_blocking(shop, silent=False, mode="php+crowdsec"):
def select_geo_region():
"""Interactive geo region selection"""
print(f"\n🌍 Wähle die Geo-Region:")
print(f" [1] {GEO_REGIONS['dach']['icon']} DACH - {GEO_REGIONS['dach']['description']}")
print(f" [2] {GEO_REGIONS['eurozone']['icon']} Eurozone+GB - {len(GEO_REGIONS['eurozone']['countries'])} Länder")
choice = input(f"\nRegion wählen [1/2]: ").strip()
if choice == "2":
return "eurozone"
else:
return "dach"
def select_mode():
"""Interactive mode selection"""
print(f"\n🔧 Wähle den Blocking-Modus:")
print(f" [1] PHP + CrowdSec (IPs werden an CrowdSec gemeldet)")
print(f" [2] Nur PHP (keine CrowdSec-Synchronisation)")
choice = input(f"\nModus wählen [1/2]: ").strip()
if choice == "2":
return "php-only"
else:
return "php+crowdsec"
def activate_blocking(shop, silent=False, mode="php+crowdsec", geo_region="dach"):
"""Activate GeoIP blocking for a single shop"""
httpdocs = os.path.join(VHOSTS_DIR, shop, 'httpdocs')
index_php = os.path.join(httpdocs, 'index.php')
backup_php = os.path.join(httpdocs, f'index.php{BACKUP_SUFFIX}')
blocking_file = os.path.join(httpdocs, BLOCKING_FILE)
region_info = get_geo_region_info(geo_region)
if os.path.isfile(backup_php):
if not silent:
print(f"⚠️ GeoIP-Blocking bereits aktiv für {shop}")
@@ -837,8 +943,8 @@ def activate_blocking(shop, silent=False, mode="php+crowdsec"):
return False
if not silent:
print(f"\n🔧 Aktiviere DACH GeoIP-Blocking für: {shop}")
print(" (Erlaubt: Deutschland, Österreich, Schweiz)")
print(f"\n🔧 Aktiviere {region_info['icon']} {region_info['name']} GeoIP-Blocking für: {shop}")
print(f" Erlaubt: {region_info['description']}")
print(f" Modus: {'PHP + CrowdSec' if mode == 'php+crowdsec' else 'Nur PHP'}")
print("=" * 60)
@@ -892,25 +998,31 @@ def activate_blocking(shop, silent=False, mode="php+crowdsec"):
print(" ✏️ index.php modifiziert")
expiry = datetime.now() + timedelta(hours=72)
countries_array = generate_php_countries_array(geo_region)
# Generate PHP script based on mode
if mode == "php+crowdsec":
geoip_content = GEOIP_SCRIPT.format(
geoip_content = GEOIP_SCRIPT_TEMPLATE.format(
region_name=region_info['name'],
region_description=region_info['description'],
expiry_date=expiry.strftime('%Y-%m-%d %H:%M:%S CET'),
expiry_timestamp=expiry.strftime('%Y-%m-%d %H:%M:%S'),
cache_file=CACHE_FILE,
log_file=LOG_FILE,
crowdsec_queue=CROWDSEC_QUEUE_FILE,
shop_name=shop
shop_name=shop,
countries_array=countries_array
)
else:
# PHP-only mode: no crowdsec queue writing
geoip_content = GEOIP_SCRIPT_PHP_ONLY.format(
geoip_content = GEOIP_SCRIPT_TEMPLATE_PHP_ONLY.format(
region_name=region_info['name'],
region_description=region_info['description'],
expiry_date=expiry.strftime('%Y-%m-%d %H:%M:%S CET'),
expiry_timestamp=expiry.strftime('%Y-%m-%d %H:%M:%S'),
cache_file=CACHE_FILE,
log_file=LOG_FILE,
shop_name=shop
shop_name=shop,
countries_array=countries_array
)
with open(blocking_file, 'w', encoding='utf-8') as f:
@@ -921,14 +1033,14 @@ def activate_blocking(shop, silent=False, mode="php+crowdsec"):
# Step 3: Register shop
if not silent:
print("\n[3/3] Registriere Shop...")
add_shop_to_active(shop, mode)
add_shop_to_active(shop, mode, geo_region)
if not silent:
print(" ✅ Shop registriert")
if not silent:
print("\n" + "=" * 60)
print(f"DACH GeoIP-Blocking aktiviert für: {shop}")
print(f" Erlaubte Länder: 🇩🇪 DE | 🇦🇹 AT | 🇨🇭 CH")
print(f"{region_info['icon']} {region_info['name']} GeoIP-Blocking aktiviert für: {shop}")
print(f" Erlaubte Länder: {region_info['description']}")
print(f" Modus: {'PHP + CrowdSec 🛡️' if mode == 'php+crowdsec' else 'Nur PHP 📝'}")
print(f" Gültig bis: {expiry.strftime('%Y-%m-%d %H:%M:%S CET')}")
print(f" PHP-Log: {os.path.join(httpdocs, LOG_FILE)}")
@@ -950,11 +1062,13 @@ def deactivate_blocking(shop, silent=False):
log_file = os.path.join(httpdocs, LOG_FILE)
queue_file = os.path.join(httpdocs, CROWDSEC_QUEUE_FILE)
# Get mode before removing from tracking
# Get mode and geo region before removing from tracking
shop_mode = get_shop_mode(shop)
shop_geo = get_shop_geo_region(shop)
region_info = get_geo_region_info(shop_geo)
if not silent:
print(f"\n🔧 Deaktiviere DACH GeoIP-Blocking für: {shop}")
print(f"\n🔧 Deaktiviere {region_info['icon']} {region_info['name']} GeoIP-Blocking für: {shop}")
print(f" Modus war: {'PHP + CrowdSec' if shop_mode == 'php+crowdsec' else 'Nur PHP'}")
print("=" * 60)
@@ -1011,7 +1125,7 @@ def deactivate_blocking(shop, silent=False):
if not silent:
print("\n" + "=" * 60)
print(f" DACH GeoIP-Blocking deaktiviert für: {shop}")
print(f"✅ GeoIP-Blocking deaktiviert für: {shop}")
print("=" * 60)
return True
@@ -1029,7 +1143,7 @@ def activate_all_shops():
return
print(f"\n{'=' * 60}")
print(f" DACH GeoIP-Blocking für ALLE Shops aktivieren")
print(f" GeoIP-Blocking für ALLE Shops aktivieren")
print(f"{'=' * 60}")
print(f"\n📋 Folgende {len(available_shops)} Shop(s) werden aktiviert:")
print(f" {COLOR_GREEN}Grün = hinter Link11{COLOR_RESET} | {COLOR_RED}Rot = Direkt{COLOR_RESET}\n")
@@ -1040,20 +1154,16 @@ def activate_all_shops():
link11_tag = "[Link11]" if link11_info['is_link11'] else "[Direkt]"
print(f"{color}{shop} {link11_tag}{COLOR_RESET}")
# Ask for mode
print(f"\n🔧 Wähle den Blocking-Modus:")
print(f" [1] PHP + CrowdSec (IPs werden an CrowdSec gemeldet)")
print(f" [2] Nur PHP (keine CrowdSec-Synchronisation)")
mode_choice = input(f"\nModus wählen [1/2]: ").strip()
# Ask for geo region
geo_region = select_geo_region()
region_info = get_geo_region_info(geo_region)
if mode_choice == "2":
mode = "php-only"
mode_display = "Nur PHP 📝"
else:
mode = "php+crowdsec"
mode_display = "PHP + CrowdSec 🛡️"
# Ask for mode
mode = select_mode()
mode_display = "PHP + CrowdSec 🛡️" if mode == "php+crowdsec" else "Nur PHP 📝"
print(f"\n⚠️ Dies aktiviert den Schutz für alle oben genannten Shops!")
print(f" Region: {region_info['icon']} {region_info['name']}")
print(f" Modus: {mode_display}")
confirm = input(f"\nFortfahren? (ja/nein): ").strip().lower()
@@ -1062,7 +1172,7 @@ def activate_all_shops():
return
print(f"\n{'=' * 60}")
print(f" Starte Aktivierung ({mode_display})...")
print(f" Starte Aktivierung ({region_info['icon']} {region_info['name']}, {mode_display})...")
print(f"{'=' * 60}")
success_count = 0
@@ -1122,29 +1232,37 @@ def activate_all_shops():
# Create blocking script based on mode
expiry = datetime.now() + timedelta(hours=72)
countries_array = generate_php_countries_array(geo_region)
if mode == "php+crowdsec":
geoip_content = GEOIP_SCRIPT.format(
geoip_content = GEOIP_SCRIPT_TEMPLATE.format(
region_name=region_info['name'],
region_description=region_info['description'],
expiry_date=expiry.strftime('%Y-%m-%d %H:%M:%S CET'),
expiry_timestamp=expiry.strftime('%Y-%m-%d %H:%M:%S'),
cache_file=CACHE_FILE,
log_file=LOG_FILE,
crowdsec_queue=CROWDSEC_QUEUE_FILE,
shop_name=shop
shop_name=shop,
countries_array=countries_array
)
else:
geoip_content = GEOIP_SCRIPT_PHP_ONLY.format(
geoip_content = GEOIP_SCRIPT_TEMPLATE_PHP_ONLY.format(
region_name=region_info['name'],
region_description=region_info['description'],
expiry_date=expiry.strftime('%Y-%m-%d %H:%M:%S CET'),
expiry_timestamp=expiry.strftime('%Y-%m-%d %H:%M:%S'),
cache_file=CACHE_FILE,
log_file=LOG_FILE,
shop_name=shop
shop_name=shop,
countries_array=countries_array
)
with open(blocking_file, 'w', encoding='utf-8') as f:
f.write(geoip_content)
# Register shop with mode
add_shop_to_active(shop, mode)
# Register shop with mode and geo region
add_shop_to_active(shop, mode, geo_region)
print(f" ✅ Aktiviert (bis {expiry.strftime('%Y-%m-%d %H:%M')})")
success_count += 1
@@ -1166,7 +1284,7 @@ def activate_all_shops():
for shop in failed_shops:
print(f"{shop}")
print(f"\n 🇩🇪 🇦🇹 🇨🇭 Nur DACH-Traffic erlaubt")
print(f"\n {region_info['icon']} Region: {region_info['name']}")
print(f" 🔧 Modus: {mode_display}")
print(f" ⏰ Gültig für 72 Stunden")
print(f"{'=' * 60}")
@@ -1181,7 +1299,7 @@ def deactivate_all_shops():
return
print(f"\n{'=' * 60}")
print(f" DACH GeoIP-Blocking für ALLE Shops deaktivieren")
print(f" GeoIP-Blocking für ALLE Shops deaktivieren")
print(f"{'=' * 60}")
print(f"\n📋 Folgende {len(active_shops)} Shop(s) werden deaktiviert:")
print(f" {COLOR_GREEN}Grün = hinter Link11{COLOR_RESET} | {COLOR_RED}Rot = Direkt{COLOR_RESET}\n")
@@ -1190,7 +1308,9 @@ def deactivate_all_shops():
link11_info = check_link11(shop)
color = COLOR_GREEN if link11_info['is_link11'] else COLOR_RED
link11_tag = "[Link11]" if link11_info['is_link11'] else "[Direkt]"
print(f"{color}{shop} {link11_tag}{COLOR_RESET}")
geo_region = get_shop_geo_region(shop)
region_info = get_geo_region_info(geo_region)
print(f"{color}{shop} {link11_tag}{COLOR_RESET} {region_info['icon']}")
print(f"\n⚠️ Dies deaktiviert den Schutz für alle oben genannten Shops!")
print(f"⚠️ Alle zugehörigen CrowdSec-Decisions werden ebenfalls entfernt!")
@@ -1404,6 +1524,11 @@ def show_all_logs():
bar = "" * min(int(req_min * 2), 20) if req_min > 0 else ""
runtime_str = format_duration(runtime) if runtime > 0 else "?"
# Get geo region icon
geo_region = get_shop_geo_region(shop)
region_info = get_geo_region_info(geo_region)
geo_icon = region_info['icon']
# Color shop name based on Link11 status
link11_info = check_link11(shop)
if link11_info['is_link11']:
@@ -1411,7 +1536,7 @@ def show_all_logs():
else:
shop_colored = f"{COLOR_RED}{shop}{COLOR_RESET}"
print(f" ├─ {shop_colored}: {count} ({req_min:.1f} req/min, seit {runtime_str}) {bar}")
print(f" ├─ {shop_colored} {geo_icon}: {count} ({req_min:.1f} req/min, seit {runtime_str}) {bar}")
# Show top IP for this shop
shop_ips = stats['ips']
@@ -1438,6 +1563,11 @@ def show_all_logs():
count = crowdsec_stats[shop]
bar = "" * min(count // 10, 20) if count > 0 else ""
# Get geo region icon
geo_region = get_shop_geo_region(shop)
region_info = get_geo_region_info(geo_region)
geo_icon = region_info['icon']
# Color shop name based on Link11 status
link11_info = check_link11(shop)
if link11_info['is_link11']:
@@ -1445,7 +1575,7 @@ def show_all_logs():
else:
shop_colored = f"{COLOR_RED}{shop}{COLOR_RESET}"
print(f" ├─ {shop_colored}: {count} {bar}")
print(f" ├─ {shop_colored} {geo_icon}: {count} {bar}")
elif check_crowdsec():
print(" └─ Keine aktiven Bans")
else:
@@ -1507,6 +1637,8 @@ def show_logs(shop):
httpdocs = os.path.join(VHOSTS_DIR, shop, 'httpdocs')
log_file = os.path.join(httpdocs, LOG_FILE)
shop_mode = get_shop_mode(shop)
shop_geo = get_shop_geo_region(shop)
region_info = get_geo_region_info(shop_geo)
# Get stats
blocks, ips, activation_time = get_shop_log_stats(shop)
@@ -1526,7 +1658,8 @@ def show_logs(shop):
mode_display = "PHP + CrowdSec 🛡️" if shop_mode == "php+crowdsec" else "Nur PHP 📝"
print(f"\n{'' * 70}")
print(f"📊 Logs für {shop} [{mode_display}]")
print(f"📊 Logs für {shop}")
print(f" {region_info['icon']} {region_info['name']} | {mode_display}")
print(f"{'' * 70}")
print(f"\n⏱️ Aktiviert: {activation_str}")
print(f"⏱️ Laufzeit: {runtime_str}")
@@ -1613,8 +1746,8 @@ def show_logs(shop):
def main():
"""Main menu"""
print("\n" + "=" * 60)
print(" GeoIP Shop Blocker Manager - DACH Version")
print(" Erlaubt: 🇩🇪 Deutschland | 🇦🇹 Österreich | 🇨🇭 Schweiz")
print(" GeoIP Shop Blocker Manager")
print(" Regionen: 🇩🇪🇦🇹🇨🇭 DACH | 🇪🇺 Eurozone+GB (22 Länder)")
print(" PHP + CrowdSec Watcher (systemd service)")
print("=" * 60)
@@ -1664,22 +1797,17 @@ def main():
if 0 <= shop_idx < len(available_shops):
selected_shop = available_shops[shop_idx]
# Ask for geo region
geo_region = select_geo_region()
region_info = get_geo_region_info(geo_region)
# Ask for mode
print(f"\n🔧 Wähle den Blocking-Modus:")
print(f" [1] PHP + CrowdSec (IPs werden an CrowdSec gemeldet)")
print(f" [2] Nur PHP (keine CrowdSec-Synchronisation)")
mode_choice = input(f"\nModus wählen [1/2]: ").strip()
mode = select_mode()
mode_display = "PHP + CrowdSec" if mode == "php+crowdsec" else "Nur PHP"
if mode_choice == "2":
mode = "php-only"
mode_display = "Nur PHP"
else:
mode = "php+crowdsec"
mode_display = "PHP + CrowdSec"
confirm = input(f"\n⚠️ DACH-Blocking ({mode_display}) aktivieren für '{selected_shop}'? (ja/nein): ").strip().lower()
confirm = input(f"\n⚠️ {region_info['icon']} {region_info['name']}-Blocking ({mode_display}) aktivieren für '{selected_shop}'? (ja/nein): ").strip().lower()
if confirm in ['ja', 'j', 'yes', 'y']:
activate_blocking(selected_shop, mode=mode)
activate_blocking(selected_shop, mode=mode, geo_region=geo_region)
else:
print("❌ Ungültig")
except ValueError:
@@ -1696,11 +1824,13 @@ def main():
print(f" {COLOR_GREEN}Grün = hinter Link11{COLOR_RESET} | {COLOR_RED}Rot = Direkt{COLOR_RESET}")
for i, shop in enumerate(active_shops, 1):
mode = get_shop_mode(shop)
geo_region = get_shop_geo_region(shop)
region_info = get_geo_region_info(geo_region)
mode_icon = "🛡️" if mode == "php+crowdsec" else "📝"
link11_info = check_link11(shop)
color = COLOR_GREEN if link11_info['is_link11'] else COLOR_RED
link11_tag = "[Link11]" if link11_info['is_link11'] else "[Direkt]"
print(f" [{i}] {color}{shop} {link11_tag}{COLOR_RESET} {mode_icon}")
print(f" [{i}] {color}{shop} {link11_tag}{COLOR_RESET} {region_info['icon']} {mode_icon}")
shop_choice = input("\nWähle einen Shop: ").strip()
try:
@@ -1726,11 +1856,13 @@ def main():
print(f" [0] 📊 ALLE Shops (Zusammenfassung)")
for i, shop in enumerate(active_shops, 1):
mode = get_shop_mode(shop)
geo_region = get_shop_geo_region(shop)
region_info = get_geo_region_info(geo_region)
mode_icon = "🛡️" if mode == "php+crowdsec" else "📝"
link11_info = check_link11(shop)
color = COLOR_GREEN if link11_info['is_link11'] else COLOR_RED
link11_tag = "[Link11]" if link11_info['is_link11'] else "[Direkt]"
print(f" [{i}] {color}{shop} {link11_tag}{COLOR_RESET} {mode_icon}")
print(f" [{i}] {color}{shop} {link11_tag}{COLOR_RESET} {region_info['icon']} {mode_icon}")
shop_choice = input("\nWähle eine Option: ").strip()
try:
@@ -1749,11 +1881,13 @@ def main():
active_shops = get_active_shops()
print(f"\n📊 Status:")
print(f" Shops gesamt: {len(shops)}")
print(f" Aktive DACH-Blockings: {len(active_shops)}")
print(f" Aktive GeoIP-Blockings: {len(active_shops)}")
print(f" {COLOR_GREEN}Grün = hinter Link11{COLOR_RESET} | {COLOR_RED}Rot = Direkt{COLOR_RESET}")
if active_shops:
for shop in active_shops:
mode = get_shop_mode(shop)
geo_region = get_shop_geo_region(shop)
region_info = get_geo_region_info(geo_region)
mode_icon = "🛡️" if mode == "php+crowdsec" else "📝"
mode_text = "PHP+CS" if mode == "php+crowdsec" else "PHP"
@@ -1772,7 +1906,7 @@ def main():
color = COLOR_GREEN if link11_info['is_link11'] else COLOR_RED
link11_tag = "[Link11]" if link11_info['is_link11'] else "[Direkt]"
print(f"{color}{shop} {link11_tag}{COLOR_RESET} [{mode_text}] {mode_icon} - {blocks} blocks ({req_min:.1f} req/min, {runtime_str})")
print(f"{color}{shop} {link11_tag}{COLOR_RESET} {region_info['icon']} [{mode_text}] {mode_icon} - {blocks} blocks ({req_min:.1f} req/min, {runtime_str})")
elif choice == "5":
activate_all_shops()