#!/usr/bin/env python3
"""Resolve the sandbox egress allowlist to systemd IPAddressAllow properties."""

import argparse
import ipaddress
import json
import socket
import sys
from pathlib import Path


def load_hosts(config: Path) -> list[str]:
    payload = json.loads(config.read_text(encoding="utf-8"))
    hosts = payload.get("hosts")
    if payload.get("schema_version") != 1 or not isinstance(hosts, list) or not hosts:
        raise ValueError("egress allowlist must be schema_version 1 with a non-empty hosts list")
    if not all(isinstance(host, str) and host for host in hosts):
        raise ValueError("egress allowlist contains an invalid host")
    return hosts


def resolve_hosts(hosts: list[str]) -> list[str]:
    addresses: set[str] = set()
    for host in hosts:
        try:
            addresses.add(str(ipaddress.ip_address(host)))
            continue
        except ValueError:
            pass
        results = socket.getaddrinfo(host, None, type=socket.SOCK_STREAM)
        resolved = {str(ipaddress.ip_address(item[4][0])) for item in results}
        if not resolved:
            raise OSError(f"{host} resolved to no addresses")
        addresses.update(resolved)
    return sorted(addresses, key=lambda value: (ipaddress.ip_address(value).version, value))


def resolver_addresses(path: Path = Path("/etc/resolv.conf")) -> list[str]:
    addresses = []
    for line in path.read_text(encoding="utf-8").splitlines():
        fields = line.split()
        if len(fields) >= 2 and fields[0] == "nameserver":
            addresses.append(str(ipaddress.ip_address(fields[1].split("%", 1)[0])))
    if not addresses:
        raise ValueError("no DNS resolver addresses found")
    return addresses


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--config", required=True, type=Path)
    parser.add_argument("--host", action="append", default=[])
    args = parser.parse_args(argv)
    try:
        hosts = [*load_hosts(args.config), *args.host, *resolver_addresses()]
        for address in resolve_hosts(hosts):
            print(address)
    except (OSError, ValueError, json.JSONDecodeError) as exc:
        print(f"egress-policy: refusing unrestricted launch: {exc}", file=sys.stderr)
        return 12
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
