From 98acbc0119f877a93c18d9508731ac4d80f7b6eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Mon, 23 Feb 2026 15:15:39 +0100 Subject: [PATCH] haproxy map --- geoip_handler.py | 58 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/geoip_handler.py b/geoip_handler.py index 09e1115..74fb074 100644 --- a/geoip_handler.py +++ b/geoip_handler.py @@ -1147,21 +1147,26 @@ class ConfigGenerator: @staticmethod def generate_haproxy_map(country_networks: dict, aggregate: bool = True, redis_ips: set = None) -> str: """ - Generate HAProxy MAP file (IP COUNTRY format) + Generate HAProxy MAP file (CIDR COUNTRY format) """ + # Get metadata countries = sorted(country_networks.keys()) - - redisstats = None + redis_stats = None if redis_ips: - redisstats = {"total": len(redis_ips), "unique": len(redis_ips), "deduped": 0} + redis_stats = { + 'total': len(redis_ips), + 'unique': len(redis_ips), + 'deduped': 0 + } handler = GeoIPHandler() - metadata = generate_metadata(countries, country_networks, redisstats, handler) + metadata = generate_metadata(countries, country_networks, redis_stats, handler) - # Aggregate networks + # Aggregate networks (for header stats only, same style as ACL) all_networks = [] - for networks in country_networks.values(): - all_networks.extend(networks) + for nets in country_networks.values(): + all_networks.extend(nets) + if redis_ips: all_networks.extend(redis_ips) @@ -1170,7 +1175,7 @@ class ConfigGenerator: else: all_networks = sorted(list(set(all_networks))) - # Generate header + # Generate header (same style as ACL) config = "# " + "="*77 + "\n" config += "# HAProxy MAP Configuration\n" config += f"# Generated: {metadata['timestamp']}\n" @@ -1182,30 +1187,47 @@ class ConfigGenerator: config += "# Data sources:\n" config += metadata['sources_formatted'] + "\n" config += "# \n" - + if metadata['redis']: config += f"# {metadata['redis']['formatted']}\n" config += "# \n" - + config += "# Cache settings:\n" config += f"# Max age: {metadata['cache_max_age_hours']} hours ({metadata['cache_max_age_days']:.1f} days)\n" config += f"# Database: {metadata['cache_db_path']}\n" config += "# \n" config += "# Usage in HAProxy:\n" - config += "# acl banned_ips src -f /path/to/this_file.acl\n" - config += "# http-request deny if banned_ips\n" + config += "# map_beg(/path/to/geo.map) -m ip $src var(txn.country)\n" config += "# \n" config += "# " + "="*77 + "\n" config += "\n" - # MAP BODY - for network in all_networks: - country = next((c for c, nets in country_networks.items() if network in nets), 'XX') - config += f"{network} {country}\n" + # MAP BODY (per-country aggregation => poprawny country, brak XX, brak pustych wyników) + for country_code, nets in sorted(country_networks.items()): + if not nets: + continue + + if aggregate: + nets = ConfigGenerator._aggregate_networks(nets) + else: + nets = sorted(list(set(nets))) + + for network in nets: + config += f"{network} {country_code}\n" + + # Redis IPs (opcjonalnie jako osobna etykieta) + if redis_ips: + redis_list = list(redis_ips) + if aggregate: + redis_list = ConfigGenerator._aggregate_networks(redis_list) + else: + redis_list = sorted(list(set(redis_list))) + + for network in redis_list: + config += f"{network} REDIS\n" return config - @staticmethod def generate_haproxy_lua(country_networks: dict, aggregate: bool = True, redis_ips: set = None) -> str: """Generate HAProxy Lua script with detailed metadata header"""