1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
//! The single address-scope classifier (`SPEC.md` §5) — the one range table every consumer asks
//! "could this address be a legitimate reflexive candidate, and could a stranger route to it?"
//! against.
//!
//! Before this crate, two predicates answered overlapping questions with range tables that had
//! drifted apart: `dig-nat`'s dial guard (`is_usable_reflexive_addr`) and `dig-node`'s on-chain gate
//! (`is_globally_routable`). [`Scope`] is the one table both are now DERIVED from; §5.4 names the
//! four places their old tables disagreed, and this table resolves each one toward the SAFER
//! reading (`SPEC.md` §5.5: a classification error toward [`Scope::NeverDialable`] costs a
//! candidate; toward [`Scope::GlobalUnicast`] puts an unreachable address into an on-chain
//! advertisement — so an ambiguous range classifies down).
use ;
/// How dialable an address is, as three tiers (`SPEC.md` §5.2). Exhaustive: adding a variant is a
/// breaking change, since [`is_usable_reflexive_addr`] and [`is_globally_routable`] are both
/// defined in terms of an exhaustive match over this enum.
/// Fold an IPv4-mapped (`::ffff:a.b.c.d`) OR deprecated IPv4-**compatible** (`::a.b.c.d`) IPv6
/// address down to the IPv4 address it embeds. A genuine IPv4 address, or a genuine native IPv6
/// address, is returned unchanged.
///
/// **Fold first, always** (`SPEC.md` §5.3): an on-path STUN server (or a lying peer) fully controls
/// every decoded byte, so classifying a 16-byte value AS IPv6 without folding first would let it
/// smuggle any rejected IPv4 range — e.g. `::ffff:127.0.0.1` or the compat form `::7f00:1` for
/// loopback — past a v6-only classifier. [`Ipv6Addr::to_ipv4`] folds BOTH forms; `to_canonical` is
/// deliberately NOT used here, since it folds only the mapped form and would miss the compat one.
///
/// This is also the reason `0.0.0.0/8` cannot be dropped from the IPv4 table as "redundant" with an
/// IPv6 unspecified/loopback check: `::` and `::1` both fold to an address in `0.0.0.0/8`
/// (`0.0.0.0` and `0.0.0.1` respectively), so that row is what actually rejects them post-fold.
pub
/// Classify a bare IP (`SPEC.md` §5.3). Folds per `fold_ip` first, so a mapped or compat IPv6
/// value is classified as the IPv4 address it represents.
///
/// A caller holding only an [`IpAddr`] (no port) MUST apply the `port == 0` rule of [`scope_of`]
/// itself if it is relevant to that call site — this function has no port to see.
/// Classify a `SocketAddr` (`SPEC.md` §5.3): [`Scope::NeverDialable`] when `addr.port() == 0`,
/// regardless of the IP, else [`scope_of_ip`] of `addr.ip()`.
/// Whether `addr` could ever be a legitimate reflexive dial target — true for [`Scope::PrivateScope`]
/// AND [`Scope::GlobalUnicast`], false only for [`Scope::NeverDialable`] (`SPEC.md` §5.2). This is
/// deliberately NOT "is this address public": a LAN or CGNAT address is a genuinely valid dial
/// target for a peer on the same site or carrier region.
/// Whether a stranger on the open internet could route to `addr` — true only for
/// [`Scope::GlobalUnicast`] (`SPEC.md` §5.2). This is the gate for anything written into an
/// on-chain advertisement: a [`Scope::PrivateScope`] reading is a true reading of the node's
/// position and is still never something to advertise to strangers.
/// The IPv4 half of the table (`SPEC.md` §5.3): 11 [`Scope::NeverDialable`] ranges, 4
/// [`Scope::PrivateScope`] ranges, everything else [`Scope::GlobalUnicast`].
/// The native-IPv6 half of the table (`SPEC.md` §5.3): 7 [`Scope::NeverDialable`] ranges, 1
/// [`Scope::PrivateScope`] range, everything else [`Scope::GlobalUnicast`]. Only ever sees a
/// genuine native IPv6 address — a mapped or compat form is folded to IPv4 by `fold_ip` before
/// [`scope_of_ip`] reaches here.