Files

66 lines
2.5 KiB
Python

"""Expected provider domains (cloud, CDN, OS, PKI).
Used to lower severity, never to hide an observation. Extend with the
ANALYZER_BENIGN_DOMAINS environment variable (comma-separated suffixes).
"""
from __future__ import annotations
import os
from typing import Optional
BENIGN_SUFFIXES: set[str] = {
# Apple
"apple.com", "aaplimg.com", "icloud.com", "apple-dns.net", "cdn-apple.com",
"mzstatic.com", "itunes-apple.com", "apple.map.fastly.net", "push.apple.com",
"ls-apple.com.akadns.net", "edge.apple", "apple-cloudkit.com",
# Akamai
"akadns.net", "akamai.net", "akamaiedge.net", "akamai.com", "akamaized.net",
"akamaihd.net",
# AWS
"amazonaws.com", "cloudfront.net", "awsstatic.com", "aws.dev", "amazon.com",
# Google / Firebase
"googleapis.com", "google.com", "gstatic.com", "ggpht.com", "youtube.com",
"crashlytics.com", "firebaseio.com", "firebase.com", "app-measurement.com",
"googleusercontent.com", "google-analytics.com", "doubleclick.net", "1e100.net",
"googlevideo.com", "gvt1.com", "gvt2.com",
# Apple analytics endpoint used by many apps
"app-analytics-services.com",
# CDNs
"fastly.net", "fbcdn.net", "cloudflare.com", "cloudflare.net",
"cloudflare-dns.com", "edgekey.net", "edgesuite.net", "llnwd.net", "cdn77.org",
"azureedge.net", "aliyuncs.com", "alicdn.com",
# Microsoft
"microsoft.com", "windows.net", "azure.com", "windowsupdate.com", "office.com",
"msftncsi.com", "live.com", "msftconnecttest.com", "office365.com",
# PKI / time
"digicert.com", "sectigo.com", "letsencrypt.org", "globalsign.com", "godaddy.com",
"ntp.org", "pool.ntp.org", "time.apple.com", "time.google.com", "time.windows.com",
# Reverse-DNS / special-use
"in-addr.arpa", "ip6.arpa", "resolver.arpa", "arpa", "local", "home.arpa",
}
def _load_extra() -> set[str]:
raw = os.environ.get("ANALYZER_BENIGN_DOMAINS", "")
return {s.strip().lower().lstrip(".") for s in raw.split(",") if s.strip()}
_EXTRA = _load_extra()
def is_benign(name: Optional[str]) -> bool:
"""Whether a host name belongs to an expected provider."""
if not name:
return False
n = str(name).rstrip(".").lower()
return any(n == s or n.endswith("." + s) for s in BENIGN_SUFFIXES | _EXTRA)
def benign_name_for_ip(ctx, ip: Optional[str]) -> Optional[str]:
"""Return a benign provider name that resolved to the address, if any."""
for name in sorted(ctx.names_for_ip(ip)):
if is_benign(name):
return name
return None