1use super::metadata::ProtocolMetadataV2;
8use crate::llm::actions::Server;
9use std::collections::HashMap;
10use std::sync::Arc;
11
12pub struct ServerRegistry {
14 protocols: HashMap<String, Arc<dyn Server>>,
16 keyword_map: HashMap<String, String>,
18}
19
20impl ServerRegistry {
21 fn new() -> Self {
23 let mut registry = Self {
24 protocols: HashMap::new(),
25 keyword_map: HashMap::new(),
26 };
27
28 registry.register_protocols();
30 registry.build_keyword_map();
31
32 registry.validate_keyword_uniqueness();
34
35 registry
36 }
37
38 fn register_protocols(&mut self) {
40 let dummy_state = Arc::new(crate::state::app_state::AppState::new());
43
44 self.register(Arc::new(crate::server::TcpProtocol::new()));
45
46 #[cfg(unix)]
47 self.register(Arc::new(crate::server::SocketFileProtocol::new()));
48
49 #[cfg(unix)]
50 self.register(Arc::new(crate::server::NamedPipeProtocol::new()));
51
52 #[cfg(unix)]
53 self.register(Arc::new(crate::server::PtyProtocol::new()));
54
55 #[cfg(unix)]
56 self.register(Arc::new(crate::server::StdioProtocol::new()));
57
58 self.register(Arc::new(crate::server::HttpProtocol::new()));
59
60 self.register(Arc::new(crate::server::Http2Protocol::new()));
61
62 self.register(Arc::new(crate::server::PypiProtocol::new()));
63
64 self.register(Arc::new(crate::server::MavenProtocol::new()));
65
66 self.register(Arc::new(crate::server::UdpProtocol::new()));
67
68 #[cfg(all(unix, feature = "libpcap"))]
69 self.register(Arc::new(crate::server::DataLinkProtocol::new()));
70
71 #[cfg(all(unix, feature = "libpcap"))]
72 self.register(Arc::new(crate::server::ArpProtocol::new()));
73
74 #[cfg(unix)]
75 self.register(Arc::new(crate::server::IcmpProtocol::new()));
76
77 #[cfg(not(target_arch = "wasm32"))]
78 self.register(Arc::new(
79 crate::server::dc_peer::actions::DcPeerProtocol::new(),
80 ));
81
82 #[cfg(not(target_arch = "wasm32"))]
83 self.register(Arc::new(crate::server::adc::actions::AdcProtocol::new()));
84
85 #[cfg(not(target_arch = "wasm32"))]
86 self.register(Arc::new(
87 crate::server::adc_peer::actions::AdcPeerProtocol::new(),
88 ));
89
90 #[cfg(not(target_arch = "wasm32"))]
91 self.register(Arc::new(
92 crate::server::soulseek::actions::SoulseekProtocol::new(),
93 ));
94
95 #[cfg(not(target_arch = "wasm32"))]
96 self.register(Arc::new(
97 crate::server::soulseek_peer::actions::SoulseekPeerProtocol::new(),
98 ));
99
100 #[cfg(not(target_arch = "wasm32"))]
101 self.register(Arc::new(
102 crate::server::gnutella::actions::GnutellaProtocol::new(),
103 ));
104
105 self.register(Arc::new(crate::server::DcProtocol::new()));
106
107 #[cfg(not(target_arch = "wasm32"))]
108 self.register(Arc::new(crate::server::DnsProtocol::new()));
109
110 #[cfg(not(target_arch = "wasm32"))]
111 self.register(Arc::new(crate::server::doq::actions::DoqProtocol::new()));
112
113 #[cfg(not(target_arch = "wasm32"))]
114 self.register(Arc::new(crate::server::DotProtocol::new()));
115
116 #[cfg(not(target_arch = "wasm32"))]
117 self.register(Arc::new(crate::server::DohProtocol::new()));
118
119 self.register(Arc::new(crate::server::DhcpProtocol::new()));
120
121 self.register(Arc::new(crate::server::BootpProtocol::new()));
122
123 #[cfg(not(target_arch = "wasm32"))]
124 self.register(Arc::new(crate::server::NtpProtocol::new()));
125
126 self.register(Arc::new(crate::server::TftpProtocol::new()));
127
128 #[cfg(not(target_arch = "wasm32"))]
129 self.register(Arc::new(crate::server::nut::actions::NutProtocol::new()));
130
131 self.register(Arc::new(crate::server::WhoisProtocol::new()));
132
133 #[cfg(unix)]
134 self.register(Arc::new(crate::server::NdpProtocol::new()));
135
136 self.register(Arc::new(crate::server::Dhcpv6Protocol::new()));
137
138 #[cfg(unix)]
139 self.register(Arc::new(crate::server::TunTapProtocol::new()));
140
141 #[cfg(unix)]
142 self.register(Arc::new(crate::server::RawIpProtocol::new()));
143
144 self.register(Arc::new(crate::server::GtpProtocol::new()));
145
146 #[cfg(unix)]
147 self.register(Arc::new(crate::server::M3uaProtocol::new()));
148
149 #[cfg(unix)]
150 self.register(Arc::new(crate::server::ngap::actions::NgapProtocol::new()));
151
152 #[cfg(unix)]
153 self.register(Arc::new(crate::server::CanProtocol::new()));
154
155 #[cfg(all(unix, feature = "libpcap"))]
156 self.register(Arc::new(crate::server::LldpProtocol::new()));
157
158 #[cfg(all(unix, feature = "libpcap"))]
159 self.register(Arc::new(crate::server::CdpProtocol::new()));
160
161 #[cfg(all(unix, feature = "libpcap"))]
162 self.register(Arc::new(crate::server::StpProtocol::new()));
163
164 #[cfg(unix)]
165 self.register(Arc::new(crate::server::VrrpProtocol::new()));
166
167 self.register(Arc::new(crate::server::HsrpProtocol::new()));
168
169 #[cfg(all(unix, feature = "libpcap"))]
170 self.register(Arc::new(crate::server::EapolProtocol::new()));
171
172 self.register(Arc::new(crate::server::WolProtocol::new()));
173
174 self.register(Arc::new(crate::server::NatsProtocol::new()));
175
176 self.register(Arc::new(crate::server::StompProtocol::new()));
177
178 self.register(Arc::new(crate::server::IdentProtocol::new()));
179
180 #[cfg(not(target_arch = "wasm32"))]
181 self.register(Arc::new(crate::server::GeminiProtocol::new()));
182
183 #[cfg(not(target_arch = "wasm32"))]
184 self.register(Arc::new(crate::server::DictProtocol::new()));
185
186 #[cfg(not(target_arch = "wasm32"))]
187 self.register(Arc::new(crate::server::BeanstalkdProtocol::new()));
188
189 #[cfg(not(target_arch = "wasm32"))]
190 self.register(Arc::new(crate::server::ZabbixProtocol::new()));
191
192 #[cfg(not(target_arch = "wasm32"))]
193 self.register(Arc::new(crate::server::GearmanProtocol::new()));
194
195 #[cfg(not(target_arch = "wasm32"))]
196 self.register(Arc::new(crate::server::NsqProtocol::new()));
197
198 self.register(Arc::new(crate::server::GopherProtocol::new()));
199
200 self.register(Arc::new(crate::server::FingerProtocol::new()));
201
202 self.register(Arc::new(crate::server::SsdpProtocol::new()));
203
204 #[cfg(not(target_arch = "wasm32"))]
205 self.register(Arc::new(crate::server::LlmnrProtocol::new()));
206
207 self.register(Arc::new(crate::server::NetbiosNsProtocol::new()));
208
209 self.register(Arc::new(crate::server::SnmpProtocol::new()));
210
211 #[cfg(unix)]
212 self.register(Arc::new(crate::server::IgmpProtocol::new()));
213
214 #[cfg(not(target_arch = "wasm32"))]
215 self.register(Arc::new(
216 crate::server::diameter::actions::DiameterProtocol::new(),
217 ));
218
219 #[cfg(not(target_arch = "wasm32"))]
220 self.register(Arc::new(
221 crate::server::tacacs::actions::TacacsProtocol::new(),
222 ));
223
224 #[cfg(not(target_arch = "wasm32"))]
225 self.register(Arc::new(
226 crate::server::netconf::actions::NetconfProtocol::new(),
227 ));
228
229 #[cfg(not(target_arch = "wasm32"))]
230 self.register(Arc::new(
231 crate::server::rpki_rtr::actions::RpkiRtrProtocol::new(),
232 ));
233
234 #[cfg(not(target_arch = "wasm32"))]
235 self.register(Arc::new(crate::server::rdap::actions::RdapProtocol::new()));
236
237 #[cfg(not(target_arch = "wasm32"))]
238 self.register(Arc::new(crate::server::hl7::actions::Hl7Protocol::new()));
239
240 #[cfg(not(target_arch = "wasm32"))]
241 self.register(Arc::new(crate::server::icap::actions::IcapProtocol::new()));
242
243 #[cfg(not(target_arch = "wasm32"))]
244 self.register(Arc::new(
245 crate::server::s7comm::actions::S7commProtocol::new(),
246 ));
247
248 #[cfg(not(target_arch = "wasm32"))]
249 self.register(Arc::new(
250 crate::server::ethernet_ip::actions::EthernetIpProtocol::new(),
251 ));
252
253 #[cfg(not(target_arch = "wasm32"))]
254 self.register(Arc::new(crate::server::dnp3::actions::Dnp3Protocol::new()));
255
256 #[cfg(not(target_arch = "wasm32"))]
257 self.register(Arc::new(
258 crate::server::iec104::actions::Iec104Protocol::new(),
259 ));
260
261 #[cfg(not(target_arch = "wasm32"))]
262 self.register(Arc::new(
263 crate::server::bacnet::actions::BacnetProtocol::new(),
264 ));
265
266 #[cfg(not(target_arch = "wasm32"))]
267 self.register(Arc::new(crate::server::opcua::actions::OpcuaProtocol::new()));
268
269 #[cfg(not(target_arch = "wasm32"))]
270 self.register(Arc::new(crate::server::ocpp::actions::OcppProtocol::new()));
271
272 #[cfg(not(target_arch = "wasm32"))]
273 self.register(Arc::new(crate::server::a2a::actions::A2aProtocol::new()));
274
275 #[cfg(not(target_arch = "wasm32"))]
276 self.register(Arc::new(
277 crate::server::graphql::actions::GraphqlProtocol::new(),
278 ));
279
280 #[cfg(not(target_arch = "wasm32"))]
281 self.register(Arc::new(
282 crate::server::fastcgi::actions::FastcgiProtocol::new(),
283 ));
284
285 #[cfg(not(target_arch = "wasm32"))]
286 self.register(Arc::new(
287 crate::server::redfish::actions::RedfishProtocol::new(),
288 ));
289
290 #[cfg(not(target_arch = "wasm32"))]
291 self.register(Arc::new(crate::server::scim::actions::ScimProtocol::new()));
292
293 #[cfg(not(target_arch = "wasm32"))]
294 self.register(Arc::new(
295 crate::server::socketio::actions::SocketIoProtocol::new(),
296 ));
297
298 #[cfg(not(target_arch = "wasm32"))]
299 self.register(Arc::new(
300 crate::server::caldav::actions::CalDavProtocol::new(),
301 ));
302
303 #[cfg(not(target_arch = "wasm32"))]
304 self.register(Arc::new(
305 crate::server::carddav::actions::CardDavProtocol::new(),
306 ));
307
308 #[cfg(not(target_arch = "wasm32"))]
309 self.register(Arc::new(crate::server::dicom::actions::DicomProtocol::new()));
310
311 #[cfg(not(target_arch = "wasm32"))]
312 self.register(Arc::new(crate::server::acme::actions::AcmeProtocol::new()));
313
314 #[cfg(not(target_arch = "wasm32"))]
315 self.register(Arc::new(crate::server::fix::actions::FixProtocol::new()));
316
317 #[cfg(not(target_arch = "wasm32"))]
318 self.register(Arc::new(crate::server::wamp::actions::WampProtocol::new()));
319
320 #[cfg(not(target_arch = "wasm32"))]
321 self.register(Arc::new(crate::server::rtmp::actions::RtmpProtocol::new()));
322
323 #[cfg(not(target_arch = "wasm32"))]
324 self.register(Arc::new(crate::server::srt::actions::SrtProtocol::new()));
325
326 #[cfg(not(target_arch = "wasm32"))]
327 self.register(Arc::new(crate::server::amqp1::actions::Amqp1Protocol::new()));
328
329 #[cfg(not(target_arch = "wasm32"))]
330 self.register(Arc::new(
331 crate::server::thrift::actions::ThriftProtocol::new(),
332 ));
333 #[cfg(not(target_arch = "wasm32"))]
334 self.register(Arc::new(crate::server::bmp::actions::BmpProtocol::new()));
335 #[cfg(not(target_arch = "wasm32"))]
336 self.register(Arc::new(
337 crate::server::mqtt_sn::actions::MqttSnProtocol::new(),
338 ));
339 #[cfg(not(target_arch = "wasm32"))]
340 self.register(Arc::new(crate::server::nbd::actions::NbdProtocol::new()));
341 #[cfg(not(target_arch = "wasm32"))]
342 self.register(Arc::new(
343 crate::server::managesieve::actions::ManageSieveProtocol::new(),
344 ));
345 #[cfg(not(target_arch = "wasm32"))]
346 self.register(Arc::new(crate::server::zenoh::actions::ZenohProtocol::new()));
347 #[cfg(not(target_arch = "wasm32"))]
348 self.register(Arc::new(crate::server::lwm2m::actions::Lwm2mProtocol::new()));
349 #[cfg(not(target_arch = "wasm32"))]
350 self.register(Arc::new(
351 crate::server::restconf::actions::RestconfProtocol::new(),
352 ));
353 #[cfg(not(target_arch = "wasm32"))]
354 self.register(Arc::new(
355 crate::server::webtransport::actions::WebTransportProtocol::new(),
356 ));
357 #[cfg(not(target_arch = "wasm32"))]
358 self.register(Arc::new(crate::server::jmap::actions::JmapProtocol::new()));
359 #[cfg(not(target_arch = "wasm32"))]
360 self.register(Arc::new(crate::server::epp::actions::EppProtocol::new()));
361 #[cfg(not(target_arch = "wasm32"))]
362 self.register(Arc::new(crate::server::lmtp::actions::LmtpProtocol::new()));
363 #[cfg(not(target_arch = "wasm32"))]
364 self.register(Arc::new(crate::server::lpd::actions::LpdProtocol::new()));
365 #[cfg(not(target_arch = "wasm32"))]
366 self.register(Arc::new(crate::server::inetd::actions::EchoProtocol::new()));
367 #[cfg(not(target_arch = "wasm32"))]
368 self.register(Arc::new(
369 crate::server::inetd::actions::DiscardProtocol::new(),
370 ));
371 #[cfg(not(target_arch = "wasm32"))]
372 self.register(Arc::new(
373 crate::server::inetd::actions::DaytimeProtocol::new(),
374 ));
375 #[cfg(not(target_arch = "wasm32"))]
376 self.register(Arc::new(crate::server::inetd::actions::QotdProtocol::new()));
377 #[cfg(not(target_arch = "wasm32"))]
378 self.register(Arc::new(
379 crate::server::inetd::actions::ChargenProtocol::new(),
380 ));
381 #[cfg(not(target_arch = "wasm32"))]
382 self.register(Arc::new(crate::server::inetd::actions::TimeProtocol::new()));
383 #[cfg(not(target_arch = "wasm32"))]
384 self.register(Arc::new(crate::server::rcon::actions::RconProtocol::new()));
385 #[cfg(not(target_arch = "wasm32"))]
386 self.register(Arc::new(crate::server::a2s::actions::A2sProtocol::new()));
387 #[cfg(not(target_arch = "wasm32"))]
388 self.register(Arc::new(
389 crate::server::minecraft::actions::MinecraftProtocol::new(),
390 ));
391 #[cfg(not(target_arch = "wasm32"))]
392 self.register(Arc::new(crate::server::ninep::actions::NinepProtocol::new()));
393 #[cfg(not(target_arch = "wasm32"))]
394 self.register(Arc::new(
395 crate::server::zeromq::actions::ZeromqProtocol::new(),
396 ));
397 #[cfg(not(target_arch = "wasm32"))]
398 self.register(Arc::new(crate::server::smpp::actions::SmppProtocol::new()));
399 #[cfg(not(target_arch = "wasm32"))]
400 self.register(Arc::new(
401 crate::server::clickhouse::actions::ClickhouseProtocol::new(),
402 ));
403 #[cfg(not(target_arch = "wasm32"))]
404 self.register(Arc::new(
405 crate::server::msgpack_rpc::actions::MsgpackRpcProtocol::new(),
406 ));
407 #[cfg(not(target_arch = "wasm32"))]
408 self.register(Arc::new(
409 crate::server::zipkin::actions::ZipkinProtocol::new(),
410 ));
411 #[cfg(not(target_arch = "wasm32"))]
412 self.register(Arc::new(
413 crate::server::capnp_rpc::actions::CapnpRpcProtocol::new(),
414 ));
415 #[cfg(not(target_arch = "wasm32"))]
416 self.register(Arc::new(crate::server::knx::actions::KnxProtocol::new()));
417 #[cfg(not(target_arch = "wasm32"))]
418 self.register(Arc::new(
419 crate::server::consul::actions::ConsulProtocol::new(),
420 ));
421 #[cfg(not(target_arch = "wasm32"))]
422 self.register(Arc::new(
423 crate::server::milter::actions::MilterProtocol::new(),
424 ));
425 #[cfg(not(target_arch = "wasm32"))]
426 self.register(Arc::new(
427 crate::server::anthropic::actions::AnthropicProtocol::new(),
428 ));
429 #[cfg(not(target_arch = "wasm32"))]
430 self.register(Arc::new(
431 crate::server::radsec::actions::RadsecProtocol::new(),
432 ));
433 #[cfg(not(target_arch = "wasm32"))]
434 self.register(Arc::new(crate::server::dbus::actions::DbusProtocol::new()));
435 #[cfg(not(target_arch = "wasm32"))]
436 self.register(Arc::new(crate::server::bfd::actions::BfdProtocol::new()));
437 #[cfg(not(target_arch = "wasm32"))]
438 self.register(Arc::new(crate::server::vxlan::actions::VxlanProtocol::new()));
439 #[cfg(not(target_arch = "wasm32"))]
440 self.register(Arc::new(crate::server::rsync::actions::RsyncProtocol::new()));
441 #[cfg(not(target_arch = "wasm32"))]
442 self.register(Arc::new(crate::server::pfcp::actions::PfcpProtocol::new()));
443 #[cfg(not(target_arch = "wasm32"))]
444 self.register(Arc::new(
445 crate::server::matrix::actions::MatrixProtocol::new(),
446 ));
447 #[cfg(not(target_arch = "wasm32"))]
448 self.register(Arc::new(
449 crate::server::libp2p::actions::Libp2pProtocol::new(),
450 ));
451 #[cfg(not(target_arch = "wasm32"))]
452 self.register(Arc::new(
453 crate::server::sunrpc::actions::SunRpcProtocol::new(),
454 ));
455 #[cfg(not(target_arch = "wasm32"))]
456 self.register(Arc::new(
457 crate::server::guacamole::actions::GuacamoleProtocol::new(),
458 ));
459 #[cfg(not(target_arch = "wasm32"))]
460 self.register(Arc::new(
461 crate::server::activitypub::actions::ActivityPubProtocol::new(),
462 ));
463 #[cfg(not(target_arch = "wasm32"))]
464 self.register(Arc::new(
465 crate::server::stratum::actions::StratumProtocol::new(),
466 ));
467 #[cfg(not(target_arch = "wasm32"))]
468 self.register(Arc::new(
469 crate::server::stratum_v2::actions::StratumV2Protocol::new(),
470 ));
471 #[cfg(not(target_arch = "wasm32"))]
472 self.register(Arc::new(
473 crate::server::pulsar::actions::PulsarProtocol::new(),
474 ));
475 #[cfg(not(target_arch = "wasm32"))]
476 self.register(Arc::new(crate::server::tr069::actions::Tr069Protocol::new()));
477 #[cfg(not(target_arch = "wasm32"))]
478 self.register(Arc::new(crate::server::sse::actions::SseProtocol::new()));
479 #[cfg(not(target_arch = "wasm32"))]
480 self.register(Arc::new(
481 crate::server::wsdiscovery::actions::WsDiscoveryProtocol::new(),
482 ));
483 #[cfg(not(target_arch = "wasm32"))]
484 self.register(Arc::new(crate::server::onvif::actions::OnvifProtocol::new()));
485 #[cfg(not(target_arch = "wasm32"))]
486 self.register(Arc::new(
487 crate::server::kerberos::actions::KerberosProtocol::new(),
488 ));
489
490 #[cfg(not(target_arch = "wasm32"))]
491 self.register(Arc::new(
492 crate::server::netflow_v9::actions::NetflowV9Protocol::new(),
493 ));
494 #[cfg(not(target_arch = "wasm32"))]
495 self.register(Arc::new(crate::server::ipfix::actions::IpfixProtocol::new()));
496 #[cfg(not(target_arch = "wasm32"))]
497 self.register(Arc::new(
498 crate::server::prometheus_remote_write::actions::PrometheusRemoteWriteProtocol::new(),
499 ));
500 #[cfg(not(target_arch = "wasm32"))]
501 self.register(Arc::new(crate::server::sflow::actions::SflowProtocol::new()));
502 #[cfg(not(target_arch = "wasm32"))]
503 self.register(Arc::new(crate::server::loki::actions::LokiProtocol::new()));
504 #[cfg(not(target_arch = "wasm32"))]
505 self.register(Arc::new(
506 crate::server::influxdb::actions::InfluxDbProtocol::new(),
507 ));
508
509 #[cfg(not(target_arch = "wasm32"))]
510 self.register(Arc::new(
511 crate::server::fluent_forward::actions::FluentForwardProtocol::new(),
512 ));
513
514 #[cfg(not(target_arch = "wasm32"))]
515 self.register(Arc::new(crate::server::gelf::actions::GelfProtocol::new()));
516
517 #[cfg(not(target_arch = "wasm32"))]
518 self.register(Arc::new(
519 crate::server::graphite::actions::GraphiteProtocol::new(),
520 ));
521
522 #[cfg(not(target_arch = "wasm32"))]
523 self.register(Arc::new(
524 crate::server::statsd::actions::StatsdProtocol::new(),
525 ));
526
527 self.register(Arc::new(crate::server::SyslogProtocol::new()));
528
529 #[cfg(not(target_arch = "wasm32"))]
530 self.register(Arc::new(crate::server::SshProtocol::new()));
531
532 #[cfg(unix)]
533 self.register(Arc::new(crate::server::SshAgentProtocol::new()));
534
535 self.register(Arc::new(crate::server::SvnProtocol::new()));
536
537 #[cfg(not(target_arch = "wasm32"))]
538 self.register(Arc::new(crate::server::IrcProtocol::new()));
539
540 #[cfg(unix)]
541 self.register(Arc::new(crate::server::XmppProtocol::new()));
542
543 self.register(Arc::new(crate::server::TelnetProtocol::new()));
544
545 #[cfg(not(target_arch = "wasm32"))]
546 self.register(Arc::new(crate::server::SmtpProtocol::new()));
547
548 self.register(Arc::new(crate::server::FtpProtocol::new()));
549
550 #[cfg(not(target_arch = "wasm32"))]
551 self.register(Arc::new(crate::server::ImapProtocol::new()));
552
553 self.register(Arc::new(crate::server::Pop3Protocol::new()));
554
555 self.register(Arc::new(crate::server::NntpProtocol::new()));
556
557 #[cfg(not(target_arch = "wasm32"))]
558 self.register(Arc::new(crate::server::MqttProtocol::new()));
559
560 self.register(Arc::new(crate::server::ModbusProtocol::new()));
561
562 self.register(Arc::new(crate::server::CoapProtocol::new()));
563
564 #[cfg(not(target_arch = "wasm32"))]
565 self.register(Arc::new(crate::server::AmqpProtocol::new()));
566
567 #[cfg(not(target_arch = "wasm32"))]
568 self.register(Arc::new(crate::server::MdnsProtocol::new()));
569
570 #[cfg(not(target_arch = "wasm32"))]
571 self.register(Arc::new(crate::server::LdapProtocol::new()));
572
573 #[cfg(not(target_arch = "wasm32"))]
574 {
575 use crate::server::connection::ConnectionId;
576 use tokio::sync::mpsc;
577 let (tx, _rx) = mpsc::unbounded_channel();
578 self.register(Arc::new(crate::server::MysqlProtocol::new(
579 ConnectionId::new(0), dummy_state.clone(),
581 tx,
582 )));
583 }
584
585 {
586 use crate::server::connection::ConnectionId;
587 use tokio::sync::mpsc;
588 let (tx, _rx) = mpsc::unbounded_channel();
589 self.register(Arc::new(crate::server::SnowflakeProtocol::new(
590 ConnectionId::new(0), dummy_state.clone(),
592 tx,
593 )));
594 }
595
596 {
597 use crate::server::connection::ConnectionId;
598 use tokio::sync::mpsc;
599 let (tx, _rx) = mpsc::unbounded_channel();
600 self.register(Arc::new(crate::server::Db2Protocol::new(
601 ConnectionId::new(0), dummy_state.clone(),
603 tx,
604 )));
605 }
606
607 #[cfg(not(target_arch = "wasm32"))]
608 {
609 use crate::server::connection::ConnectionId;
610 use tokio::sync::mpsc;
611 let (tx, _rx) = mpsc::unbounded_channel();
612 self.register(Arc::new(crate::server::MssqlProtocol::new(
613 ConnectionId::new(0), dummy_state.clone(),
615 tx,
616 )));
617 }
618
619 #[cfg(not(target_arch = "wasm32"))]
620 {
621 use crate::server::connection::ConnectionId;
622 use tokio::sync::mpsc;
623 let (tx, _rx) = mpsc::unbounded_channel();
624 self.register(Arc::new(crate::server::PostgresqlProtocol::new(
625 ConnectionId::new(0), dummy_state.clone(),
627 tx,
628 )));
629 }
630
631 #[cfg(not(target_arch = "wasm32"))]
632 {
633 use crate::server::connection::ConnectionId;
634 use tokio::sync::mpsc;
635 let (tx, _rx) = mpsc::unbounded_channel();
636 self.register(Arc::new(crate::server::RedisProtocol::new(
637 ConnectionId::new(0), dummy_state.clone(),
639 tx,
640 )));
641 }
642
643 self.register(Arc::new(crate::server::MemcachedProtocol::new()));
644
645 self.register(Arc::new(crate::server::RadiusProtocol::new()));
646
647 self.register(Arc::new(crate::server::RssProtocol::new()));
648
649 #[cfg(not(target_arch = "wasm32"))]
650 {
651 use crate::server::connection::ConnectionId;
652 use tokio::sync::mpsc;
653 let (tx, _rx) = mpsc::unbounded_channel();
654 self.register(Arc::new(crate::server::CassandraProtocol::new(
655 ConnectionId::new(0), dummy_state.clone(),
657 tx,
658 )));
659 }
660
661 {
662 use crate::server::connection::ConnectionId;
663 use tokio::sync::mpsc;
664 let (tx, _rx) = mpsc::unbounded_channel();
665 self.register(Arc::new(crate::server::MongodbProtocol::new(
666 ConnectionId::new(0), dummy_state.clone(),
668 tx,
669 )));
670 }
671
672 #[cfg(not(target_arch = "wasm32"))]
673 self.register(Arc::new(crate::server::DynamoProtocol::new()));
674
675 #[cfg(not(target_arch = "wasm32"))]
676 self.register(Arc::new(crate::server::S3Protocol::new()));
677
678 #[cfg(not(target_arch = "wasm32"))]
679 self.register(Arc::new(crate::server::SqsProtocol::new()));
680
681 self.register(Arc::new(crate::server::ElasticsearchProtocol::new()));
682
683 #[cfg(not(target_arch = "wasm32"))]
684 self.register(Arc::new(crate::server::CouchDbProtocol::new()));
685
686 self.register(Arc::new(crate::server::YarnProtocol::new()));
687
688 self.register(Arc::new(crate::server::SparkProtocol::new()));
689
690 self.register(Arc::new(crate::server::NpmProtocol::new()));
691
692 self.register(Arc::new(crate::server::OciRegistryProtocol::new()));
693
694 self.register(Arc::new(crate::server::KubernetesProtocol::new()));
695
696 #[cfg(not(target_arch = "wasm32"))]
697 self.register(Arc::new(crate::server::PrometheusProtocol::new()));
698
699 #[cfg(not(target_arch = "wasm32"))]
700 self.register(Arc::new(crate::server::OtlpProtocol::new()));
701
702 #[cfg(not(target_arch = "wasm32"))]
703 self.register(Arc::new(crate::server::DockerProtocol::new()));
704
705 #[cfg(not(target_arch = "wasm32"))]
706 self.register(Arc::new(crate::server::VaultProtocol::new()));
707
708 #[cfg(not(target_arch = "wasm32"))]
709 self.register(Arc::new(crate::server::BoltProtocol::new()));
710
711 #[cfg(not(target_arch = "wasm32"))]
712 self.register(Arc::new(crate::server::IppProtocol::new()));
713
714 #[cfg(not(target_arch = "wasm32"))]
715 self.register(Arc::new(crate::server::WebDavProtocol::new()));
716
717 #[cfg(unix)]
718 self.register(Arc::new(crate::server::NfsProtocol::new()));
719
720 #[cfg(unix)]
721 self.register(Arc::new(crate::server::NfcServerProtocol));
722
723 self.register(Arc::new(crate::server::SmbProtocol::new()));
724
725 #[cfg(unix)]
726 self.register(Arc::new(crate::server::ProxyProtocol::new()));
727
728 #[cfg(not(target_arch = "wasm32"))]
729 self.register(Arc::new(crate::server::Socks5Protocol::new()));
730
731 #[cfg(unix)]
732 self.register(Arc::new(crate::server::WireguardProtocol::new()));
733
734 #[cfg(unix)]
735 self.register(Arc::new(crate::server::OpenvpnProtocol::new()));
736
737 #[cfg(not(target_arch = "wasm32"))]
738 self.register(Arc::new(crate::server::IpsecProtocol::new()));
739
740 #[cfg(unix)]
741 self.register(Arc::new(crate::server::StunProtocol::new()));
742
743 #[cfg(unix)]
744 self.register(Arc::new(crate::server::TurnProtocol::new()));
745
746 #[cfg(not(target_arch = "wasm32"))]
747 self.register(Arc::new(crate::server::WebRtcProtocol::new()));
748
749 #[cfg(not(target_arch = "wasm32"))]
750 self.register(Arc::new(crate::server::WebRtcSignalingProtocol::new()));
751
752 #[cfg(not(target_arch = "wasm32"))]
753 self.register(Arc::new(crate::server::WebSocketProtocol::new()));
754
755 self.register(Arc::new(crate::server::SipProtocol::new()));
756 #[cfg(not(target_arch = "wasm32"))]
757 self.register(Arc::new(
758 crate::server::h323::actions::H323GatekeeperProtocol::new(),
759 ));
760 #[cfg(not(target_arch = "wasm32"))]
761 self.register(Arc::new(
762 crate::server::h323::actions::H323EndpointProtocol::new(),
763 ));
764
765 self.register(Arc::new(crate::server::RtpProtocol::new()));
766
767 self.register(Arc::new(crate::server::RtspProtocol::new()));
768
769 self.register(Arc::new(crate::server::HlsProtocol::new()));
770
771 self.register(Arc::new(crate::server::BgpProtocol::new()));
772
773 #[cfg(unix)]
774 self.register(Arc::new(crate::server::OspfProtocol::new()));
775
776 #[cfg(all(unix, feature = "libpcap"))]
777 self.register(Arc::new(crate::server::IsisProtocol::new()));
778
779 #[cfg(not(target_arch = "wasm32"))]
780 self.register(Arc::new(crate::server::RipProtocol::new()));
781
782 self.register(Arc::new(crate::server::BitcoinProtocol::new()));
783 #[cfg(not(target_arch = "wasm32"))]
784 self.register(Arc::new(
785 crate::server::devp2p::actions::Devp2pProtocol::new(),
786 ));
787 #[cfg(not(target_arch = "wasm32"))]
788 self.register(Arc::new(crate::server::NostrProtocol::new()));
789
790 #[cfg(not(target_arch = "wasm32"))]
791 self.register(Arc::new(crate::server::McpProtocol::new()));
792
793 #[cfg(not(target_arch = "wasm32"))]
794 self.register(Arc::new(crate::server::OpenAiProtocol::new()));
795
796 self.register(Arc::new(crate::server::OllamaProtocol::new()));
797
798 self.register(Arc::new(crate::server::OAuth2Protocol::new()));
799
800 self.register(Arc::new(crate::server::JsonRpcProtocol::new()));
801
802 #[cfg(not(target_arch = "wasm32"))]
803 self.register(Arc::new(crate::server::XmlRpcProtocol::new()));
804
805 #[cfg(not(target_arch = "wasm32"))]
806 self.register(Arc::new(crate::server::GrpcProtocol::new()));
807 #[cfg(not(target_arch = "wasm32"))]
808 self.register(Arc::new(
809 crate::server::grpc_web::actions::GrpcWebProtocol::new(),
810 ));
811 #[cfg(not(target_arch = "wasm32"))]
812 self.register(Arc::new(crate::server::gnmi::actions::GnmiProtocol::new()));
813 #[cfg(not(target_arch = "wasm32"))]
814 self.register(Arc::new(
815 crate::server::connect_rpc::actions::ConnectRpcProtocol::new(),
816 ));
817
818 #[cfg(not(target_arch = "wasm32"))]
819 self.register(Arc::new(crate::server::EtcdProtocol::new()));
820
821 #[cfg(not(target_arch = "wasm32"))]
822 self.register(Arc::new(crate::server::ZookeeperProtocol::new()));
823
824 #[cfg(unix)]
825 self.register(Arc::new(crate::server::TorRelayProtocol::new()));
826
827 self.register(Arc::new(crate::server::VncProtocol::new()));
828
829 self.register(Arc::new(crate::server::ReverseShellProtocol::new()));
830
831 self.register(Arc::new(crate::server::RdpProtocol::new()));
832 #[cfg(not(target_arch = "wasm32"))]
833 self.register(Arc::new(crate::server::spice::actions::SpiceProtocol::new()));
834
835 self.register(Arc::new(crate::server::OpenApiProtocol::new()));
836
837 self.register(Arc::new(crate::server::OpenIdProtocol::new()));
838
839 #[cfg(not(target_arch = "wasm32"))]
840 self.register(Arc::new(crate::server::GitProtocol::new()));
841
842 self.register(Arc::new(crate::server::MercurialProtocol::new()));
843
844 self.register(Arc::new(crate::server::KafkaProtocol::new()));
845
846 #[cfg(not(target_arch = "wasm32"))]
847 self.register(Arc::new(crate::server::Http3Protocol::new()));
848
849 #[cfg(not(target_arch = "wasm32"))]
850 self.register(Arc::new(crate::server::QuicProtocol::new()));
851
852 self.register(Arc::new(crate::server::TorrentTrackerProtocol::new()));
853
854 self.register(Arc::new(crate::server::TorrentDhtProtocol::new()));
855
856 self.register(Arc::new(crate::server::TorrentPeerProtocol::new()));
857
858 self.register(Arc::new(crate::server::TlsProtocol::new()));
859
860 self.register(Arc::new(crate::server::SamlIdpProtocol::new()));
861
862 self.register(Arc::new(crate::server::SamlSpProtocol::new()));
863
864 #[cfg(all(unix, feature = "libusb"))]
865 self.register(Arc::new(crate::server::UsbKeyboardProtocol::new()));
866
867 #[cfg(all(unix, feature = "libusb"))]
868 self.register(Arc::new(crate::server::UsbMouseProtocol::new()));
869
870 #[cfg(all(unix, feature = "libusb"))]
871 self.register(Arc::new(crate::server::UsbSerialProtocol::new()));
872
873 #[cfg(all(unix, feature = "libusb"))]
874 self.register(Arc::new(crate::server::UsbMscProtocol::new()));
875
876 #[cfg(all(unix, feature = "libusb"))]
877 self.register(Arc::new(crate::server::UsbFido2Protocol::new()));
878
879 #[cfg(all(unix, feature = "libusb"))]
880 self.register(Arc::new(crate::server::UsbSmartCardProtocol::new()));
881
882 #[cfg(all(unix, feature = "bluetooth"))]
883 self.register(Arc::new(crate::server::BluetoothBleProtocol::new()));
884
885 #[cfg(all(unix, feature = "bluetooth"))]
886 self.register(Arc::new(crate::server::BluetoothBleKeyboardProtocol::new()));
887
888 #[cfg(all(unix, feature = "bluetooth"))]
889 self.register(Arc::new(crate::server::BluetoothBleMouseProtocol::new()));
890
891 #[cfg(all(unix, feature = "bluetooth"))]
892 self.register(Arc::new(crate::server::BluetoothBleBeaconProtocol::new()));
893
894 #[cfg(all(unix, feature = "bluetooth"))]
895 self.register(Arc::new(crate::server::BluetoothBleRemoteProtocol::new()));
896
897 #[cfg(all(unix, feature = "bluetooth"))]
898 self.register(Arc::new(crate::server::BluetoothBleBatteryProtocol::new()));
899
900 #[cfg(all(unix, feature = "bluetooth"))]
901 self.register(Arc::new(crate::server::BluetoothBleHeartRateProtocol::new()));
902
903 #[cfg(all(unix, feature = "bluetooth"))]
904 self.register(Arc::new(
905 crate::server::BluetoothBleThermometerProtocol::new(),
906 ));
907
908 #[cfg(all(unix, feature = "bluetooth"))]
909 self.register(Arc::new(
910 crate::server::BluetoothBleEnvironmentalProtocol::new(),
911 ));
912
913 #[cfg(all(unix, feature = "bluetooth"))]
914 self.register(Arc::new(crate::server::BluetoothBleProximityProtocol::new()));
915
916 #[cfg(all(unix, feature = "bluetooth"))]
917 self.register(Arc::new(crate::server::BluetoothBleGamepadProtocol::new()));
918
919 #[cfg(all(unix, feature = "bluetooth"))]
920 self.register(Arc::new(crate::server::BluetoothBlePresenterProtocol::new()));
921
922 #[cfg(all(unix, feature = "bluetooth"))]
923 self.register(Arc::new(
924 crate::server::BluetoothBleFileTransferProtocol::new(),
925 ));
926
927 #[cfg(all(unix, feature = "bluetooth"))]
928 self.register(Arc::new(
929 crate::server::BluetoothBleDataStreamProtocol::new(),
930 ));
931
932 #[cfg(all(unix, feature = "bluetooth"))]
933 self.register(Arc::new(crate::server::BluetoothBleCyclingProtocol::new()));
934
935 #[cfg(all(unix, feature = "bluetooth"))]
936 self.register(Arc::new(crate::server::BluetoothBleRunningProtocol::new()));
937
938 #[cfg(all(unix, feature = "bluetooth"))]
939 self.register(Arc::new(
940 crate::server::BluetoothBleWeightScaleProtocol::new(),
941 ));
942 }
943
944 fn build_keyword_map(&mut self) {
946 for (protocol_name, protocol) in &self.protocols {
947 for keyword in protocol.keywords() {
949 let lower = keyword.to_lowercase();
950 let normalized = lower.replace(['-', ' '], "_");
954 self.keyword_map.insert(lower, protocol_name.clone());
955 self.keyword_map.insert(normalized, protocol_name.clone());
956 }
957
958 let stack_name = protocol.stack_name().to_lowercase();
961 self.keyword_map.insert(stack_name, protocol_name.clone());
962 }
963 }
964
965 pub fn get_keyword_overlaps(&self) -> Vec<(String, Vec<(String, String)>)> {
970 use std::collections::HashMap;
971
972 let mut keyword_to_protocols: HashMap<String, Vec<(String, String)>> = HashMap::new();
975
976 for (protocol_name, protocol) in &self.protocols {
977 for keyword in protocol.keywords() {
979 let key = keyword.to_lowercase();
980 keyword_to_protocols
981 .entry(key)
982 .or_default()
983 .push((protocol_name.clone(), format!("keyword '{}'", keyword)));
984 }
985
986 let stack_name = protocol.stack_name();
988 let key = stack_name.to_lowercase();
989 keyword_to_protocols.entry(key).or_default().push((
990 protocol_name.clone(),
991 format!("stack_name '{}'", stack_name),
992 ));
993 }
994
995 let mut overlaps = Vec::new();
999 for (keyword, protocols) in &keyword_to_protocols {
1000 let distinct: std::collections::HashSet<&String> =
1001 protocols.iter().map(|(name, _)| name).collect();
1002 if distinct.len() > 1 {
1003 overlaps.push((keyword.clone(), protocols.clone()));
1004 }
1005 }
1006
1007 overlaps
1008 }
1009
1010 fn validate_keyword_uniqueness(&self) {
1015 let overlaps = self.get_keyword_overlaps();
1016
1017 if !overlaps.is_empty() {
1023 use tracing::debug;
1024 debug!("Keyword overlaps detected between protocols:");
1025
1026 for (keyword, protocols) in &overlaps {
1027 debug!(" Keyword '{}' is used by:", keyword);
1028 for (protocol_name, source) in protocols {
1029 debug!(" - {} ({})", protocol_name, source);
1030 }
1031 }
1032
1033 debug!("Note: Each keyword should ideally be unique to a single protocol.");
1034 debug!(
1035 " Run 'cargo test test_keyword_overlaps -- --ignored' to see all overlaps."
1036 );
1037 }
1038 }
1039
1040 #[allow(dead_code)]
1042 fn register(&mut self, protocol: Arc<dyn Server>) {
1043 let protocol_name = protocol.protocol_name().to_string();
1044 self.protocols.insert(protocol_name, protocol);
1045 }
1046
1047 pub fn get(&self, protocol_name: &str) -> Option<Arc<dyn Server>> {
1049 self.protocols.get(protocol_name).cloned()
1050 }
1051
1052 pub fn resolve(&self, input: &str) -> Result<Arc<dyn Server>, ProtocolLookupError> {
1064 if let Some(p) = self.get(input) {
1067 return Ok(p);
1068 }
1069
1070 if let Some(name) = self.parse_from_str(input) {
1073 if let Some(p) = self.get(&name) {
1074 return Ok(p);
1075 }
1076 }
1077
1078 let input_norm = input.to_lowercase().replace(['-', ' '], "_");
1081 for (name, requires) in ALL_KNOWN_PROTOCOLS {
1082 let name_norm = name.to_lowercase().replace(['-', ' '], "_");
1083 if name_norm == input_norm {
1084 return Err(ProtocolLookupError::NotCompiled { name, requires });
1085 }
1086 }
1087
1088 Err(ProtocolLookupError::Unknown {
1091 input: input.to_string(),
1092 suggestion: suggest_protocol_name(input, ALL_KNOWN_PROTOCOLS),
1093 })
1094 }
1095
1096 pub fn parse_from_str(&self, input: &str) -> Option<String> {
1101 let input_lower = input.to_lowercase();
1102 let input_normalized = input_lower.replace(['-', ' '], "_");
1105
1106 for (protocol_name, protocol) in &self.protocols {
1108 let stack_lower = protocol.stack_name().to_lowercase();
1109 let stack_normalized = stack_lower.replace(['-', ' '], "_");
1110 if input_lower == stack_lower
1111 || input_normalized == stack_lower
1112 || input_normalized == stack_normalized
1113 {
1114 return Some(protocol_name.clone());
1115 }
1116 }
1117
1118 for (protocol_name, protocol) in &self.protocols {
1120 let proto_lower = protocol.protocol_name().to_lowercase();
1121 let proto_normalized = proto_lower.replace(['-', ' '], "_");
1122 if input_lower == proto_lower
1123 || input_normalized == proto_lower
1124 || input_normalized == proto_normalized
1125 {
1126 return Some(protocol_name.clone());
1127 }
1128 }
1129
1130 if let Some(stack) =
1135 self.match_protocol_by_any_keyword_with_boundaries(&input_lower, "mDNS")
1136 {
1137 return Some(stack);
1138 }
1139
1140 if let Some(stack) =
1142 self.match_protocol_by_any_keyword_with_boundaries(&input_lower, "IMAP")
1143 {
1144 return Some(stack);
1145 }
1146
1147 if let Some(stack) =
1149 self.match_protocol_by_any_keyword_with_boundaries(&input_lower, "SMTP")
1150 {
1151 return Some(stack);
1152 }
1153
1154 if let Some(stack) =
1156 self.match_protocol_by_any_keyword_with_boundaries(&input_lower, "SNMP")
1157 {
1158 return Some(stack);
1159 }
1160
1161 if let Some(stack) =
1163 self.match_protocol_by_any_keyword_with_boundaries(&input_lower, "PostgreSQL")
1164 {
1165 return Some(stack);
1166 }
1167
1168 if let Some(stack) =
1170 self.match_protocol_by_any_keyword_with_boundaries(&input_lower, "XmlRPC")
1171 {
1172 return Some(stack);
1173 }
1174 if let Some(stack) =
1175 self.match_protocol_by_any_keyword_with_boundaries(&input_lower, "JsonRPC")
1176 {
1177 return Some(stack);
1178 }
1179
1180 if let Some(stack) =
1182 self.match_protocol_by_any_keyword_with_boundaries(&input_lower, "Proxy")
1183 {
1184 return Some(stack);
1185 }
1186
1187 if let Some(stack) =
1189 self.match_protocol_by_any_keyword_with_boundaries(&input_lower, "TorDirectory")
1190 {
1191 return Some(stack);
1192 }
1193 if let Some(stack) =
1194 self.match_protocol_by_any_keyword_with_boundaries(&input_lower, "TorRelay")
1195 {
1196 return Some(stack);
1197 }
1198
1199 if let Some(stack) =
1205 self.match_protocol_by_any_keyword_with_boundaries(&input_lower, "WebRTC Signaling")
1206 {
1207 return Some(stack);
1208 }
1209
1210 if let Some(stack) =
1224 self.match_protocol_by_any_keyword_with_boundaries(&input_lower, "MQTT")
1225 {
1226 return Some(stack);
1227 }
1228
1229 for aws_service in ["S3", "SQS", "DynamoDB"] {
1230 if let Some(stack) =
1231 self.match_protocol_by_any_keyword_with_boundaries(&input_lower, aws_service)
1232 {
1233 return Some(stack);
1234 }
1235 }
1236
1237 let mut best: Option<(usize, &String)> = None;
1248 for (protocol_name, protocol) in &self.protocols {
1249 for keyword in protocol.keywords() {
1250 let keyword = keyword.to_lowercase();
1251 if !self.matches_with_word_boundary(&input_lower, &keyword) {
1252 continue;
1253 }
1254 let better = match best {
1255 None => true,
1256 Some((best_len, best_name)) => {
1257 keyword.len() > best_len
1258 || (keyword.len() == best_len && protocol_name < best_name)
1259 }
1260 };
1261 if better {
1262 best = Some((keyword.len(), protocol_name));
1263 }
1264 }
1265 }
1266 if let Some((_, protocol_name)) = best {
1267 return Some(protocol_name.clone());
1268 }
1269
1270 if input_lower.contains("tcp")
1272 || input_lower.contains("raw")
1273 || input_lower.contains("ftp")
1274 || input_lower.contains("custom")
1275 {
1276 return Some("TCP".to_string());
1277 }
1278
1279 None
1280 }
1281
1282 fn matches_with_word_boundary(&self, input: &str, keyword: &str) -> bool {
1290 if keyword.contains(' ') {
1292 return input.contains(keyword);
1293 }
1294
1295 let input_bytes = input.as_bytes();
1297
1298 if let Some(pos) = input.find(keyword) {
1299 let before_ok = if pos == 0 {
1301 true
1302 } else {
1303 let c = input_bytes[pos - 1];
1304 !c.is_ascii_alphanumeric() && c != b'_' && c != b'-'
1305 };
1306
1307 let end_pos = pos + keyword.len();
1309 let after_ok = if end_pos >= input.len() {
1310 true
1311 } else {
1312 let c = input_bytes[end_pos];
1313 !c.is_ascii_alphanumeric() && c != b'_' && c != b'-'
1314 };
1315
1316 return before_ok && after_ok;
1317 }
1318
1319 false
1320 }
1321
1322 fn match_protocol_by_any_keyword_with_boundaries(
1327 &self,
1328 input_lower: &str,
1329 protocol_name: &str,
1330 ) -> Option<String> {
1331 if let Some(protocol) = self.protocols.get(protocol_name) {
1332 for keyword in protocol.keywords() {
1333 if self.matches_with_word_boundary(input_lower, &keyword.to_lowercase()) {
1334 return Some(protocol_name.to_string());
1335 }
1336 }
1337 }
1338 None
1339 }
1340
1341 pub fn available_protocols(&self) -> Vec<&'static str> {
1343 let mut protocols: Vec<&'static str> =
1344 self.protocols.values().map(|p| p.protocol_name()).collect();
1345 protocols.sort();
1347 protocols
1348 }
1349
1350 pub fn stack_name_by_protocol(&self, protocol_name: &str) -> Option<&'static str> {
1352 self.get(protocol_name).map(|p| p.stack_name())
1353 }
1354
1355 pub fn metadata(&self, protocol_name: &str) -> Option<ProtocolMetadataV2> {
1357 self.get(protocol_name).map(|p| p.metadata())
1358 }
1359
1360 pub fn request_only_reason(&self, protocol_name: &str) -> Option<&'static str> {
1364 self.resolve(protocol_name)
1365 .ok()
1366 .and_then(|p| p.metadata().request_only)
1367 }
1368
1369 pub fn all_protocols(&self) -> Vec<(String, Arc<dyn Server>)> {
1371 self.protocols
1372 .iter()
1373 .map(|(name, protocol)| (name.clone(), Arc::clone(protocol)))
1374 .collect()
1375 }
1376
1377 pub fn get_excluded_protocols(
1381 &self,
1382 caps: &crate::privilege::SystemCapabilities,
1383 ) -> HashMap<String, Vec<super::dependencies::ProtocolDependency>> {
1384 let mut excluded = HashMap::new();
1385
1386 for (protocol_name, protocol) in &self.protocols {
1387 let dependencies = protocol.get_dependencies();
1388 let mut missing = Vec::new();
1389
1390 for dep in dependencies {
1391 if !dep.is_available(caps) {
1392 missing.push(dep);
1393 }
1394 }
1395
1396 if !missing.is_empty() {
1397 excluded.insert(protocol_name.clone(), missing);
1398 }
1399 }
1400
1401 excluded
1402 }
1403
1404 pub fn privileged_default_ports(
1413 &self,
1414 caps: &crate::privilege::SystemCapabilities,
1415 ) -> Vec<(String, u16)> {
1416 if caps.can_bind_privileged_ports {
1417 return Vec::new();
1418 }
1419 let mut out: Vec<(String, u16)> = self
1420 .protocols
1421 .iter()
1422 .filter_map(
1423 |(name, protocol)| match protocol.metadata().privilege_requirement {
1424 crate::protocol::metadata::PrivilegeRequirement::PrivilegedPort(port) => {
1425 Some((name.clone(), port))
1426 }
1427 _ => None,
1428 },
1429 )
1430 .collect();
1431 out.sort();
1432 out
1433 }
1434
1435 pub fn get_available_protocols(
1439 &self,
1440 caps: &crate::privilege::SystemCapabilities,
1441 ) -> Vec<String> {
1442 let excluded = self.get_excluded_protocols(caps);
1443
1444 self.protocols
1445 .keys()
1446 .filter(|name| !excluded.contains_key(*name))
1447 .cloned()
1448 .collect()
1449 }
1450
1451 pub fn is_protocol_available(
1453 &self,
1454 protocol_name: &str,
1455 caps: &crate::privilege::SystemCapabilities,
1456 ) -> bool {
1457 if let Some(protocol) = self.get(protocol_name) {
1458 let dependencies = protocol.get_dependencies();
1459 dependencies.iter().all(|dep| dep.is_available(caps))
1460 } else {
1461 false
1462 }
1463 }
1464}
1465
1466pub(crate) const ALL_KNOWN_PROTOCOLS: &[(&str, &str)] = &[
1477 ("TCP", "nothing (every build has it)"),
1478 ("SOCKET_FILE", "a Unix build (macOS or Linux)"),
1479 ("PTY", "a Unix build (macOS or Linux)"),
1483 ("STDIO", "a Unix build (macOS or Linux)"),
1484 ("NAMED_PIPE", "a Unix build (macOS or Linux)"),
1485 ("HTTP", "nothing (every build has it)"),
1486 ("HTTP2", "nothing (every build has it)"),
1487 ("PyPI", "nothing (every build has it)"),
1488 ("Maven", "nothing (every build has it)"),
1489 ("UDP", "nothing (every build has it)"),
1490 ("DataLink", "the `libpcap` feature, on Unix"),
1491 ("ARP", "the `libpcap` feature, on Unix"),
1492 ("ICMP", "a Unix build (macOS or Linux)"),
1493 ("NMDC Peer", "a native build (not the browser)"),
1494 ("ADC", "a native build (not the browser)"),
1495 ("ADC Peer", "a native build (not the browser)"),
1496 ("Soulseek", "a native build (not the browser)"),
1497 ("Soulseek Peer", "a native build (not the browser)"),
1498 ("Gnutella", "a native build (not the browser)"),
1499 ("DC", "nothing (every build has it)"),
1500 ("DNS", "a native build (not the browser)"),
1501 ("DoT", "a native build (not the browser)"),
1502 ("DoQ", "a native build (not the browser)"),
1503 ("DoH", "a native build (not the browser)"),
1504 ("DHCP", "nothing (every build has it)"),
1505 ("BOOTP", "nothing (every build has it)"),
1506 ("NTP", "a native build (not the browser)"),
1507 ("TFTP", "nothing (every build has it)"),
1508 ("NUT", "a native build (not the browser)"),
1509 ("WHOIS", "nothing (every build has it)"),
1510 ("NDP", "a Unix build (macOS or Linux)"),
1511 ("DHCPv6", "nothing (every build has it)"),
1512 ("TUN/TAP", "a Unix build (macOS or Linux)"),
1513 ("Raw IP", "a Unix build (macOS or Linux)"),
1514 ("GTP", "nothing (every build has it)"),
1515 ("M3UA", "a Unix build (macOS or Linux)"),
1516 ("NGAP", "a Unix build (macOS or Linux)"),
1517 ("CAN", "a Unix build (macOS or Linux)"),
1518 ("LLDP", "the `libpcap` feature, on Unix"),
1519 ("CDP", "the `libpcap` feature, on Unix"),
1520 ("STP", "the `libpcap` feature, on Unix"),
1521 ("VRRP", "a Unix build (macOS or Linux)"),
1522 ("HSRP", "nothing (every build has it)"),
1523 ("EAPOL", "the `libpcap` feature, on Unix"),
1524 ("Wake-on-LAN", "nothing (every build has it)"),
1525 ("NATS", "nothing (every build has it)"),
1526 ("STOMP", "nothing (every build has it)"),
1527 ("Ident", "nothing (every build has it)"),
1528 ("Gopher", "nothing (every build has it)"),
1529 ("DICT", "a native build (not the browser)"),
1530 ("Beanstalkd", "a native build (not the browser)"),
1531 ("Zabbix", "a native build (not the browser)"),
1532 ("Gearman", "a native build (not the browser)"),
1533 ("NSQ", "a native build (not the browser)"),
1534 ("Gemini", "a native build (not the browser)"),
1535 ("Finger", "nothing (every build has it)"),
1536 ("SSDP", "nothing (every build has it)"),
1537 ("LLMNR", "a native build (not the browser)"),
1538 ("NetBIOS-NS", "nothing (every build has it)"),
1539 ("SNMP", "nothing (every build has it)"),
1540 ("IGMP", "a Unix build (macOS or Linux)"),
1541 ("Syslog", "nothing (every build has it)"),
1542 ("FluentForward", "a native build (not the browser)"),
1543 ("NETFLOWV9", "a native build (not the browser)"),
1544 ("NETFLOW-V9", "a native build (not the browser)"),
1545 ("NETFLOW_V9", "a native build (not the browser)"),
1546 ("IPFIX", "a native build (not the browser)"),
1547 ("IPFIX-UDP", "a native build (not the browser)"),
1548 ("PrometheusRemoteWrite", "a native build (not the browser)"),
1549 ("RemoteWrite", "a native build (not the browser)"),
1550 ("sFlow", "a native build (not the browser)"),
1551 ("sFlow-v5", "a native build (not the browser)"),
1552 ("Loki", "a native build (not the browser)"),
1553 ("LokiPush", "a native build (not the browser)"),
1554 ("InfluxDB", "a native build (not the browser)"),
1555 ("InfluxDB2", "a native build (not the browser)"),
1556 ("GELF", "a native build (not the browser)"),
1557 ("Graylog", "a native build (not the browser)"),
1558 ("Graphite", "a native build (not the browser)"),
1559 ("StatsD", "a native build (not the browser)"),
1560 ("DogStatsD", "a native build (not the browser)"),
1561 ("SSH", "a native build (not the browser)"),
1562 ("SSH Agent", "a Unix build (macOS or Linux)"),
1563 ("SVN", "nothing (every build has it)"),
1564 ("IRC", "a native build (not the browser)"),
1565 ("XMPP", "a Unix build (macOS or Linux)"),
1566 ("Telnet", "nothing (every build has it)"),
1567 ("SMTP", "a native build (not the browser)"),
1568 ("FTP", "nothing (every build has it)"),
1569 ("IMAP", "a native build (not the browser)"),
1570 ("NNTP", "nothing (every build has it)"),
1571 ("MQTT", "a native build (not the browser)"),
1572 ("Modbus", "nothing (every build has it)"),
1573 ("CoAP", "nothing (every build has it)"),
1574 ("AMQP", "a native build (not the browser)"),
1575 ("mDNS", "a native build (not the browser)"),
1576 ("LDAP", "a native build (not the browser)"),
1577 ("MySQL", "a native build (not the browser)"),
1578 ("MSSQL", "a native build (not the browser)"),
1579 ("Snowflake", "nothing (every build has it)"),
1580 ("Db2", "nothing (every build has it)"),
1581 ("PostgreSQL", "a native build (not the browser)"),
1582 ("Memcached", "nothing (every build has it)"),
1583 ("RADIUS", "nothing (every build has it)"),
1584 ("DIAMETER", "a native build (not the browser)"),
1585 ("Redis", "a native build (not the browser)"),
1586 ("RSS", "nothing (every build has it)"),
1587 ("Cassandra", "a native build (not the browser)"),
1588 ("MongoDB", "nothing (every build has it)"),
1589 ("DynamoDB", "a native build (not the browser)"),
1590 ("SQS", "a native build (not the browser)"),
1591 ("Elasticsearch", "nothing (every build has it)"),
1592 ("CouchDB", "a native build (not the browser)"),
1593 ("YARN", "nothing (every build has it)"),
1594 ("Spark", "nothing (every build has it)"),
1595 ("NPM", "nothing (every build has it)"),
1596 ("OCI-Registry", "nothing (every build has it)"),
1597 ("Kubernetes", "nothing (every build has it)"),
1598 ("Prometheus", "a native build (not the browser)"),
1599 ("OTLP", "a native build (not the browser)"),
1600 ("Docker", "a native build (not the browser)"),
1601 ("Vault", "a native build (not the browser)"),
1602 ("Bolt", "a native build (not the browser)"),
1603 ("IPP", "a native build (not the browser)"),
1604 ("WebDAV", "a native build (not the browser)"),
1605 ("NFS", "a Unix build (macOS or Linux)"),
1606 ("nfc", "a Unix build (macOS or Linux)"),
1607 ("SMB", "nothing (every build has it)"),
1608 ("Proxy", "a Unix build (macOS or Linux)"),
1609 ("SOCKS5", "a native build (not the browser)"),
1610 ("WireGuard", "a Unix build (macOS or Linux)"),
1611 ("OpenVPN", "a Unix build (macOS or Linux)"),
1612 ("IPSec/IKEv2", "a native build (not the browser)"),
1613 ("TURN", "a Unix build (macOS or Linux)"),
1614 ("WebRTC Signaling", "a native build (not the browser)"),
1615 ("WebSocket", "a native build (not the browser)"),
1616 ("SIP", "nothing (every build has it)"),
1617 ("H323", "a native build (not the browser)"),
1618 ("H323-Gatekeeper", "a native build (not the browser)"),
1619 ("RTP", "nothing (every build has it)"),
1620 ("RTSP", "nothing (every build has it)"),
1621 ("HLS", "nothing (every build has it)"),
1622 ("ISIS", "the `libpcap` feature, on Unix"),
1623 ("RIP", "a native build (not the browser)"),
1624 ("Bitcoin P2P", "nothing (every build has it)"),
1625 ("devp2p", "a native build (not the browser)"),
1626 ("Nostr", "a native build (not the browser)"),
1627 ("MCP", "a native build (not the browser)"),
1628 ("OpenAI", "a native build (not the browser)"),
1629 ("Ollama", "nothing (every build has it)"),
1630 ("OAuth2", "nothing (every build has it)"),
1631 ("JSON-RPC", "nothing (every build has it)"),
1632 ("XML-RPC", "a native build (not the browser)"),
1633 ("gRPC", "a native build (not the browser)"),
1634 ("gRPC-Web", "a native build (not the browser)"),
1635 ("gNMI", "a native build (not the browser)"),
1636 ("ConnectRPC", "a native build (not the browser)"),
1637 ("TACACS", "a native build (not the browser)"),
1638 ("NETCONF", "a native build (not the browser)"),
1639 ("RPKI-RTR", "a native build (not the browser)"),
1640 ("RDAP", "a native build (not the browser)"),
1641 ("HL7", "a native build (not the browser)"),
1642 ("ICAP", "a native build (not the browser)"),
1643 ("OCPP", "a native build (not the browser)"),
1644 ("A2A", "a native build (not the browser)"),
1645 ("GraphQL", "a native build (not the browser)"),
1646 ("FastCGI", "a native build (not the browser)"),
1647 ("Redfish", "a native build (not the browser)"),
1648 ("SCIM", "a native build (not the browser)"),
1649 ("Socket.IO", "a native build (not the browser)"),
1650 ("CalDAV", "a native build (not the browser)"),
1651 ("CardDAV", "a native build (not the browser)"),
1652 ("DICOM", "a native build (not the browser)"),
1653 ("ACME", "a native build (not the browser)"),
1654 ("FIX", "a native build (not the browser)"),
1655 ("WAMP", "a native build (not the browser)"),
1656 ("RTMP", "a native build (not the browser)"),
1657 ("SRT", "a native build (not the browser)"),
1658 ("AMQP1", "a native build (not the browser)"),
1659 ("Thrift", "a native build (not the browser)"),
1660 ("BMP", "a native build (not the browser)"),
1661 ("MQTT-SN", "a native build (not the browser)"),
1662 ("NBD", "a native build (not the browser)"),
1663 ("ManageSieve", "a native build (not the browser)"),
1664 ("Zenoh", "a native build (not the browser)"),
1665 ("LwM2M", "a native build (not the browser)"),
1666 ("RESTCONF", "a native build (not the browser)"),
1667 ("WebTransport", "a native build (not the browser)"),
1668 ("JMAP", "a native build (not the browser)"),
1669 ("EPP", "a native build (not the browser)"),
1670 ("LMTP", "a native build (not the browser)"),
1671 ("LPD", "a native build (not the browser)"),
1672 ("Echo", "a native build (not the browser)"),
1673 ("Discard", "a native build (not the browser)"),
1674 ("Daytime", "a native build (not the browser)"),
1675 ("QOTD", "a native build (not the browser)"),
1676 ("Chargen", "a native build (not the browser)"),
1677 ("Time", "a native build (not the browser)"),
1678 ("RCON", "a native build (not the browser)"),
1679 ("A2S", "a native build (not the browser)"),
1680 ("Minecraft", "a native build (not the browser)"),
1681 ("9P", "a native build (not the browser)"),
1682 ("ZeroMQ", "a native build (not the browser)"),
1683 ("SMPP", "a native build (not the browser)"),
1684 ("ClickHouse", "a native build (not the browser)"),
1685 ("MessagePack-RPC", "a native build (not the browser)"),
1686 ("Zipkin", "a native build (not the browser)"),
1687 ("Cap'n Proto RPC", "a native build (not the browser)"),
1688 ("KNX/IP", "a native build (not the browser)"),
1689 ("Consul", "a native build (not the browser)"),
1690 ("Milter", "a native build (not the browser)"),
1691 ("Anthropic", "a native build (not the browser)"),
1692 ("RadSec", "a native build (not the browser)"),
1693 ("D-Bus", "a native build (not the browser)"),
1694 ("BFD", "a native build (not the browser)"),
1695 ("VXLAN", "a native build (not the browser)"),
1696 ("rsync", "a native build (not the browser)"),
1697 ("PFCP", "a native build (not the browser)"),
1698 ("Matrix", "a native build (not the browser)"),
1699 ("libp2p", "a native build (not the browser)"),
1700 ("SunRPC", "a native build (not the browser)"),
1701 ("Guacamole", "a native build (not the browser)"),
1702 ("ActivityPub", "a native build (not the browser)"),
1703 ("Stratum", "a native build (not the browser)"),
1704 ("Stratum V2", "a native build (not the browser)"),
1705 ("Apache Pulsar", "a native build (not the browser)"),
1706 ("TR-069 (CWMP)", "a native build (not the browser)"),
1707 ("SSE", "a native build (not the browser)"),
1708 ("WS-Discovery", "a native build (not the browser)"),
1709 ("ONVIF", "a native build (not the browser)"),
1710 ("Kerberos", "a native build (not the browser)"),
1711 ("etcd", "a native build (not the browser)"),
1712 ("ZooKeeper", "a native build (not the browser)"),
1713 ("Tor Relay", "a Unix build (macOS or Linux)"),
1714 ("VNC", "nothing (every build has it)"),
1715 ("Reverse Shell", "nothing (every build has it)"),
1716 ("RDP", "nothing (every build has it)"),
1717 ("SPICE", "a native build (not the browser)"),
1718 ("OpenAPI", "nothing (every build has it)"),
1719 ("OpenID", "nothing (every build has it)"),
1720 ("KAFKA", "nothing (every build has it)"),
1721 ("HTTP3", "a native build (not the browser)"),
1723 ("QUIC", "a native build (not the browser)"),
1724 ("Torrent-Tracker", "nothing (every build has it)"),
1725 ("Torrent-DHT", "nothing (every build has it)"),
1726 ("Torrent-Peer", "nothing (every build has it)"),
1727 ("TLS", "nothing (every build has it)"),
1728 ("SamlIdp", "nothing (every build has it)"),
1729 ("SamlSp", "nothing (every build has it)"),
1730 ("USB-Keyboard", "the `libusb` feature, on Unix"),
1731 ("USB-Mouse", "the `libusb` feature, on Unix"),
1732 ("USB-Serial", "the `libusb` feature, on Unix"),
1733 ("USB-MassStorage", "the `libusb` feature, on Unix"),
1734 ("usb-fido2", "the `libusb` feature, on Unix"),
1735 ("usb-smartcard", "the `libusb` feature, on Unix"),
1736 ("BLUETOOTH_BLE", "the `bluetooth` feature, on Unix"),
1737 ("BLUETOOTH_BLE_KEYBOARD", "the `bluetooth` feature, on Unix"),
1738 ("BLUETOOTH_BLE_MOUSE", "the `bluetooth` feature, on Unix"),
1739 ("BLUETOOTH_BLE_BEACON", "the `bluetooth` feature, on Unix"),
1740 ("BLUETOOTH_BLE_REMOTE", "the `bluetooth` feature, on Unix"),
1741 ("BLUETOOTH_BLE_BATTERY", "the `bluetooth` feature, on Unix"),
1742 (
1743 "BLUETOOTH_BLE_HEART_RATE",
1744 "the `bluetooth` feature, on Unix",
1745 ),
1746 (
1747 "BLUETOOTH_BLE_THERMOMETER",
1748 "the `bluetooth` feature, on Unix",
1749 ),
1750 (
1751 "BLUETOOTH_BLE_ENVIRONMENTAL",
1752 "the `bluetooth` feature, on Unix",
1753 ),
1754 (
1755 "BLUETOOTH_BLE_PROXIMITY",
1756 "the `bluetooth` feature, on Unix",
1757 ),
1758 ("BLUETOOTH_BLE_GAMEPAD", "the `bluetooth` feature, on Unix"),
1759 (
1760 "BLUETOOTH_BLE_PRESENTER",
1761 "the `bluetooth` feature, on Unix",
1762 ),
1763 (
1764 "BLUETOOTH_BLE_FILE_TRANSFER",
1765 "the `bluetooth` feature, on Unix",
1766 ),
1767 (
1768 "BLUETOOTH_BLE_DATA_STREAM",
1769 "the `bluetooth` feature, on Unix",
1770 ),
1771 ("BLUETOOTH_BLE_CYCLING", "the `bluetooth` feature, on Unix"),
1772 ("BLUETOOTH_BLE_RUNNING", "the `bluetooth` feature, on Unix"),
1773 (
1774 "BLUETOOTH_BLE_WEIGHT_SCALE",
1775 "the `bluetooth` feature, on Unix",
1776 ),
1777 ("POP3", "nothing (every build has it)"),
1778 ("S3", "a native build (not the browser)"),
1779 ("STUN", "a Unix build (macOS or Linux)"),
1780 ("WebRTC", "a native build (not the browser)"),
1781 ("BGP", "nothing (every build has it)"),
1782 ("OSPF", "a Unix build (macOS or Linux)"),
1783 ("Git", "a native build (not the browser)"),
1784 ("Mercurial", "nothing (every build has it)"),
1785];
1786
1787#[derive(Debug, Clone, PartialEq, Eq)]
1789pub enum ProtocolLookupError {
1790 NotCompiled {
1793 name: &'static str,
1794 requires: &'static str,
1795 },
1796 Unknown {
1798 input: String,
1799 suggestion: Option<&'static str>,
1800 },
1801}
1802
1803impl std::fmt::Display for ProtocolLookupError {
1804 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1805 match self {
1806 ProtocolLookupError::NotCompiled { name, requires } => write!(
1807 f,
1808 "Protocol '{name}' exists but is not compiled into this build: it needs {requires}"
1809 ),
1810 ProtocolLookupError::Unknown {
1811 input,
1812 suggestion: Some(s),
1813 } => write!(f, "Unknown protocol: '{input}'. Did you mean '{s}'?"),
1814 ProtocolLookupError::Unknown {
1815 input,
1816 suggestion: None,
1817 } => write!(f, "Unknown protocol: '{input}'"),
1818 }
1819 }
1820}
1821
1822impl std::error::Error for ProtocolLookupError {}
1823
1824fn suggest_protocol_name(
1827 input: &str,
1828 known: &[(&'static str, &'static str)],
1829) -> Option<&'static str> {
1830 let input_norm = input.to_lowercase();
1831 let mut best: Option<(&'static str, usize)> = None;
1832
1833 for (name, _feature) in known {
1834 let distance = levenshtein(&input_norm, &name.to_lowercase());
1835 best = match best {
1836 Some((_, best_dist)) if best_dist <= distance => best,
1837 _ => Some((name, distance)),
1838 };
1839 }
1840
1841 best.and_then(|(name, distance)| {
1842 let threshold = (input_norm.chars().count() / 3).max(2);
1843 if distance <= threshold {
1844 Some(name)
1845 } else {
1846 None
1847 }
1848 })
1849}
1850
1851fn levenshtein(a: &str, b: &str) -> usize {
1855 let a: Vec<char> = a.chars().collect();
1856 let b: Vec<char> = b.chars().collect();
1857 let mut dp: Vec<usize> = (0..=b.len()).collect();
1858
1859 for i in 1..=a.len() {
1860 let mut prev = dp[0];
1861 dp[0] = i;
1862 for j in 1..=b.len() {
1863 let tmp = dp[j];
1864 dp[j] = if a[i - 1] == b[j - 1] {
1865 prev
1866 } else {
1867 1 + prev.min(dp[j]).min(dp[j - 1])
1868 };
1869 prev = tmp;
1870 }
1871 }
1872
1873 dp[b.len()]
1874}
1875
1876static REGISTRY: once_cell::sync::Lazy<ServerRegistry> =
1878 once_cell::sync::Lazy::new(ServerRegistry::new);
1879
1880pub fn registry() -> &'static ServerRegistry {
1882 ®ISTRY
1883}