Skip to main content

mdns_sd/
service_daemon.rs

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