mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-21 06:12:21 +02:00
fix(url-safety): resolve NAT64 well-known prefix to IPv4 target
The R09 scholarly hardening routes every hop through check_outbound_url with block_private=True. On a DNS64/NAT64 network, an IPv4-only host can resolve through the RFC 6052 Well-Known Prefix. For example, export.arxiv.org resolved to 64:ff9b::924b:5b2a in the reproduced environment. CPython classifies that outer IPv6 prefix as reserved, so the URL guard rejected the request before examining the effective IPv4 destination. Decode addresses in exactly 64:ff9b::/96 to their embedded IPv4 destination and evaluate that destination under the strict outbound policy. The translated target is always checked with private-address blocking enabled. This prevents the NAT64 prefix from becoming a path to loopback, private, shared/CGNAT, link-local, multicast, unspecified, or other non-global IPv4 space. Network-specific translation prefixes are not decoded. In particular, 64:ff9b:1::/48 remains subject to the existing IPv6 policy. Coverage includes: - public IPv4 destinations embedded through the RFC 6052 prefix - loopback, link-local, private, CGNAT, multicast, unspecified, benchmark, and TEST-NET rejection - network-specific NAT64 prefixes remaining undecoded - deterministic scholarly provider tests without live DNS dependence - redirect query parameter isolation - relative redirect resolution - HTTP error fallback behavior - editor draft GET and DELETE behavior remaining unaffected R09, R11, and R01 were independently audited and otherwise left unchanged.
This commit is contained in:
@@ -4,6 +4,7 @@ The old src.search provider path aliases this module; these tests pin the
|
||||
behavior at the single implementation point.
|
||||
"""
|
||||
|
||||
import ipaddress
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
@@ -11,6 +12,34 @@ from services.search import core
|
||||
from services.search import providers
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _deterministic_outbound_dns(monkeypatch):
|
||||
"""Keep the outbound-URL policy running, but take it off live DNS.
|
||||
|
||||
``_scholarly_api_get`` validates each destination through
|
||||
``check_outbound_url`` before it reaches the mocked ``httpx`` transport, and
|
||||
that check resolves the hostname. Without this stub these tests depend on
|
||||
real DNS: on a DNS64/NAT64 network an IPv4-only host such as
|
||||
export.arxiv.org resolves to ``64:ff9b::<v4>``, so the lookup is judged on a
|
||||
synthesised address that has nothing to do with the title-resolution,
|
||||
fallback, request-parameter and ordering behaviour asserted here.
|
||||
|
||||
Only name resolution is replaced. The policy itself still runs in full, and
|
||||
a literal-IP host still resolves to itself, so a test that points at a
|
||||
prohibited address is still genuinely rejected. This is deliberately not a
|
||||
stand-in for SSRF/NAT64 coverage, which lives in tests/test_url_safety.py
|
||||
and tests/test_review_20260923_fixes.py.
|
||||
"""
|
||||
|
||||
def _resolve(host: str):
|
||||
try:
|
||||
return [str(ipaddress.ip_address(host))]
|
||||
except ValueError:
|
||||
return ["93.184.216.34"] # public, policy-clean
|
||||
|
||||
monkeypatch.setattr("src.url_safety._default_resolver", _resolve)
|
||||
|
||||
|
||||
def test_html_transport_fallback_preserves_query_constraints(monkeypatch):
|
||||
seen = []
|
||||
class Response:
|
||||
|
||||
Reference in New Issue
Block a user