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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
//! The network map: who else is on the tailnet, and how to reach them.
//!
//! # Streaming, not buffering
//!
//! A `MapResponse` for a two-node lab is 27 KB. A real tailnet's is megabytes,
//! and the connection carrying it is a long poll that never ends — so there is
//! no "the document" to hold, only a stream of them. Nothing here ever has more
//! than one JSON token and one peer under construction in hand, whatever the
//! size of what is arriving.
//!
//! That is the whole reason this is a push parser rather than a `serde` model:
//! the shape of the API is what enforces the property. A parser that returned a
//! `MapResponse` would have had to build one.
//!
//! # Deltas
//!
//! The first response is a full map; almost everything after it is a delta, and
//! the capture bears that out — five of eleven captured responses carry only
//! changes. Deltas *omit* fields rather than repeating them, so treating each
//! response as a full map silently discards every peer it did not mention. The
//! three forms are handled separately:
//!
//! - `PeersChanged` — whole peer records to insert or replace
//! - `PeersChangedPatch` — named fields of an existing peer, and nothing else
//! - `PeersRemoved` — node ids to forget
//!
//! # Scope
//!
//! Fields a headless node acts on: identity, addresses, endpoints, packet
//! filters, the DERP map, and the bounded part of `DNSConfig`. `Hostinfo` and
//! `UserProfiles` are skipped wholesale rather than parsed into something
//! nothing reads, as is `DNSConfig`'s unbounded `Routes` map — see
//! [`crate::netmap::dns`].
pub use ;
pub use DnsConfig;
pub use FrameReader;
pub use ;
pub use ;
pub use ;
pub use ;
/// How many peers a netmap may name. A small tailnet, sized for a device with
/// tens of kilobytes of RAM rather than a laptop.
pub const MAX_PEERS: usize = 32;
/// Addresses assigned to one node: normally one IPv4 and one IPv6.
///
/// A peer naming more IPv4 addresses is omitted from the map (and
/// [`Netmap::peers_truncated`] set) rather than kept with a partial list.
pub const MAX_ADDRESSES: usize = 4;
pub const MAX_PRIMARY_ROUTES: usize = 8;
/// Subnets a peer will accept traffic for. More than its own addresses, because
/// a subnet router or exit node advertises others.
///
/// These drive routing and source checks, so a peer naming more IPv4 subnets
/// is omitted from the map (and [`Netmap::peers_truncated`] set) rather than
/// kept with a partial list. The rest of the map is unaffected.
pub const MAX_ALLOWED_IPS: usize = 8;
/// Candidate IPv4 paths retained for one peer.
///
/// Ordinary clients advertise more than eight: a STUN address, a port mapping,
/// and one per interface, which on a Linux host with container or CI bridges
/// reaches ten. Each extra slot costs 6 bytes in three lists per peer (the
/// map's record and the node's two path lists), so twelve adds 2.25 KiB to
/// `Node<32>` and keeps it inside its 64 KiB device budget with `peer-names`
/// and `ssh-policy` both enabled; fourteen would not.
/// Longer lists are truncated, never rejected: a dropped candidate costs at
/// most one direct path, and the peer stays reachable through DERP.
pub const MAX_ENDPOINTS: usize = 12;
/// Hosted publishes several dozen regions. The map retains two usable relays
/// per region, while [`crate::Node`] limits live sessions separately.
pub const MAX_DERP_REGIONS: usize = 40;
/// A primary and one failover relay are retained for each region.
pub const MAX_DERP_NODES: usize = 2;
/// DERP DNS names retained by the embedded map. This keeps the capacity that
/// previous releases accepted, including custom relay hostnames.
pub const MAX_DERP_HOSTNAME: usize = 64;
/// The longest retained display name, in bytes: a DNS label's limit. Longer
/// names are cut at a character boundary.
pub const MAX_PEER_NAME: usize = 63;
/// Search domains retained from `DNSConfig`. Headscale publishes one; a
/// tailnet with split DNS publishes a handful.
pub const MAX_DNS_DOMAINS: usize = 4;
/// Upstream resolvers retained from `DNSConfig`, matching the three the
/// gateway will actually query plus one spare.
pub const MAX_DNS_RESOLVERS: usize = 4;
/// The longest domain or resolver address retained. A DoH URL longer than this
/// is dropped rather than stored cut in half.
pub const MAX_DNS_NAME: usize = 64;
/// The longest single JSON string the parser will materialise.
///
/// This bounds the parser's scratch buffer, and it is the *only* thing about
/// the document whose size matters — not the number of peers, not the total
/// length. The longest string in the captured map is a 73-character node name.
/// Maximum decoded JSON string in a streamed netmap. Hosted policy payloads
/// can exceed one KiB even when the retained peer/DERP fields are short.
pub const MAX_STRING: usize = 2 * 1024;