diff --git a/deployment/migrations/009_add_microsoft_meta_lists.sql b/deployment/migrations/009_add_microsoft_meta_lists.sql new file mode 100644 index 0000000..62f320d --- /dev/null +++ b/deployment/migrations/009_add_microsoft_meta_lists.sql @@ -0,0 +1,33 @@ +-- Migration 009: Add Microsoft Azure and Meta/Facebook public lists +-- Date: 2026-01-02 + +-- Microsoft Azure IP ranges (whitelist - cloud provider) +INSERT INTO public_lists (name, url, type, format, enabled, description, fetch_interval) +VALUES ( + 'Microsoft Azure', + 'https://raw.githubusercontent.com/femueller/cloud-ip-ranges/master/microsoft-azure-ip-ranges.json', + 'whitelist', + 'json', + true, + 'Microsoft Azure cloud IP ranges - auto-updated from Azure Service Tags', + 3600 +) ON CONFLICT (name) DO UPDATE SET + url = EXCLUDED.url, + description = EXCLUDED.description; + +-- Meta/Facebook IP ranges (whitelist - major service provider) +INSERT INTO public_lists (name, url, type, format, enabled, description, fetch_interval) +VALUES ( + 'Meta (Facebook)', + 'https://raw.githubusercontent.com/parseword/util-misc/master/block-facebook/facebook-ip-ranges.txt', + 'whitelist', + 'plain', + true, + 'Meta/Facebook IP ranges (includes Instagram, WhatsApp, Oculus) from BGP AS32934/AS54115/AS63293', + 3600 +) ON CONFLICT (name) DO UPDATE SET + url = EXCLUDED.url, + description = EXCLUDED.description; + +-- Verify insertion +SELECT id, name, type, enabled, url FROM public_lists WHERE name IN ('Microsoft Azure', 'Meta (Facebook)'); diff --git a/python_ml/list_fetcher/parsers.py b/python_ml/list_fetcher/parsers.py index 66a03c3..0b98654 100644 --- a/python_ml/list_fetcher/parsers.py +++ b/python_ml/list_fetcher/parsers.py @@ -176,6 +176,70 @@ class GCPParser(ListParser): return ips +class AzureParser(ListParser): + """Parser for Microsoft Azure IP ranges JSON (Service Tags format)""" + + @staticmethod + def parse(content: str) -> Set[tuple[str, Optional[str]]]: + """ + Parse Azure Service Tags JSON format: + { + "values": [ + { + "name": "ActionGroup", + "properties": { + "addressPrefixes": ["1.2.3.0/24", "5.6.7.0/24"] + } + } + ] + } + """ + ips = set() + + try: + data = json.loads(content) + + for value in data.get('values', []): + properties = value.get('properties', {}) + prefixes = properties.get('addressPrefixes', []) + + for prefix in prefixes: + if prefix and ListParser.validate_ip(prefix): + ips.add(ListParser.normalize_cidr(prefix)) + + except json.JSONDecodeError: + pass + + return ips + + +class MetaParser(ListParser): + """Parser for Meta/Facebook IP ranges (plain CIDR list from BGP)""" + + @staticmethod + def parse(content: str) -> Set[tuple[str, Optional[str]]]: + """ + Parse Meta format (plain CIDR list): + 31.13.24.0/21 + 31.13.64.0/18 + 157.240.0.0/17 + """ + ips = set() + lines = content.strip().split('\n') + + for line in lines: + line = line.strip() + + # Skip empty lines and comments + if not line or line.startswith('#') or line.startswith('//'): + continue + + if ListParser.validate_ip(line): + ips.add(ListParser.normalize_cidr(line)) + + return ips + + class CloudflareParser(ListParser): """Parser for Cloudflare IP list""" @@ -264,6 +328,10 @@ PARSERS: Dict[str, type[ListParser]] = { 'aws': AWSParser, 'gcp': GCPParser, 'google': GCPParser, + 'azure': AzureParser, + 'microsoft': AzureParser, + 'meta': MetaParser, + 'facebook': MetaParser, 'cloudflare': CloudflareParser, 'iana': IANAParser, 'ntp': NTPPoolParser,