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
//! LOCAL (mDNS) peer discovery (#68) — find peers on the same link with no internet at all.
//!
//! # Why this exists
//!
//! Peer resolution otherwise depends on external infrastructure: the pkarr publisher/resolver a
//! relay provides, or a dialable address someone already handed over in an invite. Two machines on
//! the same LAN with no uplink cannot find each other, though the network path between them is
//! fine. That is the scenario where "peer to peer" earns its keep — a boat, a workshop, a failed
//! uplink, a deliberately air-gapped network — and the commoner weak version too: a LAN where the
//! internet is merely flaky, so peers that could talk directly fail to resolve because resolution
//! goes out first.
//!
//! # This is a DEPENDENCY, not an implementation
//!
//! #68 concluded "there is no mDNS in iroh 1.0.3, so this needs an implementation", from a correct
//! reading of `iroh-1.0.3/src/address_lookup/` — which contains exactly `dns.rs`, `memory.rs` and
//! `pkarr.rs`. iroh 1.x did not drop mDNS; it moved it into a companion crate, and says so in the
//! module docs of that same file:
//!
//! > mDNS-based and Mainline-DHT-based Address Lookup services live in separate crates:
//! > `iroh-mdns-address-lookup` and `iroh-mainline-address-lookup`.
//!
//! So this module is thin on purpose. An mDNS responder is a multicast listener on every interface;
//! one written here would be ours to get right and ours to keep right, against a transport whose
//! address model it has to track. n0's stays version-matched to the iroh we pin.
//!
//! # What it discloses
//!
//! Advertising multicasts this node's endpoint id and its addresses to **every device on the link**,
//! unprompted and repeatedly, including machines that had no idea it existed. "Its addresses" means
//! the LAN address, the PUBLIC WAN IPv4 and global IPv6 — a café LAN learns your home/ISP address,
//! not merely that you are there. That is why `[network].local_discovery` defaults to `"off"`, a
//! deliberate departure from what #68 asked for.
//!
//! **`"resolve"` is quieter, not silent.** Resolving over mDNS means asking:
//! `MdnsAddressLookup` builds a `Discoverer::new_interactive` unconditionally (τ = 700 ms) and
//! `advertise` gates only `with_addrs`, so a resolving node multicasts a `_mcpmesh._udp.local`
//! query roughly once a second for as long as it runs. It publishes no identity and no addresses —
//! pinned on the wire — but the query itself says "an mcpmesh node is at this IP, right now". The
//! docs said "listen only" until the 0.44.0 gate captured the packets.
//!
//! **`relay_only` does not restrain any of this on a stock build.** `AddrFilter::relay_only()` is
//! installed only under the `unstable-relay-only` feature; without it the filter does not exist and
//! the full direct address set goes out. Boot warns, naming which of the two builds the operator
//! has. An earlier version of this comment asserted the filter always applied; it does not.
use EndpointId;
use AddressLookup;
use MdnsAddressLookup;
/// The mDNS service name mcpmesh nodes announce and listen on.
///
/// Deliberately NOT the crate's `irohv1` default, which is the SHARED iroh namespace: every iroh
/// application on the link would advertise into it and be resolved out of it. That is not an
/// authorization problem — resolution answers *where*, never *who may*, and a peer found this way
/// still faces the trust gate — but it is a disclosure and a noise problem, announcing this node to
/// unrelated applications and resolving endpoint ids that can never be ours.
///
/// Records take the form `<endpoint-id>._mcpmesh._udp.local`.
pub const SERVICE_NAME: &str = "mcpmesh";
/// Build the local-discovery lookup for `endpoint_id`.
///
/// **Takes the parsed [`LocalDiscovery`], not a bare `bool`, deliberately.** The 0.44.0 gate
/// mutated the call site from `local_disc.advertise` to a literal `true` — putting a node told to
/// listen only on the air, broadcasting its endpoint id — and every deterministic test stayed
/// green. A bare bool makes that a one-character edit; a struct parsed from config makes the same
/// lie require constructing a `LocalDiscovery` that disagrees with the operator's file, which is
/// visible at review. It does not make the mistake impossible, and the wire test below is what
/// actually pins it.
///
/// Fallible because a machine with no multicast-capable interface cannot run this; boot warns and
/// continues rather than refusing to start, since that is a networking condition rather than a
/// misconfiguration.
///
/// Must be called from within a tokio runtime: the crate's builder relies on
/// `Handle::current()` and PANICS otherwise.