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