Skip to main content

mdns_sd/
service_daemon.rs

1//! Service daemon for mDNS Service Discovery.
2
3// How DNS-based Service Discovery works in a nutshell:
4//
5// (excerpt from RFC 6763)
6// .... that a particular service instance can be
7//    described using a DNS SRV [RFC2782] and DNS TXT [RFC1035] record.
8//    The SRV record has a name of the form "<Instance>.<Service>.<Domain>"
9//    and gives the target host and port where the service instance can be
10//    reached.  The DNS TXT record of the same name gives additional
11//    information about this instance, in a structured form using key/value
12//    pairs, described in Section 6.  A client discovers the list of
13//    available instances of a given service type using a query for a DNS
14//    PTR [RFC1035] record with a name of the form "<Service>.<Domain>",
15//    which returns a set of zero or more names, which are the names of the
16//    aforementioned DNS SRV/TXT record pairs.
17//
18// Some naming conventions in this source code:
19//
20// `ty_domain` refers to service type together with domain name, i.e. <service>.<domain>.
21// Every <service> consists of two labels: service itself and "_udp." or "_tcp".
22// See RFC 6763 section 7 Service Names.
23//     for example: `_my-service._udp.local.`
24//
25// `fullname` refers to a full Service Instance Name, i.e. <instance>.<service>.<domain>
26//     for example: `my_home._my-service._udp.local.`
27//
28// In mDNS and DNS, the basic data structure is "Resource Record" (RR), where
29// in Service Discovery, the basic data structure is "Service Info". One Service Info
30// corresponds to a set of DNS Resource Records.
31#[cfg(feature = "logging")]
32use crate::log::{debug, error, trace};
33use crate::{
34    current_time_millis,
35    dns_cache::{DnsCache, IpType},
36    dns_parser::{
37        ip_address_rr_type, max_pkt_absolute, DnsAddress, DnsEntryExt, DnsIncoming, DnsOutgoing,
38        DnsPointer, DnsRecordBox, DnsRecordExt, DnsSrv, DnsTxt, InterfaceId, RRType, ScopedIp,
39        CLASS_CACHE_FLUSH, CLASS_IN, FLAGS_AA, FLAGS_QR_QUERY, FLAGS_QR_RESPONSE,
40        MAX_PKT_ABSOLUTE_IPV6, MAX_PKT_DEFAULT,
41    },
42    error::{e_fmt, Error, Result},
43    service_info::{
44        valid_ip_on_intf, DnsRegistry, MyIntf, Probe, ServiceInfo, ServiceStatus,
45        MULTICAST_RATE_LIMIT_MILLIS,
46    },
47    Receiver, ResolvedService, TxtProperties,
48};
49use flume::{bounded, Sender, TrySendError};
50use if_addrs::{IfAddr, Interface};
51use mio::{event::Source, net::UdpSocket as MioUdpSocket, Interest, Poll, Registry, Token};
52use socket2::Domain;
53use socket_pktinfo::PktInfoUdpSocket;
54use std::{
55    cmp::{self, Reverse},
56    collections::{hash_map::Entry, BinaryHeap, HashMap, HashSet},
57    fmt, io,
58    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, UdpSocket},
59    str, thread,
60    time::Duration,
61    vec,
62};
63
64/// The default max length of the service name without domain, not including the
65/// leading underscore (`_`). It is set to 15 per
66/// [RFC 6763 section 7.2](https://www.rfc-editor.org/rfc/rfc6763#section-7.2).
67pub const SERVICE_NAME_LEN_MAX_DEFAULT: u8 = 15;
68
69/// The default interval for checking IP changes automatically.
70pub const IP_CHECK_INTERVAL_IN_SECS_DEFAULT: u32 = 5;
71
72/// The default time out for [ServiceDaemon::verify] is 10 seconds, per
73/// [RFC 6762 section 10.4](https://datatracker.ietf.org/doc/html/rfc6762#section-10.4)
74pub const VERIFY_TIMEOUT_DEFAULT: Duration = Duration::from_secs(10);
75
76/// The smallest value accepted by [`ServiceDaemon::set_max_packet_size`].
77pub(crate) const MIN_MAX_PACKET_SIZE: usize = 512;
78
79/// The mDNS port number per RFC 6762.
80pub const MDNS_PORT: u16 = 5353;
81
82const GROUP_ADDR_V4: Ipv4Addr = Ipv4Addr::new(224, 0, 0, 251);
83const GROUP_ADDR_V6: Ipv6Addr = Ipv6Addr::new(0xff02, 0, 0, 0, 0, 0, 0, 0xfb);
84const LOOPBACK_V4: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1);
85
86const RESOLVE_WAIT_IN_MILLIS: u64 = 500;
87
88/// RFC 6762 §8.3: the two unsolicited announcements are sent "one second apart".
89/// We schedule the second one strictly wider than the §6 multicast rate-limit
90/// window ([`MULTICAST_RATE_LIMIT_MILLIS`]) so that scheduling skew — the few
91/// millis between capturing this base time and actually stamping the records as
92/// multicast — can never make the rate limit throttle the second announcement
93/// away. A small random jitter is added on top (see `ANNOUNCE_SECOND_JITTER_MILLIS`)
94/// to de-synchronize announcements across hosts and services.
95const ANNOUNCE_SECOND_DELAY_MILLIS: u64 = MULTICAST_RATE_LIMIT_MILLIS + 100;
96
97/// Upper bound (exclusive) of the random jitter added to the second announcement
98/// delay. Kept small so the spacing stays close to the RFC's "one second".
99const ANNOUNCE_SECOND_JITTER_MILLIS: u64 = 50;
100
101// The §8.3 announcement spacing MUST stay strictly wider than the §6 rate-limit
102// window, or the rate limit throttles the second announcement away (leaving only
103// one unsolicited response). Enforced at compile time so the two can't drift.
104#[allow(clippy::assertions_on_constants)]
105const _: () = assert!(ANNOUNCE_SECOND_DELAY_MILLIS > MULTICAST_RATE_LIMIT_MILLIS);
106
107/// RFC 6762 §6:
108/// In any case where there may be multiple responses, such as queries
109/// where the answer is a member of a shared resource record set, each
110/// responder SHOULD delay its response by a random amount of time
111/// selected with uniform random distribution in the range 20-120 ms.
112///
113/// 20ms suggested in the RFC is a bit too long for min. Use 10ms instead.
114const SHARED_RESPONSE_DELAY_MIN_MILLIS: u64 = 10;
115
116/// 120ms suggested in the RFC is too long for max, use 50ms instead.
117const SHARED_RESPONSE_DELAY_MAX_MILLIS: u64 = 50;
118
119/// RFC 6762 §5.2: to avoid accidental synchronization when multiple clients
120/// begin querying at exactly the same moment (e.g. because of some common
121/// external trigger event), a querier SHOULD delay the first query of a
122/// continuous-monitoring series by a randomly chosen amount in the range
123/// 20-120 ms.
124///
125/// Like the responder delay above, we use a shorter 10-50 ms window.
126const INITIAL_QUERY_DELAY_MIN_MILLIS: u64 = 10;
127const INITIAL_QUERY_DELAY_MAX_MILLIS: u64 = 50;
128
129/// Response status code for the service `unregister` call.
130#[derive(Debug)]
131pub enum UnregisterStatus {
132    /// Unregister was successful.
133    OK,
134    /// The service was not found in the registration.
135    NotFound,
136}
137
138/// Status code for the service daemon.
139#[derive(Debug, PartialEq, Clone, Eq)]
140#[non_exhaustive]
141pub enum DaemonStatus {
142    /// The daemon is running as normal.
143    Running,
144
145    /// The daemon has been shutdown.
146    Shutdown,
147}
148
149/// Different counters included in the metrics.
150/// Currently all counters are for outgoing packets.
151#[derive(Hash, Eq, PartialEq)]
152enum Counter {
153    Register,
154    RegisterResend,
155    Unregister,
156    UnregisterResend,
157    Browse,
158    ResolveHostname,
159    Respond,
160    CacheRefreshPTR,
161    CacheRefreshSrvTxt,
162    CacheRefreshAddr,
163    KnownAnswerSuppression,
164    CachedPTR,
165    CachedSRV,
166    CachedAddr,
167    CachedTxt,
168    CachedNSec,
169    CachedSubtype,
170    DnsRegistryProbe,
171    DnsRegistryActive,
172    DnsRegistryTimer,
173    DnsRegistryNameChange,
174    Timer,
175}
176
177impl fmt::Display for Counter {
178    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
179        match self {
180            Self::Register => write!(f, "register"),
181            Self::RegisterResend => write!(f, "register-resend"),
182            Self::Unregister => write!(f, "unregister"),
183            Self::UnregisterResend => write!(f, "unregister-resend"),
184            Self::Browse => write!(f, "browse"),
185            Self::ResolveHostname => write!(f, "resolve-hostname"),
186            Self::Respond => write!(f, "respond"),
187            Self::CacheRefreshPTR => write!(f, "cache-refresh-ptr"),
188            Self::CacheRefreshSrvTxt => write!(f, "cache-refresh-srv-txt"),
189            Self::CacheRefreshAddr => write!(f, "cache-refresh-addr"),
190            Self::KnownAnswerSuppression => write!(f, "known-answer-suppression"),
191            Self::CachedPTR => write!(f, "cached-ptr"),
192            Self::CachedSRV => write!(f, "cached-srv"),
193            Self::CachedAddr => write!(f, "cached-addr"),
194            Self::CachedTxt => write!(f, "cached-txt"),
195            Self::CachedNSec => write!(f, "cached-nsec"),
196            Self::CachedSubtype => write!(f, "cached-subtype"),
197            Self::DnsRegistryProbe => write!(f, "dns-registry-probe"),
198            Self::DnsRegistryActive => write!(f, "dns-registry-active"),
199            Self::DnsRegistryTimer => write!(f, "dns-registry-timer"),
200            Self::DnsRegistryNameChange => write!(f, "dns-registry-name-change"),
201            Self::Timer => write!(f, "timer"),
202        }
203    }
204}
205
206#[derive(Debug)]
207enum InternalError {
208    IntfAddrInvalid(Interface),
209}
210
211impl fmt::Display for InternalError {
212    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213        match self {
214            InternalError::IntfAddrInvalid(iface) => write!(f, "interface addr invalid: {iface:?}"),
215        }
216    }
217}
218
219type MyResult<T> = core::result::Result<T, InternalError>;
220
221/// A wrapper around UDP socket used by the mDNS daemon.
222///
223/// We do this because `mio` does not support PKTINFO and
224/// does not provide a way to implement `Source` trait directly and safely.
225struct MyUdpSocket {
226    /// The underlying socket that supports control messages like
227    /// `IP_PKTINFO` for IPv4 and `IPV6_PKTINFO` for IPv6.
228    pktinfo: PktInfoUdpSocket,
229
230    /// The mio UDP socket that is a clone of `pktinfo` and
231    /// is used for event polling.
232    mio: MioUdpSocket,
233}
234
235impl MyUdpSocket {
236    pub fn new(pktinfo: PktInfoUdpSocket) -> io::Result<Self> {
237        let std_sock = pktinfo.try_clone_std()?;
238        let mio = MioUdpSocket::from_std(std_sock);
239
240        Ok(Self { pktinfo, mio })
241    }
242}
243
244/// Implements the mio `Source` trait so that we can use `MyUdpSocket` with `Poll`.
245impl Source for MyUdpSocket {
246    fn register(
247        &mut self,
248        registry: &Registry,
249        token: Token,
250        interests: Interest,
251    ) -> io::Result<()> {
252        self.mio.register(registry, token, interests)
253    }
254
255    fn reregister(
256        &mut self,
257        registry: &Registry,
258        token: Token,
259        interests: Interest,
260    ) -> io::Result<()> {
261        self.mio.reregister(registry, token, interests)
262    }
263
264    fn deregister(&mut self, registry: &Registry) -> std::io::Result<()> {
265        self.mio.deregister(registry)
266    }
267}
268
269/// The metrics is a HashMap of (name_key, i64_value).
270/// The main purpose is to help monitoring the mDNS packet traffic.
271pub type Metrics = HashMap<String, i64>;
272
273const IPV4_SOCK_EVENT_KEY: usize = 4; // Pick a key just to indicate IPv4.
274const IPV6_SOCK_EVENT_KEY: usize = 6; // Pick a key just to indicate IPv6.
275const SIGNAL_SOCK_EVENT_KEY: usize = usize::MAX - 1; // avoid to overlap with zc.poll_ids
276
277/// A daemon thread for mDNS
278///
279/// This struct provides a handle and an API to the daemon. It is cloneable.
280#[derive(Clone)]
281pub struct ServiceDaemon {
282    /// Sender handle of the channel to the daemon.
283    sender: Sender<Command>,
284
285    /// Send to this addr to signal that a `Command` is coming.
286    ///
287    /// The daemon listens on this addr together with other mDNS sockets,
288    /// to avoid busy polling the flume channel. If there is a way to poll
289    /// the channel and mDNS sockets together, then this can be removed.
290    signal_addr: SocketAddr,
291}
292
293impl ServiceDaemon {
294    /// Creates a new daemon and spawns a thread to run the daemon.
295    ///
296    /// Creates a new mDNS service daemon using the default port (5353).
297    ///
298    /// For development/testing with custom ports, use [`ServiceDaemon::new_with_port`].
299    ///
300    /// # Errors
301    ///
302    /// Returns [`Error::Msg`] if the daemon cannot be initialized. This wraps an
303    /// underlying OS-level failure.
304    ///
305    /// Note that this constructor does not open the mDNS multicast sockets — those
306    /// are opened lazily by the daemon thread once it starts, so platform issues
307    /// such as "multicast not permitted" are surfaced later via [`DaemonEvent`] from
308    /// [`monitor`](Self::monitor) rather than here.
309    pub fn new() -> Result<Self> {
310        Self::new_with_port(MDNS_PORT)
311    }
312
313    /// Creates a new mDNS service daemon using a custom port.
314    ///
315    /// # Arguments
316    ///
317    /// * `port` - The UDP port to bind for mDNS communication.
318    ///   - In production, this should be `MDNS_PORT` (5353) per RFC 6762.
319    ///   - For development/testing, you can use a non-standard port (e.g., 5454)
320    ///     to avoid conflicts with system mDNS services.
321    ///   - Both publisher and browser must use the same port to communicate.
322    ///
323    /// # Example
324    ///
325    /// ```no_run
326    /// use mdns_sd::ServiceDaemon;
327    ///
328    /// // Use standard mDNS port (production)
329    /// let daemon = ServiceDaemon::new_with_port(5353)?;
330    ///
331    /// // Use custom port for development (avoids macOS Bonjour conflict)
332    /// let daemon_dev = ServiceDaemon::new_with_port(5454)?;
333    /// # Ok::<(), mdns_sd::Error>(())
334    /// ```
335    ///
336    /// # Errors
337    ///
338    /// See [`new`](Self::new) for the set of OS-level failures that may surface
339    /// here. Note that `port` is *not* validated against the kernel until the
340    /// daemon thread tries to bind the mDNS sockets, so an unusable `port`
341    /// (e.g., already in use, requires elevated privileges) will not be
342    /// reported by this constructor — listen for such failures via
343    /// [`monitor`](Self::monitor).
344    pub fn new_with_port(port: u16) -> Result<Self> {
345        // Use port 0 to allow the system assign a random available port,
346        // no need for a pre-defined port number.
347        let signal_addr = SocketAddrV4::new(LOOPBACK_V4, 0);
348
349        let signal_sock = UdpSocket::bind(signal_addr)
350            .map_err(|e| e_fmt!("failed to create signal_sock for daemon: {}", e))?;
351
352        // Get the socket with the OS chosen port
353        let signal_addr = signal_sock
354            .local_addr()
355            .map_err(|e| e_fmt!("failed to get signal sock addr: {}", e))?;
356
357        // Must be nonblocking so we can listen to it together with mDNS sockets.
358        signal_sock
359            .set_nonblocking(true)
360            .map_err(|e| e_fmt!("failed to set nonblocking for signal socket: {}", e))?;
361
362        let poller = Poll::new().map_err(|e| e_fmt!("failed to create mio Poll: {e}"))?;
363
364        let (sender, receiver) = bounded(100);
365
366        // Spawn the daemon thread
367        let mio_sock = MioUdpSocket::from_std(signal_sock);
368        let cmd_sender = sender.clone();
369        thread::Builder::new()
370            .name("mDNS_daemon".to_string())
371            .spawn(move || {
372                Self::daemon_thread(mio_sock, poller, receiver, port, cmd_sender, signal_addr)
373            })
374            .map_err(|e| e_fmt!("thread builder failed to spawn: {}", e))?;
375
376        Ok(Self {
377            sender,
378            signal_addr,
379        })
380    }
381
382    /// Sends `cmd` to the daemon via its channel, and sends a signal
383    /// to its sock addr to notify.
384    fn send_cmd(&self, cmd: Command) -> Result<()> {
385        let cmd_name = cmd.to_string();
386
387        // First, send to the flume channel.
388        self.sender.try_send(cmd).map_err(|e| match e {
389            TrySendError::Full(_) => Error::Again,
390            TrySendError::Disconnected(_) => Error::DaemonShutdown,
391        })?;
392
393        // Second, send a signal to notify the daemon.
394        let addr = SocketAddrV4::new(LOOPBACK_V4, 0);
395        let socket = UdpSocket::bind(addr)
396            .map_err(|e| e_fmt!("Failed to create socket to send signal: {}", e))?;
397        socket
398            .send_to(cmd_name.as_bytes(), self.signal_addr)
399            .map_err(|e| {
400                e_fmt!(
401                    "signal socket send_to {} ({}) failed: {}",
402                    self.signal_addr,
403                    cmd_name,
404                    e
405                )
406            })?;
407
408        Ok(())
409    }
410
411    /// Starts browsing for a specific service type.
412    ///
413    /// `service_type` must end with a valid mDNS domain: '._tcp.local.' or '._udp.local.'
414    ///
415    /// Returns a channel `Receiver` to receive events about the service. The caller
416    /// can call `.recv_async().await` on this receiver to handle events in an
417    /// async environment or call `.recv()` in a sync environment.
418    ///
419    /// When a new instance is found, the daemon automatically tries to resolve, i.e.
420    /// finding more details, i.e. SRV records and TXT records.
421    ///
422    /// # Errors
423    ///
424    /// Returns [`Error::Msg`] if `service_type` does not end with
425    /// `._tcp.local.` or `._udp.local.`.
426    ///
427    /// Returns [`Error::Again`] if the daemon's command queue is full.
428    ///
429    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
430    pub fn browse(&self, service_type: &str) -> Result<Receiver<ServiceEvent>> {
431        check_domain_suffix(service_type)?;
432
433        let (resp_s, resp_r) = bounded(10);
434        self.send_cmd(Command::Browse(service_type.to_string(), 1, false, resp_s))?;
435        Ok(resp_r)
436    }
437
438    /// Preforms a "cache-only" browse.
439    ///
440    /// `service_type` must end with a valid mDNS domain: '._tcp.local.' or '._udp.local.'
441    ///
442    /// The functionality is identical to 'browse', but the service events are based solely on the contents
443    /// of the daemon's cache. No actual mDNS query is sent to the network.
444    ///
445    /// See [accept_unsolicited](Self::accept_unsolicited) if you want to do cache-only browsing.
446    ///
447    /// # Errors
448    ///
449    /// Same error conditions as [`browse`](Self::browse).
450    pub fn browse_cache(&self, service_type: &str) -> Result<Receiver<ServiceEvent>> {
451        check_domain_suffix(service_type)?;
452
453        let (resp_s, resp_r) = bounded(10);
454        self.send_cmd(Command::Browse(service_type.to_string(), 1, true, resp_s))?;
455        Ok(resp_r)
456    }
457
458    /// Stops searching for a specific service type.
459    ///
460    /// # Errors
461    ///
462    /// Returns [`Error::Again`] if the daemon's command queue is full.
463    ///
464    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
465    pub fn stop_browse(&self, ty_domain: &str) -> Result<()> {
466        self.send_cmd(Command::StopBrowse(ty_domain.to_string()))
467    }
468
469    /// Starts querying for the ip addresses of a hostname.
470    ///
471    /// Returns a channel `Receiver` to receive events about the hostname.
472    /// The caller can call `.recv_async().await` on this receiver to handle events in an
473    /// async environment or call `.recv()` in a sync environment.
474    ///
475    /// The `timeout` is specified in milliseconds.
476    ///
477    /// # Errors
478    ///
479    /// Returns [`Error::Msg`] if:
480    ///
481    /// - `hostname` does not end with `.local.`;
482    /// - `hostname` is exactly `.local.` (the label before `.local.` is empty);
483    /// - `hostname` is longer than 255 bytes.
484    ///
485    /// Returns [`Error::Again`] if the daemon's command queue is full.
486    ///
487    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
488    pub fn resolve_hostname(
489        &self,
490        hostname: &str,
491        timeout: Option<u64>,
492    ) -> Result<Receiver<HostnameResolutionEvent>> {
493        check_hostname(hostname)?;
494        let (resp_s, resp_r) = bounded(10);
495        self.send_cmd(Command::ResolveHostname(
496            hostname.to_string(),
497            1,
498            resp_s,
499            timeout,
500        ))?;
501        Ok(resp_r)
502    }
503
504    /// Stops querying for the ip addresses of a hostname.
505    ///
506    /// # Errors
507    ///
508    /// Same error conditions as [`stop_browse`](Self::stop_browse).
509    pub fn stop_resolve_hostname(&self, hostname: &str) -> Result<()> {
510        self.send_cmd(Command::StopResolveHostname(hostname.to_string()))
511    }
512
513    /// Registers a service provided by this host.
514    ///
515    /// If `service_info` has no addresses yet and its `addr_auto` is enabled,
516    /// this method will automatically fill in addresses from the host.
517    ///
518    /// To re-announce a service with an updated `service_info`, just call
519    /// this `register` function again. No need to call `unregister` first.
520    ///
521    /// # Errors
522    ///
523    /// Returns [`Error::Msg`] if the [`ServiceInfo`] is malformed, for example:
524    ///
525    /// - the fullname does not end with `._tcp.local.` or `._udp.local.`;
526    /// - the hostname does not end with `.local.`, is exactly `.local.`, or
527    ///   is longer than 255 bytes.
528    ///
529    /// Returns [`Error::Again`] if the daemon's command queue is full.
530    ///
531    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
532    pub fn register(&self, service_info: ServiceInfo) -> Result<()> {
533        check_service_name(service_info.get_fullname())?;
534        check_hostname(service_info.get_hostname())?;
535
536        self.send_cmd(Command::Register(service_info.into()))
537    }
538
539    /// Unregisters a service. This is a graceful shutdown of a service.
540    ///
541    /// Returns a channel receiver that is used to receive the status code
542    /// of the unregister.
543    ///
544    /// # Errors
545    ///
546    /// Returns [`Error::Again`] if the daemon's command queue is full.
547    ///
548    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
549    pub fn unregister(&self, fullname: &str) -> Result<Receiver<UnregisterStatus>> {
550        let (resp_s, resp_r) = bounded(1);
551        self.send_cmd(Command::Unregister(fullname.to_lowercase(), resp_s))?;
552        Ok(resp_r)
553    }
554
555    /// Starts to monitor events from the daemon.
556    ///
557    /// Returns a channel [`Receiver`] of [`DaemonEvent`].
558    ///
559    /// # Errors
560    ///
561    /// Returns [`Error::Again`] if the daemon's command queue is full.
562    ///
563    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
564    pub fn monitor(&self) -> Result<Receiver<DaemonEvent>> {
565        let (resp_s, resp_r) = bounded(100);
566        self.send_cmd(Command::Monitor(resp_s))?;
567        Ok(resp_r)
568    }
569
570    /// Shuts down the daemon thread and returns a channel to receive the status.
571    ///
572    /// # Errors
573    ///
574    /// Returns [`Error::Again`] if the daemon's command queue is full.
575    ///
576    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
577    pub fn shutdown(&self) -> Result<Receiver<DaemonStatus>> {
578        let (resp_s, resp_r) = bounded(1);
579        self.send_cmd(Command::Exit(resp_s))?;
580        Ok(resp_r)
581    }
582
583    /// Returns the status of the daemon.
584    ///
585    /// # Errors
586    ///
587    /// Returns [`Error::Again`] if the daemon's command queue is full.
588    ///
589    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
590    pub fn status(&self) -> Result<Receiver<DaemonStatus>> {
591        let (resp_s, resp_r) = bounded(1);
592
593        if self.sender.is_disconnected() {
594            resp_s
595                .send(DaemonStatus::Shutdown)
596                .map_err(|e| e_fmt!("failed to send daemon status to the client: {}", e))?;
597        } else {
598            self.send_cmd(Command::GetStatus(resp_s))?;
599        }
600
601        Ok(resp_r)
602    }
603
604    /// Returns a channel receiver for the metrics, e.g. input/output counters.
605    ///
606    /// The metrics returned is a snapshot. Hence the caller should call
607    /// this method repeatedly if they want to monitor the metrics continuously.
608    ///
609    /// # Errors
610    ///
611    /// Returns [`Error::Again`] if the daemon's command queue is full.
612    ///
613    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
614    pub fn get_metrics(&self) -> Result<Receiver<Metrics>> {
615        let (resp_s, resp_r) = bounded(1);
616        self.send_cmd(Command::GetMetrics(resp_s))?;
617        Ok(resp_r)
618    }
619
620    /// Change the max length allowed for a service name.
621    ///
622    /// As RFC 6763 defines a length max for a service name, a user should not call
623    /// this method unless they have to. See [`SERVICE_NAME_LEN_MAX_DEFAULT`].
624    ///
625    /// `len_max` is capped at an internal limit, which is currently 30.
626    ///
627    /// # Errors
628    ///
629    /// Returns [`Error::Msg`] if `len_max` exceeds the internal cap (30).
630    ///
631    /// Returns [`Error::Again`] if the daemon's command queue is full.
632    ///
633    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
634    pub fn set_service_name_len_max(&self, len_max: u8) -> Result<()> {
635        const SERVICE_NAME_LEN_MAX_LIMIT: u8 = 30; // Double the default length max.
636
637        if len_max > SERVICE_NAME_LEN_MAX_LIMIT {
638            return Err(Error::Msg(format!(
639                "service name length max {len_max} is too large"
640            )));
641        }
642
643        self.send_cmd(Command::SetOption(DaemonOption::ServiceNameLenMax(len_max)))
644    }
645
646    /// Change the max byte size of a packet this daemon generates on the interfaces
647    /// matching `if_kind`. Use `IfKind::All` to change it on every interface. Messages
648    /// that don't fit are split across multiple packets. A single record that doesn't
649    /// fit in a packet is sent alone in a packet of up to 8952 bytes over IPv6 or 8972
650    /// bytes over IPv4, per RFC 6762 section 17.
651    ///
652    /// The default is `MAX_PKT_DEFAULT` (1452 bytes), small enough to fit in one
653    /// Ethernet frame over either IPv4 or IPv6.
654    ///
655    /// `size` must be in the range `512..=8952`. The minimum of 512 bytes is the classic
656    /// UDP DNS message size of RFC 1035. The maximum of 8952 bytes follows from RFC 6762
657    /// section 17, which caps an mDNS packet at 9000 bytes: we subtract the
658    /// bigger of the two IP headers so that a generated packet is legal over either
659    /// IP version.
660    pub fn set_max_packet_size(&self, if_kind: impl IntoIfKindVec, size: usize) -> Result<()> {
661        if size < MIN_MAX_PACKET_SIZE {
662            return Err(Error::Msg(format!(
663                "max packet size {size} is too small, must be at least {MIN_MAX_PACKET_SIZE}"
664            )));
665        }
666
667        if size > MAX_PKT_ABSOLUTE_IPV6 {
668            return Err(Error::Msg(format!(
669                "max packet size {size} is too big, must be at most {MAX_PKT_ABSOLUTE_IPV6}"
670            )));
671        }
672
673        let if_kind_vec = if_kind.into_vec();
674        self.send_cmd(Command::SetOption(DaemonOption::MaxPacketSize(
675            if_kind_vec.kinds,
676            size,
677        )))
678    }
679
680    /// Change the interval for checking IP changes automatically.
681    ///
682    /// Setting the interval to 0 disables the IP check.
683    ///
684    /// See [`IP_CHECK_INTERVAL_IN_SECS_DEFAULT`] for the default interval.
685    pub fn set_ip_check_interval(&self, interval_in_secs: u32) -> Result<()> {
686        let interval_in_millis = interval_in_secs as u64 * 1000;
687        self.send_cmd(Command::SetOption(DaemonOption::IpCheckInterval(
688            interval_in_millis,
689        )))
690    }
691
692    /// Get the current interval in seconds for checking IP changes automatically.
693    pub fn get_ip_check_interval(&self) -> Result<u32> {
694        let (resp_s, resp_r) = bounded(1);
695        self.send_cmd(Command::GetOption(resp_s))?;
696
697        let option = resp_r
698            .recv_timeout(Duration::from_secs(10))
699            .map_err(|e| e_fmt!("failed to receive ip check interval: {}", e))?;
700        let ip_check_interval_in_secs = option.ip_check_interval / 1000;
701        Ok(ip_check_interval_in_secs as u32)
702    }
703
704    /// Include interfaces that match `if_kind` for this service daemon.
705    ///
706    /// For example:
707    /// ```ignore
708    ///     daemon.enable_interface("en0")?;
709    /// ```
710    pub fn enable_interface(&self, if_kind: impl IntoIfKindVec) -> Result<()> {
711        let if_kind_vec = if_kind.into_vec();
712        self.send_cmd(Command::SetOption(DaemonOption::EnableInterface(
713            if_kind_vec.kinds,
714        )))
715    }
716
717    /// Ignore/exclude interfaces that match `if_kind` for this daemon.
718    ///
719    /// For example:
720    /// ```ignore
721    ///     daemon.disable_interface(IfKind::IPv6)?;
722    /// ```
723    pub fn disable_interface(&self, if_kind: impl IntoIfKindVec) -> Result<()> {
724        let if_kind_vec = if_kind.into_vec();
725        self.send_cmd(Command::SetOption(DaemonOption::DisableInterface(
726            if_kind_vec.kinds,
727        )))
728    }
729
730    /// If `accept` is true, accept and cache all responses, even if there is no active querier
731    /// for a given service type. This is useful / necessary when doing cache-only browsing. See
732    /// [browse_cache](Self::browse_cache).
733    ///
734    /// If `accept` is false (default), accept only responses matching queries that we have initiated.
735    ///
736    /// For example:
737    /// ```ignore
738    ///     daemon.accept_unsolicited(true)?;
739    /// ```
740    pub fn accept_unsolicited(&self, accept: bool) -> Result<()> {
741        self.send_cmd(Command::SetOption(DaemonOption::AcceptUnsolicited(accept)))
742    }
743
744    /// Include or exclude Apple P2P interfaces, e.g. "awdl0", "llw0".
745    /// By default, they are excluded.
746    pub fn include_apple_p2p(&self, include: bool) -> Result<()> {
747        self.send_cmd(Command::SetOption(DaemonOption::IncludeAppleP2P(include)))
748    }
749
750    #[cfg(test)]
751    pub fn test_down_interface(&self, ifname: &str) -> Result<()> {
752        self.send_cmd(Command::SetOption(DaemonOption::TestDownInterface(
753            ifname.to_string(),
754        )))
755    }
756
757    #[cfg(test)]
758    pub fn test_up_interface(&self, ifname: &str) -> Result<()> {
759        self.send_cmd(Command::SetOption(DaemonOption::TestUpInterface(
760            ifname.to_string(),
761        )))
762    }
763
764    /// Enable or disable the loopback for locally sent multicast packets in IPv4.
765    ///
766    /// By default, multicast loop is enabled for IPv4. When disabled, a querier will not
767    /// receive announcements from a responder on the same host.
768    ///
769    /// Reference: <https://learn.microsoft.com/en-us/windows/win32/winsock/ip-multicast-2>
770    ///
771    /// "The Winsock version of the IP_MULTICAST_LOOP option is semantically different than
772    /// the UNIX version of the IP_MULTICAST_LOOP option:
773    ///
774    /// In Winsock, the IP_MULTICAST_LOOP option applies only to the receive path.
775    /// In the UNIX version, the IP_MULTICAST_LOOP option applies to the send path."
776    ///
777    /// Which means, in order NOT to receive localhost announcements, you want to call
778    /// this API on the querier side on Windows, but on the responder side on Unix.
779    pub fn set_multicast_loop_v4(&self, on: bool) -> Result<()> {
780        self.send_cmd(Command::SetOption(DaemonOption::MulticastLoopV4(on)))
781    }
782
783    /// Enable or disable the loopback for locally sent multicast packets in IPv6.
784    ///
785    /// By default, multicast loop is enabled for IPv6. When disabled, a querier will not
786    /// receive announcements from a responder on the same host.
787    ///
788    /// Reference: <https://learn.microsoft.com/en-us/windows/win32/winsock/ip-multicast-2>
789    ///
790    /// "The Winsock version of the IP_MULTICAST_LOOP option is semantically different than
791    /// the UNIX version of the IP_MULTICAST_LOOP option:
792    ///
793    /// In Winsock, the IP_MULTICAST_LOOP option applies only to the receive path.
794    /// In the UNIX version, the IP_MULTICAST_LOOP option applies to the send path."
795    ///
796    /// Which means, in order NOT to receive localhost announcements, you want to call
797    /// this API on the querier side on Windows, but on the responder side on Unix.
798    pub fn set_multicast_loop_v6(&self, on: bool) -> Result<()> {
799        self.send_cmd(Command::SetOption(DaemonOption::MulticastLoopV6(on)))
800    }
801
802    /// Proactively confirms whether a service instance still valid.
803    ///
804    /// This call will issue queries for a service instance's SRV record and Address records.
805    ///
806    /// For `timeout`, most users should use [VERIFY_TIMEOUT_DEFAULT]
807    /// unless there is a reason not to follow RFC.
808    ///
809    /// If no response is received within `timeout`, the current resource
810    /// records will be flushed, and if needed, `ServiceRemoved` event will be
811    /// sent to active queriers.
812    ///
813    /// Reference: [RFC 6762](https://datatracker.ietf.org/doc/html/rfc6762#section-10.4)
814    ///
815    /// # Errors
816    ///
817    /// Returns [`Error::Again`] if the daemon's command queue is full.
818    ///
819    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
820    pub fn verify(&self, instance_fullname: String, timeout: Duration) -> Result<()> {
821        self.send_cmd(Command::Verify(instance_fullname, timeout))
822    }
823
824    fn daemon_thread(
825        signal_sock: MioUdpSocket,
826        poller: Poll,
827        receiver: Receiver<Command>,
828        port: u16,
829        cmd_sender: Sender<Command>,
830        signal_addr: SocketAddr,
831    ) {
832        let mut zc = Zeroconf::new(signal_sock, poller, port, cmd_sender, signal_addr);
833
834        if let Some(cmd) = zc.run(receiver) {
835            match cmd {
836                Command::Exit(resp_s) => {
837                    // It is guaranteed that the receiver already dropped,
838                    // i.e. the daemon command channel closed.
839                    if let Err(e) = resp_s.send(DaemonStatus::Shutdown) {
840                        debug!("exit: failed to send response of shutdown: {}", e);
841                    }
842                }
843                _ => {
844                    debug!("Unexpected command: {:?}", cmd);
845                }
846            }
847        }
848    }
849}
850
851/// Creates a new UDP socket that uses `intf` to send and recv multicast.
852fn _new_socket_bind(intf: &Interface, should_loop: bool) -> Result<MyUdpSocket> {
853    // Use the same socket for receiving and sending multicast packets.
854    // Such socket has to bind to INADDR_ANY or IN6ADDR_ANY.
855    let intf_ip = &intf.ip();
856    match intf_ip {
857        IpAddr::V4(ip) => {
858            let addr = SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), MDNS_PORT);
859            let sock = new_socket(addr.into(), true)?;
860
861            // Join mDNS group to receive packets.
862            sock.join_multicast_v4(&GROUP_ADDR_V4, ip)
863                .map_err(|e| e_fmt!("join multicast group on addr {}: {}", intf_ip, e))?;
864
865            // Set IP_MULTICAST_IF to send packets.
866            sock.set_multicast_if_v4(ip)
867                .map_err(|e| e_fmt!("set multicast_if on addr {}: {}", ip, e))?;
868
869            // Per RFC 6762 section 11:
870            // "All Multicast DNS responses (including responses sent via unicast) SHOULD
871            // be sent with IP TTL set to 255."
872            // Here we set the TTL to 255 for multicast as we don't support unicast yet.
873            sock.set_multicast_ttl_v4(255)
874                .map_err(|e| e_fmt!("set set_multicast_ttl_v4 on addr {}: {}", ip, e))?;
875
876            if !should_loop {
877                sock.set_multicast_loop_v4(false)
878                    .map_err(|e| e_fmt!("failed to set multicast loop v4 for {ip}: {e}"))?;
879            }
880
881            // Test if we can send packets successfully.
882            let multicast_addr = SocketAddrV4::new(GROUP_ADDR_V4, MDNS_PORT).into();
883            let test_packets = DnsOutgoing::new(0).to_data_on_wire(MAX_PKT_DEFAULT, true);
884            for packet in test_packets {
885                sock.send_to(&packet, &multicast_addr)
886                    .map_err(|e| e_fmt!("send multicast packet on addr {}: {}", ip, e))?;
887            }
888            MyUdpSocket::new(sock)
889                .map_err(|e| e_fmt!("failed to create MySocket for interface {}: {e}", intf.name))
890        }
891        IpAddr::V6(ip) => {
892            let addr = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), MDNS_PORT, 0, 0);
893            let sock = new_socket(addr.into(), true)?;
894
895            let if_index = intf.index.unwrap_or(0);
896
897            // Join mDNS group to receive packets.
898            sock.join_multicast_v6(&GROUP_ADDR_V6, if_index)
899                .map_err(|e| e_fmt!("join multicast group on addr {}: {}", ip, e))?;
900
901            // Set IPV6_MULTICAST_IF to send packets.
902            sock.set_multicast_if_v6(if_index)
903                .map_err(|e| e_fmt!("set multicast_if on addr {}: {}", ip, e))?;
904
905            // We are not sending multicast packets to test this socket as there might
906            // be many IPv6 interfaces on a host and could cause such send error:
907            // "No buffer space available (os error 55)".
908
909            MyUdpSocket::new(sock)
910                .map_err(|e| e_fmt!("failed to create MySocket for interface {}: {e}", intf.name))
911        }
912    }
913}
914
915/// Creates a new UDP socket to bind to `port` with REUSEPORT option.
916/// `non_block` indicates whether to set O_NONBLOCK for the socket.
917fn new_socket(addr: SocketAddr, non_block: bool) -> Result<PktInfoUdpSocket> {
918    let domain = match addr {
919        SocketAddr::V4(_) => socket2::Domain::IPV4,
920        SocketAddr::V6(_) => socket2::Domain::IPV6,
921    };
922
923    let fd = PktInfoUdpSocket::new(domain).map_err(|e| e_fmt!("create socket failed: {}", e))?;
924
925    fd.set_reuse_address(true)
926        .map_err(|e| e_fmt!("set ReuseAddr failed: {}", e))?;
927    #[cfg(unix)]
928    if let Err(e) = fd.set_reuse_port(true) {
929        debug!(
930            "SO_REUSEPORT is not supported, continuing without it: {}",
931            e
932        );
933    }
934
935    if non_block {
936        fd.set_nonblocking(true)
937            .map_err(|e| e_fmt!("set O_NONBLOCK: {}", e))?;
938    }
939
940    fd.bind(&addr.into())
941        .map_err(|e| e_fmt!("socket bind to {} failed: {}", &addr, e))?;
942
943    trace!("new socket bind to {}", &addr);
944    Ok(fd)
945}
946
947/// Specify a UNIX timestamp in millis to run `command` for the next time.
948struct ReRun {
949    /// UNIX timestamp in millis.
950    next_time: u64,
951    command: Command,
952}
953
954/// A query response deferred per RFC 6762 §6 (shared response).
955struct DelayedResponse {
956    /// UNIX timestamp in millis at which to send `out`.
957    next_time: u64,
958    out: DnsOutgoing,
959    if_index: u32,
960    is_ipv4: bool,
961}
962
963/// Specify kinds of interfaces. It is used to enable or to disable interfaces in the daemon.
964///
965/// Note that for ergonomic reasons, `From<&str>` and `From<IpAddr>` are implemented.
966#[derive(Debug, Clone)]
967#[non_exhaustive]
968pub enum IfKind {
969    /// All interfaces.
970    All,
971
972    /// All IPv4 interfaces.
973    IPv4,
974
975    /// All IPv6 interfaces.
976    IPv6,
977
978    /// By the interface name, for example "en0"
979    Name(String),
980
981    /// By an IPv4 or IPv6 address.
982    /// This is used to look up the interface. The semantics is to identify an interface of
983    /// IPv4 or IPv6, not a specific address on the interface.
984    Addr(IpAddr),
985
986    /// 127.0.0.1 (or anything in 127.0.0.0/8), enabled by default.
987    ///
988    /// Loopback interfaces are required by some use cases (e.g., OSCQuery) for publishing.
989    LoopbackV4,
990
991    /// ::1/128, enabled by default.
992    LoopbackV6,
993
994    /// By interface index, IPv4 only.
995    IndexV4(u32),
996
997    /// By interface index, IPv6 only.
998    IndexV6(u32),
999
1000    /// By a user-supplied predicate function.
1001    Predicate(IfPredicate),
1002}
1003
1004impl IfKind {
1005    /// Checks if `intf` matches with this interface kind.
1006    pub(crate) fn matches(&self, intf: &Interface) -> bool {
1007        match self {
1008            Self::All => true,
1009            Self::IPv4 => intf.ip().is_ipv4(),
1010            Self::IPv6 => intf.ip().is_ipv6(),
1011            Self::Name(ifname) => ifname == &intf.name,
1012            Self::Addr(addr) => addr == &intf.ip(),
1013            Self::LoopbackV4 => intf.is_loopback() && intf.ip().is_ipv4(),
1014            Self::LoopbackV6 => intf.is_loopback() && intf.ip().is_ipv6(),
1015            Self::IndexV4(idx) => intf.index == Some(*idx) && intf.ip().is_ipv4(),
1016            Self::IndexV6(idx) => intf.index == Some(*idx) && intf.ip().is_ipv6(),
1017            Self::Predicate(p) => p.matches(intf),
1018        }
1019    }
1020}
1021
1022/// The first use case of specifying an interface was to
1023/// use an interface name. Hence adding this for ergonomic reasons.
1024impl From<&str> for IfKind {
1025    fn from(val: &str) -> Self {
1026        Self::Name(val.to_string())
1027    }
1028}
1029
1030impl From<&String> for IfKind {
1031    fn from(val: &String) -> Self {
1032        Self::Name(val.to_string())
1033    }
1034}
1035
1036/// Still for ergonomic reasons.
1037impl From<IpAddr> for IfKind {
1038    fn from(val: IpAddr) -> Self {
1039        Self::Addr(val)
1040    }
1041}
1042
1043/// A list of `IfKind` that can be used to match interfaces.
1044pub struct IfKindVec {
1045    kinds: Vec<IfKind>,
1046}
1047
1048/// A trait that converts a type into a Vec of `IfKind`.
1049pub trait IntoIfKindVec {
1050    fn into_vec(self) -> IfKindVec;
1051}
1052
1053impl<T: Into<IfKind>> IntoIfKindVec for T {
1054    fn into_vec(self) -> IfKindVec {
1055        let if_kind: IfKind = self.into();
1056        IfKindVec {
1057            kinds: vec![if_kind],
1058        }
1059    }
1060}
1061
1062impl<T: Into<IfKind>> IntoIfKindVec for Vec<T> {
1063    fn into_vec(self) -> IfKindVec {
1064        let kinds: Vec<IfKind> = self.into_iter().map(|x| x.into()).collect();
1065        IfKindVec { kinds }
1066    }
1067}
1068
1069/// A predicate function for matching against interfaces.
1070#[derive(Clone)]
1071pub struct IfPredicate(std::sync::Arc<dyn Fn(&Interface) -> bool + Send + Sync>);
1072
1073impl IfPredicate {
1074    /// Creates a predicate from a closure that decides whether an interface
1075    /// matches.
1076    ///
1077    /// # Example
1078    ///
1079    /// ```no_run
1080    /// # use mdns_sd::IfPredicate;
1081    /// // Match any interface that doesn't look like a virtual bridge
1082    /// IfPredicate::new(|intf| !intf.name.starts_with("virbr"));
1083    /// ```
1084    pub fn new(predicate: impl Fn(&Interface) -> bool + Send + Sync + 'static) -> Self {
1085        Self(std::sync::Arc::new(predicate))
1086    }
1087
1088    pub(crate) fn matches(&self, intf: &Interface) -> bool {
1089        self.0(intf)
1090    }
1091}
1092
1093impl std::fmt::Debug for IfPredicate {
1094    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1095        write!(f, "IfPredicate(...)")
1096    }
1097}
1098
1099/// Selection of interfaces.
1100struct IfSelection {
1101    /// The interfaces to be selected.
1102    if_kind: IfKind,
1103
1104    /// Whether the `if_kind` should be enabled or not.
1105    selected: bool,
1106}
1107
1108/// Selection of the max packet size of interfaces.
1109struct MaxPacketSizeSelection {
1110    /// The interfaces to be selected.
1111    if_kind: IfKind,
1112
1113    /// Max byte size of a packet generated for the selected interfaces.
1114    max_packet_size: usize,
1115}
1116
1117/// A struct holding the state. It was inspired by `zeroconf` package in Python.
1118struct Zeroconf {
1119    /// The mDNS port number to use for socket binding.
1120    /// Typically MDNS_PORT (5353), but can be customized for development/testing.
1121    port: u16,
1122
1123    /// Local interfaces keyed by interface index.
1124    my_intfs: HashMap<u32, MyIntf>,
1125
1126    /// A common socket for IPv4 interfaces. It's None if IPv4 is disabled in OS kernel.
1127    ipv4_sock: Option<MyUdpSocket>,
1128
1129    /// A common socket for IPv6 interfaces. It's None if IPv6 is disabled in OS kernel.
1130    ipv6_sock: Option<MyUdpSocket>,
1131
1132    /// Local registered services, keyed by service full names.
1133    my_services: HashMap<String, ServiceInfo>,
1134
1135    /// Received DNS records.
1136    cache: DnsCache,
1137
1138    /// Registered service records, keyed by interface index.
1139    dns_registry_map: HashMap<u32, DnsRegistry>,
1140
1141    /// Active "Browse" commands.
1142    service_queriers: HashMap<String, Sender<ServiceEvent>>, // <ty_domain, channel::sender>
1143
1144    /// Active "ResolveHostname" commands.
1145    ///
1146    /// The timestamps are set at the future timestamp when the command should timeout.
1147    /// `hostname` is case-insensitive and stored in lowercase.
1148    hostname_resolvers: HashMap<String, (Sender<HostnameResolutionEvent>, Option<u64>)>, // <hostname, (channel::sender, UNIX timestamp in millis)>
1149
1150    /// All repeating transmissions.
1151    retransmissions: Vec<ReRun>,
1152
1153    /// Query responses deferred per RFC 6762 §6.
1154    delayed_responses: Vec<DelayedResponse>,
1155
1156    counters: Metrics,
1157
1158    /// Waits for incoming packets.
1159    poller: Poll,
1160
1161    /// Channels to notify events.
1162    monitors: Vec<Sender<DaemonEvent>>,
1163
1164    /// Options
1165    service_name_len_max: u8,
1166
1167    /// Interval in millis to check IP address changes.
1168    ip_check_interval: u64,
1169
1170    /// All max packet size selections called to the daemon, in call order.
1171    /// For an interface matched by more than one, the last one wins.
1172    max_packet_sizes: Vec<MaxPacketSizeSelection>,
1173
1174    /// All interface selections called to the daemon.
1175    if_selections: Vec<IfSelection>,
1176
1177    /// Socket for signaling.
1178    signal_sock: MioUdpSocket,
1179
1180    /// Timestamps marking where we need another iteration of the run loop,
1181    /// to react to events like retransmissions, cache refreshes, interface IP address changes, etc.
1182    ///
1183    /// When the run loop goes through a single iteration, it will
1184    /// set its timeout to the earliest timer in this list.
1185    timers: BinaryHeap<Reverse<u64>>,
1186
1187    status: DaemonStatus,
1188
1189    /// Service instances that are pending for resolving SRV and TXT.
1190    pending_resolves: HashSet<String>,
1191
1192    /// Service instances that are already resolved.
1193    resolved: HashSet<String>,
1194
1195    multicast_loop_v4: bool,
1196
1197    multicast_loop_v6: bool,
1198
1199    accept_unsolicited: bool,
1200
1201    include_apple_p2p: bool,
1202
1203    cmd_sender: Sender<Command>,
1204
1205    signal_addr: SocketAddr,
1206
1207    #[cfg(test)]
1208    test_down_interfaces: HashSet<String>,
1209}
1210
1211/// Join the multicast group for the given interface.
1212fn join_multicast_group(my_sock: &PktInfoUdpSocket, intf: &Interface) -> Result<()> {
1213    let intf_ip = &intf.ip();
1214    match intf_ip {
1215        IpAddr::V4(ip) => {
1216            // Join mDNS group to receive packets.
1217            debug!("join multicast group V4 on {} addr {ip}", intf.name);
1218            my_sock
1219                .join_multicast_v4(&GROUP_ADDR_V4, ip)
1220                .map_err(|e| e_fmt!("PKT join multicast group on addr {}: {}", intf_ip, e))?;
1221        }
1222        IpAddr::V6(ip) => {
1223            let if_index = intf.index.unwrap_or(0);
1224            // Join mDNS group to receive packets.
1225            debug!(
1226                "join multicast group V6 on {} addr {ip} with index {if_index}",
1227                intf.name
1228            );
1229            my_sock
1230                .join_multicast_v6(&GROUP_ADDR_V6, if_index)
1231                .map_err(|e| e_fmt!("PKT join multicast group on addr {}: {}", ip, e))?;
1232        }
1233    }
1234    Ok(())
1235}
1236
1237impl Zeroconf {
1238    fn new(
1239        signal_sock: MioUdpSocket,
1240        poller: Poll,
1241        port: u16,
1242        cmd_sender: Sender<Command>,
1243        signal_addr: SocketAddr,
1244    ) -> Self {
1245        // Get interfaces.
1246        let my_ifaddrs = my_ip_interfaces(true);
1247
1248        // Create a socket for every IP addr.
1249        // Note: it is possible that `my_ifaddrs` contains the same IP addr with different interface names,
1250        // or the same interface name with different IP addrs.
1251        let mut my_intfs = HashMap::new();
1252        let mut dns_registry_map = HashMap::new();
1253
1254        // Use the same socket for receiving and sending multicast packets.
1255        // Such socket has to bind to INADDR_ANY or IN6ADDR_ANY.
1256        let mut ipv4_sock = None;
1257        let addr = SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), port);
1258        match new_socket(addr.into(), true) {
1259            Ok(sock) => {
1260                // Per RFC 6762 section 11:
1261                // "All Multicast DNS responses (including responses sent via unicast) SHOULD
1262                // be sent with IP TTL set to 255."
1263                // Here we set the TTL to 255 for multicast as we don't support unicast yet.
1264                sock.set_multicast_ttl_v4(255)
1265                    .map_err(|e| e_fmt!("set set_multicast_ttl_v4 on addr: {}", e))
1266                    .ok();
1267
1268                // This clones a socket.
1269                ipv4_sock = match MyUdpSocket::new(sock) {
1270                    Ok(s) => Some(s),
1271                    Err(e) => {
1272                        debug!("failed to create IPv4 MyUdpSocket: {e}");
1273                        None
1274                    }
1275                };
1276            }
1277            // Per RFC 6762 section 11:}
1278            Err(e) => debug!("failed to create IPv4 socket: {e}"),
1279        }
1280
1281        let mut ipv6_sock = None;
1282        let addr = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), port, 0, 0);
1283        match new_socket(addr.into(), true) {
1284            Ok(sock) => {
1285                // Per RFC 6762 section 11:
1286                // "All Multicast DNS responses (including responses sent via unicast) SHOULD
1287                // be sent with IP TTL set to 255."
1288                sock.set_multicast_hops_v6(255)
1289                    .map_err(|e| e_fmt!("set set_multicast_hops_v6: {}", e))
1290                    .ok();
1291
1292                // This clones the ipv6 socket.
1293                ipv6_sock = match MyUdpSocket::new(sock) {
1294                    Ok(s) => Some(s),
1295                    Err(e) => {
1296                        debug!("failed to create IPv6 MyUdpSocket: {e}");
1297                        None
1298                    }
1299                };
1300            }
1301            Err(e) => debug!("failed to create IPv6 socket: {e}"),
1302        }
1303
1304        // Configure sockets to join multicast groups.
1305        for intf in my_ifaddrs {
1306            let sock_opt = if intf.ip().is_ipv4() {
1307                &ipv4_sock
1308            } else {
1309                &ipv6_sock
1310            };
1311            let Some(sock) = sock_opt else {
1312                debug!(
1313                    "no socket available for interface {} with addr {}. Skipped.",
1314                    intf.name,
1315                    intf.ip()
1316                );
1317                continue;
1318            };
1319
1320            if let Err(e) = join_multicast_group(&sock.pktinfo, &intf) {
1321                debug!("failed to join multicast: {}: {e}. Skipped.", &intf.ip());
1322            }
1323
1324            let if_index = intf.index.unwrap_or(0);
1325
1326            // Add this interface address if not already present.
1327            dns_registry_map
1328                .entry(if_index)
1329                .or_insert_with(DnsRegistry::new);
1330
1331            my_intfs
1332                .entry(if_index)
1333                .and_modify(|v: &mut MyIntf| {
1334                    v.addrs.insert(intf.addr.clone());
1335                })
1336                .or_insert(MyIntf {
1337                    name: intf.name.clone(),
1338                    index: if_index,
1339                    addrs: HashSet::from([intf.addr]),
1340                    max_packet_size_v4: MAX_PKT_DEFAULT,
1341                    max_packet_size_v6: MAX_PKT_DEFAULT,
1342                });
1343        }
1344
1345        let monitors = Vec::new();
1346        let service_name_len_max = SERVICE_NAME_LEN_MAX_DEFAULT;
1347        let ip_check_interval = IP_CHECK_INTERVAL_IN_SECS_DEFAULT as u64 * 1000;
1348
1349        let timers = BinaryHeap::new();
1350
1351        // Enable everything, including loopback interfaces.
1352        let if_selections = vec![];
1353
1354        let status = DaemonStatus::Running;
1355
1356        Self {
1357            port,
1358            my_intfs,
1359            ipv4_sock,
1360            ipv6_sock,
1361            my_services: HashMap::new(),
1362            cache: DnsCache::new(),
1363            dns_registry_map,
1364            hostname_resolvers: HashMap::new(),
1365            service_queriers: HashMap::new(),
1366            retransmissions: Vec::new(),
1367            delayed_responses: Vec::new(),
1368            counters: HashMap::new(),
1369            poller,
1370            monitors,
1371            service_name_len_max,
1372            ip_check_interval,
1373            max_packet_sizes: Vec::new(),
1374            if_selections,
1375            signal_sock,
1376            timers,
1377            status,
1378            pending_resolves: HashSet::new(),
1379            resolved: HashSet::new(),
1380            multicast_loop_v4: true,
1381            multicast_loop_v6: true,
1382            accept_unsolicited: false,
1383            include_apple_p2p: false,
1384            cmd_sender,
1385            signal_addr,
1386
1387            #[cfg(test)]
1388            test_down_interfaces: HashSet::new(),
1389        }
1390    }
1391
1392    /// Send a Command into the daemon channel and poke the signal socket to wake the poll loop.
1393    fn send_cmd_to_self(&self, cmd: Command) -> Result<()> {
1394        let cmd_name = cmd.to_string();
1395
1396        self.cmd_sender.try_send(cmd).map_err(|e| match e {
1397            TrySendError::Full(_) => Error::Again,
1398            TrySendError::Disconnected(_) => Error::DaemonShutdown,
1399        })?;
1400
1401        let addr = SocketAddrV4::new(LOOPBACK_V4, 0);
1402        let socket = UdpSocket::bind(addr)
1403            .map_err(|e| e_fmt!("Failed to create socket to send signal: {}", e))?;
1404        socket
1405            .send_to(cmd_name.as_bytes(), self.signal_addr)
1406            .map_err(|e| {
1407                e_fmt!(
1408                    "signal socket send_to {} ({}) failed: {}",
1409                    self.signal_addr,
1410                    cmd_name,
1411                    e
1412                )
1413            })?;
1414
1415        Ok(())
1416    }
1417
1418    /// Clean up all resources before shutdown.
1419    ///
1420    /// This method:
1421    /// 1. Unregisters all registered services (sends goodbye packets)
1422    /// 2. Stops all active browse operations
1423    /// 3. Stops all active hostname resolution operations
1424    /// 4. Clears all retransmissions
1425    /// 5. Drops all pending delayed responses
1426    fn cleanup(&mut self) {
1427        debug!("Starting cleanup for shutdown");
1428
1429        // 1. Unregister all services - send goodbye packets
1430        let service_names: Vec<String> = self.my_services.keys().cloned().collect();
1431        for fullname in service_names {
1432            if let Some(info) = self.my_services.get(&fullname) {
1433                debug!("Unregistering service during shutdown: {}", &fullname);
1434
1435                for intf in self.my_intfs.values() {
1436                    if let Some(sock) = self.ipv4_sock.as_ref() {
1437                        self.unregister_service(info, intf, &sock.pktinfo);
1438                    }
1439
1440                    if let Some(sock) = self.ipv6_sock.as_ref() {
1441                        self.unregister_service(info, intf, &sock.pktinfo);
1442                    }
1443                }
1444            }
1445        }
1446        self.my_services.clear();
1447
1448        // 2. Stop all browse operations
1449        let browse_types: Vec<String> = self.service_queriers.keys().cloned().collect();
1450        for ty_domain in browse_types {
1451            debug!("Stopping browse during shutdown: {}", &ty_domain);
1452            if let Some(sender) = self.service_queriers.remove(&ty_domain) {
1453                // Notify the client
1454                if let Err(e) = sender.send(ServiceEvent::SearchStopped(ty_domain.clone())) {
1455                    debug!("Failed to send SearchStopped during shutdown: {}", e);
1456                }
1457            }
1458        }
1459
1460        // 3. Stop all hostname resolution operations
1461        let hostnames: Vec<String> = self.hostname_resolvers.keys().cloned().collect();
1462        for hostname in hostnames {
1463            debug!(
1464                "Stopping hostname resolution during shutdown: {}",
1465                &hostname
1466            );
1467            if let Some((sender, _timeout)) = self.hostname_resolvers.remove(&hostname) {
1468                // Notify the client
1469                if let Err(e) =
1470                    sender.send(HostnameResolutionEvent::SearchStopped(hostname.clone()))
1471                {
1472                    debug!(
1473                        "Failed to send HostnameResolutionEvent::SearchStopped during shutdown: {}",
1474                        e
1475                    );
1476                }
1477            }
1478        }
1479
1480        // 4. Clear all retransmissions
1481        self.retransmissions.clear();
1482
1483        // 5. Drop any pending delayed responses
1484        self.delayed_responses.clear();
1485
1486        debug!("Cleanup completed");
1487    }
1488
1489    /// The main event loop of the daemon thread
1490    ///
1491    /// In each round, it will:
1492    /// 1. select the listening sockets with a timeout.
1493    /// 2. process the incoming packets if any.
1494    /// 3. try_recv on its channel and execute commands.
1495    /// 4. announce its registered services.
1496    /// 5. process retransmissions if any.
1497    fn run(&mut self, receiver: Receiver<Command>) -> Option<Command> {
1498        // Add the daemon's signal socket to the poller.
1499        if let Err(e) = self.poller.registry().register(
1500            &mut self.signal_sock,
1501            mio::Token(SIGNAL_SOCK_EVENT_KEY),
1502            mio::Interest::READABLE,
1503        ) {
1504            debug!("failed to add signal socket to the poller: {}", e);
1505            return None;
1506        }
1507
1508        if let Some(sock) = self.ipv4_sock.as_mut() {
1509            if let Err(e) = self.poller.registry().register(
1510                sock,
1511                mio::Token(IPV4_SOCK_EVENT_KEY),
1512                mio::Interest::READABLE,
1513            ) {
1514                debug!("failed to register ipv4 socket: {}", e);
1515                return None;
1516            }
1517        }
1518
1519        if let Some(sock) = self.ipv6_sock.as_mut() {
1520            if let Err(e) = self.poller.registry().register(
1521                sock,
1522                mio::Token(IPV6_SOCK_EVENT_KEY),
1523                mio::Interest::READABLE,
1524            ) {
1525                debug!("failed to register ipv6 socket: {}", e);
1526                return None;
1527            }
1528        }
1529
1530        // Setup timer for IP checks.
1531        let mut next_ip_check = if self.ip_check_interval > 0 {
1532            current_time_millis() + self.ip_check_interval
1533        } else {
1534            0
1535        };
1536
1537        if next_ip_check > 0 {
1538            self.add_timer(next_ip_check);
1539        }
1540
1541        // Start the run loop.
1542
1543        let mut events = mio::Events::with_capacity(1024);
1544        loop {
1545            let now = current_time_millis();
1546
1547            let earliest_timer = self.peek_earliest_timer();
1548            let timeout = earliest_timer.map(|timer| {
1549                // If `timer` already passed, set `timeout` to be 1ms.
1550                let millis = if timer > now { timer - now } else { 1 };
1551                Duration::from_millis(millis)
1552            });
1553
1554            // Process incoming packets, command events and optional timeout.
1555            events.clear();
1556            match self.poller.poll(&mut events, timeout) {
1557                Ok(_) => self.handle_poller_events(&events),
1558                Err(e) => debug!("failed to select from sockets: {}", e),
1559            }
1560
1561            let now = current_time_millis();
1562
1563            // Remove the timers if already passed.
1564            self.pop_timers_till(now);
1565
1566            // Remove hostname resolvers with expired timeouts.
1567            for hostname in self
1568                .hostname_resolvers
1569                .clone()
1570                .into_iter()
1571                .filter(|(_, (_, timeout))| timeout.map(|t| now >= t).unwrap_or(false))
1572                .map(|(hostname, _)| hostname)
1573            {
1574                trace!("hostname resolver timeout for {}", &hostname);
1575                call_hostname_resolution_listener(
1576                    &self.hostname_resolvers,
1577                    &hostname,
1578                    HostnameResolutionEvent::SearchTimeout(hostname.to_owned()),
1579                );
1580                call_hostname_resolution_listener(
1581                    &self.hostname_resolvers,
1582                    &hostname,
1583                    HostnameResolutionEvent::SearchStopped(hostname.to_owned()),
1584                );
1585                self.hostname_resolvers.remove(&hostname);
1586            }
1587
1588            // process commands from the command channel
1589            while let Ok(command) = receiver.try_recv() {
1590                if matches!(command, Command::Exit(_)) {
1591                    debug!("Exit command received, performing cleanup");
1592                    self.cleanup();
1593                    self.status = DaemonStatus::Shutdown;
1594                    return Some(command);
1595                }
1596                self.exec_command(command, false);
1597            }
1598
1599            // check for repeated commands and run them if their time is up.
1600            let mut i = 0;
1601            while i < self.retransmissions.len() {
1602                if now >= self.retransmissions[i].next_time {
1603                    let rerun = self.retransmissions.remove(i);
1604                    self.exec_command(rerun.command, true);
1605                } else {
1606                    i += 1;
1607                }
1608            }
1609
1610            // Send delayed responses whose time is up (RFC 6762 §6).
1611            let mut i = 0;
1612            while i < self.delayed_responses.len() {
1613                if now >= self.delayed_responses[i].next_time {
1614                    let resp = self.delayed_responses.remove(i);
1615                    self.send_delayed_response(resp);
1616                } else {
1617                    i += 1;
1618                }
1619            }
1620
1621            // Refresh cached service records with active queriers
1622            self.refresh_active_services();
1623
1624            // Refresh cached A/AAAA records with active queriers
1625            let mut query_count = 0;
1626            for (hostname, _sender) in self.hostname_resolvers.iter() {
1627                for (hostname, ip_addr) in
1628                    self.cache.refresh_due_hostname_resolutions(hostname).iter()
1629                {
1630                    self.send_query(hostname, ip_address_rr_type(&ip_addr.to_ip_addr()));
1631                    query_count += 1;
1632                }
1633            }
1634
1635            self.increase_counter(Counter::CacheRefreshAddr, query_count);
1636
1637            // check and evict expired records in our cache
1638            let now = current_time_millis();
1639
1640            // Notify service listeners about the expired records.
1641            let expired_services = self.cache.evict_expired_services(now);
1642            if !expired_services.is_empty() {
1643                debug!(
1644                    "run: send {} service removal to listeners",
1645                    expired_services.len()
1646                );
1647                self.notify_service_removal(expired_services);
1648            }
1649
1650            // Notify hostname listeners about the expired records.
1651            let expired_addrs = self.cache.evict_expired_addr(now);
1652            for (hostname, addrs) in expired_addrs {
1653                call_hostname_resolution_listener(
1654                    &self.hostname_resolvers,
1655                    &hostname,
1656                    HostnameResolutionEvent::AddressesRemoved(hostname.clone(), addrs),
1657                );
1658                let instances = self.cache.get_instances_on_host(&hostname);
1659                let instance_set: HashSet<String> = instances.into_iter().collect();
1660                self.resolve_updated_instances(&instance_set);
1661            }
1662
1663            // Send out probing queries.
1664            self.probing_handler();
1665
1666            // check IP changes if next_ip_check is reached.
1667            if now >= next_ip_check && next_ip_check > 0 {
1668                next_ip_check = now + self.ip_check_interval;
1669                self.add_timer(next_ip_check);
1670
1671                self.check_ip_changes();
1672            }
1673        }
1674    }
1675
1676    fn process_set_option(&mut self, daemon_opt: DaemonOption) {
1677        match daemon_opt {
1678            DaemonOption::ServiceNameLenMax(length) => self.service_name_len_max = length,
1679            DaemonOption::IpCheckInterval(interval) => self.ip_check_interval = interval,
1680            DaemonOption::MaxPacketSize(if_kind, size) => self.set_max_packet_size(if_kind, size),
1681            DaemonOption::EnableInterface(if_kind) => self.enable_interface(if_kind),
1682            DaemonOption::DisableInterface(if_kind) => self.disable_interface(if_kind),
1683            DaemonOption::MulticastLoopV4(on) => self.set_multicast_loop_v4(on),
1684            DaemonOption::MulticastLoopV6(on) => self.set_multicast_loop_v6(on),
1685            DaemonOption::AcceptUnsolicited(accept) => self.set_accept_unsolicited(accept),
1686            DaemonOption::IncludeAppleP2P(enable) => self.set_apple_p2p(enable),
1687            #[cfg(test)]
1688            DaemonOption::TestDownInterface(ifname) => {
1689                self.test_down_interfaces.insert(ifname);
1690            }
1691            #[cfg(test)]
1692            DaemonOption::TestUpInterface(ifname) => {
1693                self.test_down_interfaces.remove(&ifname);
1694            }
1695        }
1696    }
1697
1698    fn enable_interface(&mut self, kinds: Vec<IfKind>) {
1699        debug!("enable_interface: {:?}", kinds);
1700        let interfaces = my_ip_interfaces_inner(true, self.include_apple_p2p);
1701
1702        for if_kind in kinds {
1703            self.if_selections.push(IfSelection {
1704                if_kind: resolve_addr_to_index(if_kind, &interfaces),
1705                selected: true,
1706            });
1707        }
1708
1709        self.apply_intf_selections(interfaces);
1710    }
1711
1712    fn disable_interface(&mut self, kinds: Vec<IfKind>) {
1713        debug!("disable_interface: {:?}", kinds);
1714        let interfaces = my_ip_interfaces_inner(true, self.include_apple_p2p);
1715
1716        for if_kind in kinds {
1717            self.if_selections.push(IfSelection {
1718                if_kind: resolve_addr_to_index(if_kind, &interfaces),
1719                selected: false,
1720            });
1721        }
1722
1723        self.apply_intf_selections(interfaces);
1724    }
1725
1726    fn set_max_packet_size(&mut self, kinds: Vec<IfKind>, size: usize) {
1727        debug!("set_max_packet_size: {:?} {}", kinds, size);
1728        let interfaces = my_ip_interfaces_inner(true, self.include_apple_p2p);
1729
1730        for if_kind in kinds {
1731            self.max_packet_sizes.push(MaxPacketSizeSelection {
1732                if_kind: resolve_addr_to_index(if_kind, &interfaces),
1733                max_packet_size: size,
1734            });
1735        }
1736
1737        self.apply_max_packet_sizes(&interfaces);
1738    }
1739
1740    /// Resolve all max packet size selections against `interfaces` and store the
1741    /// outcome in every interface in `my_intfs`.
1742    fn apply_max_packet_sizes(&mut self, interfaces: &[Interface]) {
1743        for (if_index, my_intf) in self.my_intfs.iter_mut() {
1744            let v4 = resolve_max_packet_size(&self.max_packet_sizes, interfaces, *if_index, true);
1745            let v6 = resolve_max_packet_size(&self.max_packet_sizes, interfaces, *if_index, false);
1746
1747            if my_intf.max_packet_size_v4 != v4 || my_intf.max_packet_size_v6 != v6 {
1748                debug!(
1749                    "interface {}: max packet size v4 {} -> {v4}, v6 {} -> {v6}",
1750                    my_intf.name, my_intf.max_packet_size_v4, my_intf.max_packet_size_v6
1751                );
1752                my_intf.max_packet_size_v4 = v4;
1753                my_intf.max_packet_size_v6 = v6;
1754            }
1755        }
1756    }
1757
1758    fn set_multicast_loop_v4(&mut self, on: bool) {
1759        let Some(sock) = self.ipv4_sock.as_mut() else {
1760            return;
1761        };
1762        self.multicast_loop_v4 = on;
1763        sock.pktinfo
1764            .set_multicast_loop_v4(on)
1765            .map_err(|e| e_fmt!("failed to set multicast loop v4: {}", e))
1766            .unwrap();
1767    }
1768
1769    fn set_multicast_loop_v6(&mut self, on: bool) {
1770        let Some(sock) = self.ipv6_sock.as_mut() else {
1771            return;
1772        };
1773        self.multicast_loop_v6 = on;
1774        sock.pktinfo
1775            .set_multicast_loop_v6(on)
1776            .map_err(|e| e_fmt!("failed to set multicast loop v6: {}", e))
1777            .unwrap();
1778    }
1779
1780    fn set_accept_unsolicited(&mut self, accept: bool) {
1781        self.accept_unsolicited = accept;
1782    }
1783
1784    fn set_apple_p2p(&mut self, include: bool) {
1785        if self.include_apple_p2p != include {
1786            self.include_apple_p2p = include;
1787            self.apply_intf_selections(my_ip_interfaces_inner(true, self.include_apple_p2p));
1788        }
1789    }
1790
1791    fn notify_monitors(&mut self, event: DaemonEvent) {
1792        // Only retain the monitors that are still connected.
1793        self.monitors.retain(|sender| {
1794            if let Err(e) = sender.try_send(event.clone()) {
1795                debug!("notify_monitors: try_send: {}", &e);
1796                if matches!(e, TrySendError::Disconnected(_)) {
1797                    return false; // This monitor is dropped.
1798                }
1799            }
1800            true
1801        });
1802    }
1803
1804    /// Remove `addr` in my services that enabled `addr_auto`.
1805    fn del_addr_in_my_services(&mut self, addr: &IpAddr) {
1806        for (_, service_info) in self.my_services.iter_mut() {
1807            if service_info.is_addr_auto() {
1808                service_info.remove_ipaddr(addr);
1809            }
1810        }
1811    }
1812
1813    fn add_timer(&mut self, next_time: u64) {
1814        self.timers.push(Reverse(next_time));
1815    }
1816
1817    fn peek_earliest_timer(&self) -> Option<u64> {
1818        self.timers.peek().map(|Reverse(v)| *v)
1819    }
1820
1821    fn _pop_earliest_timer(&mut self) -> Option<u64> {
1822        self.timers.pop().map(|Reverse(v)| v)
1823    }
1824
1825    /// Pop all timers that are already passed till `now`.
1826    fn pop_timers_till(&mut self, now: u64) {
1827        while let Some(Reverse(v)) = self.timers.peek() {
1828            if *v > now {
1829                break;
1830            }
1831            self.timers.pop();
1832        }
1833    }
1834
1835    /// Apply all selections to `interfaces` and return the selected addresses.
1836    fn selected_intfs(&self, interfaces: Vec<Interface>) -> HashSet<Interface> {
1837        let intf_count = interfaces.len();
1838        let mut intf_selections = vec![true; intf_count];
1839
1840        // apply if_selections
1841        for selection in self.if_selections.iter() {
1842            // Mark the interfaces for this selection.
1843            for i in 0..intf_count {
1844                if selection.if_kind.matches(&interfaces[i]) {
1845                    intf_selections[i] = selection.selected;
1846                }
1847            }
1848        }
1849
1850        let mut selected_addrs = HashSet::new();
1851        for i in 0..intf_count {
1852            if intf_selections[i] {
1853                selected_addrs.insert(interfaces[i].clone());
1854            }
1855        }
1856
1857        selected_addrs
1858    }
1859
1860    /// Apply all selections to `interfaces`.
1861    ///
1862    /// For any interface, add it if selected but not bound yet,
1863    /// delete it if not selected but still bound.
1864    fn apply_intf_selections(&mut self, interfaces: Vec<Interface>) {
1865        // By default, we enable all interfaces.
1866        let intf_count = interfaces.len();
1867        let mut intf_selections = vec![true; intf_count];
1868
1869        // apply if_selections
1870        for selection in self.if_selections.iter() {
1871            // Mark the interfaces for this selection.
1872            for i in 0..intf_count {
1873                if selection.if_kind.matches(&interfaces[i]) {
1874                    intf_selections[i] = selection.selected;
1875                }
1876            }
1877        }
1878
1879        // Update `my_intfs` based on the selections.
1880        for (idx, intf) in interfaces.iter().enumerate() {
1881            if intf_selections[idx] {
1882                // Add the interface
1883                self.add_interface(intf, &interfaces);
1884            } else {
1885                // Remove the interface
1886                self.del_interface_addr(intf);
1887            }
1888        }
1889
1890        // An interface that lost an address may now match a different selection.
1891        // (`add_interface` already resolved the ones that gained one.)
1892        self.apply_max_packet_sizes(&interfaces);
1893    }
1894
1895    fn del_ip(&mut self, ip: IpAddr) {
1896        self.del_addr_in_my_services(&ip);
1897        self.notify_monitors(DaemonEvent::IpDel(ip));
1898    }
1899
1900    /// Check for IP changes and update [my_intfs] as needed.
1901    fn check_ip_changes(&mut self) {
1902        // Get the current interfaces.
1903        let my_ifaddrs = my_ip_interfaces_inner(true, self.include_apple_p2p);
1904
1905        #[cfg(test)]
1906        let my_ifaddrs: Vec<_> = my_ifaddrs
1907            .into_iter()
1908            .filter(|intf| !self.test_down_interfaces.contains(&intf.name))
1909            .collect();
1910
1911        let ifaddrs_map: HashMap<u32, Vec<&IfAddr>> =
1912            my_ifaddrs.iter().fold(HashMap::new(), |mut acc, intf| {
1913                let if_index = intf.index.unwrap_or(0);
1914                acc.entry(if_index).or_default().push(&intf.addr);
1915                acc
1916            });
1917
1918        let mut deleted_intfs = Vec::new();
1919        let mut deleted_ips = Vec::new();
1920
1921        for (if_index, my_intf) in self.my_intfs.iter_mut() {
1922            let mut last_ipv4 = None;
1923            let mut last_ipv6 = None;
1924
1925            if let Some(current_addrs) = ifaddrs_map.get(if_index) {
1926                my_intf.addrs.retain(|addr| {
1927                    if current_addrs.contains(&addr) {
1928                        true
1929                    } else {
1930                        match addr.ip() {
1931                            IpAddr::V4(ipv4) => last_ipv4 = Some(ipv4),
1932                            IpAddr::V6(ipv6) => last_ipv6 = Some(ipv6),
1933                        }
1934                        deleted_ips.push(addr.ip());
1935                        false
1936                    }
1937                });
1938                if my_intf.addrs.is_empty() {
1939                    deleted_intfs.push((*if_index, last_ipv4, last_ipv6))
1940                }
1941            } else {
1942                // If it does not exist, remove the interface.
1943                debug!(
1944                    "check_ip_changes: interface {} ({}) no longer exists, removing",
1945                    my_intf.name, if_index
1946                );
1947                for addr in my_intf.addrs.iter() {
1948                    match addr.ip() {
1949                        IpAddr::V4(ipv4) => last_ipv4 = Some(ipv4),
1950                        IpAddr::V6(ipv6) => last_ipv6 = Some(ipv6),
1951                    }
1952                    deleted_ips.push(addr.ip())
1953                }
1954                deleted_intfs.push((*if_index, last_ipv4, last_ipv6));
1955            }
1956        }
1957
1958        if !deleted_ips.is_empty() || !deleted_intfs.is_empty() {
1959            debug!(
1960                "check_ip_changes: {} deleted ips {} deleted intfs",
1961                deleted_ips.len(),
1962                deleted_intfs.len()
1963            );
1964        }
1965
1966        for ip in deleted_ips {
1967            self.del_ip(ip);
1968        }
1969
1970        for (if_index, last_ipv4, last_ipv6) in deleted_intfs {
1971            let Some(my_intf) = self.my_intfs.remove(&if_index) else {
1972                continue;
1973            };
1974
1975            if let Some(ipv4) = last_ipv4 {
1976                debug!("leave multicast for {ipv4}");
1977                if let Some(sock) = self.ipv4_sock.as_mut() {
1978                    if let Err(e) = sock.pktinfo.leave_multicast_v4(&GROUP_ADDR_V4, &ipv4) {
1979                        debug!("leave multicast group for addr {ipv4}: {e}");
1980                    }
1981                }
1982            }
1983
1984            if let Some(ipv6) = last_ipv6 {
1985                debug!("leave multicast for {ipv6}");
1986                if let Some(sock) = self.ipv6_sock.as_mut() {
1987                    if let Err(e) = sock
1988                        .pktinfo
1989                        .leave_multicast_v6(&GROUP_ADDR_V6, my_intf.index)
1990                    {
1991                        debug!("leave multicast group for IPv6: {ipv6}: {e}");
1992                    }
1993                }
1994            }
1995
1996            // Remove cache records for this interface.
1997            let intf_id = InterfaceId {
1998                name: my_intf.name.to_string(),
1999                index: my_intf.index,
2000            };
2001            let result = self.cache.remove_records_on_intf(intf_id);
2002            self.notify_service_removal(result.removed_instances);
2003            self.resolve_updated_instances(&result.modified_instances);
2004        }
2005
2006        // Add newly found interfaces only if in our selections.
2007        self.apply_intf_selections(my_ifaddrs);
2008    }
2009
2010    /// Remove an interface address when it was down, disabled or removed from the system.
2011    /// If no more addresses on the interface, remove the interface as well.
2012    fn del_interface_addr(&mut self, intf: &Interface) {
2013        let if_index = intf.index.unwrap_or(0);
2014        debug!(
2015            "del_interface_addr: {} ({if_index}) addr {}",
2016            intf.name,
2017            intf.ip()
2018        );
2019
2020        let Some(my_intf) = self.my_intfs.get_mut(&if_index) else {
2021            debug!("del_interface_addr: interface {} not found", intf.name);
2022            return;
2023        };
2024
2025        let mut ip_removed = false;
2026
2027        if my_intf.addrs.remove(&intf.addr) {
2028            ip_removed = true;
2029
2030            match intf.addr.ip() {
2031                IpAddr::V4(ipv4) => {
2032                    if my_intf.next_ifaddr_v4().is_none() {
2033                        if let Some(sock) = self.ipv4_sock.as_mut() {
2034                            if let Err(e) = sock.pktinfo.leave_multicast_v4(&GROUP_ADDR_V4, &ipv4) {
2035                                debug!("leave multicast group for addr {ipv4}: {e}");
2036                            } else {
2037                                debug!("leave multicast for {ipv4}");
2038                            }
2039                        }
2040                    }
2041                }
2042
2043                IpAddr::V6(ipv6) => {
2044                    if my_intf.next_ifaddr_v6().is_none() {
2045                        if let Some(sock) = self.ipv6_sock.as_mut() {
2046                            if let Err(e) =
2047                                sock.pktinfo.leave_multicast_v6(&GROUP_ADDR_V6, if_index)
2048                            {
2049                                debug!("leave multicast group for addr {ipv6}: {e}");
2050                            }
2051                        }
2052                    }
2053                }
2054            }
2055
2056            if my_intf.addrs.is_empty() {
2057                // If no more addresses, remove the interface.
2058                debug!("del_interface_addr: removing interface {}", intf.name);
2059                self.my_intfs.remove(&if_index);
2060                self.dns_registry_map.remove(&if_index);
2061                self.cache
2062                    .remove_addrs_on_disabled_intf(if_index, IpType::BOTH);
2063            } else {
2064                // Interface still has addresses of the other IP version.
2065                // Remove cached address records for the disabled IP version
2066                // only if no more addresses of that version remain.
2067                let is_v4 = intf.addr.ip().is_ipv4();
2068                let version_gone = if is_v4 {
2069                    my_intf.next_ifaddr_v4().is_none()
2070                } else {
2071                    my_intf.next_ifaddr_v6().is_none()
2072                };
2073                if version_gone {
2074                    let ip_type = if is_v4 { IpType::V4 } else { IpType::V6 };
2075                    self.cache.remove_addrs_on_disabled_intf(if_index, ip_type);
2076                }
2077            }
2078        }
2079
2080        if ip_removed {
2081            // Notify the monitors.
2082            self.notify_monitors(DaemonEvent::IpDel(intf.ip()));
2083            // Remove the interface from my services that enabled `addr_auto`.
2084            self.del_addr_in_my_services(&intf.ip());
2085        }
2086    }
2087
2088    /// Add the address of `intf` to `my_intfs`, and announce our services on it.
2089    ///
2090    /// `interfaces` is the full list the caller is applying, needed to resolve the
2091    /// max packet size of the interface before we send anything on it.
2092    fn add_interface(&mut self, intf: &Interface, interfaces: &[Interface]) {
2093        let sock_opt = if intf.ip().is_ipv4() {
2094            &self.ipv4_sock
2095        } else {
2096            &self.ipv6_sock
2097        };
2098
2099        let Some(sock) = sock_opt else {
2100            debug!(
2101                "add_interface: no socket available for interface {} with addr {}. Skipped.",
2102                intf.name,
2103                intf.ip()
2104            );
2105            return;
2106        };
2107
2108        let if_index = intf.index.unwrap_or(0);
2109        let mut new_addr = false;
2110
2111        match self.my_intfs.entry(if_index) {
2112            Entry::Occupied(mut entry) => {
2113                // If intf has a new address, add it to the existing interface.
2114                let my_intf = entry.get_mut();
2115                if !my_intf.addrs.contains(&intf.addr) {
2116                    if let Err(e) = join_multicast_group(&sock.pktinfo, intf) {
2117                        debug!("add_interface: socket_config {}: {e}", &intf.name);
2118                    }
2119                    my_intf.addrs.insert(intf.addr.clone());
2120                    new_addr = true;
2121                }
2122            }
2123            Entry::Vacant(entry) => {
2124                if let Err(e) = join_multicast_group(&sock.pktinfo, intf) {
2125                    debug!("add_interface: socket_config {}: {e}. Skipped.", &intf.name);
2126                    return;
2127                }
2128
2129                new_addr = true;
2130                let new_intf = MyIntf {
2131                    name: intf.name.clone(),
2132                    index: if_index,
2133                    addrs: HashSet::from([intf.addr.clone()]),
2134                    max_packet_size_v4: MAX_PKT_DEFAULT,
2135                    max_packet_size_v6: MAX_PKT_DEFAULT,
2136                };
2137                entry.insert(new_intf);
2138            }
2139        }
2140
2141        if !new_addr {
2142            trace!("add_interface: interface {} already exists", &intf.name);
2143            return;
2144        }
2145
2146        debug!("add new interface {}: {}", intf.name, intf.ip());
2147
2148        // Resolve before announcing, so the first packet out already honors it.
2149        let v4 = resolve_max_packet_size(&self.max_packet_sizes, interfaces, if_index, true);
2150        let v6 = resolve_max_packet_size(&self.max_packet_sizes, interfaces, if_index, false);
2151        if let Some(my_intf) = self.my_intfs.get_mut(&if_index) {
2152            my_intf.max_packet_size_v4 = v4;
2153            my_intf.max_packet_size_v6 = v6;
2154        }
2155
2156        let Some(my_intf) = self.my_intfs.get(&if_index) else {
2157            debug!("add_interface: cannot find if_index {if_index}");
2158            return;
2159        };
2160
2161        let dns_registry = match self.dns_registry_map.get_mut(&if_index) {
2162            Some(registry) => registry,
2163            None => self
2164                .dns_registry_map
2165                .entry(if_index)
2166                .or_insert_with(DnsRegistry::new),
2167        };
2168
2169        for (_, service_info) in self.my_services.iter_mut() {
2170            if service_info.is_addr_auto() {
2171                service_info.insert_ipaddr(intf);
2172
2173                if let Ok(true) = announce_service_on_intf(
2174                    dns_registry,
2175                    service_info,
2176                    my_intf,
2177                    &sock.pktinfo,
2178                    self.port,
2179                ) {
2180                    debug!(
2181                        "Announce service {} on {}",
2182                        service_info.get_fullname(),
2183                        intf.ip()
2184                    );
2185                    service_info.set_status(if_index, ServiceStatus::Announced);
2186                } else {
2187                    for timer in dns_registry.new_timers.drain(..) {
2188                        self.timers.push(Reverse(timer));
2189                    }
2190                    service_info.set_status(if_index, ServiceStatus::Probing);
2191                }
2192            }
2193        }
2194
2195        // Send browse queries on the new interface without known answers.
2196        // This avoids known-answer suppression (RFC 6762 Section 7.1) that
2197        // would cause the responder to suppress its response, preventing
2198        // address records from being attributed to the new interface.
2199        if let Some(my_intf) = self.my_intfs.get(&if_index) {
2200            for ty in self.service_queriers.keys() {
2201                self.send_query_on_intf(ty, RRType::PTR, my_intf);
2202            }
2203        }
2204
2205        // Notify the monitors.
2206        self.notify_monitors(DaemonEvent::IpAdd(intf.ip()));
2207    }
2208
2209    /// Registers a service.
2210    ///
2211    /// RFC 6762 section 8.3.
2212    /// ...the Multicast DNS responder MUST send
2213    ///    an unsolicited Multicast DNS response containing, in the Answer
2214    ///    Section, all of its newly registered resource records
2215    ///
2216    /// Zeroconf will then respond to requests for information about this service.
2217    fn register_service(&mut self, mut info: ServiceInfo) {
2218        // Check the service name length.
2219        if let Err(e) = check_service_name_length(info.get_type(), self.service_name_len_max) {
2220            error!("check_service_name_length: {}", &e);
2221            self.notify_monitors(DaemonEvent::Error(e));
2222            return;
2223        }
2224
2225        if info.is_addr_auto() {
2226            let selected_intfs =
2227                self.selected_intfs(my_ip_interfaces_inner(true, self.include_apple_p2p));
2228            for intf in selected_intfs {
2229                info.insert_ipaddr(&intf);
2230            }
2231        }
2232
2233        debug!("register service {:?}", &info);
2234
2235        let outgoing_addrs = self.send_unsolicited_response(&mut info);
2236        if !outgoing_addrs.is_empty() {
2237            self.notify_monitors(DaemonEvent::Announce(
2238                info.get_fullname().to_string(),
2239                format!("{:?}", &outgoing_addrs),
2240            ));
2241        }
2242
2243        // The key has to be lower case letter as DNS record name is case insensitive.
2244        // The info will have the original name.
2245        let service_fullname = info.get_fullname().to_lowercase();
2246        self.my_services.insert(service_fullname, info);
2247    }
2248
2249    /// Sends out announcement of `info` on every valid interface.
2250    /// Returns the list of interface IPs that sent out the announcement.
2251    fn send_unsolicited_response(&mut self, info: &mut ServiceInfo) -> Vec<IpAddr> {
2252        let mut outgoing_addrs = Vec::new();
2253        let mut outgoing_intfs = HashSet::new();
2254
2255        let mut invalid_intf_addrs = HashSet::new();
2256
2257        for (if_index, intf) in self.my_intfs.iter() {
2258            let dns_registry = match self.dns_registry_map.get_mut(if_index) {
2259                Some(registry) => registry,
2260                None => self
2261                    .dns_registry_map
2262                    .entry(*if_index)
2263                    .or_insert_with(DnsRegistry::new),
2264            };
2265
2266            let mut announced = false;
2267
2268            // IPv4
2269            if let Some(sock) = self.ipv4_sock.as_mut() {
2270                match announce_service_on_intf(dns_registry, info, intf, &sock.pktinfo, self.port) {
2271                    Ok(true) => {
2272                        for addr in intf.addrs.iter().filter(|a| a.ip().is_ipv4()) {
2273                            outgoing_addrs.push(addr.ip());
2274                        }
2275                        outgoing_intfs.insert(intf.index);
2276
2277                        debug!(
2278                            "Announce service IPv4 {} on {}",
2279                            info.get_fullname(),
2280                            intf.name
2281                        );
2282                        announced = true;
2283                    }
2284                    Ok(false) => {}
2285                    Err(InternalError::IntfAddrInvalid(intf_addr)) => {
2286                        invalid_intf_addrs.insert(intf_addr);
2287                    }
2288                }
2289            }
2290
2291            if let Some(sock) = self.ipv6_sock.as_mut() {
2292                match announce_service_on_intf(dns_registry, info, intf, &sock.pktinfo, self.port) {
2293                    Ok(true) => {
2294                        for addr in intf.addrs.iter().filter(|a| a.ip().is_ipv6()) {
2295                            outgoing_addrs.push(addr.ip());
2296                        }
2297                        outgoing_intfs.insert(intf.index);
2298
2299                        debug!(
2300                            "Announce service IPv6 {} on {}",
2301                            info.get_fullname(),
2302                            intf.name
2303                        );
2304                        announced = true;
2305                    }
2306                    Ok(false) => {}
2307                    Err(InternalError::IntfAddrInvalid(intf_addr)) => {
2308                        invalid_intf_addrs.insert(intf_addr);
2309                    }
2310                }
2311            }
2312
2313            if announced {
2314                info.set_status(intf.index, ServiceStatus::Announced);
2315            } else {
2316                for timer in dns_registry.new_timers.drain(..) {
2317                    self.timers.push(Reverse(timer));
2318                }
2319                info.set_status(*if_index, ServiceStatus::Probing);
2320            }
2321        }
2322
2323        if !invalid_intf_addrs.is_empty() {
2324            let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addrs));
2325        }
2326
2327        // RFC 6762 section 8.3.
2328        // ..The Multicast DNS responder MUST send at least two unsolicited
2329        //    responses, one second apart.
2330        let next_time = current_time_millis()
2331            + ANNOUNCE_SECOND_DELAY_MILLIS
2332            + fastrand::u64(0..ANNOUNCE_SECOND_JITTER_MILLIS);
2333        for if_index in outgoing_intfs {
2334            self.add_retransmission(
2335                next_time,
2336                Command::RegisterResend(info.get_fullname().to_string(), if_index),
2337            );
2338        }
2339
2340        outgoing_addrs
2341    }
2342
2343    /// Send probings or finish them if expired. Notify waiting services.
2344    fn probing_handler(&mut self) {
2345        let now = current_time_millis();
2346        let mut invalid_intf_addrs = HashSet::new();
2347
2348        for (if_index, intf) in self.my_intfs.iter() {
2349            let Some(dns_registry) = self.dns_registry_map.get_mut(if_index) else {
2350                continue;
2351            };
2352
2353            let (out, expired_probes) = check_probing(dns_registry, &mut self.timers, now);
2354
2355            // send probing.
2356            if !out.questions().is_empty() {
2357                trace!("sending out probing of questions: {:?}", out.questions());
2358                if let Some(sock) = self.ipv4_sock.as_mut() {
2359                    if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
2360                        send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None)
2361                    {
2362                        invalid_intf_addrs.insert(intf_addr);
2363                    }
2364                }
2365                if let Some(sock) = self.ipv6_sock.as_mut() {
2366                    if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
2367                        send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None)
2368                    {
2369                        invalid_intf_addrs.insert(intf_addr);
2370                    }
2371                }
2372            }
2373
2374            // For finished probes, wake up services that are waiting for the probes.
2375            let waiting_services =
2376                handle_expired_probes(expired_probes, &intf.name, dns_registry, &mut self.monitors);
2377
2378            for service_name in waiting_services {
2379                // service names are lowercase
2380                if let Some(info) = self.my_services.get_mut(&service_name.to_lowercase()) {
2381                    if info.get_status(*if_index) == ServiceStatus::Announced {
2382                        debug!("service {} already announced", info.get_fullname());
2383                        continue;
2384                    }
2385
2386                    let announced_v4 = if let Some(sock) = self.ipv4_sock.as_mut() {
2387                        match announce_service_on_intf(
2388                            dns_registry,
2389                            info,
2390                            intf,
2391                            &sock.pktinfo,
2392                            self.port,
2393                        ) {
2394                            Ok(announced) => announced,
2395                            Err(InternalError::IntfAddrInvalid(intf_addr)) => {
2396                                invalid_intf_addrs.insert(intf_addr);
2397                                false
2398                            }
2399                        }
2400                    } else {
2401                        false
2402                    };
2403                    let announced_v6 = if let Some(sock) = self.ipv6_sock.as_mut() {
2404                        match announce_service_on_intf(
2405                            dns_registry,
2406                            info,
2407                            intf,
2408                            &sock.pktinfo,
2409                            self.port,
2410                        ) {
2411                            Ok(announced) => announced,
2412                            Err(InternalError::IntfAddrInvalid(intf_addr)) => {
2413                                invalid_intf_addrs.insert(intf_addr);
2414                                false
2415                            }
2416                        }
2417                    } else {
2418                        false
2419                    };
2420
2421                    if announced_v4 || announced_v6 {
2422                        let next_time = now
2423                            + ANNOUNCE_SECOND_DELAY_MILLIS
2424                            + fastrand::u64(0..ANNOUNCE_SECOND_JITTER_MILLIS);
2425                        let command =
2426                            Command::RegisterResend(info.get_fullname().to_string(), *if_index);
2427                        self.retransmissions.push(ReRun { next_time, command });
2428                        self.timers.push(Reverse(next_time));
2429
2430                        let fullname = dns_registry.resolve_name(&service_name).to_string();
2431
2432                        let hostname = dns_registry.resolve_name(info.get_hostname());
2433
2434                        debug!("wake up: announce service {} on {}", fullname, intf.name);
2435                        notify_monitors(
2436                            &mut self.monitors,
2437                            DaemonEvent::Announce(fullname, format!("{}:{}", hostname, &intf.name)),
2438                        );
2439
2440                        info.set_status(*if_index, ServiceStatus::Announced);
2441                    }
2442                }
2443            }
2444        }
2445
2446        if !invalid_intf_addrs.is_empty() {
2447            let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addrs));
2448        }
2449    }
2450
2451    fn unregister_service(
2452        &self,
2453        info: &ServiceInfo,
2454        intf: &MyIntf,
2455        sock: &PktInfoUdpSocket,
2456    ) -> Vec<u8> {
2457        let is_ipv4 = sock.domain() == Domain::IPV4;
2458
2459        // Goodbye records must carry the names peers actually cached: if
2460        // probing renamed a record on this interface, withdraw the renamed
2461        // name, not the original one from `ServiceInfo`.
2462        let (fullname, hostname) = match self.dns_registry_map.get(&intf.index) {
2463            Some(dns_registry) => (
2464                dns_registry.resolve_name(info.get_fullname()),
2465                dns_registry.resolve_name(info.get_hostname()),
2466            ),
2467            None => (info.get_fullname(), info.get_hostname()),
2468        };
2469
2470        let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE | FLAGS_AA);
2471        out.add_answer_at_time(
2472            DnsPointer::new(
2473                info.get_type(),
2474                RRType::PTR,
2475                CLASS_IN,
2476                0,
2477                fullname.to_string(),
2478            ),
2479            0,
2480        );
2481
2482        if let Some(sub) = info.get_subtype() {
2483            trace!("Adding subdomain {}", sub);
2484            out.add_answer_at_time(
2485                DnsPointer::new(sub, RRType::PTR, CLASS_IN, 0, fullname.to_string()),
2486                0,
2487            );
2488        }
2489
2490        out.add_answer_at_time(
2491            DnsSrv::new(
2492                fullname,
2493                CLASS_IN | CLASS_CACHE_FLUSH,
2494                0,
2495                info.get_priority(),
2496                info.get_weight(),
2497                info.get_port(),
2498                hostname.to_string(),
2499            ),
2500            0,
2501        );
2502        out.add_answer_at_time(
2503            DnsTxt::new(
2504                fullname,
2505                CLASS_IN | CLASS_CACHE_FLUSH,
2506                0,
2507                info.generate_txt(),
2508            ),
2509            0,
2510        );
2511
2512        let if_addrs = if is_ipv4 {
2513            info.get_addrs_on_my_intf_v4(intf)
2514        } else {
2515            info.get_addrs_on_my_intf_v6(intf)
2516        };
2517
2518        if if_addrs.is_empty() {
2519            return vec![];
2520        }
2521
2522        for address in if_addrs {
2523            out.add_answer_at_time(
2524                DnsAddress::new(
2525                    hostname,
2526                    ip_address_rr_type(&address),
2527                    CLASS_IN | CLASS_CACHE_FLUSH,
2528                    0,
2529                    address,
2530                    intf.into(),
2531                ),
2532                0,
2533            );
2534        }
2535
2536        // Only (at most) one packet is expected to be sent out.
2537        let sent_vec = match send_dns_outgoing(&out, intf, sock, self.port, None, None) {
2538            Ok(sent_vec) => sent_vec,
2539            Err(InternalError::IntfAddrInvalid(intf_addr)) => {
2540                let invalid_intf_addrs = HashSet::from([intf_addr]);
2541                let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addrs));
2542                vec![]
2543            }
2544        };
2545        sent_vec.into_iter().next().unwrap_or_default()
2546    }
2547
2548    /// Binds a channel `listener` to querying mDNS hostnames.
2549    ///
2550    /// If there is already a `listener`, it will be updated, i.e. overwritten.
2551    fn add_hostname_resolver(
2552        &mut self,
2553        hostname: String,
2554        listener: Sender<HostnameResolutionEvent>,
2555        timeout: Option<u64>,
2556    ) {
2557        let real_timeout = timeout.map(|t| current_time_millis() + t);
2558        self.hostname_resolvers
2559            .insert(hostname.to_lowercase(), (listener, real_timeout));
2560        if let Some(t) = real_timeout {
2561            self.add_timer(t);
2562        }
2563    }
2564
2565    /// Sends a multicast query for `name` with `qtype`.
2566    fn send_query(&self, name: &str, qtype: RRType) {
2567        self.send_query_vec(&[(name, qtype)]);
2568    }
2569
2570    /// Sends a query on a specific interface without known answers.
2571    ///
2572    /// Used when a new interface is added so the responder won't suppress
2573    /// its response due to known-answer suppression (RFC 6762 Section 7.1).
2574    fn send_query_on_intf(&self, name: &str, qtype: RRType, intf: &MyIntf) {
2575        let mut out = DnsOutgoing::new(FLAGS_QR_QUERY);
2576        out.add_question(name, qtype);
2577
2578        let mut invalid_intf_addrs = HashSet::new();
2579        if let Some(sock) = self.ipv4_sock.as_ref() {
2580            if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
2581                send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None)
2582            {
2583                invalid_intf_addrs.insert(intf_addr);
2584            }
2585        }
2586        if let Some(sock) = self.ipv6_sock.as_ref() {
2587            if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
2588                send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None)
2589            {
2590                invalid_intf_addrs.insert(intf_addr);
2591            }
2592        }
2593        if !invalid_intf_addrs.is_empty() {
2594            let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addrs));
2595        }
2596    }
2597
2598    /// Sends out a list of `questions` (i.e. DNS questions) via multicast.
2599    fn send_query_vec(&self, questions: &[(&str, RRType)]) {
2600        let mut out = DnsOutgoing::new(FLAGS_QR_QUERY);
2601        let now = current_time_millis();
2602
2603        for (name, qtype) in questions {
2604            out.add_question(name, *qtype);
2605
2606            for record in self.cache.get_known_answers(name, *qtype, now) {
2607                /*
2608                RFC 6762 section 7.1: https://datatracker.ietf.org/doc/html/rfc6762#section-7.1
2609                ...
2610                    When a Multicast DNS querier sends a query to which it already knows
2611                    some answers, it populates the Answer Section of the DNS query
2612                    message with those answers.
2613                 */
2614                trace!("add known answer: {:?}", record.record);
2615                let mut new_record = record.record.clone();
2616                new_record.get_record_mut().update_ttl(now);
2617                out.add_answer_box(new_record);
2618            }
2619        }
2620
2621        let mut invalid_intf_addrs = HashSet::new();
2622        for (_, intf) in self.my_intfs.iter() {
2623            if let Some(sock) = self.ipv4_sock.as_ref() {
2624                if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
2625                    send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None)
2626                {
2627                    invalid_intf_addrs.insert(intf_addr);
2628                }
2629            }
2630            if let Some(sock) = self.ipv6_sock.as_ref() {
2631                if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
2632                    send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None)
2633                {
2634                    invalid_intf_addrs.insert(intf_addr);
2635                }
2636            }
2637        }
2638
2639        if !invalid_intf_addrs.is_empty() {
2640            let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addrs));
2641        }
2642    }
2643
2644    /// Reads one UDP datagram from the socket of `intf`.
2645    ///
2646    /// Returns false if failed to receive a packet,
2647    /// otherwise returns true.
2648    fn handle_read(&mut self, event_key: usize) -> bool {
2649        let is_ipv4 = event_key == IPV4_SOCK_EVENT_KEY;
2650        let sock_opt = match event_key {
2651            IPV4_SOCK_EVENT_KEY => &mut self.ipv4_sock,
2652            IPV6_SOCK_EVENT_KEY => &mut self.ipv6_sock,
2653            _ => {
2654                debug!("handle_read: unknown token {}", event_key);
2655                return false;
2656            }
2657        };
2658        let Some(sock) = sock_opt.as_mut() else {
2659            debug!("handle_read: socket not available for token {}", event_key);
2660            return false;
2661        };
2662        // The buffer is one byte bigger than the biggest legal message, so that an
2663        // over-sized datagram can be told apart from a legal one that happens to be
2664        // exactly at the limit.
2665        let max_size = max_pkt_absolute(is_ipv4);
2666        let mut buf = vec![0u8; max_size + 1];
2667
2668        // Read the next mDNS UDP datagram.
2669        let (sz, pktinfo) = match sock.pktinfo.recv(&mut buf) {
2670            Ok(sz) => sz,
2671            Err(e) => {
2672                if e.kind() != std::io::ErrorKind::WouldBlock {
2673                    debug!("listening socket read failed: {}", e);
2674                }
2675                return false;
2676            }
2677        };
2678
2679        // RFC 6762 section 17 caps an mDNS packet at 9000 bytes including the IP and
2680        // UDP headers. A datagram over that arrives truncated, and decoding a
2681        // truncated message does not fail cleanly: names run into whatever bytes
2682        // follow, yielding bogus records or confusing parse errors. Drop it instead.
2683        //
2684        // On Windows, `recv` fails with WSAEMSGSIZE for such a datagram instead of
2685        // truncating it, so it is dropped by the error branch above. Either way it
2686        // is never decoded.
2687        if sz > max_size {
2688            debug!(
2689                "handle_read: dropping over-sized datagram of at least {} bytes (max {})",
2690                sz, max_size
2691            );
2692            return true; // We still read something.
2693        }
2694
2695        // Find the interface that received the packet.
2696        let pkt_if_index = pktinfo.if_index as u32;
2697        let Some(my_intf) = self.my_intfs.get(&pkt_if_index) else {
2698            debug!(
2699                "handle_read: no interface found for pktinfo if_index: {}",
2700                pktinfo.if_index
2701            );
2702            return true; // We still return true to indicate that we read something.
2703        };
2704
2705        // Drop packets for an IP version that has been disabled on this interface.
2706        // This is needed because some times the socket layer may still receive packets
2707        // for an IP version even after we left the multicast group for that IP version.
2708        // We want to drop such packets to avoid unnecessary processing.
2709        let is_ipv4 = event_key == IPV4_SOCK_EVENT_KEY;
2710        if (is_ipv4 && my_intf.next_ifaddr_v4().is_none())
2711            || (!is_ipv4 && my_intf.next_ifaddr_v6().is_none())
2712        {
2713            debug!(
2714                "handle_read: dropping {} packet on intf {} (disabled)",
2715                if is_ipv4 { "IPv4" } else { "IPv6" },
2716                my_intf.name
2717            );
2718            return true;
2719        }
2720
2721        buf.truncate(sz); // reduce potential processing errors
2722
2723        match DnsIncoming::new(buf, my_intf.into()) {
2724            Ok(msg) => {
2725                if msg.is_query() {
2726                    let querier_addr = pktinfo.addr_src;
2727                    self.handle_query(msg, pkt_if_index, querier_addr);
2728                } else if msg.is_response() {
2729                    self.handle_response(msg, pkt_if_index);
2730                } else {
2731                    debug!("Invalid message: not query and not response");
2732                }
2733            }
2734            Err(e) => debug!("Invalid incoming DNS message: {}", e),
2735        }
2736
2737        true
2738    }
2739
2740    /// Returns true, if sent query. Returns false if SRV already exists.
2741    fn query_unresolved(&mut self, instance: &str) -> bool {
2742        if !valid_instance_name(instance) {
2743            trace!("instance name {} not valid", instance);
2744            return false;
2745        }
2746
2747        if let Some(records) = self.cache.get_srv(instance) {
2748            for record in records {
2749                if let Some(srv) = record.record.any().downcast_ref::<DnsSrv>() {
2750                    if self.cache.get_addr(srv.host()).is_none() {
2751                        self.send_query_vec(&[(srv.host(), RRType::A), (srv.host(), RRType::AAAA)]);
2752                        return true;
2753                    }
2754                }
2755            }
2756        } else {
2757            self.send_query(instance, RRType::ANY);
2758            return true;
2759        }
2760
2761        false
2762    }
2763
2764    /// Checks if `ty_domain` has records in the cache. If yes, sends the
2765    /// cached records via `sender`.
2766    fn query_cache_for_service(
2767        &mut self,
2768        ty_domain: &str,
2769        sender: &Sender<ServiceEvent>,
2770        now: u64,
2771    ) {
2772        let mut resolved: HashSet<String> = HashSet::new();
2773        let mut unresolved: HashSet<String> = HashSet::new();
2774
2775        if let Some(records) = self.cache.get_ptr(ty_domain) {
2776            for record in records.iter().filter(|r| !r.record.expires_soon(now)) {
2777                if let Some(ptr) = record.record.any().downcast_ref::<DnsPointer>() {
2778                    let mut new_event = None;
2779                    match self.resolve_service_from_cache(ty_domain, ptr.alias()) {
2780                        Ok(resolved_service) => {
2781                            if resolved_service.is_valid() {
2782                                debug!("Resolved service from cache: {}", ptr.alias());
2783                                new_event =
2784                                    Some(ServiceEvent::ServiceResolved(Box::new(resolved_service)));
2785                            } else {
2786                                debug!("Resolved service is not valid: {}", ptr.alias());
2787                            }
2788                        }
2789                        Err(err) => {
2790                            debug!("Error while resolving service from cache: {}", err);
2791                            continue;
2792                        }
2793                    }
2794
2795                    match sender.send(ServiceEvent::ServiceFound(
2796                        ty_domain.to_string(),
2797                        ptr.alias().to_string(),
2798                    )) {
2799                        Ok(()) => debug!("sent service found {}", ptr.alias()),
2800                        Err(e) => {
2801                            debug!("failed to send service found: {}", e);
2802                            continue;
2803                        }
2804                    }
2805
2806                    if let Some(event) = new_event {
2807                        resolved.insert(ptr.alias().to_string());
2808                        match sender.send(event) {
2809                            Ok(()) => debug!("sent service resolved: {}", ptr.alias()),
2810                            Err(e) => debug!("failed to send service resolved: {}", e),
2811                        }
2812                    } else {
2813                        unresolved.insert(ptr.alias().to_string());
2814                    }
2815                }
2816            }
2817        }
2818
2819        for instance in resolved.drain() {
2820            self.pending_resolves.remove(&instance);
2821            self.resolved.insert(instance);
2822        }
2823
2824        for instance in unresolved.drain() {
2825            self.add_pending_resolve(instance);
2826        }
2827    }
2828
2829    /// Checks if `hostname` has records in the cache. If yes, sends the
2830    /// cached records via `sender`.
2831    fn query_cache_for_hostname(
2832        &mut self,
2833        hostname: &str,
2834        sender: Sender<HostnameResolutionEvent>,
2835    ) {
2836        let addresses_map = self.cache.get_addresses_for_host(hostname);
2837        for (name, addresses) in addresses_map {
2838            match sender.send(HostnameResolutionEvent::AddressesFound(name, addresses)) {
2839                Ok(()) => trace!("sent hostname addresses found"),
2840                Err(e) => debug!("failed to send hostname addresses found: {}", e),
2841            }
2842        }
2843    }
2844
2845    fn add_pending_resolve(&mut self, instance: String) {
2846        if !self.pending_resolves.contains(&instance) {
2847            let next_time = current_time_millis() + RESOLVE_WAIT_IN_MILLIS;
2848            self.add_retransmission(next_time, Command::Resolve(instance.clone(), 1));
2849            self.pending_resolves.insert(instance);
2850        }
2851    }
2852
2853    /// Creates a `ResolvedService` from the cache.
2854    fn resolve_service_from_cache(
2855        &self,
2856        ty_domain: &str,
2857        fullname: &str,
2858    ) -> Result<ResolvedService> {
2859        let now = current_time_millis();
2860        let mut resolved_service = ResolvedService {
2861            ty_domain: ty_domain.to_string(),
2862            sub_ty_domain: None,
2863            fullname: fullname.to_string(),
2864            host: String::new(),
2865            port: 0,
2866            addresses: HashSet::new(),
2867            txt_properties: TxtProperties::new(),
2868        };
2869
2870        // Be sure setting `subtype` if available even when querying for the parent domain.
2871        if let Some(subtype) = self.cache.get_subtype(fullname) {
2872            trace!(
2873                "ty_domain: {} found subtype {} for instance: {}",
2874                ty_domain,
2875                subtype,
2876                fullname
2877            );
2878            if resolved_service.sub_ty_domain.is_none() {
2879                resolved_service.sub_ty_domain = Some(subtype.to_string());
2880            }
2881        }
2882
2883        // resolve SRV record
2884        if let Some(records) = self.cache.get_srv(fullname) {
2885            if let Some(answer) = records.iter().find(|r| !r.record.expires_soon(now)) {
2886                if let Some(dns_srv) = answer.record.any().downcast_ref::<DnsSrv>() {
2887                    resolved_service.host = dns_srv.host().to_string();
2888                    resolved_service.port = dns_srv.port();
2889                }
2890            }
2891        }
2892
2893        // resolve TXT record
2894        if let Some(records) = self.cache.get_txt(fullname) {
2895            if let Some(record) = records.iter().find(|r| !r.record.expires_soon(now)) {
2896                if let Some(dns_txt) = record.record.any().downcast_ref::<DnsTxt>() {
2897                    resolved_service.txt_properties = dns_txt.text().into();
2898                }
2899            }
2900        }
2901
2902        // resolve A and AAAA records
2903        if let Some(records) = self.cache.get_addr(&resolved_service.host) {
2904            for answer in records.iter() {
2905                if let Some(dns_a) = answer.record.any().downcast_ref::<DnsAddress>() {
2906                    if dns_a.expires_soon(now) {
2907                        trace!(
2908                            "Addr expired or expires soon: {}",
2909                            dns_a.address().to_ip_addr()
2910                        );
2911                    } else {
2912                        let scoped = dns_a.address();
2913                        if let ScopedIp::V4(v4) = &scoped {
2914                            // Merge interface_ids if this V4 addr already exists.
2915                            // Linear scan by IP since Eq/Hash include interface_ids.
2916                            let existing = resolved_service
2917                                .addresses
2918                                .iter()
2919                                .find(|a| a.to_ip_addr() == IpAddr::V4(*v4.addr()))
2920                                .cloned();
2921                            if let Some(mut existing) = existing {
2922                                resolved_service.addresses.remove(&existing);
2923                                if let ScopedIp::V4(existing_v4) = &mut existing {
2924                                    for id in v4.interface_ids() {
2925                                        existing_v4.add_interface_id(id.clone());
2926                                    }
2927                                }
2928                                resolved_service.addresses.insert(existing);
2929                            } else {
2930                                resolved_service.addresses.insert(scoped);
2931                            }
2932                        } else {
2933                            resolved_service.addresses.insert(scoped);
2934                        }
2935                    }
2936                }
2937            }
2938        }
2939
2940        Ok(resolved_service)
2941    }
2942
2943    fn handle_poller_events(&mut self, events: &mio::Events) {
2944        for ev in events.iter() {
2945            trace!("event received with key {:?}", ev.token());
2946            if ev.token().0 == SIGNAL_SOCK_EVENT_KEY {
2947                // Drain signals as we will drain commands as well.
2948                self.signal_sock_drain();
2949
2950                if let Err(e) = self.poller.registry().reregister(
2951                    &mut self.signal_sock,
2952                    ev.token(),
2953                    mio::Interest::READABLE,
2954                ) {
2955                    debug!("failed to modify poller for signal socket: {}", e);
2956                }
2957                continue; // Next event.
2958            }
2959
2960            // Read until no more packets available.
2961            while self.handle_read(ev.token().0) {}
2962
2963            // we continue to monitor this socket.
2964            if ev.token().0 == IPV4_SOCK_EVENT_KEY {
2965                // Re-register the IPv4 socket for reading.
2966                if let Some(sock) = self.ipv4_sock.as_mut() {
2967                    if let Err(e) =
2968                        self.poller
2969                            .registry()
2970                            .reregister(sock, ev.token(), mio::Interest::READABLE)
2971                    {
2972                        debug!("modify poller for IPv4 socket: {}", e);
2973                    }
2974                }
2975            } else if ev.token().0 == IPV6_SOCK_EVENT_KEY {
2976                // Re-register the IPv6 socket for reading.
2977                if let Some(sock) = self.ipv6_sock.as_mut() {
2978                    if let Err(e) =
2979                        self.poller
2980                            .registry()
2981                            .reregister(sock, ev.token(), mio::Interest::READABLE)
2982                    {
2983                        debug!("modify poller for IPv6 socket: {}", e);
2984                    }
2985                }
2986            }
2987        }
2988    }
2989
2990    /// Deal with incoming response packets.  All answers
2991    /// are held in the cache, and listeners are notified.
2992    fn handle_response(&mut self, mut msg: DnsIncoming, if_index: u32) {
2993        let now = current_time_millis();
2994
2995        // remove records that are expired.
2996        let mut record_predicate = |record: &DnsRecordBox| {
2997            if !record.get_record().is_expired(now) {
2998                return true;
2999            }
3000
3001            debug!("record is expired, removing it from cache.");
3002            if self.cache.remove(record) {
3003                // for PTR records, send event to listeners
3004                if let Some(dns_ptr) = record.any().downcast_ref::<DnsPointer>() {
3005                    call_service_listener(
3006                        &self.service_queriers,
3007                        dns_ptr.get_name(),
3008                        ServiceEvent::ServiceRemoved(
3009                            dns_ptr.get_name().to_string(),
3010                            dns_ptr.alias().to_string(),
3011                        ),
3012                    );
3013                }
3014            }
3015            false
3016        };
3017        msg.answers_mut().retain(&mut record_predicate);
3018        msg.authorities_mut().retain(&mut record_predicate);
3019        msg.additionals_mut().retain(&mut record_predicate);
3020
3021        // check possible conflicts and handle them.
3022        self.conflict_handler(&msg, if_index);
3023
3024        // check if the message is for us.
3025        let mut is_for_us = true; // assume it is for us.
3026
3027        // If there are any PTR records in the answers, there should be
3028        // at least one PTR for us. Otherwise, the message is not for us.
3029        // If there are no PTR records at all, assume this message is for us.
3030        for answer in msg.answers() {
3031            if answer.get_type() == RRType::PTR {
3032                if self.service_queriers.contains_key(answer.get_name()) {
3033                    is_for_us = true;
3034                    break; // OK to break: at least one PTR for us.
3035                } else {
3036                    is_for_us = false;
3037                }
3038            } else if answer.get_type() == RRType::A || answer.get_type() == RRType::AAAA {
3039                // If there is a hostname querier for this address, then it is for us.
3040                let answer_lowercase = answer.get_name().to_lowercase();
3041                if self.hostname_resolvers.contains_key(&answer_lowercase) {
3042                    is_for_us = true;
3043                    break; // OK to break: at least one hostname for us.
3044                }
3045            }
3046        }
3047
3048        // if we explicitily want to accept unsolicited responses, we should consider all messages as for us.
3049        if self.accept_unsolicited {
3050            is_for_us = true;
3051        }
3052
3053        /// Represents a DNS record change that involves one service instance.
3054        struct InstanceChange {
3055            ty: RRType,   // The type of DNS record for the instance.
3056            name: String, // The name of the record.
3057        }
3058
3059        // Go through all answers to get the new and updated records.
3060        // For new PTR records, send out ServiceFound immediately. For others,
3061        // collect them into `changes`.
3062        //
3063        // Note: we don't try to identify the update instances based on
3064        // each record immediately as the answers are likely related to each
3065        // other.
3066        let mut changes = Vec::new();
3067        let mut timers = Vec::new();
3068        let Some(my_intf) = self.my_intfs.get(&if_index) else {
3069            return;
3070        };
3071        for record in msg.all_records() {
3072            match self
3073                .cache
3074                .add_or_update(my_intf, record, &mut timers, is_for_us)
3075            {
3076                Some((dns_record, true)) => {
3077                    timers.push(dns_record.record.get_record().get_expire_time());
3078                    timers.push(dns_record.record.get_record().get_refresh_time());
3079
3080                    let ty = dns_record.record.get_type();
3081                    let name = dns_record.record.get_name();
3082
3083                    // Positive dump: a new record was accepted into the cache.
3084                    // Counterpart to the "skipping record" debug line in the parser.
3085                    debug!("cache: new record: {:?}", &dns_record.record);
3086
3087                    // Only process PTR that does not expire soon (i.e. TTL > 1).
3088                    if ty == RRType::PTR && dns_record.record.get_record().get_ttl() > 1 {
3089                        if self.service_queriers.contains_key(name) {
3090                            timers.push(dns_record.record.get_record().get_refresh_time());
3091                        }
3092
3093                        // send ServiceFound
3094                        if let Some(dns_ptr) = dns_record.record.any().downcast_ref::<DnsPointer>()
3095                        {
3096                            debug!("calling listener with service found: {name}");
3097                            call_service_listener(
3098                                &self.service_queriers,
3099                                name,
3100                                ServiceEvent::ServiceFound(
3101                                    name.to_string(),
3102                                    dns_ptr.alias().to_string(),
3103                                ),
3104                            );
3105                            changes.push(InstanceChange {
3106                                ty,
3107                                name: dns_ptr.alias().to_string(),
3108                            });
3109                        }
3110                    } else {
3111                        changes.push(InstanceChange {
3112                            ty,
3113                            name: name.to_string(),
3114                        });
3115                    }
3116                }
3117                Some((dns_record, false)) => {
3118                    timers.push(dns_record.record.get_record().get_expire_time());
3119                    timers.push(dns_record.record.get_record().get_refresh_time());
3120                }
3121                _ => {}
3122            }
3123        }
3124
3125        // Add timers for the new records.
3126        for t in timers {
3127            self.add_timer(t);
3128        }
3129
3130        // Go through remaining changes to see if any hostname resolutions were found or updated.
3131        for change in changes
3132            .iter()
3133            .filter(|change| change.ty == RRType::A || change.ty == RRType::AAAA)
3134        {
3135            let addr_map = self.cache.get_addresses_for_host(&change.name);
3136            for (name, addresses) in addr_map {
3137                call_hostname_resolution_listener(
3138                    &self.hostname_resolvers,
3139                    &change.name,
3140                    HostnameResolutionEvent::AddressesFound(name, addresses),
3141                )
3142            }
3143        }
3144
3145        // Identify the instances that need to be "resolved".
3146        let mut updated_instances = HashSet::new();
3147        for update in changes {
3148            match update.ty {
3149                RRType::PTR | RRType::SRV | RRType::TXT => {
3150                    updated_instances.insert(update.name);
3151                }
3152                RRType::A | RRType::AAAA => {
3153                    let instances = self.cache.get_instances_on_host(&update.name);
3154                    updated_instances.extend(instances);
3155                }
3156                _ => {}
3157            }
3158        }
3159
3160        self.resolve_updated_instances(&updated_instances);
3161    }
3162
3163    fn conflict_handler(&mut self, msg: &DnsIncoming, if_index: u32) {
3164        let Some(my_intf) = self.my_intfs.get(&if_index) else {
3165            debug!("handle_response: no intf found for index {if_index}");
3166            return;
3167        };
3168
3169        let Some(dns_registry) = self.dns_registry_map.get_mut(&if_index) else {
3170            return;
3171        };
3172
3173        for answer in msg.answers().iter() {
3174            let mut new_records = Vec::new();
3175
3176            let name = answer.get_name();
3177            let Some(probe) = dns_registry.probing.get_mut(name) else {
3178                continue;
3179            };
3180
3181            // check against possible multicast forwarding
3182            if answer.get_type() == RRType::A || answer.get_type() == RRType::AAAA {
3183                if let Some(answer_addr) = answer.any().downcast_ref::<DnsAddress>() {
3184                    if answer_addr.interface_id.index != if_index {
3185                        debug!(
3186                            "conflict handler: answer addr {:?} not in the subnet of intf {}",
3187                            answer_addr, my_intf.name
3188                        );
3189                        continue;
3190                    }
3191                }
3192
3193                // double check if any other address record matches rrdata,
3194                // as there could be multiple addresses for the same name.
3195                let any_match = probe.records.iter().any(|r| {
3196                    r.get_type() == answer.get_type()
3197                        && r.get_class() == answer.get_class()
3198                        && r.rrdata_match(answer.as_ref())
3199                });
3200                if any_match {
3201                    continue; // no conflict for this answer.
3202                }
3203            }
3204
3205            probe.records.retain(|record| {
3206                if record.get_type() == answer.get_type()
3207                    && record.get_class() == answer.get_class()
3208                    && !record.rrdata_match(answer.as_ref())
3209                {
3210                    debug!(
3211                        "found conflict name: '{name}' record: {}: {} PEER: {}",
3212                        record.get_type(),
3213                        record.rdata_print(),
3214                        answer.rdata_print()
3215                    );
3216
3217                    // create a new name for this record
3218                    // then remove the old record in probing.
3219                    let mut new_record = record.clone();
3220                    let new_name = match record.get_type() {
3221                        RRType::A => hostname_change(name),
3222                        RRType::AAAA => hostname_change(name),
3223                        _ => name_change(name),
3224                    };
3225                    new_record.get_record_mut().set_new_name(new_name);
3226                    new_records.push(new_record);
3227                    return false; // old record is dropped from the probe.
3228                }
3229
3230                true
3231            });
3232
3233            // ?????
3234            // if probe.records.is_empty() {
3235            //     dns_registry.probing.remove(name);
3236            // }
3237
3238            // Probing again with the new names.
3239            let create_time = current_time_millis() + fastrand::u64(0..250);
3240
3241            let waiting_services = probe.waiting_services.clone();
3242
3243            for record in new_records {
3244                if dns_registry.update_hostname(name, record.get_name(), create_time) {
3245                    self.timers.push(Reverse(create_time));
3246                }
3247
3248                // remember the name changes (note: `name` might not be the original, it could be already changed once.)
3249                dns_registry.name_changes.insert(
3250                    record.get_record().get_original_name().to_string(),
3251                    record.get_name().to_string(),
3252                );
3253
3254                let new_probe = match dns_registry.probing.get_mut(record.get_name()) {
3255                    Some(p) => p,
3256                    None => {
3257                        let new_probe = dns_registry
3258                            .probing
3259                            .entry(record.get_name().to_string())
3260                            .or_insert_with(|| {
3261                                debug!("conflict handler: new probe of {}", record.get_name());
3262                                Probe::new(create_time)
3263                            });
3264                        self.timers.push(Reverse(new_probe.next_send));
3265                        new_probe
3266                    }
3267                };
3268
3269                debug!(
3270                    "insert record with new name '{}' {} into probe",
3271                    record.get_name(),
3272                    record.get_type()
3273                );
3274                new_probe.insert_record(record);
3275
3276                new_probe.waiting_services.extend(waiting_services.clone());
3277            }
3278        }
3279    }
3280
3281    /// Resolve the updated (including new) instances.
3282    ///
3283    /// Note: it is possible that more than 1 PTR pointing to the same
3284    /// instance. For example, a regular service type PTR and a sub-type
3285    /// service type PTR can both point to the same service instance.
3286    /// This loop automatically handles the sub-type PTRs.
3287    fn resolve_updated_instances(&mut self, updated_instances: &HashSet<String>) {
3288        if updated_instances.is_empty() {
3289            return;
3290        }
3291
3292        let mut resolved: HashSet<String> = HashSet::new();
3293        let mut unresolved: HashSet<String> = HashSet::new();
3294        let mut removed_instances = HashMap::new();
3295
3296        let now = current_time_millis();
3297
3298        for (ty_domain, records) in self.cache.all_ptr().iter() {
3299            if !self.service_queriers.contains_key(ty_domain) {
3300                // No need to resolve if not in our queries.
3301                continue;
3302            }
3303
3304            for ptr in records.iter().filter(|r| !r.record.expires_soon(now)) {
3305                let Some(dns_ptr) = ptr.record.any().downcast_ref::<DnsPointer>() else {
3306                    continue;
3307                };
3308
3309                let instance = dns_ptr.alias();
3310                if !updated_instances.contains(instance) {
3311                    continue;
3312                }
3313
3314                let Ok(resolved_service) = self.resolve_service_from_cache(ty_domain, instance)
3315                else {
3316                    continue;
3317                };
3318
3319                debug!("resolve_updated_instances: from cache: {instance}");
3320                if resolved_service.is_valid() {
3321                    debug!(
3322                        "resolved '{}' -> host '{}' port {} addrs {:?}",
3323                        instance,
3324                        resolved_service.host,
3325                        resolved_service.port,
3326                        resolved_service.addresses,
3327                    );
3328                    resolved.insert(instance.to_string());
3329                    let event = ServiceEvent::ServiceResolved(Box::new(resolved_service));
3330                    call_service_listener(&self.service_queriers, ty_domain, event);
3331                } else {
3332                    debug!("Resolved service is not valid: {instance}");
3333                    if self.resolved.remove(dns_ptr.alias()) {
3334                        removed_instances
3335                            .entry(ty_domain.to_string())
3336                            .or_insert_with(HashSet::new)
3337                            .insert(instance.to_string());
3338                    }
3339                    unresolved.insert(instance.to_string());
3340                }
3341            }
3342        }
3343
3344        for instance in resolved.drain() {
3345            self.pending_resolves.remove(&instance);
3346            self.resolved.insert(instance);
3347        }
3348
3349        for instance in unresolved.drain() {
3350            self.add_pending_resolve(instance);
3351        }
3352
3353        if !removed_instances.is_empty() {
3354            debug!(
3355                "resolve_updated_instances: removed {}",
3356                &removed_instances.len()
3357            );
3358            self.notify_service_removal(removed_instances);
3359        }
3360    }
3361
3362    /// Handle incoming query packets, figure out whether and what to respond.
3363    fn handle_query(&mut self, msg: DnsIncoming, if_index: u32, querier_addr: SocketAddr) {
3364        let querier_ip = querier_addr.ip();
3365        let is_ipv4 = querier_ip.is_ipv4();
3366        let sock_opt = if is_ipv4 {
3367            &self.ipv4_sock
3368        } else {
3369            &self.ipv6_sock
3370        };
3371        let Some(sock) = sock_opt.as_ref() else {
3372            debug!("handle_query: socket not available for intf {}", if_index);
3373            return;
3374        };
3375
3376        let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE | FLAGS_AA);
3377        let mut delayed = false;
3378
3379        // Special meta-query "_services._dns-sd._udp.<Domain>".
3380        // See https://datatracker.ietf.org/doc/html/rfc6763#section-9
3381        const META_QUERY: &str = "_services._dns-sd._udp.local.";
3382
3383        let Some(dns_registry) = self.dns_registry_map.get_mut(&if_index) else {
3384            debug!("missing dns registry for intf {}", if_index);
3385            return;
3386        };
3387
3388        let Some(intf) = self.my_intfs.get(&if_index) else {
3389            debug!("handle_query: no intf found for index {if_index}");
3390            return;
3391        };
3392
3393        for question in msg.questions().iter() {
3394            let qtype = question.entry_type();
3395            let q_name = question.entry_name();
3396
3397            if qtype == RRType::PTR {
3398                // PTR answers are shared records: defer the response unless this
3399                // is a legacy-unicast (source port != 5353) or probe-defense
3400                // (records in the Authority Section) query.
3401                if querier_addr.port() == MDNS_PORT && msg.num_authorities() == 0 {
3402                    delayed = true;
3403                }
3404                for service in self.my_services.values() {
3405                    if service.get_status(if_index) != ServiceStatus::Announced {
3406                        continue;
3407                    }
3408
3409                    if service.matches_type_or_subtype(q_name) {
3410                        out.add_answer_with_additionals(&msg, service, intf, dns_registry, is_ipv4);
3411                    } else if q_name == META_QUERY {
3412                        let ttl = service.get_other_ttl();
3413                        let alias = service.get_type().to_string();
3414                        let ptr = DnsPointer::new(q_name, RRType::PTR, CLASS_IN, ttl, alias);
3415                        if !out.add_answer(&msg, ptr) {
3416                            trace!("answer was not added for meta-query {:?}", &question);
3417                        }
3418                    }
3419                }
3420            } else {
3421                // Simultaneous Probe Tiebreaking (RFC 6762 section 8.2)
3422                if qtype == RRType::ANY && msg.num_authorities() > 0 {
3423                    if let Some(probe) = dns_registry.probing.get_mut(q_name) {
3424                        probe.tiebreaking(&msg, q_name);
3425                    }
3426                }
3427
3428                if qtype == RRType::A || qtype == RRType::AAAA || qtype == RRType::ANY {
3429                    for service in self.my_services.values() {
3430                        if service.get_status(if_index) != ServiceStatus::Announced {
3431                            continue;
3432                        }
3433
3434                        let service_hostname = dns_registry.resolve_name(service.get_hostname());
3435
3436                        if service_hostname.to_lowercase() == question.entry_name().to_lowercase() {
3437                            // Pick addresses based on the question type, not the
3438                            // socket family. RFC 6762 doesn't require A queries
3439                            // to come over IPv4 transport — Android's getaddrinfo
3440                            // routinely sends both A and AAAA queries over its
3441                            // preferred IPv6 mDNS socket and expects A records
3442                            // to be answered with v4 addresses.
3443                            let mut intf_addrs: Vec<IpAddr> = Vec::new();
3444                            if qtype == RRType::A || qtype == RRType::ANY {
3445                                intf_addrs.extend(service.get_addrs_on_my_intf_v4(intf));
3446                            }
3447                            if qtype == RRType::AAAA || qtype == RRType::ANY {
3448                                intf_addrs.extend(service.get_addrs_on_my_intf_v6(intf));
3449                            }
3450                            if intf_addrs.is_empty()
3451                                && (qtype == RRType::A || qtype == RRType::AAAA)
3452                            {
3453                                let t = match qtype {
3454                                    RRType::A => "TYPE_A",
3455                                    RRType::AAAA => "TYPE_AAAA",
3456                                    _ => "invalid_type",
3457                                };
3458                                trace!(
3459                                    "Cannot find valid addrs for {} response on intf {:?}",
3460                                    t,
3461                                    &intf
3462                                );
3463                                continue;
3464                            }
3465                            for address in intf_addrs {
3466                                out.add_answer(
3467                                    &msg,
3468                                    DnsAddress::new(
3469                                        service_hostname,
3470                                        ip_address_rr_type(&address),
3471                                        CLASS_IN | CLASS_CACHE_FLUSH,
3472                                        service.get_host_ttl(),
3473                                        address,
3474                                        intf.into(),
3475                                    ),
3476                                );
3477                            }
3478                        }
3479                    }
3480                }
3481
3482                let query_name = q_name.to_lowercase();
3483                let service_opt = self
3484                    .my_services
3485                    .iter()
3486                    .find(|(k, _v)| dns_registry.resolve_name(k.as_str()) == query_name)
3487                    .map(|(_, v)| v);
3488
3489                let Some(service) = service_opt else {
3490                    continue;
3491                };
3492
3493                if service.get_status(if_index) != ServiceStatus::Announced {
3494                    continue;
3495                }
3496
3497                let intf_addrs = if is_ipv4 {
3498                    service.get_addrs_on_my_intf_v4(intf)
3499                } else {
3500                    service.get_addrs_on_my_intf_v6(intf)
3501                };
3502                if intf_addrs.is_empty() {
3503                    debug!(
3504                        "Cannot find valid addrs for TYPE_SRV response on intf {:?}",
3505                        &intf
3506                    );
3507                    continue;
3508                }
3509
3510                add_answer_of_service(
3511                    &mut out,
3512                    &msg,
3513                    question.entry_name(),
3514                    service,
3515                    qtype,
3516                    intf_addrs,
3517                );
3518            }
3519        }
3520
3521        // Defer PTR responses (RFC 6762 §6).
3522        if delayed && out.answers_count() > 0 {
3523            out.set_id(msg.id());
3524            self.increase_counter(Counter::KnownAnswerSuppression, out.known_answer_count());
3525            let delay =
3526                fastrand::u64(SHARED_RESPONSE_DELAY_MIN_MILLIS..SHARED_RESPONSE_DELAY_MAX_MILLIS);
3527            let next_time = current_time_millis() + delay;
3528            self.delayed_responses.push(DelayedResponse {
3529                next_time,
3530                out,
3531                if_index,
3532                is_ipv4,
3533            });
3534            self.add_timer(next_time);
3535            return;
3536        }
3537
3538        if out.answers_count() > 0 {
3539            out.set_id(msg.id());
3540
3541            // Pick a source IfAddr on `intf` whose subnet contains the querier's IP.
3542            // It's OK if it's None, `send_dns_outgoing` will then pick one address.
3543            let matched_source = intf
3544                .addrs
3545                .iter()
3546                .find(|if_addr| valid_ip_on_intf(&querier_ip, if_addr));
3547
3548            // RFC 6762 §6.7 (Legacy Unicast Responses): if the querier's source
3549            // port is not 5353, it's a one-shot legacy querier (e.g. Android's
3550            // getaddrinfo, iOS resolver fallback). The response MUST be unicast
3551            // back to the querier's source IP and port; multicast replies will
3552            // never reach the querier's ephemeral socket. Legacy unicast
3553            // responses must also echo the question section, clear the
3554            // cache-flush bit (legacy resolvers don't understand it), and cap
3555            // record TTLs to 10 seconds (see update_records_for_legacy_unicast).
3556            let unicast_dest = if querier_addr.port() != MDNS_PORT {
3557                Some(querier_addr)
3558            } else {
3559                None
3560            };
3561
3562            if unicast_dest.is_some() {
3563                for q in msg.questions() {
3564                    out.add_question(q.entry_name(), q.entry_type());
3565                }
3566                out.update_records_for_legacy_unicast();
3567                out.set_multicast(false);
3568            } else if msg.num_authorities() == 0 {
3569                // RFC 6762 §6: a record MUST NOT be multicast on an interface
3570                // more than once per second. Two exceptions skip the limit here:
3571                //   - Unicast responses (handled above).
3572                //   - Answering probe queries: a probe carries the proposed
3573                //     records in its Authority Section, and we MUST defend our
3574                //     records immediately so the prober detects the conflict.
3575                dns_registry.apply_multicast_rate_limit(&mut out, current_time_millis(), is_ipv4);
3576            }
3577
3578            if out.answers_count() > 0 {
3579                debug!("sending response on intf {}", &intf.name);
3580                if let Err(InternalError::IntfAddrInvalid(intf_addr)) = send_dns_outgoing(
3581                    &out,
3582                    intf,
3583                    &sock.pktinfo,
3584                    self.port,
3585                    matched_source,
3586                    unicast_dest,
3587                ) {
3588                    let invalid_intf_addr = HashSet::from([intf_addr]);
3589                    let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addr));
3590                }
3591
3592                let if_name = intf.name.clone();
3593
3594                self.increase_counter(Counter::Respond, 1);
3595                self.notify_monitors(DaemonEvent::Respond(if_name));
3596            }
3597        }
3598
3599        self.increase_counter(Counter::KnownAnswerSuppression, out.known_answer_count());
3600    }
3601
3602    /// Multicasts a PTR query response that was deferred per RFC 6762 §6.
3603    ///
3604    /// Re-resolves the socket and interface from `if_index`, so it is safe to
3605    /// call from the timer loop after the borrows taken while building the
3606    /// response are gone. The original querier is no longer known, so the
3607    /// response is always a plain multicast (no unicast destination, no
3608    /// source-address preference); the §6 once-per-second multicast rate limit
3609    /// still applies.
3610    fn send_delayed_response(&mut self, resp: DelayedResponse) {
3611        let DelayedResponse {
3612            mut out,
3613            if_index,
3614            is_ipv4,
3615            ..
3616        } = resp;
3617
3618        let sock_opt = if is_ipv4 {
3619            &self.ipv4_sock
3620        } else {
3621            &self.ipv6_sock
3622        };
3623        let Some(sock) = sock_opt.as_ref() else {
3624            debug!("send_delayed_response: socket not available for intf {if_index}");
3625            return;
3626        };
3627
3628        if let Some(dns_registry) = self.dns_registry_map.get_mut(&if_index) {
3629            dns_registry.apply_multicast_rate_limit(&mut out, current_time_millis(), is_ipv4);
3630        }
3631        if out.answers_count() == 0 {
3632            return;
3633        }
3634
3635        let Some(intf) = self.my_intfs.get(&if_index) else {
3636            debug!("send_delayed_response: no intf found for index {if_index}");
3637            return;
3638        };
3639
3640        let if_name = intf.name.clone();
3641        debug!("sending delayed response on intf {}", &if_name);
3642        let send_result = send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None);
3643
3644        if let Err(InternalError::IntfAddrInvalid(intf_addr)) = send_result {
3645            let invalid_intf_addr = HashSet::from([intf_addr]);
3646            let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addr));
3647        }
3648
3649        self.increase_counter(Counter::Respond, 1);
3650        self.notify_monitors(DaemonEvent::Respond(if_name));
3651    }
3652
3653    /// Increases the value of `counter` by `count`.
3654    fn increase_counter(&mut self, counter: Counter, count: i64) {
3655        let key = counter.to_string();
3656        match self.counters.get_mut(&key) {
3657            Some(v) => *v += count,
3658            None => {
3659                self.counters.insert(key, count);
3660            }
3661        }
3662    }
3663
3664    /// Sets the value of `counter` to `count`.
3665    fn set_counter(&mut self, counter: Counter, count: i64) {
3666        let key = counter.to_string();
3667        self.counters.insert(key, count);
3668    }
3669
3670    fn signal_sock_drain(&self) {
3671        let mut signal_buf = [0; 1024];
3672
3673        // This recv is non-blocking as the socket is non-blocking.
3674        while let Ok(sz) = self.signal_sock.recv(&mut signal_buf) {
3675            trace!(
3676                "signal socket recvd: {}",
3677                String::from_utf8_lossy(&signal_buf[0..sz])
3678            );
3679        }
3680    }
3681
3682    fn add_retransmission(&mut self, next_time: u64, command: Command) {
3683        self.retransmissions.push(ReRun { next_time, command });
3684        self.add_timer(next_time);
3685    }
3686
3687    /// Sends service removal event to listeners for expired service records.
3688    /// `expired`: map of service type domain to set of instance names.
3689    fn notify_service_removal(&self, expired: HashMap<String, HashSet<String>>) {
3690        for (ty_domain, sender) in self.service_queriers.iter() {
3691            if let Some(instances) = expired.get(ty_domain) {
3692                for instance_name in instances {
3693                    let event = ServiceEvent::ServiceRemoved(
3694                        ty_domain.to_string(),
3695                        instance_name.to_string(),
3696                    );
3697                    match sender.send(event) {
3698                        Ok(()) => debug!("notify_service_removal: sent ServiceRemoved to listener of {ty_domain}: {instance_name}"),
3699                        Err(e) => debug!("Failed to send event: {}", e),
3700                    }
3701                }
3702            }
3703        }
3704    }
3705
3706    /// The entry point that executes all commands received by the daemon.
3707    ///
3708    /// `repeating`: whether this is a retransmission.
3709    fn exec_command(&mut self, command: Command, repeating: bool) {
3710        trace!("exec_command: {:?} repeating: {}", &command, repeating);
3711        match command {
3712            Command::Browse(ty, next_delay, cache_only, listener) => {
3713                self.exec_command_browse(repeating, ty, next_delay, cache_only, listener);
3714            }
3715
3716            Command::ResolveHostname(hostname, next_delay, listener, timeout) => {
3717                self.exec_command_resolve_hostname(
3718                    repeating, hostname, next_delay, listener, timeout,
3719                );
3720            }
3721
3722            Command::Register(service_info) => {
3723                self.register_service(*service_info);
3724                self.increase_counter(Counter::Register, 1);
3725            }
3726
3727            Command::RegisterResend(fullname, intf) => {
3728                trace!("register-resend service: {fullname} on {}", &intf);
3729                if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
3730                    self.exec_command_register_resend(fullname, intf)
3731                {
3732                    let invalid_intf_addr = HashSet::from([intf_addr]);
3733                    let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addr));
3734                }
3735            }
3736
3737            Command::Unregister(fullname, resp_s) => {
3738                trace!("unregister service {} repeat {}", &fullname, &repeating);
3739                self.exec_command_unregister(repeating, fullname, resp_s);
3740            }
3741
3742            Command::UnregisterResend(packet, if_index, is_ipv4) => {
3743                self.exec_command_unregister_resend(packet, if_index, is_ipv4);
3744            }
3745
3746            Command::StopBrowse(ty_domain) => self.exec_command_stop_browse(ty_domain),
3747
3748            Command::StopResolveHostname(hostname) => {
3749                self.exec_command_stop_resolve_hostname(hostname.to_lowercase())
3750            }
3751
3752            Command::Resolve(instance, try_count) => self.exec_command_resolve(instance, try_count),
3753
3754            Command::GetMetrics(resp_s) => self.exec_command_get_metrics(resp_s),
3755
3756            Command::GetStatus(resp_s) => match resp_s.send(self.status.clone()) {
3757                Ok(()) => trace!("Sent status to the client"),
3758                Err(e) => debug!("Failed to send status: {}", e),
3759            },
3760
3761            Command::Monitor(resp_s) => {
3762                self.monitors.push(resp_s);
3763            }
3764
3765            Command::SetOption(daemon_opt) => {
3766                self.process_set_option(daemon_opt);
3767            }
3768
3769            Command::GetOption(resp_s) => {
3770                let val = DaemonOptionVal {
3771                    _service_name_len_max: self.service_name_len_max,
3772                    ip_check_interval: self.ip_check_interval,
3773                };
3774                if let Err(e) = resp_s.send(val) {
3775                    debug!("Failed to send options: {}", e);
3776                }
3777            }
3778
3779            Command::Verify(instance_fullname, timeout) => {
3780                self.exec_command_verify(instance_fullname, timeout, repeating);
3781            }
3782
3783            Command::InvalidIntfAddrs(invalid_intf_addrs) => {
3784                for intf_addr in invalid_intf_addrs {
3785                    self.del_interface_addr(&intf_addr);
3786                }
3787
3788                self.check_ip_changes();
3789            }
3790
3791            _ => {
3792                debug!("unexpected command: {:?}", &command);
3793            }
3794        }
3795    }
3796
3797    fn exec_command_get_metrics(&mut self, resp_s: Sender<HashMap<String, i64>>) {
3798        self.set_counter(Counter::CachedPTR, self.cache.ptr_count() as i64);
3799        self.set_counter(Counter::CachedSRV, self.cache.srv_count() as i64);
3800        self.set_counter(Counter::CachedAddr, self.cache.addr_count() as i64);
3801        self.set_counter(Counter::CachedTxt, self.cache.txt_count() as i64);
3802        self.set_counter(Counter::CachedNSec, self.cache.nsec_count() as i64);
3803        self.set_counter(Counter::CachedSubtype, self.cache.subtype_count() as i64);
3804        self.set_counter(Counter::Timer, self.timers.len() as i64);
3805
3806        let dns_registry_probe_count: usize = self
3807            .dns_registry_map
3808            .values()
3809            .map(|r| r.probing.len())
3810            .sum();
3811        self.set_counter(Counter::DnsRegistryProbe, dns_registry_probe_count as i64);
3812
3813        let dns_registry_active_count: usize = self
3814            .dns_registry_map
3815            .values()
3816            .map(|r| r.active.values().map(|a| a.len()).sum::<usize>())
3817            .sum();
3818        self.set_counter(Counter::DnsRegistryActive, dns_registry_active_count as i64);
3819
3820        let dns_registry_timer_count: usize = self
3821            .dns_registry_map
3822            .values()
3823            .map(|r| r.new_timers.len())
3824            .sum();
3825        self.set_counter(Counter::DnsRegistryTimer, dns_registry_timer_count as i64);
3826
3827        let dns_registry_name_change_count: usize = self
3828            .dns_registry_map
3829            .values()
3830            .map(|r| r.name_changes.len())
3831            .sum();
3832        self.set_counter(
3833            Counter::DnsRegistryNameChange,
3834            dns_registry_name_change_count as i64,
3835        );
3836
3837        // Send the metrics to the client.
3838        if let Err(e) = resp_s.send(self.counters.clone()) {
3839            debug!("Failed to send metrics: {}", e);
3840        }
3841    }
3842
3843    fn exec_command_browse(
3844        &mut self,
3845        repeating: bool,
3846        ty: String,
3847        next_delay: u32,
3848        cache_only: bool,
3849        listener: Sender<ServiceEvent>,
3850    ) {
3851        let pretty_addrs: Vec<String> = self
3852            .my_intfs
3853            .iter()
3854            .map(|(if_index, itf)| format!("{} ({if_index})", itf.name))
3855            .collect();
3856
3857        if let Err(e) = listener.send(ServiceEvent::SearchStarted(format!(
3858            "{ty} on {} interfaces [{}]",
3859            pretty_addrs.len(),
3860            pretty_addrs.join(", ")
3861        ))) {
3862            debug!(
3863                "Failed to send SearchStarted({})(repeating:{}): {}",
3864                &ty, repeating, e
3865            );
3866            return;
3867        }
3868
3869        let now = current_time_millis();
3870        if !repeating {
3871            // Binds a `listener` to querying mDNS domain type `ty`.
3872            //
3873            // If there is already a `listener`, it will be updated, i.e. overwritten.
3874            self.service_queriers.insert(ty.clone(), listener.clone());
3875
3876            // if we already have the records in our cache, just send them
3877            self.query_cache_for_service(&ty, &listener, now);
3878        }
3879
3880        if cache_only {
3881            // If cache_only is true, we do not send a query.
3882            match listener.send(ServiceEvent::SearchStopped(ty.clone())) {
3883                Ok(()) => debug!("SearchStopped sent for {}", &ty),
3884                Err(e) => debug!("Failed to send SearchStopped: {}", e),
3885            }
3886            return;
3887        }
3888
3889        if !repeating {
3890            // RFC 6762 §5.2: delay the first query by a random jitter.
3891            let jitter =
3892                fastrand::u64(INITIAL_QUERY_DELAY_MIN_MILLIS..INITIAL_QUERY_DELAY_MAX_MILLIS);
3893            self.add_retransmission(now + jitter, Command::Browse(ty, 1, cache_only, listener));
3894            return;
3895        }
3896
3897        self.send_query(&ty, RRType::PTR);
3898        self.increase_counter(Counter::Browse, 1);
3899
3900        let next_time = now + (next_delay * 1000) as u64;
3901        let max_delay = 60 * 60;
3902        let delay = cmp::min(next_delay * 2, max_delay);
3903        self.add_retransmission(next_time, Command::Browse(ty, delay, cache_only, listener));
3904    }
3905
3906    fn exec_command_resolve_hostname(
3907        &mut self,
3908        repeating: bool,
3909        hostname: String,
3910        next_delay: u32,
3911        listener: Sender<HostnameResolutionEvent>,
3912        timeout: Option<u64>,
3913    ) {
3914        let addr_list: Vec<_> = self.my_intfs.iter().collect();
3915        if let Err(e) = listener.send(HostnameResolutionEvent::SearchStarted(format!(
3916            "{} on addrs {:?}",
3917            &hostname, &addr_list
3918        ))) {
3919            debug!(
3920                "Failed to send ResolveStarted({})(repeating:{}): {}",
3921                &hostname, repeating, e
3922            );
3923            return;
3924        }
3925        let now = current_time_millis();
3926        if !repeating {
3927            self.add_hostname_resolver(hostname.to_owned(), listener.clone(), timeout);
3928            // if we already have the records in our cache, just send them
3929            self.query_cache_for_hostname(&hostname, listener.clone());
3930
3931            // RFC 6762 §5.2: delay the first query by a random jitter.
3932            let jitter =
3933                fastrand::u64(INITIAL_QUERY_DELAY_MIN_MILLIS..INITIAL_QUERY_DELAY_MAX_MILLIS);
3934            self.add_retransmission(
3935                now + jitter,
3936                Command::ResolveHostname(hostname, 1, listener, None),
3937            );
3938            return;
3939        }
3940
3941        self.send_query_vec(&[(&hostname, RRType::A), (&hostname, RRType::AAAA)]);
3942        self.increase_counter(Counter::ResolveHostname, 1);
3943
3944        let next_time = now + u64::from(next_delay) * 1000;
3945        let max_delay = 60 * 60;
3946        let delay = cmp::min(next_delay * 2, max_delay);
3947
3948        // Only add retransmission if it does not exceed the hostname resolver timeout, if any.
3949        if self
3950            .hostname_resolvers
3951            .get(&hostname)
3952            .and_then(|(_sender, timeout)| *timeout)
3953            .map(|timeout| next_time < timeout)
3954            .unwrap_or(true)
3955        {
3956            self.add_retransmission(
3957                next_time,
3958                Command::ResolveHostname(hostname, delay, listener, None),
3959            );
3960        }
3961    }
3962
3963    fn exec_command_resolve(&mut self, instance: String, try_count: u16) {
3964        let pending_query = self.query_unresolved(&instance);
3965        let max_try = 3;
3966        if pending_query && try_count < max_try {
3967            // Note that if the current try already succeeds, the next retransmission
3968            // will be no-op as the cache has been updated.
3969            let next_time = current_time_millis() + RESOLVE_WAIT_IN_MILLIS;
3970            self.add_retransmission(next_time, Command::Resolve(instance, try_count + 1));
3971        }
3972    }
3973
3974    fn exec_command_unregister(
3975        &mut self,
3976        repeating: bool,
3977        fullname: String,
3978        resp_s: Sender<UnregisterStatus>,
3979    ) {
3980        let response = match self.my_services.remove_entry(&fullname) {
3981            None => {
3982                debug!("unregister: cannot find such service {}", &fullname);
3983                UnregisterStatus::NotFound
3984            }
3985            Some((_k, info)) => {
3986                let mut timers = Vec::new();
3987
3988                for (if_index, intf) in self.my_intfs.iter() {
3989                    if let Some(sock) = self.ipv4_sock.as_ref() {
3990                        let packet = self.unregister_service(&info, intf, &sock.pktinfo);
3991                        // repeat for one time just in case some peers miss the message
3992                        if !repeating && !packet.is_empty() {
3993                            let next_time = current_time_millis() + 120;
3994                            self.retransmissions.push(ReRun {
3995                                next_time,
3996                                command: Command::UnregisterResend(packet, *if_index, true),
3997                            });
3998                            timers.push(next_time);
3999                        }
4000                    }
4001
4002                    // ipv6
4003                    if let Some(sock) = self.ipv6_sock.as_ref() {
4004                        let packet = self.unregister_service(&info, intf, &sock.pktinfo);
4005                        if !repeating && !packet.is_empty() {
4006                            let next_time = current_time_millis() + 120;
4007                            self.retransmissions.push(ReRun {
4008                                next_time,
4009                                command: Command::UnregisterResend(packet, *if_index, false),
4010                            });
4011                            timers.push(next_time);
4012                        }
4013                    }
4014                }
4015
4016                for t in timers {
4017                    self.add_timer(t);
4018                }
4019
4020                self.increase_counter(Counter::Unregister, 1);
4021                UnregisterStatus::OK
4022            }
4023        };
4024        if let Err(e) = resp_s.send(response) {
4025            debug!("unregister: failed to send response: {}", e);
4026        }
4027    }
4028
4029    fn exec_command_unregister_resend(&mut self, packet: Vec<u8>, if_index: u32, is_ipv4: bool) {
4030        let Some(intf) = self.my_intfs.get(&if_index) else {
4031            return;
4032        };
4033        let sock_opt = if is_ipv4 {
4034            &self.ipv4_sock
4035        } else {
4036            &self.ipv6_sock
4037        };
4038        let Some(sock) = sock_opt else {
4039            return;
4040        };
4041
4042        let if_addr = if is_ipv4 {
4043            match intf.next_ifaddr_v4() {
4044                Some(addr) => addr,
4045                None => return,
4046            }
4047        } else {
4048            match intf.next_ifaddr_v6() {
4049                Some(addr) => addr,
4050                None => return,
4051            }
4052        };
4053
4054        debug!("UnregisterResend from {:?}", if_addr);
4055        multicast_on_intf(
4056            &packet[..],
4057            &intf.name,
4058            intf.index,
4059            if_addr,
4060            &sock.pktinfo,
4061            self.port,
4062        );
4063
4064        self.increase_counter(Counter::UnregisterResend, 1);
4065    }
4066
4067    fn exec_command_stop_browse(&mut self, ty_domain: String) {
4068        match self.service_queriers.remove_entry(&ty_domain) {
4069            None => debug!("StopBrowse: cannot find querier for {}", &ty_domain),
4070            Some((ty, sender)) => {
4071                // Remove pending browse commands in the reruns.
4072                trace!("StopBrowse: removed queryer for {}", &ty);
4073                let mut i = 0;
4074                while i < self.retransmissions.len() {
4075                    if let Command::Browse(t, _, _, _) = &self.retransmissions[i].command {
4076                        if t == &ty {
4077                            self.retransmissions.remove(i);
4078                            trace!("StopBrowse: removed retransmission for {}", &ty);
4079                            continue;
4080                        }
4081                    }
4082                    i += 1;
4083                }
4084
4085                // Remove cache entries.
4086                self.cache.remove_service_type(&ty_domain);
4087
4088                // Notify the client.
4089                match sender.send(ServiceEvent::SearchStopped(ty_domain)) {
4090                    Ok(()) => trace!("Sent SearchStopped to the listener"),
4091                    Err(e) => debug!("Failed to send SearchStopped: {}", e),
4092                }
4093            }
4094        }
4095    }
4096
4097    fn exec_command_stop_resolve_hostname(&mut self, hostname: String) {
4098        if let Some((host, (sender, _timeout))) = self.hostname_resolvers.remove_entry(&hostname) {
4099            // Remove pending resolve commands in the reruns.
4100            trace!("StopResolve: removed queryer for {}", &host);
4101            let mut i = 0;
4102            while i < self.retransmissions.len() {
4103                if let Command::Resolve(t, _) = &self.retransmissions[i].command {
4104                    if t == &host {
4105                        self.retransmissions.remove(i);
4106                        trace!("StopResolve: removed retransmission for {}", &host);
4107                        continue;
4108                    }
4109                }
4110                i += 1;
4111            }
4112
4113            // Notify the client.
4114            match sender.send(HostnameResolutionEvent::SearchStopped(hostname)) {
4115                Ok(()) => trace!("Sent SearchStopped to the listener"),
4116                Err(e) => debug!("Failed to send SearchStopped: {}", e),
4117            }
4118        }
4119    }
4120
4121    fn exec_command_register_resend(&mut self, fullname: String, if_index: u32) -> MyResult<()> {
4122        let Some(info) = self.my_services.get_mut(&fullname) else {
4123            trace!("announce: cannot find such service {}", &fullname);
4124            return Ok(());
4125        };
4126
4127        let Some(dns_registry) = self.dns_registry_map.get_mut(&if_index) else {
4128            return Ok(());
4129        };
4130
4131        let Some(intf) = self.my_intfs.get(&if_index) else {
4132            return Ok(());
4133        };
4134
4135        let announced_v4 = if let Some(sock) = self.ipv4_sock.as_ref() {
4136            announce_service_on_intf(dns_registry, info, intf, &sock.pktinfo, self.port)?
4137        } else {
4138            false
4139        };
4140        let announced_v6 = if let Some(sock) = self.ipv6_sock.as_ref() {
4141            announce_service_on_intf(dns_registry, info, intf, &sock.pktinfo, self.port)?
4142        } else {
4143            false
4144        };
4145
4146        if announced_v4 || announced_v6 {
4147            let hostname = dns_registry.resolve_name(info.get_hostname());
4148            let service_name = dns_registry.resolve_name(&fullname).to_string();
4149
4150            debug!("resend: announce service {service_name} on {}", intf.name);
4151
4152            notify_monitors(
4153                &mut self.monitors,
4154                DaemonEvent::Announce(service_name, format!("{}:{}", hostname, &intf.name)),
4155            );
4156            info.set_status(if_index, ServiceStatus::Announced);
4157        } else {
4158            debug!("register-resend should not fail");
4159        }
4160
4161        self.increase_counter(Counter::RegisterResend, 1);
4162        Ok(())
4163    }
4164
4165    fn exec_command_verify(&mut self, instance: String, timeout: Duration, repeating: bool) {
4166        /*
4167        RFC 6762 section 10.4:
4168        ...
4169        When the cache receives this hint that it should reconfirm some
4170        record, it MUST issue two or more queries for the resource record in
4171        dispute.  If no response is received within ten seconds, then, even
4172        though its TTL may indicate that it is not yet due to expire, that
4173        record SHOULD be promptly flushed from the cache.
4174        */
4175        let now = current_time_millis();
4176        let expire_at = if repeating {
4177            None
4178        } else {
4179            Some(now + timeout.as_millis() as u64)
4180        };
4181
4182        // send query for the resource records.
4183        let record_vec = self.cache.service_verify_queries(&instance, expire_at);
4184
4185        if !record_vec.is_empty() {
4186            let query_vec: Vec<(&str, RRType)> = record_vec
4187                .iter()
4188                .map(|(record, rr_type)| (record.as_str(), *rr_type))
4189                .collect();
4190            self.send_query_vec(&query_vec);
4191
4192            if let Some(new_expire) = expire_at {
4193                self.add_timer(new_expire); // ensure a check for the new expire time.
4194
4195                // schedule a resend 1 second later
4196                self.add_retransmission(now + 1000, Command::Verify(instance, timeout));
4197            }
4198        }
4199    }
4200
4201    /// Refresh cached service records with active queriers
4202    fn refresh_active_services(&mut self) {
4203        let mut query_ptr_count = 0;
4204        let mut query_srv_count = 0;
4205        let mut new_timers = HashSet::new();
4206        let mut query_addr_count = 0;
4207
4208        for (ty_domain, _sender) in self.service_queriers.iter() {
4209            let refreshed_timers = self.cache.refresh_due_ptr(ty_domain);
4210            if !refreshed_timers.is_empty() {
4211                trace!("sending refresh query for PTR: {}", ty_domain);
4212                self.send_query(ty_domain, RRType::PTR);
4213                query_ptr_count += 1;
4214                new_timers.extend(refreshed_timers);
4215            }
4216
4217            let (instances, timers) = self.cache.refresh_due_srv_txt(ty_domain);
4218            for (instance, types) in instances {
4219                trace!("sending refresh query for: {}", &instance);
4220                let query_vec = types
4221                    .into_iter()
4222                    .map(|ty| (instance.as_str(), ty))
4223                    .collect::<Vec<_>>();
4224                self.send_query_vec(&query_vec);
4225                query_srv_count += 1;
4226            }
4227            new_timers.extend(timers);
4228            let (hostnames, timers) = self.cache.refresh_due_hosts(ty_domain);
4229            for hostname in hostnames.iter() {
4230                trace!("sending refresh queries for A and AAAA:  {}", hostname);
4231                self.send_query_vec(&[(hostname, RRType::A), (hostname, RRType::AAAA)]);
4232                query_addr_count += 2;
4233            }
4234            new_timers.extend(timers);
4235        }
4236
4237        for timer in new_timers {
4238            self.add_timer(timer);
4239        }
4240
4241        self.increase_counter(Counter::CacheRefreshPTR, query_ptr_count);
4242        self.increase_counter(Counter::CacheRefreshSrvTxt, query_srv_count);
4243        self.increase_counter(Counter::CacheRefreshAddr, query_addr_count);
4244    }
4245}
4246
4247/// Adds one or more answers of a service for incoming msg and RR entry name.
4248fn add_answer_of_service(
4249    out: &mut DnsOutgoing,
4250    msg: &DnsIncoming,
4251    entry_name: &str,
4252    service: &ServiceInfo,
4253    qtype: RRType,
4254    intf_addrs: Vec<IpAddr>,
4255) {
4256    if qtype == RRType::SRV || qtype == RRType::ANY {
4257        out.add_answer(
4258            msg,
4259            DnsSrv::new(
4260                entry_name,
4261                CLASS_IN | CLASS_CACHE_FLUSH,
4262                service.get_host_ttl(),
4263                service.get_priority(),
4264                service.get_weight(),
4265                service.get_port(),
4266                service.get_hostname().to_string(),
4267            ),
4268        );
4269    }
4270
4271    if qtype == RRType::TXT || qtype == RRType::ANY {
4272        out.add_answer(
4273            msg,
4274            DnsTxt::new(
4275                entry_name,
4276                CLASS_IN | CLASS_CACHE_FLUSH,
4277                service.get_other_ttl(),
4278                service.generate_txt(),
4279            ),
4280        );
4281    }
4282
4283    if qtype == RRType::SRV {
4284        for address in intf_addrs {
4285            out.add_additional_answer(DnsAddress::new(
4286                service.get_hostname(),
4287                ip_address_rr_type(&address),
4288                CLASS_IN | CLASS_CACHE_FLUSH,
4289                service.get_host_ttl(),
4290                address,
4291                InterfaceId::default(),
4292            ));
4293        }
4294    }
4295}
4296
4297/// All possible events sent to the client from the daemon
4298/// regarding service discovery.
4299#[derive(Clone, Debug)]
4300#[non_exhaustive]
4301pub enum ServiceEvent {
4302    /// Started searching for a service type.
4303    SearchStarted(String),
4304
4305    /// Found a specific (service_type, fullname).
4306    ServiceFound(String, String),
4307
4308    /// Resolved a service instance in a ResolvedService struct.
4309    ServiceResolved(Box<ResolvedService>),
4310
4311    /// A service instance (service_type, fullname) was removed.
4312    ServiceRemoved(String, String),
4313
4314    /// Stopped searching for a service type.
4315    SearchStopped(String),
4316}
4317
4318/// All possible events sent to the client from the daemon
4319/// regarding host resolution.
4320#[derive(Clone, Debug)]
4321#[non_exhaustive]
4322pub enum HostnameResolutionEvent {
4323    /// Started searching for the ip address of a hostname.
4324    SearchStarted(String),
4325    /// One or more addresses for a hostname has been found.
4326    AddressesFound(String, HashSet<ScopedIp>),
4327    /// One or more addresses for a hostname has been removed.
4328    AddressesRemoved(String, HashSet<ScopedIp>),
4329    /// The search for the ip address of a hostname has timed out.
4330    SearchTimeout(String),
4331    /// Stopped searching for the ip address of a hostname.
4332    SearchStopped(String),
4333}
4334
4335/// Some notable events from the daemon besides [`ServiceEvent`].
4336/// These events are expected to happen infrequently.
4337#[derive(Clone, Debug)]
4338#[non_exhaustive]
4339pub enum DaemonEvent {
4340    /// Daemon unsolicitly announced a service from an interface.
4341    Announce(String, String),
4342
4343    /// Daemon encountered an error.
4344    Error(Error),
4345
4346    /// Daemon detected a new IP address from the host.
4347    IpAdd(IpAddr),
4348
4349    /// Daemon detected a IP address removed from the host.
4350    IpDel(IpAddr),
4351
4352    /// Daemon resolved a name conflict by changing one of its names.
4353    /// see [DnsNameChange] for more details.
4354    NameChange(DnsNameChange),
4355
4356    /// Send out a multicast response via an interface.
4357    Respond(String),
4358}
4359
4360/// Represents a name change due to a name conflict resolution.
4361/// See [RFC 6762 section 9](https://datatracker.ietf.org/doc/html/rfc6762#section-9)
4362#[derive(Clone, Debug)]
4363pub struct DnsNameChange {
4364    /// The original name set in `ServiceInfo` by the user.
4365    pub original: String,
4366
4367    /// A new name is created by appending a suffix after the original name.
4368    ///
4369    /// - for a service instance name, the suffix is `(N)`, where N starts at 2.
4370    /// - for a host name, the suffix is `-N`, where N starts at 2.
4371    ///
4372    /// For example:
4373    ///
4374    /// - Service name `foo._service-type._udp` becomes `foo (2)._service-type._udp`
4375    /// - Host name `foo.local.` becomes `foo-2.local.`
4376    pub new_name: String,
4377
4378    /// The resource record type
4379    pub rr_type: RRType,
4380
4381    /// The interface where the name conflict and its change happened.
4382    pub intf_name: String,
4383}
4384
4385/// Commands supported by the daemon
4386#[derive(Debug)]
4387enum Command {
4388    /// Browsing for a service type (ty_domain, next_time_delay_in_seconds, channel::sender)
4389    Browse(String, u32, bool, Sender<ServiceEvent>),
4390
4391    /// Resolve a hostname to IP addresses.
4392    ResolveHostname(String, u32, Sender<HostnameResolutionEvent>, Option<u64>), // (hostname, next_time_delay_in_seconds, sender, timeout_in_milliseconds)
4393
4394    /// Register a service
4395    Register(Box<ServiceInfo>),
4396
4397    /// Unregister a service
4398    Unregister(String, Sender<UnregisterStatus>), // (fullname)
4399
4400    /// Announce again a service to local network
4401    RegisterResend(String, u32), // (fullname)
4402
4403    /// Resend unregister packet.
4404    UnregisterResend(Vec<u8>, u32, bool), // (packet content, if_index, is_ipv4)
4405
4406    /// Stop browsing a service type
4407    StopBrowse(String), // (ty_domain)
4408
4409    /// Stop resolving a hostname
4410    StopResolveHostname(String), // (hostname)
4411
4412    /// Send query to resolve a service instance.
4413    /// This is used when a PTR record exists but SRV & TXT records are missing.
4414    Resolve(String, u16), // (service_instance_fullname, try_count)
4415
4416    /// Read the current values of the counters
4417    GetMetrics(Sender<Metrics>),
4418
4419    /// Get the current status of the daemon.
4420    GetStatus(Sender<DaemonStatus>),
4421
4422    /// Monitor noticeable events in the daemon.
4423    Monitor(Sender<DaemonEvent>),
4424
4425    SetOption(DaemonOption),
4426
4427    GetOption(Sender<DaemonOptionVal>),
4428
4429    /// Proactively confirm a DNS resource record.
4430    ///
4431    /// The intention is to check if a service name or IP address still valid
4432    /// before its TTL expires.
4433    Verify(String, Duration),
4434
4435    /// Invalidate some interface addresses.
4436    InvalidIntfAddrs(HashSet<Interface>),
4437
4438    Exit(Sender<DaemonStatus>),
4439}
4440
4441impl fmt::Display for Command {
4442    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4443        match self {
4444            Self::Browse(_, _, _, _) => write!(f, "Command Browse"),
4445            Self::ResolveHostname(_, _, _, _) => write!(f, "Command ResolveHostname"),
4446            Self::Exit(_) => write!(f, "Command Exit"),
4447            Self::GetStatus(_) => write!(f, "Command GetStatus"),
4448            Self::GetMetrics(_) => write!(f, "Command GetMetrics"),
4449            Self::Monitor(_) => write!(f, "Command Monitor"),
4450            Self::Register(_) => write!(f, "Command Register"),
4451            Self::RegisterResend(_, _) => write!(f, "Command RegisterResend"),
4452            Self::SetOption(_) => write!(f, "Command SetOption"),
4453            Self::GetOption(_) => write!(f, "Command GetOption"),
4454            Self::StopBrowse(_) => write!(f, "Command StopBrowse"),
4455            Self::StopResolveHostname(_) => write!(f, "Command StopResolveHostname"),
4456            Self::Unregister(_, _) => write!(f, "Command Unregister"),
4457            Self::UnregisterResend(_, _, _) => write!(f, "Command UnregisterResend"),
4458            Self::Resolve(_, _) => write!(f, "Command Resolve"),
4459            Self::Verify(_, _) => write!(f, "Command VerifyResource"),
4460            Self::InvalidIntfAddrs(_) => write!(f, "Command InvalidIntfAddrs"),
4461        }
4462    }
4463}
4464
4465struct DaemonOptionVal {
4466    _service_name_len_max: u8,
4467    ip_check_interval: u64,
4468}
4469
4470#[derive(Debug)]
4471enum DaemonOption {
4472    ServiceNameLenMax(u8),
4473    IpCheckInterval(u64),
4474    MaxPacketSize(Vec<IfKind>, usize),
4475    EnableInterface(Vec<IfKind>),
4476    DisableInterface(Vec<IfKind>),
4477    MulticastLoopV4(bool),
4478    MulticastLoopV6(bool),
4479    AcceptUnsolicited(bool),
4480    IncludeAppleP2P(bool),
4481    #[cfg(test)]
4482    TestDownInterface(String),
4483    #[cfg(test)]
4484    TestUpInterface(String),
4485}
4486
4487/// The length of Service Domain name supported in this lib.
4488const DOMAIN_LEN: usize = "._tcp.local.".len();
4489
4490/// Validate the length of "service_name" in a "_<service_name>.<domain_name>." string.
4491fn check_service_name_length(ty_domain: &str, limit: u8) -> Result<()> {
4492    if ty_domain.len() <= DOMAIN_LEN + 1 {
4493        // service name cannot be empty or only '_'.
4494        return Err(e_fmt!("Service type name cannot be empty: {}", ty_domain));
4495    }
4496
4497    let service_name_len = ty_domain.len() - DOMAIN_LEN - 1; // exclude the leading `_`
4498    if service_name_len > limit as usize {
4499        return Err(e_fmt!("Service name length must be <= {} bytes", limit));
4500    }
4501    Ok(())
4502}
4503
4504/// Checks if `name` ends with a valid domain: '._tcp.local.' or '._udp.local.'
4505fn check_domain_suffix(name: &str) -> Result<()> {
4506    if !(name.ends_with("._tcp.local.") || name.ends_with("._udp.local.")) {
4507        return Err(e_fmt!(
4508            "mDNS service {} must end with '._tcp.local.' or '._udp.local.'",
4509            name
4510        ));
4511    }
4512
4513    Ok(())
4514}
4515
4516/// Validate the service name in a fully qualified name.
4517///
4518/// A Full Name = <Instance>.<Service>.<Domain>
4519/// The only `<Domain>` supported are "._tcp.local." and "._udp.local.".
4520///
4521/// Note: this function does not check for the length of the service name.
4522/// Instead, `register_service` method will check the length.
4523fn check_service_name(fullname: &str) -> Result<()> {
4524    check_domain_suffix(fullname)?;
4525
4526    let remaining: Vec<&str> = fullname[..fullname.len() - DOMAIN_LEN].split('.').collect();
4527    let name = remaining.last().ok_or_else(|| e_fmt!("No service name"))?;
4528
4529    if &name[0..1] != "_" {
4530        return Err(e_fmt!("Service name must start with '_'"));
4531    }
4532
4533    let name = &name[1..];
4534
4535    if name.contains("--") {
4536        return Err(e_fmt!("Service name must not contain '--'"));
4537    }
4538
4539    if name.starts_with('-') || name.ends_with('-') {
4540        return Err(e_fmt!("Service name (%s) may not start or end with '-'"));
4541    }
4542
4543    let ascii_count = name.chars().filter(|c| c.is_ascii_alphabetic()).count();
4544    if ascii_count < 1 {
4545        return Err(e_fmt!(
4546            "Service name must contain at least one letter (eg: 'A-Za-z')"
4547        ));
4548    }
4549
4550    Ok(())
4551}
4552
4553/// Validate a hostname.
4554fn check_hostname(hostname: &str) -> Result<()> {
4555    if !hostname.ends_with(".local.") {
4556        return Err(e_fmt!("Hostname must end with '.local.': {hostname}"));
4557    }
4558
4559    if hostname == ".local." {
4560        return Err(e_fmt!(
4561            "The part of the hostname before '.local.' cannot be empty"
4562        ));
4563    }
4564
4565    if hostname.len() > 255 {
4566        return Err(e_fmt!("Hostname length must be <= 255 bytes"));
4567    }
4568
4569    Ok(())
4570}
4571
4572fn call_service_listener(
4573    listeners_map: &HashMap<String, Sender<ServiceEvent>>,
4574    ty_domain: &str,
4575    event: ServiceEvent,
4576) {
4577    if let Some(listener) = listeners_map.get(ty_domain) {
4578        match listener.send(event) {
4579            Ok(()) => trace!("Sent event to listener successfully"),
4580            Err(e) => debug!("Failed to send event: {}", e),
4581        }
4582    }
4583}
4584
4585fn call_hostname_resolution_listener(
4586    listeners_map: &HashMap<String, (Sender<HostnameResolutionEvent>, Option<u64>)>,
4587    hostname: &str,
4588    event: HostnameResolutionEvent,
4589) {
4590    let hostname_lower = hostname.to_lowercase();
4591    if let Some(listener) = listeners_map.get(&hostname_lower).map(|(l, _)| l) {
4592        match listener.send(event) {
4593            Ok(()) => trace!("Sent event to listener successfully"),
4594            Err(e) => debug!("Failed to send event: {}", e),
4595        }
4596    }
4597}
4598
4599/// Returns valid network interfaces in the host system.
4600/// Operational down interfaces are excluded.
4601/// Loopback interfaces are excluded if `with_loopback` is false.
4602fn my_ip_interfaces(with_loopback: bool) -> Vec<Interface> {
4603    my_ip_interfaces_inner(with_loopback, false)
4604}
4605
4606fn my_ip_interfaces_inner(with_loopback: bool, with_apple_p2p: bool) -> Vec<Interface> {
4607    if_addrs::get_if_addrs()
4608        .unwrap_or_default()
4609        .into_iter()
4610        .filter(|i| {
4611            i.is_oper_up()
4612                && !i.is_p2p()
4613                && (!i.is_loopback() || with_loopback)
4614                && (with_apple_p2p || !is_apple_p2p_by_name(&i.name))
4615        })
4616        .collect()
4617}
4618
4619/// Checks if the interface name indicates it's an Apple peer-to-peer interface,
4620/// which should be ignored by default.
4621fn is_apple_p2p_by_name(name: &str) -> bool {
4622    let p2p_prefixes = ["awdl", "llw"];
4623    p2p_prefixes.iter().any(|prefix| name.starts_with(prefix))
4624}
4625
4626/// How to encode and where to send outgoing messages on one interface.
4627#[derive(Clone, Copy, Debug)]
4628struct SendConfig {
4629    /// The mDNS port to send to.
4630    port: u16,
4631
4632    /// Max byte size of a generated packet.
4633    /// See [`ServiceDaemon::set_max_packet_size`].
4634    max_packet_size: usize,
4635
4636    /// Whether the packets go out over IPv4, which decides their absolute
4637    /// ceiling: see [`max_pkt_absolute`].
4638    is_ipv4: bool,
4639}
4640
4641/// Send an outgoing mDNS query or response, and returns the packet bytes.
4642/// Returns empty vec if no valid interface address is found.
4643fn send_dns_outgoing(
4644    out: &DnsOutgoing,
4645    my_intf: &MyIntf,
4646    sock: &PktInfoUdpSocket,
4647    port: u16,
4648    source: Option<&IfAddr>,
4649    unicast_dest: Option<SocketAddr>,
4650) -> MyResult<Vec<Vec<u8>>> {
4651    let if_name = &my_intf.name;
4652
4653    let if_addr = match source {
4654        Some(addr) => addr,
4655        None => {
4656            if sock.domain() == Domain::IPV4 {
4657                match my_intf.next_ifaddr_v4() {
4658                    Some(addr) => addr,
4659                    None => return Ok(vec![]),
4660                }
4661            } else {
4662                match my_intf.next_ifaddr_v6() {
4663                    Some(addr) => addr,
4664                    None => return Ok(vec![]),
4665                }
4666            }
4667        }
4668    };
4669
4670    // The limits are per address family, so read them off the address we send from.
4671    let is_ipv4 = if_addr.ip().is_ipv4();
4672    let config = SendConfig {
4673        port,
4674        max_packet_size: my_intf.max_packet_size(is_ipv4),
4675        is_ipv4,
4676    };
4677
4678    send_dns_outgoing_impl(
4679        out,
4680        if_name,
4681        my_intf.index,
4682        if_addr,
4683        sock,
4684        config,
4685        unicast_dest,
4686    )
4687}
4688
4689/// Send an outgoing mDNS query or response, and returns the packet bytes.
4690fn send_dns_outgoing_impl(
4691    out: &DnsOutgoing,
4692    if_name: &str,
4693    if_index: u32,
4694    if_addr: &IfAddr,
4695    sock: &PktInfoUdpSocket,
4696    config: SendConfig,
4697    unicast_dest: Option<SocketAddr>,
4698) -> MyResult<Vec<Vec<u8>>> {
4699    let qtype = if out.is_query() {
4700        "query"
4701    } else {
4702        if out.answers_count() == 0 && out.additionals().is_empty() {
4703            return Ok(vec![]); // no need to send empty response
4704        }
4705        "response"
4706    };
4707    trace!(
4708        "send {}: {} questions {} answers {} authorities {} additional",
4709        qtype,
4710        out.questions().len(),
4711        out.answers_count(),
4712        out.authorities().len(),
4713        out.additionals().len()
4714    );
4715
4716    match if_addr.ip() {
4717        IpAddr::V4(ipv4) => {
4718            if let Err(e) = sock.set_multicast_if_v4(&ipv4) {
4719                debug!(
4720                    "send_dns_outgoing: failed to set multicast interface for IPv4 {}: {}",
4721                    ipv4, e
4722                );
4723                // cannot send without a valid interface
4724                if e.kind() == std::io::ErrorKind::AddrNotAvailable {
4725                    let intf_addr = Interface {
4726                        name: if_name.to_string(),
4727                        addr: if_addr.clone(),
4728                        index: Some(if_index),
4729                        oper_status: if_addrs::IfOperStatus::Down,
4730                        is_p2p: false,
4731                        #[cfg(windows)]
4732                        adapter_name: String::new(),
4733                    };
4734                    return Err(InternalError::IntfAddrInvalid(intf_addr));
4735                }
4736                return Ok(vec![]); // non-fatal other failure
4737            }
4738        }
4739        IpAddr::V6(ipv6) => {
4740            if let Err(e) = sock.set_multicast_if_v6(if_index) {
4741                debug!(
4742                    "send_dns_outgoing: failed to set multicast interface for IPv6 {}: {}",
4743                    ipv6, e
4744                );
4745                // cannot send without a valid interface
4746                if e.kind() == std::io::ErrorKind::AddrNotAvailable {
4747                    let intf_addr = Interface {
4748                        name: if_name.to_string(),
4749                        addr: if_addr.clone(),
4750                        index: Some(if_index),
4751                        oper_status: if_addrs::IfOperStatus::Down,
4752                        is_p2p: false,
4753                        #[cfg(windows)]
4754                        adapter_name: String::new(),
4755                    };
4756                    return Err(InternalError::IntfAddrInvalid(intf_addr));
4757                }
4758                return Ok(vec![]); // non-fatal other failure
4759            }
4760        }
4761    }
4762
4763    let packet_list = out.to_data_on_wire(config.max_packet_size, config.is_ipv4);
4764    for packet in packet_list.iter() {
4765        match unicast_dest {
4766            Some(dest) => unicast_on_intf(packet, if_name, dest, sock),
4767            None => multicast_on_intf(packet, if_name, if_index, if_addr, sock, config.port),
4768        }
4769    }
4770    Ok(packet_list)
4771}
4772
4773/// Sends a unicast packet directly to `dest` (used for RFC 6762 §6.7
4774/// legacy unicast responses).
4775fn unicast_on_intf(packet: &[u8], if_name: &str, dest: SocketAddr, socket: &PktInfoUdpSocket) {
4776    let max_size = max_pkt_absolute(dest.is_ipv4());
4777    if packet.len() > max_size {
4778        debug!("Drop over-sized packet ({} > {max_size})", packet.len());
4779        return;
4780    }
4781
4782    let sock_addr = dest.into();
4783    match socket.send_to(packet, &sock_addr) {
4784        Ok(sz) => trace!(
4785            "sent unicast {} bytes on interface {} to {}",
4786            sz,
4787            if_name,
4788            dest
4789        ),
4790        Err(e) => trace!(
4791            "Failed to send unicast to {} via {:?}: {}",
4792            dest,
4793            &if_name,
4794            e
4795        ),
4796    }
4797}
4798
4799/// Sends a multicast packet, and returns the packet bytes.
4800fn multicast_on_intf(
4801    packet: &[u8],
4802    if_name: &str,
4803    if_index: u32,
4804    if_addr: &IfAddr,
4805    socket: &PktInfoUdpSocket,
4806    port: u16,
4807) {
4808    let max_size = max_pkt_absolute(if_addr.ip().is_ipv4());
4809    if packet.len() > max_size {
4810        debug!("Drop over-sized packet ({} > {max_size})", packet.len());
4811        return;
4812    }
4813
4814    let addr: SocketAddr = match if_addr {
4815        if_addrs::IfAddr::V4(_) => SocketAddrV4::new(GROUP_ADDR_V4, port).into(),
4816        if_addrs::IfAddr::V6(_) => {
4817            let mut sock = SocketAddrV6::new(GROUP_ADDR_V6, port, 0, 0);
4818            sock.set_scope_id(if_index); // Choose iface for multicast
4819            sock.into()
4820        }
4821    };
4822
4823    // Sends out `packet` to `addr` on the socket.
4824    let sock_addr = addr.into();
4825    match socket.send_to(packet, &sock_addr) {
4826        Ok(sz) => trace!(
4827            "sent out {} bytes on interface {} (idx {}) addr {}",
4828            sz,
4829            if_name,
4830            if_index,
4831            if_addr.ip()
4832        ),
4833        Err(e) => trace!("Failed to send to {} via {:?}: {}", addr, &if_name, e),
4834    }
4835}
4836
4837/// Returns true if `name` is a valid instance name of format:
4838/// <instance>.<service_type>.<_udp|_tcp>.local.
4839/// Note: <instance> could contain '.' as well.
4840fn valid_instance_name(name: &str) -> bool {
4841    name.split('.').count() >= 5
4842}
4843
4844fn notify_monitors(monitors: &mut Vec<Sender<DaemonEvent>>, event: DaemonEvent) {
4845    monitors.retain(|sender| {
4846        if let Err(e) = sender.try_send(event.clone()) {
4847            debug!("notify_monitors: try_send: {}", &e);
4848            if matches!(e, TrySendError::Disconnected(_)) {
4849                return false; // This monitor is dropped.
4850            }
4851        }
4852        true
4853    });
4854}
4855
4856/// Check if all unique records passed "probing", and if yes, create a packet
4857/// to announce the service.
4858fn prepare_announce(
4859    info: &ServiceInfo,
4860    intf: &MyIntf,
4861    dns_registry: &mut DnsRegistry,
4862    is_ipv4: bool,
4863) -> Option<DnsOutgoing> {
4864    let intf_addrs = if is_ipv4 {
4865        info.get_addrs_on_my_intf_v4(intf)
4866    } else {
4867        info.get_addrs_on_my_intf_v6(intf)
4868    };
4869
4870    if intf_addrs.is_empty() {
4871        debug!(
4872            "prepare_announce (ipv4: {is_ipv4}): no valid addrs on interface {}",
4873            &intf.name
4874        );
4875        return None;
4876    }
4877
4878    // check if we changed our name due to conflicts.
4879    let service_fullname = dns_registry.resolve_name(info.get_fullname());
4880
4881    debug!(
4882        "prepare to announce service {service_fullname} on {:?}",
4883        &intf_addrs
4884    );
4885
4886    let mut probing_count = 0;
4887    let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE | FLAGS_AA);
4888    let create_time = current_time_millis() + fastrand::u64(0..250);
4889
4890    out.add_answer_at_time(
4891        DnsPointer::new(
4892            info.get_type(),
4893            RRType::PTR,
4894            CLASS_IN,
4895            info.get_other_ttl(),
4896            service_fullname.to_string(),
4897        ),
4898        0,
4899    );
4900
4901    if let Some(sub) = info.get_subtype() {
4902        trace!("Adding subdomain {}", sub);
4903        out.add_answer_at_time(
4904            DnsPointer::new(
4905                sub,
4906                RRType::PTR,
4907                CLASS_IN,
4908                info.get_other_ttl(),
4909                service_fullname.to_string(),
4910            ),
4911            0,
4912        );
4913    }
4914
4915    // SRV records.
4916    let hostname = dns_registry.resolve_name(info.get_hostname()).to_string();
4917
4918    let mut srv = DnsSrv::new(
4919        info.get_fullname(),
4920        CLASS_IN | CLASS_CACHE_FLUSH,
4921        info.get_host_ttl(),
4922        info.get_priority(),
4923        info.get_weight(),
4924        info.get_port(),
4925        hostname,
4926    );
4927
4928    if let Some(new_name) = dns_registry.name_changes.get(info.get_fullname()) {
4929        srv.get_record_mut().set_new_name(new_name.to_string());
4930    }
4931
4932    if !info.requires_probe()
4933        || dns_registry.is_probing_done(&srv, info.get_fullname(), create_time)
4934    {
4935        out.add_answer_at_time(srv, 0);
4936    } else {
4937        probing_count += 1;
4938    }
4939
4940    // TXT records.
4941
4942    let mut txt = DnsTxt::new(
4943        info.get_fullname(),
4944        CLASS_IN | CLASS_CACHE_FLUSH,
4945        info.get_other_ttl(),
4946        info.generate_txt(),
4947    );
4948
4949    if let Some(new_name) = dns_registry.name_changes.get(info.get_fullname()) {
4950        txt.get_record_mut().set_new_name(new_name.to_string());
4951    }
4952
4953    if !info.requires_probe()
4954        || dns_registry.is_probing_done(&txt, info.get_fullname(), create_time)
4955    {
4956        out.add_answer_at_time(txt, 0);
4957    } else {
4958        probing_count += 1;
4959    }
4960
4961    // Address records. (A and AAAA)
4962
4963    let hostname = info.get_hostname();
4964    for address in intf_addrs {
4965        let mut dns_addr = DnsAddress::new(
4966            hostname,
4967            ip_address_rr_type(&address),
4968            CLASS_IN | CLASS_CACHE_FLUSH,
4969            info.get_host_ttl(),
4970            address,
4971            intf.into(),
4972        );
4973
4974        if let Some(new_name) = dns_registry.name_changes.get(hostname) {
4975            dns_addr.get_record_mut().set_new_name(new_name.to_string());
4976        }
4977
4978        if !info.requires_probe()
4979            || dns_registry.is_probing_done(&dns_addr, info.get_fullname(), create_time)
4980        {
4981            out.add_answer_at_time(dns_addr, 0);
4982        } else {
4983            probing_count += 1;
4984        }
4985    }
4986
4987    if probing_count > 0 {
4988        return None;
4989    }
4990
4991    Some(out)
4992}
4993
4994/// Send an unsolicited response for owned service via `intf` and `sock`.
4995/// Returns true if sent out successfully for IPv4 or IPv6.
4996fn announce_service_on_intf(
4997    dns_registry: &mut DnsRegistry,
4998    info: &ServiceInfo,
4999    intf: &MyIntf,
5000    sock: &PktInfoUdpSocket,
5001    port: u16,
5002) -> MyResult<bool> {
5003    let is_ipv4 = sock.domain() == Domain::IPV4;
5004    if let Some(mut out) = prepare_announce(info, intf, dns_registry, is_ipv4) {
5005        // RFC 6762 §6: a record MUST NOT be multicast on an interface more than
5006        // once per second. Announcements are unsolicited multicast responses.
5007        dns_registry.apply_multicast_rate_limit(&mut out, current_time_millis(), is_ipv4);
5008        if out.answers_count() > 0 {
5009            let _ = send_dns_outgoing(&out, intf, sock, port, None, None)?;
5010        }
5011        return Ok(true);
5012    }
5013
5014    Ok(false)
5015}
5016
5017/// Returns a new name based on the `original` to avoid conflicts.
5018/// If the name already contains a number in parentheses, increments that number.
5019///
5020/// Examples:
5021/// - `foo.local.` becomes `foo (2).local.`
5022/// - `foo (2).local.` becomes `foo (3).local.`
5023/// - `foo (9)` becomes `foo (10)`
5024fn name_change(original: &str) -> String {
5025    let mut parts: Vec<_> = original.split('.').collect();
5026    let Some(first_part) = parts.get_mut(0) else {
5027        return format!("{original} (2)");
5028    };
5029
5030    let mut new_name = format!("{first_part} (2)");
5031
5032    // check if there is already has `(<num>)` suffix.
5033    if let Some(paren_pos) = first_part.rfind(" (") {
5034        // Check if there's a closing parenthesis
5035        if let Some(end_paren) = first_part[paren_pos..].find(')') {
5036            let absolute_end_pos = paren_pos + end_paren;
5037            // Only process if the closing parenthesis is the last character
5038            if absolute_end_pos == first_part.len() - 1 {
5039                let num_start = paren_pos + 2; // Skip " ("
5040                                               // Try to parse the number between parentheses
5041                if let Ok(number) = first_part[num_start..absolute_end_pos].parse::<u32>() {
5042                    let base_name = &first_part[..paren_pos];
5043                    new_name = format!("{} ({})", base_name, number + 1)
5044                }
5045            }
5046        }
5047    }
5048
5049    *first_part = &new_name;
5050    parts.join(".")
5051}
5052
5053/// Returns a new name based on the `original` to avoid conflicts.
5054/// If the name already contains a hyphenated number, increments that number.
5055///
5056/// Examples:
5057/// - `foo.local.` becomes `foo-2.local.`
5058/// - `foo-2.local.` becomes `foo-3.local.`
5059/// - `foo` becomes `foo-2`
5060fn hostname_change(original: &str) -> String {
5061    let mut parts: Vec<_> = original.split('.').collect();
5062    let Some(first_part) = parts.get_mut(0) else {
5063        return format!("{original}-2");
5064    };
5065
5066    let mut new_name = format!("{first_part}-2");
5067
5068    // check if there is already a `-<num>` suffix
5069    if let Some(hyphen_pos) = first_part.rfind('-') {
5070        // Try to parse everything after the hyphen as a number
5071        if let Ok(number) = first_part[hyphen_pos + 1..].parse::<u32>() {
5072            let base_name = &first_part[..hyphen_pos];
5073            new_name = format!("{}-{}", base_name, number + 1);
5074        }
5075    }
5076
5077    *first_part = &new_name;
5078    parts.join(".")
5079}
5080
5081/// Check probes in a registry and returns: a probing packet to send out, and a list of probe names
5082/// that are finished.
5083fn check_probing(
5084    dns_registry: &mut DnsRegistry,
5085    timers: &mut BinaryHeap<Reverse<u64>>,
5086    now: u64,
5087) -> (DnsOutgoing, Vec<String>) {
5088    let mut expired_probes = Vec::new();
5089    let mut out = DnsOutgoing::new(FLAGS_QR_QUERY);
5090
5091    for (name, probe) in dns_registry.probing.iter_mut() {
5092        if now >= probe.next_send {
5093            if probe.expired(now) {
5094                // move the record to active
5095                expired_probes.push(name.clone());
5096            } else {
5097                out.add_question(name, RRType::ANY);
5098
5099                /*
5100                RFC 6762 section 8.2: https://datatracker.ietf.org/doc/html/rfc6762#section-8.2
5101                ...
5102                for tiebreaking to work correctly in all
5103                cases, the Authority Section must contain *all* the records and
5104                proposed rdata being probed for uniqueness.
5105                    */
5106                for record in probe.records.iter() {
5107                    out.add_authority(record.clone());
5108                }
5109
5110                probe.update_next_send(now);
5111
5112                // add timer
5113                timers.push(Reverse(probe.next_send));
5114            }
5115        }
5116    }
5117
5118    (out, expired_probes)
5119}
5120
5121/// Process expired probes on an interface and return a list of services
5122/// that are waiting for the probe to finish.
5123///
5124/// `DnsNameChange` events are sent to the monitors.
5125fn handle_expired_probes(
5126    expired_probes: Vec<String>,
5127    intf_name: &str,
5128    dns_registry: &mut DnsRegistry,
5129    monitors: &mut Vec<Sender<DaemonEvent>>,
5130) -> HashSet<String> {
5131    let mut waiting_services = HashSet::new();
5132
5133    for name in expired_probes {
5134        let Some(probe) = dns_registry.probing.remove(&name) else {
5135            continue;
5136        };
5137
5138        // send notifications about name changes
5139        for record in probe.records.iter() {
5140            if let Some(new_name) = record.get_record().get_new_name() {
5141                dns_registry
5142                    .name_changes
5143                    .insert(name.clone(), new_name.to_string());
5144
5145                let event = DnsNameChange {
5146                    original: record.get_record().get_original_name().to_string(),
5147                    new_name: new_name.to_string(),
5148                    rr_type: record.get_type(),
5149                    intf_name: intf_name.to_string(),
5150                };
5151                debug!("Name change event: {:?}", &event);
5152                notify_monitors(monitors, DaemonEvent::NameChange(event));
5153            }
5154        }
5155
5156        // move RR from probe to active.
5157        debug!(
5158            "probe of '{name}' finished: move {} records to active. ({} waiting services)",
5159            probe.records.len(),
5160            probe.waiting_services.len(),
5161        );
5162
5163        // Move records to active and plan to wake up services if records are not empty.
5164        if !probe.records.is_empty() {
5165            match dns_registry.active.get_mut(&name) {
5166                Some(records) => {
5167                    records.extend(probe.records);
5168                }
5169                None => {
5170                    dns_registry.active.insert(name, probe.records);
5171                }
5172            }
5173
5174            waiting_services.extend(probe.waiting_services);
5175        }
5176    }
5177
5178    waiting_services
5179}
5180
5181/// Returns the max packet size to use on the interface `if_index` for the given
5182/// address family, i.e. the size of the last selection matching it, or
5183/// [`MAX_PKT_DEFAULT`] if none does.
5184///
5185/// A selection matches an address, so it applies as soon as any address of the
5186/// interface in that family matches. That keeps the two families independent:
5187/// e.g. [`IfKind::IPv4`] leaves the IPv6 side of the interface alone.
5188fn resolve_max_packet_size(
5189    selections: &[MaxPacketSizeSelection],
5190    interfaces: &[Interface],
5191    if_index: u32,
5192    is_ipv4: bool,
5193) -> usize {
5194    let mut size = MAX_PKT_DEFAULT;
5195
5196    for selection in selections {
5197        let matched = interfaces.iter().any(|intf| {
5198            intf.index.unwrap_or(0) == if_index
5199                && intf.ip().is_ipv4() == is_ipv4
5200                && selection.if_kind.matches(intf)
5201        });
5202        if matched {
5203            size = selection.max_packet_size;
5204        }
5205    }
5206
5207    size
5208}
5209
5210/// Resolves `IfKind::Addr(ip)` to `IndexV4(if_index)` or `IndexV6(if_index)`.
5211fn resolve_addr_to_index(if_kind: IfKind, interfaces: &[Interface]) -> IfKind {
5212    if let IfKind::Addr(addr) = &if_kind {
5213        if let Some(intf) = interfaces.iter().find(|intf| &intf.ip() == addr) {
5214            let if_index = intf.index.unwrap_or(0);
5215            return if addr.is_ipv4() {
5216                IfKind::IndexV4(if_index)
5217            } else {
5218                IfKind::IndexV6(if_index)
5219            };
5220        }
5221    }
5222    if_kind
5223}
5224
5225#[cfg(test)]
5226mod tests {
5227    use super::{
5228        _new_socket_bind, check_domain_suffix, check_service_name_length, hostname_change,
5229        my_ip_interfaces, name_change, resolve_max_packet_size, send_dns_outgoing_impl,
5230        valid_instance_name, valid_ip_on_intf, DaemonEvent, HostnameResolutionEvent, IfKind,
5231        MaxPacketSizeSelection, MyIntf, SendConfig, ServiceDaemon, ServiceEvent, ServiceInfo,
5232        GROUP_ADDR_V4, INITIAL_QUERY_DELAY_MAX_MILLIS, INITIAL_QUERY_DELAY_MIN_MILLIS,
5233        MAX_PKT_ABSOLUTE_IPV6, MAX_PKT_DEFAULT, MDNS_PORT, MIN_MAX_PACKET_SIZE,
5234        SHARED_RESPONSE_DELAY_MAX_MILLIS, SHARED_RESPONSE_DELAY_MIN_MILLIS,
5235    };
5236    use crate::{
5237        dns_parser::{
5238            DnsEntryExt, DnsIncoming, DnsOutgoing, DnsPointer, InterfaceId, RRType, ScopedIp,
5239            CLASS_IN, FLAGS_AA, FLAGS_QR_QUERY, FLAGS_QR_RESPONSE, LEGACY_UNICAST_MAX_TTL,
5240        },
5241        service_daemon::{add_answer_of_service, check_hostname},
5242    };
5243    use if_addrs::{IfAddr, Ifv4Addr, Ifv6Addr, Interface};
5244    use std::{
5245        collections::HashSet,
5246        net::{IpAddr, Ipv4Addr, Ipv6Addr, UdpSocket},
5247        time::{Duration, Instant, SystemTime},
5248    };
5249    use test_log::test;
5250
5251    /// Builds an interface address for the max packet size tests below.
5252    fn test_interface(name: &str, index: u32, addr: IfAddr) -> Interface {
5253        Interface {
5254            name: name.to_string(),
5255            addr,
5256            index: Some(index),
5257            oper_status: if_addrs::IfOperStatus::Up,
5258            is_p2p: false,
5259            #[cfg(windows)]
5260            adapter_name: String::new(),
5261        }
5262    }
5263
5264    fn test_ifaddr_v4(ip: Ipv4Addr) -> IfAddr {
5265        IfAddr::V4(Ifv4Addr {
5266            ip,
5267            netmask: Ipv4Addr::new(255, 255, 255, 0),
5268            broadcast: None,
5269            prefixlen: 24,
5270        })
5271    }
5272
5273    fn test_ifaddr_v6(ip: Ipv6Addr) -> IfAddr {
5274        IfAddr::V6(Ifv6Addr {
5275            ip,
5276            netmask: Ipv6Addr::from(u128::MAX << 64),
5277            broadcast: None,
5278            prefixlen: 64,
5279        })
5280    }
5281
5282    #[test]
5283    fn test_resolve_max_packet_size() {
5284        // en0 is dual-stack, en1 is IPv4 only.
5285        let interfaces = vec![
5286            test_interface("en0", 1, test_ifaddr_v4(Ipv4Addr::new(192, 168, 1, 2))),
5287            test_interface(
5288                "en0",
5289                1,
5290                test_ifaddr_v6(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 1)),
5291            ),
5292            test_interface("en1", 2, test_ifaddr_v4(Ipv4Addr::new(10, 0, 0, 2))),
5293        ];
5294
5295        let resolve = |selections: &[MaxPacketSizeSelection], if_index, is_ipv4| {
5296            resolve_max_packet_size(selections, &interfaces, if_index, is_ipv4)
5297        };
5298
5299        // No selection: every interface keeps the default.
5300        assert_eq!(resolve(&[], 1, true), MAX_PKT_DEFAULT);
5301        assert_eq!(resolve(&[], 1, false), MAX_PKT_DEFAULT);
5302
5303        // A selection by name applies to the interface it matches, both families.
5304        let by_name = vec![MaxPacketSizeSelection {
5305            if_kind: IfKind::Name("en0".to_string()),
5306            max_packet_size: 8000,
5307        }];
5308        assert_eq!(resolve(&by_name, 1, true), 8000);
5309        assert_eq!(resolve(&by_name, 1, false), 8000);
5310        assert_eq!(resolve(&by_name, 2, true), MAX_PKT_DEFAULT);
5311
5312        // For an interface matched more than once, the last selection wins.
5313        let overlapping = vec![
5314            MaxPacketSizeSelection {
5315                if_kind: IfKind::All,
5316                max_packet_size: 8000,
5317            },
5318            MaxPacketSizeSelection {
5319                if_kind: IfKind::Name("en1".to_string()),
5320                max_packet_size: 4000,
5321            },
5322        ];
5323        assert_eq!(resolve(&overlapping, 1, true), 8000);
5324        assert_eq!(resolve(&overlapping, 1, false), 8000);
5325        assert_eq!(resolve(&overlapping, 2, true), 4000);
5326
5327        // A selection of one address family leaves the other one alone.
5328        let v4_only = vec![MaxPacketSizeSelection {
5329            if_kind: IfKind::IPv4,
5330            max_packet_size: 8000,
5331        }];
5332        assert_eq!(resolve(&v4_only, 1, true), 8000);
5333        assert_eq!(resolve(&v4_only, 1, false), MAX_PKT_DEFAULT);
5334
5335        let v6_only = vec![MaxPacketSizeSelection {
5336            if_kind: IfKind::IPv6,
5337            max_packet_size: 8000,
5338        }];
5339        assert_eq!(resolve(&v6_only, 1, false), 8000);
5340        assert_eq!(resolve(&v6_only, 1, true), MAX_PKT_DEFAULT);
5341        // en1 has no IPv6 address, so the IPv6 selection cannot reach it.
5342        assert_eq!(resolve(&v6_only, 2, true), MAX_PKT_DEFAULT);
5343        assert_eq!(resolve(&v6_only, 2, false), MAX_PKT_DEFAULT);
5344
5345        // Same for an index selection, which names a family too.
5346        let by_index_v4 = vec![MaxPacketSizeSelection {
5347            if_kind: IfKind::IndexV4(1),
5348            max_packet_size: 8000,
5349        }];
5350        assert_eq!(resolve(&by_index_v4, 1, true), 8000);
5351        assert_eq!(resolve(&by_index_v4, 1, false), MAX_PKT_DEFAULT);
5352    }
5353
5354    /// A size outside [`MIN_MAX_PACKET_SIZE`]..=[`MAX_PKT_ABSOLUTE_IPV6`] is rejected
5355    /// rather than clamped, so what reaches the encoder is always legal.
5356    #[test]
5357    fn test_set_max_packet_size_range() {
5358        let daemon = ServiceDaemon::new().unwrap();
5359
5360        assert!(daemon
5361            .set_max_packet_size(IfKind::All, MIN_MAX_PACKET_SIZE - 1)
5362            .is_err());
5363        assert!(daemon
5364            .set_max_packet_size(IfKind::All, MAX_PKT_ABSOLUTE_IPV6 + 1)
5365            .is_err());
5366
5367        // Both ends of the range are accepted.
5368        assert!(daemon
5369            .set_max_packet_size(IfKind::All, MIN_MAX_PACKET_SIZE)
5370            .is_ok());
5371        assert!(daemon
5372            .set_max_packet_size(IfKind::All, MAX_PKT_ABSOLUTE_IPV6)
5373            .is_ok());
5374
5375        daemon.shutdown().unwrap();
5376    }
5377
5378    #[test]
5379    fn test_response_source_ifaddr_match() {
5380        // When an interface has multiple IPs on unrelated subnets,
5381        // handle_query should pick the IfAddr whose subnet contains the querier,
5382        // and fall back to None if none match.
5383        let ifaddr_a = IfAddr::V4(Ifv4Addr {
5384            ip: Ipv4Addr::new(192, 168, 1, 148),
5385            netmask: Ipv4Addr::new(255, 255, 255, 0),
5386            broadcast: None,
5387            prefixlen: 24,
5388        });
5389        let ifaddr_b = IfAddr::V4(Ifv4Addr {
5390            ip: Ipv4Addr::new(10, 238, 0, 51),
5391            netmask: Ipv4Addr::new(255, 255, 255, 0),
5392            broadcast: None,
5393            prefixlen: 24,
5394        });
5395
5396        let intf = MyIntf {
5397            name: "dummy0".to_string(),
5398            index: 1,
5399            addrs: HashSet::from([ifaddr_a.clone(), ifaddr_b.clone()]),
5400            max_packet_size_v4: MAX_PKT_DEFAULT,
5401            max_packet_size_v6: MAX_PKT_DEFAULT,
5402        };
5403
5404        let pick = |querier: IpAddr| -> Option<IfAddr> {
5405            intf.addrs
5406                .iter()
5407                .find(|a| valid_ip_on_intf(&querier, a))
5408                .cloned()
5409        };
5410
5411        assert_eq!(
5412            pick(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 2))),
5413            Some(ifaddr_a)
5414        );
5415        assert_eq!(
5416            pick(IpAddr::V4(Ipv4Addr::new(10, 238, 0, 99))),
5417            Some(ifaddr_b)
5418        );
5419        // Querier not on any local subnet: fall back to None.
5420        assert_eq!(pick(IpAddr::V4(Ipv4Addr::new(172, 16, 0, 1))), None);
5421    }
5422
5423    #[test]
5424    fn test_instance_name() {
5425        assert!(valid_instance_name("my-laser._printer._tcp.local."));
5426        assert!(valid_instance_name("my-laser.._printer._tcp.local."));
5427        assert!(!valid_instance_name("_printer._tcp.local."));
5428    }
5429
5430    #[test]
5431    fn test_legacy_unicast_response() {
5432        // RFC 6762 §6.7: a query whose UDP source port is not 5353 (a
5433        // "legacy" / "one-shot" querier, e.g. Android's getaddrinfo) must
5434        // get its response via unicast, sent back to the querier's source
5435        // address, with the question echoed and the cache-flush bit cleared.
5436        //
5437        // This test sends such a query from an ephemeral port and asserts
5438        // the response arrives on that same socket. The socket is not joined
5439        // to the mDNS multicast group, so a multicast-only reply would never
5440        // reach it — simply receiving the response proves it was unicast.
5441
5442        let intf_ip = match my_ip_interfaces(false)
5443            .into_iter()
5444            .find_map(|intf| match intf.ip() {
5445                IpAddr::V4(ip) => Some(ip),
5446                IpAddr::V6(_) => None,
5447            }) {
5448            Some(ip) => ip,
5449            None => {
5450                println!("No IPv4 interface available; skipping test.");
5451                return;
5452            }
5453        };
5454
5455        // Register a service with a unique hostname on this host.
5456        let daemon = ServiceDaemon::new().expect("Failed to create daemon");
5457        let unique = SystemTime::now()
5458            .duration_since(SystemTime::UNIX_EPOCH)
5459            .unwrap()
5460            .as_micros();
5461        let hostname = format!("legacy-unicast-test-{unique}.local.");
5462        let service_info = ServiceInfo::new(
5463            "_legacy-uni._udp.local.",
5464            "test_instance",
5465            &hostname,
5466            &[IpAddr::V4(intf_ip)] as &[IpAddr],
5467            5353, // arbitrary; the test only resolves the hostname
5468            None,
5469        )
5470        .expect("invalid service info");
5471        daemon.register(service_info).expect("register service");
5472
5473        // A one-shot querier: ephemeral source port, not 5353. Binding to
5474        // `intf_ip` directs the multicast query out that interface, which is
5475        // one the daemon is listening on.
5476        let querier = UdpSocket::bind((intf_ip, 0)).expect("bind querier socket");
5477        querier
5478            .set_multicast_loop_v4(true)
5479            .expect("enable multicast loopback");
5480        querier
5481            .set_read_timeout(Some(Duration::from_millis(500)))
5482            .expect("set read timeout");
5483        assert_ne!(
5484            querier.local_addr().unwrap().port(),
5485            MDNS_PORT,
5486            "querier must use an ephemeral (non-5353) source port"
5487        );
5488
5489        // Build a one-question A-record query for our hostname, carrying a
5490        // distinctive non-zero id that the legacy unicast response must echo.
5491        // `set_multicast(false)` makes the query serialize with that id on the
5492        // wire rather than 0.
5493        const QUERY_ID: u16 = 0x4a17;
5494        let mut query = DnsOutgoing::new(FLAGS_QR_QUERY);
5495        query.set_id(QUERY_ID);
5496        query.set_multicast(false);
5497        query.add_question(&hostname, RRType::A);
5498        let query_packet = query
5499            .to_data_on_wire(MAX_PKT_DEFAULT, true)
5500            .pop()
5501            .expect("query serialized to one packet");
5502
5503        let if_id = InterfaceId {
5504            name: "test".to_string(),
5505            index: 0,
5506        };
5507
5508        // The service is announced asynchronously after register(), so retry
5509        // the query until our answer comes back or the deadline passes.
5510        let deadline = Instant::now() + Duration::from_secs(8);
5511        let mut response = None;
5512        'outer: while Instant::now() < deadline {
5513            querier
5514                .send_to(&query_packet, (GROUP_ADDR_V4, MDNS_PORT))
5515                .expect("send query");
5516
5517            // Drain whatever has arrived; on read timeout the loop ends and
5518            // we re-send the query.
5519            let mut buf = [0u8; 1500];
5520            while let Ok((len, from)) = querier.recv_from(&mut buf) {
5521                let Ok(msg) = DnsIncoming::new(buf[..len].to_vec(), if_id.clone()) else {
5522                    continue;
5523                };
5524                if msg.is_response()
5525                    && msg
5526                        .answers()
5527                        .iter()
5528                        .any(|a| a.get_name().eq_ignore_ascii_case(&hostname))
5529                {
5530                    response = Some((msg, from));
5531                    break 'outer;
5532                }
5533            }
5534        }
5535
5536        let (msg, from) = response.expect(
5537            "expected a unicast response to the legacy query; \
5538             a multicast-only reply would never reach this un-joined socket",
5539        );
5540
5541        // The reply came back to our ephemeral socket, from the mDNS port.
5542        assert_eq!(
5543            from.port(),
5544            MDNS_PORT,
5545            "response should originate from the mDNS port"
5546        );
5547
5548        // RFC 6762 §6.7: the response header must echo the querier's id.
5549        assert_eq!(
5550            msg.id(),
5551            QUERY_ID,
5552            "legacy unicast response must echo the query id"
5553        );
5554
5555        // RFC 6762 §6.7: the original question must be echoed.
5556        assert!(
5557            msg.questions()
5558                .iter()
5559                .any(|q| q.entry_name().eq_ignore_ascii_case(&hostname)),
5560            "legacy unicast response must echo the question section"
5561        );
5562
5563        // RFC 6762 §6.7 / §10.2: the answer must be the A record we asked
5564        // for, with the cache-flush bit cleared.
5565        let answer = msg
5566            .answers()
5567            .iter()
5568            .find(|a| a.get_name().eq_ignore_ascii_case(&hostname))
5569            .expect("response contains an answer for our hostname");
5570        assert_eq!(
5571            answer.get_type(),
5572            RRType::A,
5573            "an A query should be answered with an A record"
5574        );
5575        assert!(
5576            !answer.get_cache_flush(),
5577            "legacy unicast responses must clear the cache-flush bit"
5578        );
5579
5580        assert!(
5581            answer.get_record().get_ttl() <= LEGACY_UNICAST_MAX_TTL,
5582            "legacy unicast response TTL {} exceeds the {}s cap",
5583            answer.get_record().get_ttl(),
5584            LEGACY_UNICAST_MAX_TTL
5585        );
5586
5587        daemon.shutdown().unwrap();
5588    }
5589
5590    #[test]
5591    fn test_shared_response_delay_bounds() {
5592        // A shared-record (PTR) response is delayed by a uniform-random amount.
5593        // We deviate from the RFC 6762 §6 suggested 20-120 ms window and use a
5594        // shorter 10-50 ms delay (`MAX` is the exclusive upper bound, so the
5595        // actual delay is 10..=49 ms).
5596        assert_eq!(SHARED_RESPONSE_DELAY_MIN_MILLIS, 10);
5597        assert_eq!(SHARED_RESPONSE_DELAY_MAX_MILLIS, 50);
5598        for _ in 0..10_000 {
5599            let d =
5600                fastrand::u64(SHARED_RESPONSE_DELAY_MIN_MILLIS..SHARED_RESPONSE_DELAY_MAX_MILLIS);
5601            assert!(
5602                (SHARED_RESPONSE_DELAY_MIN_MILLIS..SHARED_RESPONSE_DELAY_MAX_MILLIS).contains(&d),
5603                "delay {} ms is outside the configured {}-{} ms range",
5604                d,
5605                SHARED_RESPONSE_DELAY_MIN_MILLIS,
5606                SHARED_RESPONSE_DELAY_MAX_MILLIS
5607            );
5608        }
5609    }
5610
5611    #[test]
5612    fn test_initial_query_delayed() {
5613        // RFC 6762 §5.2: a querier delays the first query of a continuous
5614        // monitoring series by a random amount (we use a 10-50 ms window).
5615        // Start a browse and observe, on a socket joined to the mDNS group, the
5616        // daemon's first PTR query for our (unique) service type. Assert it
5617        // arrives no sooner than ~10 ms after `browse()` — i.e. it is not sent
5618        // immediately.
5619        use socket2::{Domain, Protocol, Socket, Type};
5620
5621        let (intf, intf_ip) = match my_ip_interfaces(false)
5622            .into_iter()
5623            .find_map(|intf| match intf.ip() {
5624                IpAddr::V4(ip) if !ip.is_loopback() => Some((intf, ip)),
5625                _ => None,
5626            }) {
5627            Some(pair) => pair,
5628            None => {
5629                println!("No IPv4 interface available; skipping test.");
5630                return;
5631            }
5632        };
5633        let interface_id = InterfaceId::from(&intf);
5634
5635        // A receiver socket joined to the mDNS group on this interface. The
5636        // daemon loops back its multicast by default, so its outgoing query is
5637        // delivered here on the same host.
5638        let sock = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP)).unwrap();
5639        sock.set_reuse_address(true).unwrap();
5640        #[cfg(unix)]
5641        sock.set_reuse_port(true).unwrap();
5642        sock.bind(&std::net::SocketAddr::from((Ipv4Addr::UNSPECIFIED, MDNS_PORT)).into())
5643            .unwrap();
5644        sock.join_multicast_v4(&GROUP_ADDR_V4, &intf_ip).unwrap();
5645        sock.set_read_timeout(Some(Duration::from_millis(200)))
5646            .unwrap();
5647        let sock: UdpSocket = sock.into();
5648
5649        // Unique service type, kept within the RFC 6763 §7.2 15-byte label limit.
5650        let unique = SystemTime::now()
5651            .duration_since(SystemTime::UNIX_EPOCH)
5652            .unwrap()
5653            .as_micros()
5654            % 1_000_000_000;
5655        let service_type = format!("_qd{unique}._udp.local.");
5656
5657        let daemon = ServiceDaemon::new().expect("Failed to create daemon");
5658
5659        let sent_at = Instant::now();
5660        let _browse = daemon.browse(&service_type).expect("browse");
5661
5662        // Read packets until we see our own PTR query or time out. The 10-50 ms
5663        // jitter plus command/scheduling latency comfortably fits in 2 s.
5664        let deadline = Instant::now() + Duration::from_secs(2);
5665        let mut buf = [0u8; 2048];
5666        let mut measured = None;
5667        while Instant::now() < deadline {
5668            let n = match sock.recv_from(&mut buf) {
5669                Ok((n, _)) => n,
5670                Err(_) => continue, // read timeout; keep polling until the deadline
5671            };
5672            let Ok(msg) = DnsIncoming::new(buf[..n].to_vec(), interface_id.clone()) else {
5673                continue;
5674            };
5675            if msg.is_query()
5676                && msg
5677                    .questions()
5678                    .iter()
5679                    .any(|q| q.entry_name() == service_type)
5680            {
5681                measured = Some(sent_at.elapsed());
5682                break;
5683            }
5684        }
5685
5686        daemon.shutdown().unwrap();
5687
5688        let elapsed = measured.expect("expected the daemon to send a PTR query for our browse");
5689        let tolerance = Duration::from_millis(2);
5690        assert!(
5691            elapsed + tolerance >= Duration::from_millis(INITIAL_QUERY_DELAY_MIN_MILLIS),
5692            "first browse query was sent after only {:?}; the first query of a series must be \
5693             delayed (10-50 ms window), not sent immediately",
5694            elapsed
5695        );
5696
5697        // Upper bound: the query must fall within the jitter window. Allow
5698        // generous slack above INITIAL_QUERY_DELAY_MAX_MILLIS for command
5699        // handoff, event-loop wakeup, and loopback latency, while still catching
5700        // a regression to a much larger delay (e.g. the RFC's 120 ms window).
5701        let scheduling_slack = Duration::from_millis(50);
5702        assert!(
5703            elapsed <= Duration::from_millis(INITIAL_QUERY_DELAY_MAX_MILLIS) + scheduling_slack,
5704            "first browse query was sent after {:?}, beyond the {}-{} ms jitter window (plus slack)",
5705            elapsed,
5706            INITIAL_QUERY_DELAY_MIN_MILLIS,
5707            INITIAL_QUERY_DELAY_MAX_MILLIS
5708        );
5709    }
5710
5711    #[test]
5712    fn test_shared_ptr_response_delayed() {
5713        // RFC 6762 §6: a PTR (shared record set) response sent by multicast is
5714        // delayed by a uniform-random amount (we use a 10-50 ms window). Register
5715        // a service, then as a proper multicast querier (source port 5353) send a
5716        // PTR query and assert the daemon emits its response no sooner than ~10 ms
5717        // after the query. (A legacy unicast querier gets an *immediate* response
5718        // instead; see `test_legacy_unicast_response`.)
5719        use socket2::{Domain, Protocol, Socket, Type};
5720
5721        let intf_ip = match my_ip_interfaces(false)
5722            .into_iter()
5723            .find_map(|intf| match intf.ip() {
5724                IpAddr::V4(ip) if !ip.is_loopback() => Some(ip),
5725                _ => None,
5726            }) {
5727            Some(ip) => ip,
5728            None => {
5729                println!("No IPv4 interface available; skipping test.");
5730                return;
5731            }
5732        };
5733
5734        let daemon = ServiceDaemon::new().expect("Failed to create daemon");
5735        let monitor = daemon.monitor().expect("monitor daemon events");
5736
5737        // Keep the service name (the `_sd…` label) within the 15-byte limit
5738        // that RFC 6763 §7.2 imposes, while staying unique per run.
5739        let unique = SystemTime::now()
5740            .duration_since(SystemTime::UNIX_EPOCH)
5741            .unwrap()
5742            .as_micros()
5743            % 1_000_000_000;
5744        let service_type = format!("_sd{unique}._udp.local.");
5745        let hostname = format!("sd{unique}.local.");
5746        let service_info = ServiceInfo::new(
5747            &service_type,
5748            "test_instance",
5749            &hostname,
5750            &[IpAddr::V4(intf_ip)] as &[IpAddr],
5751            5353,
5752            None,
5753        )
5754        .expect("invalid service info");
5755        daemon.register(service_info).expect("register service");
5756
5757        // A proper multicast querier: source port 5353 so the daemon takes the
5758        // shared-record (delayed) path rather than the legacy-unicast one. We only
5759        // *send* on this socket; the response is observed through the monitor.
5760        let sock = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP)).unwrap();
5761        sock.set_reuse_address(true).unwrap();
5762        #[cfg(unix)]
5763        sock.set_reuse_port(true).unwrap();
5764        sock.bind(&std::net::SocketAddr::from((Ipv4Addr::UNSPECIFIED, MDNS_PORT)).into())
5765            .unwrap();
5766        sock.set_multicast_if_v4(&intf_ip).unwrap();
5767        // Loop the query back to the daemon's socket on this same host.
5768        sock.set_multicast_loop_v4(true).unwrap();
5769        let sock: UdpSocket = sock.into();
5770
5771        // Build the PTR query for our service type.
5772        let mut query = DnsOutgoing::new(FLAGS_QR_QUERY);
5773        query.add_question(&service_type, RRType::PTR);
5774        let query_packet = query
5775            .to_data_on_wire(MAX_PKT_DEFAULT, true)
5776            .pop()
5777            .expect("one packet");
5778
5779        // Wait for the initial announcements and the §6 rate-limit window (1s) to
5780        // pass, so our query elicits a fresh (delayed) response instead of being
5781        // suppressed by the rate limiter.
5782        std::thread::sleep(Duration::from_secs(3));
5783
5784        // Retry until the daemon emits a Respond for our query. A query landing
5785        // inside the 1 s multicast rate-limit window is rate-limited to an empty
5786        // response (no send, no event), so we simply re-query on the next pass.
5787        let deadline = Instant::now() + Duration::from_secs(8);
5788        let mut measured = None;
5789        while Instant::now() < deadline {
5790            // Drop any Respond events queued earlier so we time only the response
5791            // to the query we are about to send.
5792            while monitor.try_recv().is_ok() {}
5793
5794            let sent_at = Instant::now();
5795            sock.send_to(&query_packet, (GROUP_ADDR_V4, MDNS_PORT))
5796                .expect("send query");
5797
5798            // The delay window is 10-50 ms; 700 ms comfortably covers it plus any
5799            // scheduling slack. Ignore unrelated events; on timeout, re-query.
5800            let attempt_deadline = sent_at + Duration::from_millis(700);
5801            loop {
5802                let remaining = attempt_deadline.saturating_duration_since(Instant::now());
5803                if remaining.is_zero() {
5804                    break;
5805                }
5806                match monitor.recv_timeout(remaining) {
5807                    Ok(DaemonEvent::Respond(_)) => {
5808                        measured = Some(sent_at.elapsed());
5809                        break;
5810                    }
5811                    Ok(_) => continue, // some other daemon event; keep waiting
5812                    Err(_) => break,   // timed out; re-query
5813                }
5814            }
5815            if measured.is_some() {
5816                break;
5817            }
5818        }
5819
5820        let elapsed =
5821            measured.expect("expected the daemon to respond to our PTR query within the deadline");
5822        assert!(
5823            elapsed >= Duration::from_millis(8),
5824            "PTR response was sent after only {:?}; a shared-record response must be \
5825             delayed (10-50 ms window), not sent immediately",
5826            elapsed
5827        );
5828        assert!(
5829            elapsed <= Duration::from_millis(600),
5830            "PTR response was sent after {:?}; expected within the 10-50 ms delay window",
5831            elapsed
5832        );
5833
5834        daemon.shutdown().unwrap();
5835    }
5836
5837    #[test]
5838    fn test_check_service_name_length() {
5839        let result = check_service_name_length("_tcp", 100);
5840        assert!(result.is_err());
5841        if let Err(e) = result {
5842            println!("{}", e);
5843        }
5844    }
5845
5846    #[test]
5847    fn test_check_hostname() {
5848        // valid hostnames
5849        for hostname in &[
5850            "my_host.local.",
5851            &("A".repeat(255 - ".local.".len()) + ".local."),
5852        ] {
5853            let result = check_hostname(hostname);
5854            assert!(result.is_ok());
5855        }
5856
5857        // erroneous hostnames
5858        for hostname in &[
5859            "my_host.local",
5860            ".local.",
5861            &("A".repeat(256 - ".local.".len()) + ".local."),
5862        ] {
5863            let result = check_hostname(hostname);
5864            assert!(result.is_err());
5865            if let Err(e) = result {
5866                println!("{}", e);
5867            }
5868        }
5869    }
5870
5871    #[test]
5872    fn test_check_domain_suffix() {
5873        assert!(check_domain_suffix("_missing_dot._tcp.local").is_err());
5874        assert!(check_domain_suffix("_missing_bar.tcp.local.").is_err());
5875        assert!(check_domain_suffix("_mis_spell._tpp.local.").is_err());
5876        assert!(check_domain_suffix("_mis_spell._upp.local.").is_err());
5877        assert!(check_domain_suffix("_has_dot._tcp.local.").is_ok());
5878        assert!(check_domain_suffix("_goodname._udp.local.").is_ok());
5879    }
5880
5881    #[test]
5882    fn test_service_with_temporarily_invalidated_ptr() {
5883        // Create a daemon
5884        let d = ServiceDaemon::new().expect("Failed to create daemon");
5885
5886        let service = "_test_inval_ptr._udp.local.";
5887        let host_name = "my_host_tmp_invalidated_ptr.local.";
5888        let intfs: Vec<_> = my_ip_interfaces(false);
5889        let intf_ips: Vec<_> = intfs.iter().map(|intf| intf.ip()).collect();
5890        let port = 5201;
5891        let my_service =
5892            ServiceInfo::new(service, "my_instance", host_name, &intf_ips[..], port, None)
5893                .expect("invalid service info")
5894                .enable_addr_auto();
5895        let result = d.register(my_service.clone());
5896        assert!(result.is_ok());
5897
5898        // Browse for a service
5899        let browse_chan = d.browse(service).unwrap();
5900        let timeout = Duration::from_secs(2);
5901        let mut resolved = false;
5902
5903        while let Ok(event) = browse_chan.recv_timeout(timeout) {
5904            match event {
5905                ServiceEvent::ServiceResolved(info) => {
5906                    resolved = true;
5907                    println!("Resolved a service of {}", &info.fullname);
5908                    break;
5909                }
5910                e => {
5911                    println!("Received event {:?}", e);
5912                }
5913            }
5914        }
5915
5916        assert!(resolved);
5917
5918        println!("Stopping browse of {}", service);
5919        // Pause browsing so restarting will cause a new immediate query.
5920        // Unregistering will not work here, it will invalidate all the records.
5921        d.stop_browse(service).unwrap();
5922
5923        // Ensure the search is stopped.
5924        // Reduces the chance of receiving an answer adding the ptr back to the
5925        // cache causing the later browse to return directly from the cache.
5926        // (which invalidates what this test is trying to test for.)
5927        let mut stopped = false;
5928        while let Ok(event) = browse_chan.recv_timeout(timeout) {
5929            match event {
5930                ServiceEvent::SearchStopped(_) => {
5931                    stopped = true;
5932                    println!("Stopped browsing service");
5933                    break;
5934                }
5935                // Other `ServiceResolved` messages may be received
5936                // here as they come from different interfaces.
5937                // That's fine for this test.
5938                e => {
5939                    println!("Received event {:?}", e);
5940                }
5941            }
5942        }
5943
5944        assert!(stopped);
5945
5946        // Invalidate the ptr from the service to the host.
5947        let invalidate_ptr_packet = DnsPointer::new(
5948            my_service.get_type(),
5949            RRType::PTR,
5950            CLASS_IN,
5951            0,
5952            my_service.get_fullname().to_string(),
5953        );
5954
5955        let mut packet_buffer = DnsOutgoing::new(FLAGS_QR_RESPONSE | FLAGS_AA);
5956        packet_buffer.add_additional_answer(invalidate_ptr_packet);
5957
5958        for intf in intfs {
5959            let sock = _new_socket_bind(&intf, true).unwrap();
5960            send_dns_outgoing_impl(
5961                &packet_buffer,
5962                &intf.name,
5963                intf.index.unwrap_or(0),
5964                &intf.addr,
5965                &sock.pktinfo,
5966                SendConfig {
5967                    port: MDNS_PORT,
5968                    max_packet_size: MAX_PKT_DEFAULT,
5969                    is_ipv4: intf.addr.ip().is_ipv4(),
5970                },
5971                None,
5972            )
5973            .unwrap();
5974        }
5975
5976        println!(
5977            "Sent PTR record invalidation. Starting second browse for {}",
5978            service
5979        );
5980
5981        // Restart the browse to force the sender to re-send the announcements.
5982        let browse_chan = d.browse(service).unwrap();
5983
5984        resolved = false;
5985        while let Ok(event) = browse_chan.recv_timeout(timeout) {
5986            match event {
5987                ServiceEvent::ServiceResolved(info) => {
5988                    resolved = true;
5989                    println!("Resolved a service of {}", &info.fullname);
5990                    break;
5991                }
5992                e => {
5993                    println!("Received event {:?}", e);
5994                }
5995            }
5996        }
5997
5998        assert!(resolved);
5999        d.shutdown().unwrap();
6000    }
6001
6002    #[test]
6003    fn test_expired_srv() {
6004        // construct service info
6005        let service_type = "_expired-srv._udp.local.";
6006        let instance = "test_instance";
6007        let host_name = "expired_srv_host.local.";
6008        let mut my_service = ServiceInfo::new(service_type, instance, host_name, "", 5023, None)
6009            .unwrap()
6010            .enable_addr_auto();
6011        // let fullname = my_service.get_fullname().to_string();
6012
6013        // set SRV to expire soon.
6014        let new_ttl = 3; // for testing only.
6015        my_service._set_host_ttl(new_ttl);
6016
6017        // register my service
6018        let mdns_server = ServiceDaemon::new().expect("Failed to create mdns server");
6019        let result = mdns_server.register(my_service);
6020        assert!(result.is_ok());
6021
6022        let mdns_client = ServiceDaemon::new().expect("Failed to create mdns client");
6023        let browse_chan = mdns_client.browse(service_type).unwrap();
6024        let timeout = Duration::from_secs(2);
6025        let mut resolved = false;
6026
6027        while let Ok(event) = browse_chan.recv_timeout(timeout) {
6028            if let ServiceEvent::ServiceResolved(info) = event {
6029                resolved = true;
6030                println!("Resolved a service of {}", &info.fullname);
6031                break;
6032            }
6033        }
6034
6035        assert!(resolved);
6036
6037        // Exit the server so that no more responses.
6038        mdns_server.shutdown().unwrap();
6039
6040        // SRV record in the client cache will expire.
6041        let expire_timeout = Duration::from_secs(new_ttl as u64);
6042        while let Ok(event) = browse_chan.recv_timeout(expire_timeout) {
6043            if let ServiceEvent::ServiceRemoved(service_type, full_name) = event {
6044                println!("Service removed: {}: {}", &service_type, &full_name);
6045                break;
6046            }
6047        }
6048    }
6049
6050    #[test]
6051    fn test_hostname_resolution_address_removed() {
6052        // Create a mDNS server
6053        let server = ServiceDaemon::new().expect("Failed to create server");
6054        let hostname = "addr_remove_host._tcp.local.";
6055        let service_ip_addr: ScopedIp = my_ip_interfaces(false)
6056            .iter()
6057            .find(|iface| iface.ip().is_ipv4())
6058            .map(|iface| iface.into())
6059            .unwrap();
6060
6061        let mut my_service = ServiceInfo::new(
6062            "_host_res_test._tcp.local.",
6063            "my_instance",
6064            hostname,
6065            service_ip_addr.to_ip_addr(),
6066            1234,
6067            None,
6068        )
6069        .expect("invalid service info");
6070
6071        // Set a short TTL for addresses for testing.
6072        let addr_ttl = 2;
6073        my_service._set_host_ttl(addr_ttl); // Expire soon
6074
6075        server.register(my_service).unwrap();
6076
6077        // Create a mDNS client for resolving the hostname.
6078        let client = ServiceDaemon::new().expect("Failed to create client");
6079        let event_receiver = client.resolve_hostname(hostname, None).unwrap();
6080        let resolved = loop {
6081            match event_receiver.recv() {
6082                Ok(HostnameResolutionEvent::AddressesFound(found_hostname, addresses)) => {
6083                    assert_eq!(found_hostname, hostname);
6084                    assert!(addresses.contains(&service_ip_addr));
6085                    println!("address found: {:?}", &addresses);
6086                    break true;
6087                }
6088                Ok(HostnameResolutionEvent::SearchStopped(_)) => break false,
6089                Ok(_event) => {}
6090                Err(_) => break false,
6091            }
6092        };
6093
6094        assert!(resolved);
6095
6096        // Shutdown the server so no more responses / refreshes for addresses.
6097        server.shutdown().unwrap();
6098
6099        // Wait till hostname address record expires, with 1 second grace period.
6100        let timeout = Duration::from_secs(addr_ttl as u64 + 1);
6101        let removed = loop {
6102            match event_receiver.recv_timeout(timeout) {
6103                Ok(HostnameResolutionEvent::AddressesRemoved(removed_host, addresses)) => {
6104                    assert_eq!(removed_host, hostname);
6105                    assert!(addresses.contains(&service_ip_addr));
6106
6107                    println!(
6108                        "address removed: hostname: {} addresses: {:?}",
6109                        &hostname, &addresses
6110                    );
6111                    break true;
6112                }
6113                Ok(_event) => {}
6114                Err(_) => {
6115                    break false;
6116                }
6117            }
6118        };
6119
6120        assert!(removed);
6121
6122        client.shutdown().unwrap();
6123    }
6124
6125    #[test]
6126    fn test_refresh_ptr() {
6127        // construct service info
6128        let service_type = "_refresh-ptr._udp.local.";
6129        let instance = "test_instance";
6130        let host_name = "refresh_ptr_host.local.";
6131        let service_ip_addr = my_ip_interfaces(false)
6132            .iter()
6133            .find(|iface| iface.ip().is_ipv4())
6134            .map(|iface| iface.ip())
6135            .unwrap();
6136
6137        let mut my_service = ServiceInfo::new(
6138            service_type,
6139            instance,
6140            host_name,
6141            service_ip_addr,
6142            5023,
6143            None,
6144        )
6145        .unwrap();
6146
6147        let new_ttl = 3; // for testing only.
6148        my_service._set_other_ttl(new_ttl);
6149
6150        // register my service
6151        let mdns_server = ServiceDaemon::new().expect("Failed to create mdns server");
6152        let result = mdns_server.register(my_service);
6153        assert!(result.is_ok());
6154
6155        let mdns_client = ServiceDaemon::new().expect("Failed to create mdns client");
6156        let browse_chan = mdns_client.browse(service_type).unwrap();
6157        let timeout = Duration::from_millis(1500); // Give at least 1 second for the service probing.
6158        let mut resolved = false;
6159
6160        // resolve the service first.
6161        while let Ok(event) = browse_chan.recv_timeout(timeout) {
6162            if let ServiceEvent::ServiceResolved(info) = event {
6163                resolved = true;
6164                println!("Resolved a service of {}", &info.fullname);
6165                break;
6166            }
6167        }
6168
6169        assert!(resolved);
6170
6171        // wait over 80% of TTL, and refresh PTR should be sent out.
6172        let timeout = Duration::from_millis(new_ttl as u64 * 1000 * 90 / 100);
6173        while let Ok(event) = browse_chan.recv_timeout(timeout) {
6174            println!("event: {:?}", &event);
6175        }
6176
6177        // verify refresh counter.
6178        let metrics_chan = mdns_client.get_metrics().unwrap();
6179        let metrics = metrics_chan.recv_timeout(timeout).unwrap();
6180        let ptr_refresh_counter = metrics["cache-refresh-ptr"];
6181        assert_eq!(ptr_refresh_counter, 1);
6182        let srvtxt_refresh_counter = metrics["cache-refresh-srv-txt"];
6183        assert_eq!(srvtxt_refresh_counter, 1);
6184
6185        // Exit the server so that no more responses.
6186        mdns_server.shutdown().unwrap();
6187        mdns_client.shutdown().unwrap();
6188    }
6189
6190    #[test]
6191    fn test_name_change() {
6192        assert_eq!(name_change("foo.local."), "foo (2).local.");
6193        assert_eq!(name_change("foo (2).local."), "foo (3).local.");
6194        assert_eq!(name_change("foo (9).local."), "foo (10).local.");
6195        assert_eq!(name_change("foo"), "foo (2)");
6196        assert_eq!(name_change("foo (2)"), "foo (3)");
6197        assert_eq!(name_change(""), " (2)");
6198
6199        // Additional edge cases
6200        assert_eq!(name_change("foo (abc)"), "foo (abc) (2)"); // Invalid number
6201        assert_eq!(name_change("foo (2"), "foo (2 (2)"); // Missing closing parenthesis
6202        assert_eq!(name_change("foo (2) extra"), "foo (2) extra (2)"); // Extra text after number
6203    }
6204
6205    #[test]
6206    fn test_hostname_change() {
6207        assert_eq!(hostname_change("foo.local."), "foo-2.local.");
6208        assert_eq!(hostname_change("foo"), "foo-2");
6209        assert_eq!(hostname_change("foo-2.local."), "foo-3.local.");
6210        assert_eq!(hostname_change("foo-9"), "foo-10");
6211        assert_eq!(hostname_change("test-42.domain."), "test-43.domain.");
6212    }
6213
6214    #[test]
6215    fn test_add_answer_txt_ttl() {
6216        // construct a simple service info
6217        let service_type = "_test_add_answer._udp.local.";
6218        let instance = "test_instance";
6219        let host_name = "add_answer_host.local.";
6220        let service_intf = my_ip_interfaces(false)
6221            .into_iter()
6222            .find(|iface| iface.ip().is_ipv4())
6223            .unwrap();
6224        let service_ip_addr = service_intf.ip();
6225        let my_service = ServiceInfo::new(
6226            service_type,
6227            instance,
6228            host_name,
6229            service_ip_addr,
6230            5023,
6231            None,
6232        )
6233        .unwrap();
6234
6235        // construct a DnsOutgoing message
6236        let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE | FLAGS_AA);
6237
6238        // Construct a dummy DnsIncoming message
6239        let mut dummy_data = out.to_data_on_wire(MAX_PKT_DEFAULT, true);
6240        let interface_id = InterfaceId::from(&service_intf);
6241        let incoming = DnsIncoming::new(dummy_data.pop().unwrap(), interface_id).unwrap();
6242
6243        // Add an answer of TXT type for the service.
6244        let if_addrs = vec![service_intf.ip()];
6245        add_answer_of_service(
6246            &mut out,
6247            &incoming,
6248            instance,
6249            &my_service,
6250            RRType::TXT,
6251            if_addrs,
6252        );
6253
6254        // Check if the answer was added correctly
6255        assert!(
6256            out.answers_count() > 0,
6257            "No answers added to the outgoing message"
6258        );
6259
6260        // Check if the first answer is of type TXT
6261        let answer = out._answers().first().unwrap();
6262        assert_eq!(answer.0.get_type(), RRType::TXT);
6263
6264        // Check TTL is set properly for the TXT record
6265        assert_eq!(answer.0.get_record().get_ttl(), my_service.get_other_ttl());
6266    }
6267
6268    #[test]
6269    fn test_interface_flip() {
6270        // start a server
6271        let ty_domain = "_intf-flip._udp.local.";
6272        let host_name = "intf_flip.local.";
6273        let now = SystemTime::now()
6274            .duration_since(SystemTime::UNIX_EPOCH)
6275            .unwrap();
6276        let instance_name = now.as_micros().to_string(); // Create a unique name.
6277        let port = 5200;
6278
6279        // Get a single IPv4 address
6280        let (ip_addr1, intf_name) = my_ip_interfaces(false)
6281            .iter()
6282            .find(|iface| iface.ip().is_ipv4())
6283            .map(|iface| (iface.ip(), iface.name.clone()))
6284            .unwrap();
6285
6286        println!("Using interface {} with IP {}", intf_name, ip_addr1);
6287
6288        // Register the service.
6289        let service1 = ServiceInfo::new(ty_domain, &instance_name, host_name, ip_addr1, port, None)
6290            .expect("valid service info");
6291        let server1 = ServiceDaemon::new().expect("failed to start server");
6292        server1
6293            .register(service1)
6294            .expect("Failed to register service1");
6295
6296        // wait for the service announced.
6297        std::thread::sleep(Duration::from_secs(2));
6298
6299        // start a client
6300        let client = ServiceDaemon::new().expect("failed to start client");
6301
6302        let receiver = client.browse(ty_domain).unwrap();
6303
6304        let timeout = Duration::from_secs(3);
6305        let mut got_data = false;
6306
6307        while let Ok(event) = receiver.recv_timeout(timeout) {
6308            if let ServiceEvent::ServiceResolved(_) = event {
6309                println!("Received ServiceResolved event");
6310                got_data = true;
6311                break;
6312            }
6313        }
6314
6315        assert!(got_data, "Should receive ServiceResolved event");
6316
6317        // Set a short IP check interval to detect interface changes quickly.
6318        client.set_ip_check_interval(1).unwrap();
6319
6320        // Now shutdown the interface and expect the client to lose the service.
6321        println!("Shutting down interface {}", &intf_name);
6322        client.test_down_interface(&intf_name).unwrap();
6323
6324        let mut got_removed = false;
6325
6326        while let Ok(event) = receiver.recv_timeout(timeout) {
6327            if let ServiceEvent::ServiceRemoved(ty_domain, instance) = event {
6328                got_removed = true;
6329                println!("removed: {ty_domain} : {instance}");
6330                break;
6331            }
6332        }
6333        assert!(got_removed, "Should receive ServiceRemoved event");
6334
6335        println!("Bringing up interface {}", &intf_name);
6336        client.test_up_interface(&intf_name).unwrap();
6337        let mut got_data = false;
6338        while let Ok(event) = receiver.recv_timeout(timeout) {
6339            if let ServiceEvent::ServiceResolved(resolved) = event {
6340                got_data = true;
6341                println!("Received ServiceResolved: {:?}", resolved);
6342                break;
6343            }
6344        }
6345        assert!(
6346            got_data,
6347            "Should receive ServiceResolved event after interface is back up"
6348        );
6349
6350        server1.shutdown().unwrap();
6351        client.shutdown().unwrap();
6352    }
6353
6354    #[test]
6355    fn test_cache_only() {
6356        // construct service info
6357        let service_type = "_cache_only._udp.local.";
6358        let instance = "test_instance";
6359        let host_name = "cache_only_host.local.";
6360        let service_ip_addr = my_ip_interfaces(false)
6361            .iter()
6362            .find(|iface| iface.ip().is_ipv4())
6363            .map(|iface| iface.ip())
6364            .unwrap();
6365
6366        let mut my_service = ServiceInfo::new(
6367            service_type,
6368            instance,
6369            host_name,
6370            service_ip_addr,
6371            5023,
6372            None,
6373        )
6374        .unwrap();
6375
6376        let new_ttl = 3; // for testing only.
6377        my_service._set_other_ttl(new_ttl);
6378
6379        let mdns_client = ServiceDaemon::new().expect("Failed to create mdns client");
6380
6381        // make a single browse request to record that we are interested in the service.  This ensures that
6382        // subsequent announcements are cached.
6383        let browse_chan = mdns_client.browse_cache(service_type).unwrap();
6384        std::thread::sleep(Duration::from_secs(2));
6385
6386        // register my service
6387        let mdns_server = ServiceDaemon::new().expect("Failed to create mdns server");
6388        let result = mdns_server.register(my_service);
6389        assert!(result.is_ok());
6390
6391        let timeout = Duration::from_millis(1500); // Give at least 1 second for the service probing.
6392        let mut resolved = false;
6393
6394        // resolve the service.
6395        while let Ok(event) = browse_chan.recv_timeout(timeout) {
6396            if let ServiceEvent::ServiceResolved(info) = event {
6397                resolved = true;
6398                println!("Resolved a service of {}", &info.get_fullname());
6399                break;
6400            }
6401        }
6402
6403        assert!(resolved);
6404
6405        // Exit the server so that no more responses.
6406        mdns_server.shutdown().unwrap();
6407        mdns_client.shutdown().unwrap();
6408    }
6409
6410    #[test]
6411    fn test_cache_only_unsolicited() {
6412        let service_type = "_c_unsolicit._udp.local.";
6413        let instance = "test_instance";
6414        let host_name = "c_unsolicit_host.local.";
6415        let service_ip_addr = my_ip_interfaces(false)
6416            .iter()
6417            .find(|iface| iface.ip().is_ipv4())
6418            .map(|iface| iface.ip())
6419            .unwrap();
6420
6421        let my_service = ServiceInfo::new(
6422            service_type,
6423            instance,
6424            host_name,
6425            service_ip_addr,
6426            5023,
6427            None,
6428        )
6429        .unwrap();
6430
6431        // register my service
6432        let mdns_server = ServiceDaemon::new().expect("Failed to create mdns server");
6433        let result = mdns_server.register(my_service);
6434        assert!(result.is_ok());
6435
6436        let mdns_client = ServiceDaemon::new().expect("Failed to create mdns client");
6437        mdns_client.accept_unsolicited(true).unwrap();
6438
6439        // Wait a bit for the service announcements to go out, before calling browse_cache.  This ensures
6440        // that the announcements are treated as unsolicited
6441        std::thread::sleep(Duration::from_secs(2));
6442        let browse_chan = mdns_client.browse_cache(service_type).unwrap();
6443        let timeout = Duration::from_millis(1500); // Give at least 1 second for the service probing.
6444        let mut resolved = false;
6445
6446        // resolve the service.
6447        while let Ok(event) = browse_chan.recv_timeout(timeout) {
6448            if let ServiceEvent::ServiceResolved(info) = event {
6449                resolved = true;
6450                println!("Resolved a service of {}", &info.get_fullname());
6451                break;
6452            }
6453        }
6454
6455        assert!(resolved);
6456
6457        // Exit the server so that no more responses.
6458        mdns_server.shutdown().unwrap();
6459        mdns_client.shutdown().unwrap();
6460    }
6461
6462    #[test]
6463    fn test_custom_port_isolation() {
6464        // This test verifies:
6465        // 1. Daemons on a custom port can communicate with each other
6466        // 2. Daemons on different ports are isolated (no cross-talk)
6467
6468        let service_type = "_custom_port._udp.local.";
6469        let instance_custom = "custom_port_instance";
6470        let instance_default = "default_port_instance";
6471        let host_name = "custom_port_host.local.";
6472
6473        let service_ip_addr = my_ip_interfaces(false)
6474            .iter()
6475            .find(|iface| iface.ip().is_ipv4())
6476            .map(|iface| iface.ip())
6477            .expect("Test requires an IPv4 interface");
6478
6479        // Create service info for custom port (5454)
6480        let service_custom = ServiceInfo::new(
6481            service_type,
6482            instance_custom,
6483            host_name,
6484            service_ip_addr,
6485            8080,
6486            None,
6487        )
6488        .unwrap();
6489
6490        // Create service info for default port (5353)
6491        let service_default = ServiceInfo::new(
6492            service_type,
6493            instance_default,
6494            host_name,
6495            service_ip_addr,
6496            8081,
6497            None,
6498        )
6499        .unwrap();
6500
6501        // Create two daemons on custom port 5454
6502        let custom_port = 5454u16;
6503        let server_custom =
6504            ServiceDaemon::new_with_port(custom_port).expect("Failed to create custom port server");
6505        let client_custom =
6506            ServiceDaemon::new_with_port(custom_port).expect("Failed to create custom port client");
6507
6508        // Create daemon on default port (5353)
6509        let server_default = ServiceDaemon::new().expect("Failed to create default port server");
6510
6511        // Register service on custom port
6512        server_custom
6513            .register(service_custom.clone())
6514            .expect("Failed to register custom port service");
6515
6516        // Register service on default port
6517        server_default
6518            .register(service_default.clone())
6519            .expect("Failed to register default port service");
6520
6521        // Browse from custom port client
6522        let browse_custom = client_custom
6523            .browse(service_type)
6524            .expect("Failed to browse on custom port");
6525
6526        let timeout = Duration::from_secs(3);
6527        let mut found_custom = false;
6528        let mut found_default_on_custom = false;
6529
6530        // Custom port client should find the custom port service
6531        while let Ok(event) = browse_custom.recv_timeout(timeout) {
6532            if let ServiceEvent::ServiceResolved(info) = event {
6533                println!(
6534                    "Custom port client resolved: {} on port {}",
6535                    info.get_fullname(),
6536                    info.get_port()
6537                );
6538                if info.get_fullname().starts_with(instance_custom) {
6539                    found_custom = true;
6540                    assert_eq!(info.get_port(), 8080);
6541                }
6542                if info.get_fullname().starts_with(instance_default) {
6543                    found_default_on_custom = true;
6544                }
6545            }
6546        }
6547
6548        assert!(
6549            found_custom,
6550            "Custom port client should find service on custom port"
6551        );
6552        assert!(
6553            !found_default_on_custom,
6554            "Custom port client should NOT find service on default port"
6555        );
6556
6557        // Now verify the default port daemon can find its own services
6558        // but not the custom port services
6559        let client_default = ServiceDaemon::new().expect("Failed to create default port client");
6560        let browse_default = client_default
6561            .browse(service_type)
6562            .expect("Failed to browse on default port");
6563
6564        let mut found_default = false;
6565        let mut found_custom_on_default = false;
6566
6567        while let Ok(event) = browse_default.recv_timeout(timeout) {
6568            if let ServiceEvent::ServiceResolved(info) = event {
6569                println!(
6570                    "Default port client resolved: {} on port {}",
6571                    info.get_fullname(),
6572                    info.get_port()
6573                );
6574                if info.get_fullname().starts_with(instance_default) {
6575                    found_default = true;
6576                    assert_eq!(info.get_port(), 8081);
6577                }
6578                if info.get_fullname().starts_with(instance_custom) {
6579                    found_custom_on_default = true;
6580                }
6581            }
6582        }
6583
6584        assert!(
6585            found_default,
6586            "Default port client should find service on default port"
6587        );
6588        assert!(
6589            !found_custom_on_default,
6590            "Default port client should NOT find service on custom port"
6591        );
6592
6593        // Cleanup
6594        server_custom.shutdown().unwrap();
6595        client_custom.shutdown().unwrap();
6596        server_default.shutdown().unwrap();
6597        client_default.shutdown().unwrap();
6598    }
6599}