Skip to main content

volto/
policy.rs

1//! Destination policy: which targets this proxy is willing to reach.
2//!
3//! RFC 9298 §7 and RFC 9114 §4.4 both warn about the same thing from different
4//! angles: a proxy that will dial anything is a reflector, a port scanner, and a
5//! way to borrow the proxy's own source address. That last one is the sharpest —
6//! plenty of services trust `127.0.0.1` or a private range without further
7//! authentication, and the proxy is *inside* that perimeter.
8//!
9//! So the defaults deny private address space, and the operator can open it with
10//! `security.allow_private_networks` for the deployments where the point of the
11//! proxy is to reach a private network.
12//!
13//! # Normalization comes first
14//!
15//! `::ffff:127.0.0.1` is loopback wearing an IPv6 hat: the kernel routes it to
16//! 127.0.0.1, while a naive matcher sees an IPv6 address that matches none of the
17//! IPv4 rules. Every check therefore starts by canonicalizing
18//! ([`canonical`]), and the deprecated `::/96` compatible range is folded in for
19//! the same reason.
20//!
21//! # Two buckets
22//!
23//! * **Never allowed** — the unspecified address, the IPv4 broadcast address and
24//!   all multicast. These are not unicast targets at all; sending to them is an
25//!   amplification primitive, so `allow_private_networks` does not unlock them.
26//! * **Private** — everything RFC 6890 calls special-purpose and this proxy
27//!   might actually reach: `0.0.0.0/8`, loopback, RFC 1918, link-local, shared
28//!   address space, the benchmarking and documentation ranges, reserved space,
29//!   6to4 relay anycast, ULA, ORCHID, the local-use NAT64 prefix and the
30//!   deprecated IPv4-compatible and IPv6 site-local spaces. Denied by default,
31//!   unlocked by `allow_private_networks`.
32//!
33//! # Transition addresses are judged as IPv4
34//!
35//! The well-known NAT64 prefix, 6to4 and Teredo addresses embed an IPv4 address
36//! at a fixed place, and a host that routes them reaches exactly that address.
37//! `64:ff9b::7f00:1` is therefore 127.0.0.1 with three extra steps, and letting
38//! it past because it is syntactically a global IPv6 address would undo the
39//! whole IPv4 half of this module. `embedded_ipv4` unwraps them before any rule
40//! is applied.
41//!
42//! The local-use NAT64 prefix `64:ff9b:1::/48` (RFC 8215) is the one transition
43//! form that is not unwrapped. Its operator chooses the layout, RFC 8215 §5
44//! forbids a reader assuming one, and a guess can read a private target as
45//! public. The whole prefix sits in the private bucket instead.
46
47use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
48
49use crate::config;
50
51/// The destination rules in force for a connection.
52pub struct Policy {
53    /// Whether loopback and other private ranges may be dialled.
54    allow_private_networks: bool,
55    /// Target ports that are refused regardless of address.
56    ///
57    /// A `Vec` scanned linearly: realistic deny lists hold a handful of ports, so
58    /// a set would cost more in hashing than it saves in comparisons.
59    denied_ports: Vec<u16>,
60}
61
62impl Policy {
63    /// Builds the policy described by the `[security]` section.
64    pub fn new(security: &config::Security) -> Self {
65        Self {
66            allow_private_networks: security.allow_private_networks,
67            denied_ports: security.denied_ports.clone(),
68        }
69    }
70
71    /// Whether a target port may be reached at all.
72    ///
73    /// Checked before name resolution: it needs no address, and refusing early
74    /// means a denied port cannot be used to make the proxy run DNS lookups.
75    pub fn allows_port(&self, port: u16) -> bool {
76        !self.denied_ports.contains(&port)
77    }
78
79    /// Whether one resolved address may be dialled.
80    pub fn allows_address(&self, ip: IpAddr) -> bool {
81        let ip = canonical(ip);
82        // A transition address is judged as the IPv4 address it carries, since
83        // that is what a host routing it actually reaches. Done here rather than
84        // inside the two rules below because the verdict may be either of them:
85        // an embedded multicast or unspecified address is never allowed, an
86        // embedded private one is private.
87        let ip = embedded_ipv4(ip).map_or(ip, IpAddr::V4);
88
89        if is_never_allowed(ip) {
90            return false;
91        }
92        if is_private(ip) {
93            return self.allow_private_networks;
94        }
95
96        true
97    }
98
99    /// The subset of `addresses` this proxy may dial.
100    ///
101    /// A name that resolves to both a public and a private address keeps only the
102    /// public ones, which is what makes DNS rebinding onto loopback pointless.
103    pub fn allowed_addresses(&self, addresses: &[SocketAddr]) -> Vec<SocketAddr> {
104        addresses
105            .iter()
106            .copied()
107            .filter(|address| self.allows_address(address.ip()))
108            .collect()
109    }
110}
111
112/// Whether every resolved address is the unspecified address (`0.0.0.0` / `::`).
113///
114/// This is the shape a filtering resolver uses to say "no": ad and telemetry
115/// blockers answer a blocked name with the unspecified address rather than with
116/// NXDOMAIN. Those answers are refused by [`Policy::allows_address`] like any
117/// other unroutable target, but the refusal is routine housekeeping rather than
118/// evidence of anything — on a host whose resolver filters, it is the bulk of all
119/// refusals.
120///
121/// Callers use this to decide two things (decision D49). It picks the log level:
122/// a blackhole is an INFO, every other refusal a WARN. And it picks the answer:
123/// a blackholed name gets a 200 whose stream closes immediately, so the client
124/// sees a tunnel that opened and died — the same thing a transport without an
125/// in-band refusal channel shows it — while every other refusal keeps its 403
126/// and its RFC 9209 `destination_ip_prohibited` reason. The split exists because
127/// the blackhole decision was made by the resolver upstream, not by this proxy,
128/// and a refusal from this proxy would misattribute it.
129///
130/// The test is deliberately all-or-nothing, and deliberately narrow to the
131/// unspecified address:
132///
133/// * **All**, because a name resolving to `0.0.0.0` *and* `10.0.0.1` is not a
134///   blackhole. The private address is a real target that the policy just
135///   refused, which is exactly the SSRF-shaped evidence worth keeping loud.
136/// * **Unspecified only**, because loopback, RFC 1918 and the rest of the private
137///   space are what an attacker aims at, and a probe of them must stay visible.
138///   The unspecified address is the one entry in the deny list that reaches
139///   nothing at all.
140///
141/// An empty list is not a blackhole. It cannot arise on the paths that call this
142/// (resolution either fails or yields addresses), and "no addresses at all" is no
143/// reason to quieten a warning.
144pub fn is_dns_blackhole(addresses: &[SocketAddr]) -> bool {
145    !addresses.is_empty()
146        && addresses
147            .iter()
148            .all(|address| canonical(address.ip()).is_unspecified())
149}
150
151/// Normalizes an address into the form the kernel will actually route.
152///
153/// IPv4-mapped IPv6 (`::ffff:a.b.c.d`) becomes the IPv4 address it stands for.
154/// The deprecated IPv4-compatible range (`::a.b.c.d`, RFC 4291 §2.5.5.1) is left
155/// as IPv6 on purpose and handled by `is_private`, because mapping it to IPv4
156/// would turn `::1` into `0.0.0.1` and quietly lose the loopback meaning.
157pub fn canonical(ip: IpAddr) -> IpAddr {
158    match ip {
159        IpAddr::V6(v6) => v6.to_canonical(),
160        v4 => v4,
161    }
162}
163
164/// Addresses that are never a legitimate tunnel target.
165///
166/// Not affected by `allow_private_networks`: these are not unicast destinations,
167/// and a proxy that forwards to them is an amplifier (RFC 9298 §7).
168fn is_never_allowed(ip: IpAddr) -> bool {
169    match ip {
170        IpAddr::V4(v4) => v4.is_unspecified() || v4.is_broadcast() || v4.is_multicast(),
171        IpAddr::V6(v6) => v6.is_unspecified() || v6.is_multicast(),
172    }
173}
174
175/// Addresses only reachable when `allow_private_networks` is on.
176///
177/// The list is RFC 6890's special-purpose registry minus the entries
178/// [`is_never_allowed`] has already claimed. Everything on it is either not
179/// globally reachable or not a destination an internet-facing proxy has any
180/// business dialling, and every one of them is a way past
181/// `allow_private_networks = false` if it is missing: `100.64.0.0/10` is where a
182/// carrier-grade NAT keeps its subscribers, `198.18.0.0/15` is what some
183/// networks number their own infrastructure with, `192.0.0.0/24` holds protocol
184/// assignments including the DS-Lite `192.0.0.0/29` link, and `240.0.0.0/4` is
185/// routed inside more than one large private network in practice.
186///
187/// One entry is here despite having left the registry: `fec0::/10`, the IPv6
188/// site-local prefix RFC 3879 deprecated. New stacks treat it as global unicast,
189/// which is exactly why it is worth denying — a network that numbered its
190/// interior with it before 2004 still routes it, and nothing on the public
191/// internet answers there, so a request for it is either a mistake or a way in.
192///
193/// One entry is here because its contents cannot be read: `64:ff9b:1::/48`, the
194/// local-use NAT64 prefix (RFC 8215). It carries an IPv4 address, but the
195/// operator picks the layout and RFC 8215 §5 forbids assuming one, so the whole
196/// prefix follows the switch rather than the address it might contain
197/// ([`is_local_use_nat64`], and [`embedded_ipv4`] for the reasoning).
198///
199/// One entry is deliberately absent: `2001::/23`, RFC 6890 Table 22's IETF
200/// Protocol Assignments (from RFC 2928) — the IPv6 counterpart of the
201/// `192.0.0.0/24` this list does claim. Every one of its Source, Destination,
202/// Forwardable and Global attributes is "False\[1\]", and footnote \[1\] is "Unless
203/// allowed by a more specific allocation": inside the /23 sit allocations that
204/// are routed services rather than reserved space, `2001:1::1` and `2001:1::2`
205/// (the PCP and STUN anycast addresses) and `2001:4:112::/48` (AS112). Denying
206/// the whole block would take those with it, so it is left public and only the
207/// more-specific allocations worth denying are claimed one at a time — the
208/// benchmarking range, ORCHID and Teredo below.
209fn is_private(ip: IpAddr) -> bool {
210    match ip {
211        IpAddr::V4(v4) => {
212            let octets = v4.octets();
213
214            // `is_private` is 10/8, 172.16/12 and 192.168/16; `is_link_local` is
215            // 169.254/16.
216            // 0.0.0.0/8 — "this host on this network" (RFC 6890 Table 1, from
217            // RFC 1122). Only the all-zero address at the bottom of the block is
218            // `is_never_allowed`, and that check runs first; the rest of it is a
219            // source address a host uses before it has one, never a destination.
220            (octets[0] == 0)
221                || v4.is_loopback()
222                || v4.is_private()
223                || v4.is_link_local()
224                // 100.64.0.0/10 — shared address space (RFC 6598), i.e. the
225                // inside of a carrier-grade NAT.
226                || (octets[0] == 100 && octets[1] & 0xc0 == 64)
227                // 192.0.0.0/24 — IETF protocol assignments (RFC 6890).
228                || (octets[0] == 192 && octets[1] == 0 && octets[2] == 0)
229                // 198.18.0.0/15 — benchmarking (RFC 2544).
230                || (octets[0] == 198 && octets[1] & 0xfe == 18)
231                // 192.88.99.0/24 — 6to4 relay anycast (RFC 6890 Table 10, from
232                // RFC 3068). RFC 7526 deprecated the relays and the registry
233                // kept the entry, so the prefix now reaches whoever still
234                // announces it rather than any relay this proxy meant to use.
235                || (octets[0] == 192 && octets[1] == 88 && octets[2] == 99)
236                // 240.0.0.0/4 — reserved (RFC 1112 §4). The broadcast address at
237                // the top of it is already `is_never_allowed`, which runs first.
238                || octets[0] & 0xf0 == 240
239                || is_ipv4_documentation(octets)
240        }
241        IpAddr::V6(v6) => {
242            v6.is_loopback()
243                || is_unique_local(v6)
244                || is_unicast_link_local(v6)
245                || is_site_local(v6)
246                || is_ipv4_compatible(v6)
247                || is_ipv6_documentation(v6)
248                || is_ipv6_benchmarking(v6)
249                || is_orchid(v6)
250                || is_discard_only(v6)
251                || is_local_use_nat64(v6)
252        }
253    }
254}
255
256/// The three IPv4 documentation ranges (RFC 5737).
257///
258/// Reachable nowhere by definition, and the ranges examples and test fixtures
259/// are written with — so a request for one is a misconfiguration rather than a
260/// destination, and it should not turn into a connection attempt against
261/// whoever happens to announce them.
262fn is_ipv4_documentation(octets: [u8; 4]) -> bool {
263    // 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24.
264    (octets[0] == 192 && octets[1] == 0 && octets[2] == 2)
265        || (octets[0] == 198 && octets[1] == 51 && octets[2] == 100)
266        || (octets[0] == 203 && octets[1] == 0 && octets[2] == 113)
267}
268
269/// `2001:db8::/32` — the IPv6 documentation range (RFC 3849).
270fn is_ipv6_documentation(v6: Ipv6Addr) -> bool {
271    let segments = v6.segments();
272    segments[0] == 0x2001 && segments[1] == 0x0db8
273}
274
275/// `2001:2::/48` — the IPv6 benchmarking range (RFC 6890 Table 24, from
276/// RFC 5180).
277///
278/// The IPv6 counterpart of `198.18.0.0/15`, and there for the same reason: it is
279/// what a lab numbers a device under test with, so a request for it is either a
280/// misconfiguration or an attempt to reach that lab.
281fn is_ipv6_benchmarking(v6: Ipv6Addr) -> bool {
282    let segments = v6.segments();
283    segments[0] == 0x2001 && segments[1] == 0x0002 && segments[2] == 0x0000
284}
285
286/// `2001:10::/28` — ORCHID (RFC 6890 Table 26, from RFC 4843).
287///
288/// An ORCHID is a hash of a host identity, not a locator: nothing forwards one,
289/// so a tunnel to it can only ever hold a slot. The registry entry carries a
290/// termination date of March 2014 and its successor prefix `2001:20::/28` is not
291/// in RFC 6890, so only the original block is claimed here.
292fn is_orchid(v6: Ipv6Addr) -> bool {
293    let segments = v6.segments();
294    segments[0] == 0x2001 && segments[1] & 0xfff0 == 0x0010
295}
296
297/// `100::/64` — the discard-only prefix (RFC 6666).
298///
299/// Traffic to it is meant to be black-holed, which makes it a way to ask this
300/// proxy to open a tunnel that can only ever hold a slot.
301fn is_discard_only(v6: Ipv6Addr) -> bool {
302    let segments = v6.segments();
303    segments[0] == 0x0100 && segments[1..4].iter().all(|segment| *segment == 0)
304}
305
306/// `64:ff9b:1::/48`, the local-use NAT64 prefix (RFC 8215).
307///
308/// An address here is a translation of some IPv4 address, and the operator
309/// chooses where in the address that IPv4 address sits. RFC 8215 §5 says a
310/// reader must not guess: "they must not make any assumptions regarding the
311/// syntax or properties of those addresses (e.g., the existence and location of
312/// embedded IPv4 addresses)". So the whole prefix is private, and it is
313/// `allow_private_networks` that decides whether it may be dialled. See
314/// [`embedded_ipv4`] for what reading a layout would cost.
315fn is_local_use_nat64(v6: Ipv6Addr) -> bool {
316    v6.octets()[..6] == [0x00, 0x64, 0xff, 0x9b, 0x00, 0x01]
317}
318
319/// The IPv4 address an IPv6 transition address carries, if it carries one.
320///
321/// A host that routes any of these reaches the embedded IPv4 address, so this is
322/// what the IPv4 rules must be applied to — otherwise `2002:0a00:0001::` is a
323/// route to 10.0.0.1 that `allow_private_networks = false` never sees.
324///
325/// The three forms that matter here:
326///
327/// * `64:ff9b::/96` — the well-known NAT64 prefix (RFC 6052 §2.1), with the
328///   address in the last 32 bits;
329/// * `2002::/16` — 6to4 (RFC 3056), with the address at bits 16-47;
330/// * `2001::/32` — Teredo (RFC 4380 §4). The client's own IPv4 address is the
331///   last 32 bits with every bit inverted, which is the one this proxy would
332///   reach.
333///
334/// The deprecated `::/96` IPv4-compatible range is deliberately **not** here:
335/// unwrapping it would turn `::1` into 0.0.0.1 and lose the loopback meaning, so
336/// [`is_ipv4_compatible`] keeps claiming it wholesale instead.
337///
338/// # The local-use prefix is refused whole rather than read
339///
340/// The well-known prefix is fixed at /96 by RFC 6052 §3.1, so there is one
341/// answer for it. `64:ff9b:1::/48` is not like that. RFC 8215 §5: "64:ff9b:1::/48
342/// is intended as a technology-agnostic and generic reservation. A network
343/// operator may freely use it in combination with any kind of IPv4/IPv6
344/// translation mechanism deployed within their network." The same section
345/// forbids reading one of these addresses: "By default, IPv6 nodes and
346/// applications must not treat IPv6 addresses within 64:ff9b:1::/48 differently
347/// from other globally scoped IPv6 addresses. In particular, they must not make
348/// any assumptions regarding the syntax or properties of those addresses (e.g.,
349/// the existence and location of embedded IPv4 addresses)". RFC 6052 §2.2
350/// allows prefix lengths of 32, 40, 48, 56, 64 and 96, and the four that are /48
351/// or longer fit inside this reservation, each with the address in a different
352/// place. Nothing in an address says which of them produced it.
353///
354/// Picking one layout judges an address deployed at another by octets no
355/// translator will send to, and the direction of that error is not always the
356/// refusing one: at the /64 layout the operator's subnet octets are read as the
357/// first half of the address, so a subnet that spells a public IPv4 prefix hides
358/// a private target from `allow_private_networks = false`. So this function
359/// reads no layout at all, and [`is_local_use_nat64`] puts the whole /48 in the
360/// private bucket instead.
361fn embedded_ipv4(ip: IpAddr) -> Option<Ipv4Addr> {
362    let IpAddr::V6(v6) = ip else {
363        return None;
364    };
365    let octets = v6.octets();
366
367    // 64:ff9b::/96
368    if octets[..4] == [0x00, 0x64, 0xff, 0x9b] && octets[4..12].iter().all(|byte| *byte == 0) {
369        return Some(Ipv4Addr::new(
370            octets[12], octets[13], octets[14], octets[15],
371        ));
372    }
373
374    // 2002::/16
375    if octets[..2] == [0x20, 0x02] {
376        return Some(Ipv4Addr::new(octets[2], octets[3], octets[4], octets[5]));
377    }
378
379    // 2001::/32
380    if octets[..4] == [0x20, 0x01, 0x00, 0x00] {
381        return Some(Ipv4Addr::new(
382            octets[12] ^ 0xff,
383            octets[13] ^ 0xff,
384            octets[14] ^ 0xff,
385            octets[15] ^ 0xff,
386        ));
387    }
388
389    None
390}
391
392/// `fc00::/7` — unique local addresses (RFC 4193).
393///
394/// Hand-rolled because `Ipv6Addr::is_unique_local` is still unstable.
395fn is_unique_local(v6: Ipv6Addr) -> bool {
396    v6.segments()[0] & 0xfe00 == 0xfc00
397}
398
399/// `fe80::/10` — link-local unicast (RFC 4291 §2.5.6).
400///
401/// Hand-rolled because `Ipv6Addr::is_unicast_link_local` is still unstable.
402fn is_unicast_link_local(v6: Ipv6Addr) -> bool {
403    v6.segments()[0] & 0xffc0 == 0xfe80
404}
405
406/// `fec0::/10` — the deprecated site-local unicast prefix (RFC 3879).
407///
408/// Adjacent to link-local and, on a network old enough to still use it, just as
409/// internal. Nothing routes it globally, so denying it costs no legitimate
410/// destination.
411fn is_site_local(v6: Ipv6Addr) -> bool {
412    v6.segments()[0] & 0xffc0 == 0xfec0
413}
414
415/// `::/96` — the deprecated IPv4-compatible range, and `::1` with it.
416///
417/// Treated as private rather than as ordinary IPv6: stacks that still honour the
418/// range route `::127.0.0.1` to loopback, which would otherwise be a second way
419/// around the IPv4 rules. The unspecified address is in here too, but
420/// [`is_never_allowed`] has already claimed it.
421fn is_ipv4_compatible(v6: Ipv6Addr) -> bool {
422    v6.octets()[..12].iter().all(|byte| *byte == 0)
423}
424
425#[cfg(test)]
426mod tests {
427    use super::*;
428
429    fn policy(allow_private: bool, denied_ports: &[u16]) -> Policy {
430        Policy::new(&config::Security {
431            allow_private_networks: allow_private,
432            denied_ports: denied_ports.to_vec(),
433            ..Default::default()
434        })
435    }
436
437    fn ip(text: &str) -> IpAddr {
438        text.parse().expect("address literal")
439    }
440
441    /// Every range the spec names, in both address families.
442    const PRIVATE: &[&str] = &[
443        // IPv4
444        // RFC 6890 Table 1, "this host on this network". 0.0.0.0 itself is in
445        // NEVER, so the representative is the address above it.
446        "0.0.0.1",
447        "0.255.255.255",
448        "127.0.0.1",
449        "127.255.255.254",
450        "10.0.0.1",
451        "10.255.255.255",
452        "172.16.0.1",
453        "172.31.255.255",
454        "192.168.0.1",
455        "192.168.255.255",
456        "169.254.169.254", // the cloud metadata address, the classic prize
457        // RFC 6598 shared address space: the inside of a carrier-grade NAT.
458        "100.64.0.0",
459        "100.127.255.255",
460        // RFC 6890 IETF protocol assignments, including the DS-Lite link.
461        "192.0.0.0",
462        "192.0.0.255",
463        // RFC 2544 benchmarking, which some networks number infrastructure with.
464        "198.18.0.0",
465        "198.19.255.255",
466        // RFC 6890 Table 10, 6to4 relay anycast, deprecated by RFC 7526.
467        "192.88.99.0",
468        "192.88.99.255",
469        // RFC 5737 documentation.
470        "192.0.2.1",
471        "198.51.100.1",
472        "203.0.113.1",
473        // RFC 1112 §4 reserved space, routed inside some large networks.
474        "240.0.0.0",
475        "255.255.255.254",
476        // IPv6
477        "::1",
478        "fc00::1",
479        "fdff::1",
480        "fe80::1",
481        "febf::1",
482        // RFC 3879 deprecated site-local, still routed on networks that predate
483        // the deprecation.
484        "fec0::1",
485        "feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
486        // RFC 3849 documentation and the RFC 6666 discard prefix.
487        "2001:db8::1",
488        "100::1",
489        "100:0:0:0:ffff::",
490        // RFC 6890 Table 24, IPv6 benchmarking (RFC 5180).
491        "2001:2::1",
492        "2001:2:0:ffff:ffff:ffff:ffff:ffff",
493        // RFC 6890 Table 26, ORCHID (RFC 4843).
494        "2001:10::1",
495        "2001:1f:ffff:ffff:ffff:ffff:ffff:ffff",
496    ];
497
498    const PUBLIC: &[&str] = &[
499        "1.1.1.1",
500        "8.8.8.8",
501        "93.184.216.34",
502        "172.32.0.1",  // just outside 172.16/12
503        "172.15.0.1",  // just below it
504        "169.253.0.1", // just outside 169.254/16
505        "11.0.0.1",
506        "192.169.0.1",
507        // The neighbours of every range added for RFC 6890, on both sides.
508        "100.63.255.255", // just below 100.64/10
509        "100.128.0.0",    // just above it
510        "192.0.1.1",      // just above 192.0.0/24, and not 192.0.2/24
511        "198.17.255.255", // just below 198.18/15
512        "198.20.0.0",     // just above it
513        "1.0.0.0",        // just above 0.0.0.0/8, which has nothing below it
514        "192.88.98.255",  // just below 192.88.99/24
515        "192.88.100.0",   // just above it
516        "192.0.3.1",      // just above 192.0.2/24
517        "198.51.101.1",   // just above 198.51.100/24
518        "203.0.114.1",    // just above 203.0.113/24
519        // 224/4 through 239/8 is multicast and sits in NEVER, so the last public
520        // address below the reserved block is the one at the top of 223/8.
521        "223.255.255.255",
522        "2001:4860:4860::8888",
523        "2606:4700::1111",
524        "fbff::1",      // just below fc00::/7
525        "fe7f::1",      // just below fe80::/10; above it fec0::/10 runs into ff00::/8
526        "2001:db9::1",  // just above 2001:db8::/32
527        "100:0:0:1::1", // just outside 100::/64
528        // Teredo is 2001::/32 and is unwrapped before the rules run, so the
529        // address just below 2001:2::/48 is taken from 2001:1::/32.
530        "2001:1:ffff:ffff:ffff:ffff:ffff:ffff", // just below 2001:2::/48
531        "2001:2:1::1",                          // just above it
532        "2001:f:ffff:ffff:ffff:ffff:ffff:ffff", // just below 2001:10::/28
533        "2001:20::1",                           // just above it, ORCHIDv2
534    ];
535
536    const NEVER: &[&str] = &[
537        "0.0.0.0",
538        "255.255.255.255",
539        "224.0.0.1",
540        "239.255.255.255",
541        "::",
542        "ff02::1",
543        "ff05::1:3",
544    ];
545
546    #[test]
547    fn private_ranges_are_denied_by_default() {
548        let policy = policy(false, &[]);
549        for address in PRIVATE {
550            assert!(
551                !policy.allows_address(ip(address)),
552                "{address} must be denied by default"
553            );
554        }
555    }
556
557    #[test]
558    fn public_addresses_are_allowed() {
559        for allow_private in [false, true] {
560            let policy = policy(allow_private, &[]);
561            for address in PUBLIC {
562                assert!(
563                    policy.allows_address(ip(address)),
564                    "{address} must be allowed (allow_private={allow_private})"
565                );
566            }
567        }
568    }
569
570    #[test]
571    fn private_ranges_can_be_opened_up() {
572        let policy = policy(true, &[]);
573        for address in PRIVATE {
574            assert!(
575                policy.allows_address(ip(address)),
576                "{address} must be allowed once private networks are"
577            );
578        }
579    }
580
581    /// Multicast, broadcast and the unspecified address are amplification
582    /// primitives, not destinations: no switch opens them.
583    #[test]
584    fn unroutable_and_multicast_addresses_are_never_allowed() {
585        for allow_private in [false, true] {
586            let policy = policy(allow_private, &[]);
587            for address in NEVER {
588                assert!(
589                    !policy.allows_address(ip(address)),
590                    "{address} must never be allowed (allow_private={allow_private})"
591                );
592            }
593        }
594    }
595
596    /// The classic bypass: an IPv4 address in IPv6 clothing.
597    #[test]
598    fn ipv4_mapped_addresses_are_matched_as_ipv4() {
599        let strict = policy(false, &[]);
600
601        for address in [
602            "::ffff:127.0.0.1",
603            "::ffff:10.0.0.1",
604            "::ffff:192.168.1.1",
605            "::ffff:169.254.169.254",
606            // The same addresses written the way a resolver hands them over.
607            "::ffff:7f00:1",
608            "::ffff:a00:1",
609        ] {
610            assert!(
611                !strict.allows_address(ip(address)),
612                "{address} is loopback/private in disguise and must be denied"
613            );
614        }
615
616        // A mapped *public* address is still allowed: normalization must not turn
617        // into a blanket ban on the mapped form.
618        assert!(strict.allows_address(ip("::ffff:8.8.8.8")));
619
620        // And the mapped form follows the switch exactly like the bare form.
621        let permissive = policy(true, &[]);
622        assert!(permissive.allows_address(ip("::ffff:127.0.0.1")));
623    }
624
625    /// Every added range at both of its edges, so a mask typo cannot pass.
626    ///
627    /// The `PRIVATE`/`PUBLIC` lists above already carry these; this states the
628    /// adjacency directly, because "first address in, neighbour out" is the
629    /// property a wrong mask breaks and a list of literals does not say out loud.
630    #[test]
631    fn the_special_purpose_ranges_stop_where_they_should() {
632        let strict = policy(false, &[]);
633
634        for (last_public, first_private, last_private, first_public) in [
635            // 0.0.0.0/8 starts at the bottom of the address space, so it has no
636            // public neighbour below it and the address above it stands in for
637            // both ends. Its first address is `is_never_allowed`, which runs
638            // first, hence 0.0.0.1 as the first private one.
639            ("1.0.0.0", "0.0.0.1", "0.255.255.255", "1.0.0.0"),
640            (
641                "100.63.255.255",
642                "100.64.0.0",
643                "100.127.255.255",
644                "100.128.0.0",
645            ),
646            ("191.255.255.255", "192.0.0.0", "192.0.0.255", "192.0.1.0"),
647            (
648                "198.17.255.255",
649                "198.18.0.0",
650                "198.19.255.255",
651                "198.20.0.0",
652            ),
653            (
654                "192.88.98.255",
655                "192.88.99.0",
656                "192.88.99.255",
657                "192.88.100.0",
658            ),
659            ("192.0.1.255", "192.0.2.0", "192.0.2.255", "192.0.3.0"),
660            (
661                "198.51.99.255",
662                "198.51.100.0",
663                "198.51.100.255",
664                "198.51.101.0",
665            ),
666            (
667                "203.0.112.255",
668                "203.0.113.0",
669                "203.0.113.255",
670                "203.0.114.0",
671            ),
672            // 240/4 runs to the broadcast address, which `is_never_allowed`
673            // claims first — so there is no "first public" above it. The address
674            // just below the range is multicast for the same reason, hence
675            // 223.255.255.255 as the public neighbour.
676            (
677                "223.255.255.255",
678                "240.0.0.0",
679                "255.255.255.254",
680                "223.255.255.255",
681            ),
682        ] {
683            for public in [last_public, first_public] {
684                assert!(
685                    strict.allows_address(ip(public)),
686                    "{public} is outside the range and must stay reachable"
687                );
688            }
689            for private in [first_private, last_private] {
690                assert!(
691                    !strict.allows_address(ip(private)),
692                    "{private} is inside the range and must be denied"
693                );
694            }
695        }
696
697        // The broadcast address is inside 240/4 but `is_never_allowed` wins, so
698        // opening private space does not open it. The unspecified address sits
699        // the same way inside 0.0.0.0/8.
700        assert!(!policy(true, &[]).allows_address(ip("255.255.255.255")));
701        assert!(policy(true, &[]).allows_address(ip("240.0.0.1")));
702        assert!(!policy(true, &[]).allows_address(ip("0.0.0.0")));
703        assert!(policy(true, &[]).allows_address(ip("0.0.0.1")));
704
705        // fec0::/10 has no public neighbour on either side: below it is fe80::/10
706        // (link-local, private) and above it ff00::/8 (multicast, never), so the
707        // edges are stated against those instead. The nearest public address is
708        // the one just below fe80::/10.
709        assert!(strict.allows_address(ip("fe7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff")));
710        for private in [
711            "fe80::",
712            "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
713            "fec0::",
714            "feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
715        ] {
716            assert!(
717                !strict.allows_address(ip(private)),
718                "{private} is inside a private range and must be denied"
719            );
720            assert!(
721                policy(true, &[]).allows_address(ip(private)),
722                "{private} must follow the switch"
723            );
724        }
725        assert!(!policy(true, &[]).allows_address(ip("ff00::")));
726
727        // The two IPv6 blocks carved out of 2001::/23. Their neighbours are
728        // picked to miss Teredo (2001::/32), which is unwrapped before any of
729        // these rules run, and ORCHIDv2 (2001:20::/28) is deliberately public:
730        // RFC 6890's registry does not carry it.
731        for (last_public, first_private, last_private, first_public) in [
732            (
733                "2001:1:ffff:ffff:ffff:ffff:ffff:ffff",
734                "2001:2::",
735                "2001:2:0:ffff:ffff:ffff:ffff:ffff",
736                "2001:2:1::",
737            ),
738            (
739                "2001:f:ffff:ffff:ffff:ffff:ffff:ffff",
740                "2001:10::",
741                "2001:1f:ffff:ffff:ffff:ffff:ffff:ffff",
742                "2001:20::",
743            ),
744        ] {
745            for public in [last_public, first_public] {
746                assert!(
747                    strict.allows_address(ip(public)),
748                    "{public} is outside the range and must stay reachable"
749                );
750            }
751            for private in [first_private, last_private] {
752                assert!(
753                    !strict.allows_address(ip(private)),
754                    "{private} is inside the range and must be denied"
755                );
756                assert!(
757                    policy(true, &[]).allows_address(ip(private)),
758                    "{private} must follow the switch"
759                );
760            }
761        }
762    }
763
764    /// NAT64, 6to4 and Teredo addresses are routes to an IPv4 address, so they
765    /// are judged as that address and not as the global-looking IPv6 they are
766    /// written as.
767    #[test]
768    fn transition_addresses_are_judged_by_the_ipv4_they_carry() {
769        let strict = policy(false, &[]);
770        let permissive = policy(true, &[]);
771
772        // Embedding something private: denied by default, reachable once private
773        // space is opened, exactly like the bare IPv4 address would be.
774        for address in [
775            "64:ff9b::7f00:1",          // NAT64 well-known prefix, 127.0.0.1
776            "64:ff9b::a00:1",           // 10.0.0.1
777            "64:ff9b::a9fe:a9fe",       // 169.254.169.254, the metadata address
778            "2002:a00:1::",             // 6to4, 10.0.0.1
779            "2002:7f00:1::",            // 6to4, 127.0.0.1
780            "2001:0:0:0:0:0:f5ff:fffe", // Teredo, 10.0.0.1 inverted
781        ] {
782            assert!(
783                !strict.allows_address(ip(address)),
784                "{address} carries a private IPv4 address and must be denied"
785            );
786            assert!(
787                permissive.allows_address(ip(address)),
788                "{address} must follow the switch like the address it carries"
789            );
790        }
791
792        // Embedding something public stays public: unwrapping must not become a
793        // blanket ban on the transition forms.
794        for address in [
795            "64:ff9b::808:808",         // NAT64, 8.8.8.8
796            "2002:808:808::",           // 6to4, 8.8.8.8
797            "2001:0:0:0:0:0:f7f7:f7f7", // Teredo, 8.8.8.8 inverted
798        ] {
799            assert!(
800                strict.allows_address(ip(address)),
801                "{address} carries a public IPv4 address and must be reachable"
802            );
803        }
804
805        // And an embedded address that is never allowed stays never allowed, so
806        // the switch cannot open it.
807        for address in ["64:ff9b::", "2002::", "64:ff9b::e000:1"] {
808            for policy in [&strict, &permissive] {
809                assert!(
810                    !policy.allows_address(ip(address)),
811                    "{address} carries an address that is never a destination"
812                );
813            }
814        }
815    }
816
817    /// The local-use NAT64 prefix is private as a whole, at every layout.
818    ///
819    /// RFC 8215 §5 forbids assuming where the IPv4 address sits inside
820    /// `64:ff9b:1::/48`, so this proxy does not look for one. Each address below
821    /// is a translation of 10.0.0.1 at one of the RFC 6052 §2.2 layouts that fit
822    /// inside that /48, and in each of them the four octets a /48 reader takes
823    /// spell a public address instead. Reading the layout would therefore let a
824    /// private target past `allow_private_networks = false`.
825    #[test]
826    fn the_local_use_nat64_prefix_is_private_at_every_layout() {
827        let strict = policy(false, &[]);
828        let permissive = policy(true, &[]);
829
830        for (address, layout, misread) in [
831            ("64:ff9b:1:80a:0:1::", "/56", "8.10.0.0"),
832            ("64:ff9b:1:808:a:0:100:0", "/64", "8.8.10.0"),
833            ("64:ff9b:1:808:8:800:a00:1", "/96", "8.8.8.8"),
834        ] {
835            assert!(
836                !strict.allows_address(ip(address)),
837                "{address} translates 10.0.0.1 at the {layout} layout \
838                 and must be denied rather than read as {misread}"
839            );
840            assert!(
841                permissive.allows_address(ip(address)),
842                "{address} is private and must follow the switch"
843            );
844        }
845    }
846
847    /// The extraction itself, address by address.
848    ///
849    /// The bucket assertions above would pass on a near-miss — 169.254.0.169 is
850    /// as link-local as 169.254.169.254 — so the exact value is asserted here.
851    #[test]
852    fn the_embedded_ipv4_is_extracted_exactly() {
853        for (address, expected) in [
854            // RFC 6052 §2.1: the well-known prefix, address in the last 32 bits.
855            ("64:ff9b::7f00:1", "127.0.0.1"),
856            ("64:ff9b::808:808", "8.8.8.8"),
857            ("64:ff9b::", "0.0.0.0"),
858            // 6to4: bits 16-47.
859            ("2002:a00:1::", "10.0.0.1"),
860            ("2002:808:808::1", "8.8.8.8"),
861            // Teredo: the last 32 bits, every bit inverted.
862            ("2001:0:0:0:0:0:f5ff:fffe", "10.0.0.1"),
863            ("2001:0:808:808:0:0:f7f7:f7f7", "8.8.8.8"),
864        ] {
865            assert_eq!(
866                embedded_ipv4(ip(address)).map(IpAddr::V4),
867                Some(ip(expected)),
868                "{address} carries {expected}"
869            );
870        }
871
872        // Everything else carries nothing: the local-use prefix whose layout must
873        // not be guessed, the ranges that merely look adjacent, and the
874        // deprecated `::/96` form that must stay whole.
875        for address in [
876            "64:ff9b:1::1",              // the local-use prefix, read at no layout
877            "64:ff9b:1:a9fe:a9:fe00::",  // the /48 layout, once read as 169.254.169.254
878            "64:ff9b:1:808:8:800:a00:1", // the /96 layout, once read as 8.8.8.8
879            "2001:db8::1",               // documentation, not Teredo
880            "2003::1",                   // not 6to4
881            "64:ff9c::1",                // not the NAT64 prefix
882            "64:ff9b:2::1",              // outside the local-use prefix
883            "::1",
884            "::127.0.0.1",
885            "2606:4700::1111",
886            "8.8.8.8",
887        ] {
888            assert_eq!(embedded_ipv4(ip(address)), None, "{address}");
889        }
890    }
891
892    /// A Teredo address's *client* IPv4 is the inverted last 32 bits, and the
893    /// bits in between are a server address this proxy never dials — so the
894    /// verdict must come from the right half of the address.
895    #[test]
896    fn a_teredo_address_is_read_from_its_client_field() {
897        // 2001:0:<server>:<flags+port>:<client>. The server field here is a
898        // public address and the client field a private one; the verdict follows
899        // the client field.
900        let strict = policy(false, &[]);
901        assert!(!strict.allows_address(ip("2001:0:808:808:0:0:f5ff:fffe")));
902
903        // The mirror image: private-looking server field, public client field.
904        assert!(strict.allows_address(ip("2001:0:a00:1:0:0:f7f7:f7f7")));
905    }
906
907    /// The deprecated sibling of the mapped form, `::a.b.c.d`.
908    #[test]
909    fn ipv4_compatible_addresses_are_denied_by_default() {
910        let policy = policy(false, &[]);
911        for address in ["::127.0.0.1", "::10.0.0.1", "::8.8.8.8", "::0.0.0.1"] {
912            assert!(
913                !policy.allows_address(ip(address)),
914                "{address} is deprecated IPv4-compatible space and must be denied"
915            );
916        }
917    }
918
919    #[test]
920    fn canonicalization_unwraps_only_the_mapped_form() {
921        assert_eq!(canonical(ip("::ffff:127.0.0.1")), ip("127.0.0.1"));
922        assert_eq!(canonical(ip("127.0.0.1")), ip("127.0.0.1"));
923        assert_eq!(canonical(ip("2001:db8::1")), ip("2001:db8::1"));
924        // `::1` must keep its loopback meaning rather than becoming 0.0.0.1.
925        assert_eq!(canonical(ip("::1")), ip("::1"));
926    }
927
928    #[test]
929    fn denied_ports_are_refused() {
930        let policy = policy(false, &[25]);
931        assert!(!policy.allows_port(25));
932        assert!(policy.allows_port(443));
933        assert!(policy.allows_port(80));
934    }
935
936    /// Surge's UDP availability test is a DNS query through the tunnel, so 53 has
937    /// to work with a stock configuration.
938    #[test]
939    fn port_53_is_allowed_with_the_default_deny_list() {
940        let policy = Policy::new(&config::Security::default());
941        assert!(
942            policy.allows_port(53),
943            "Surge tests UDP by resolving a name"
944        );
945        assert!(!policy.allows_port(25));
946    }
947
948    /// A name that resolves to a mix keeps only what may be dialled — the reason
949    /// resolution is explicit rather than left to `TcpStream::connect`.
950    #[test]
951    fn filtering_keeps_the_dialable_addresses() {
952        let policy = policy(false, &[]);
953        let addresses: Vec<SocketAddr> = [
954            "127.0.0.1:443",
955            "8.8.8.8:443",
956            "[::1]:443",
957            "[2606:4700::1111]:443",
958            "[::ffff:10.0.0.1]:443",
959        ]
960        .iter()
961        .map(|a| a.parse().expect("socket address"))
962        .collect();
963
964        let allowed = policy.allowed_addresses(&addresses);
965        assert_eq!(
966            allowed,
967            vec![
968                "8.8.8.8:443".parse().unwrap(),
969                "[2606:4700::1111]:443".parse().unwrap()
970            ]
971        );
972    }
973
974    fn addresses(literals: &[&str]) -> Vec<SocketAddr> {
975        literals
976            .iter()
977            .map(|a| a.parse().expect("socket address"))
978            .collect()
979    }
980
981    /// The answer a filtering resolver gives, in every spelling it gives it in.
982    #[test]
983    fn an_all_unspecified_answer_is_a_blackhole() {
984        for literals in [
985            &["0.0.0.0:443"][..],
986            &["0.0.0.0:53", "0.0.0.0:53"][..],
987            &["[::]:443"][..],
988            // IPv4-mapped: unspecified once canonicalized, like everywhere else.
989            &["[::ffff:0.0.0.0]:443"][..],
990            &["0.0.0.0:443", "[::]:443", "[::ffff:0.0.0.0]:443"][..],
991        ] {
992            assert!(
993                is_dns_blackhole(&addresses(literals)),
994                "{literals:?} is a filtered answer and must be recognised as one"
995            );
996        }
997    }
998
999    /// The half of the rule that keeps SSRF probes loud: anything that is not
1000    /// *only* the unspecified address stays an ordinary policy refusal.
1001    #[test]
1002    fn private_and_mixed_answers_are_not_blackholes() {
1003        for literals in [
1004            // A private address alongside the blackhole is still a private
1005            // address, and reaching for it is the thing worth warning about.
1006            &["0.0.0.0:443", "10.0.0.1:443"][..],
1007            &["[::]:443", "[::1]:443"][..],
1008            // Pure loopback / RFC 1918 / link-local: refused, never quietly.
1009            &["127.0.0.1:443"][..],
1010            &["10.0.0.1:443", "192.168.1.1:443"][..],
1011            &["169.254.169.254:80"][..],
1012            &["[::1]:443"][..],
1013            // Broadcast and multicast are refused for their own reasons.
1014            &["255.255.255.255:443"][..],
1015            &["224.0.0.1:443"][..],
1016            // A public address is not a blackhole either, mixed in or alone.
1017            &["0.0.0.0:443", "8.8.8.8:443"][..],
1018        ] {
1019            assert!(
1020                !is_dns_blackhole(&addresses(literals)),
1021                "{literals:?} must stay an ordinary policy refusal"
1022            );
1023        }
1024    }
1025
1026    /// Unreachable on the calling paths, but "nothing resolved" is not evidence
1027    /// of filtering, so it takes the loud branch.
1028    #[test]
1029    fn no_addresses_is_not_a_blackhole() {
1030        assert!(!is_dns_blackhole(&[]));
1031    }
1032
1033    #[test]
1034    fn filtering_everything_out_yields_an_empty_list() {
1035        let policy = policy(false, &[]);
1036        let addresses: Vec<SocketAddr> = ["127.0.0.1:443", "[::ffff:127.0.0.1]:443"]
1037            .iter()
1038            .map(|a| a.parse().expect("socket address"))
1039            .collect();
1040
1041        assert!(policy.allowed_addresses(&addresses).is_empty());
1042    }
1043}