Block SDK-managed secondary connector peers
This commit is contained in:
@@ -85,8 +85,26 @@ def validate_unpinned_sdk_http_url(
|
||||
|
||||
active_policy = policy or outbound_http_policy()
|
||||
validate_outbound_http_url(value, label=label, policy=active_policy)
|
||||
_raise_unpinned_transport(label)
|
||||
|
||||
|
||||
def validate_unpinned_sdk_host(
|
||||
hostname: str,
|
||||
*,
|
||||
port: int,
|
||||
label: str,
|
||||
policy: OutboundHttpPolicy | None = None,
|
||||
) -> None:
|
||||
"""Validate a host and then reject an SDK that may select another peer."""
|
||||
|
||||
active_policy = policy or outbound_http_policy()
|
||||
validate_outbound_host(hostname, port=port, label=label, policy=active_policy)
|
||||
_raise_unpinned_transport(label)
|
||||
|
||||
|
||||
def _raise_unpinned_transport(label: str) -> None:
|
||||
raise OutboundHttpBlocked(
|
||||
f"{label} uses an SDK that cannot pin connection peers or revalidate every SDK-managed redirect; "
|
||||
f"{label} uses an SDK that cannot pin every connection peer or revalidate SDK-managed redirects/referrals; "
|
||||
"it is disabled until that transport supports connection-time DNS/IP pinning"
|
||||
)
|
||||
|
||||
@@ -154,41 +172,6 @@ def create_outbound_connection(
|
||||
raise OutboundHttpBlocked(f"{label} hostname did not resolve to a usable address")
|
||||
|
||||
|
||||
def pinned_outbound_hostname(
|
||||
hostname: str,
|
||||
*,
|
||||
port: int,
|
||||
label: str = "Connector host",
|
||||
policy: OutboundHttpPolicy | None = None,
|
||||
) -> str:
|
||||
"""Return a validated numeric target for a transport without socket injection.
|
||||
|
||||
Public-only deployments may safely replace a DNS name with its validated
|
||||
numeric answer. Private-network deployments fail closed for DNS names: a
|
||||
protocol SDK may need the original name for authentication, so silently
|
||||
replacing it would not be a generally safe pinning strategy. Explicit IP
|
||||
endpoints remain usable after the normal address checks.
|
||||
"""
|
||||
|
||||
active_policy = policy or outbound_http_policy()
|
||||
host = str(hostname).strip().rstrip(".")
|
||||
if active_policy.allow_private_networks:
|
||||
try:
|
||||
ipaddress.ip_address(host.split("%", 1)[0])
|
||||
except ValueError as exc:
|
||||
raise OutboundHttpBlocked(
|
||||
f"{label} uses a hostname with a transport that cannot pin DNS resolution while private-network "
|
||||
"access is enabled; use an explicit IP endpoint or a connector transport with connection-time "
|
||||
"DNS/IP pinning"
|
||||
) from exc
|
||||
records = _resolved_address_records(host, port=port, label=label, policy=active_policy)
|
||||
if active_policy.allow_private_networks:
|
||||
return host
|
||||
addresses = tuple(dict.fromkeys(str(item[4][0]).split("%", 1)[0] for item in records if item[4]))
|
||||
ipv4 = next((address for address in addresses if ":" not in address), None)
|
||||
return ipv4 or addresses[0]
|
||||
|
||||
|
||||
def build_outbound_http_opener(*handlers: urllib.request.BaseHandler) -> urllib.request.OpenerDirector:
|
||||
"""Build a proxy-free urllib opener whose sockets use approved addresses."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user