1 { config, lib, pkgs, ... }:
6 cfg = config.services.avahi;
8 yesNo = yes : if yes then "yes" else "no";
10 avahiDaemonConf = with cfg; pkgs.writeText "avahi-daemon.conf" ''
12 ${# Users can set `networking.hostName' to the empty string, when getting
13 # a host name from DHCP. In that case, let Avahi take whatever the
14 # current host name is; setting `host-name' to the empty string in
15 # `avahi-daemon.conf' would be invalid.
16 optionalString (hostName != "") "host-name=${hostName}"}
17 browse-domains=${concatStringsSep ", " browseDomains}
18 use-ipv4=${yesNo ipv4}
19 use-ipv6=${yesNo ipv6}
20 ${optionalString (interfaces!=null) "allow-interfaces=${concatStringsSep "," interfaces}"}
21 ${optionalString (domainName!=null) "domain-name=${domainName}"}
22 allow-point-to-point=${yesNo allowPointToPoint}
23 ${optionalString (cacheEntriesMax!=null) "cache-entries-max=${toString cacheEntriesMax}"}
26 enable-wide-area=${yesNo wideArea}
29 disable-publishing=${yesNo (!publish.enable)}
30 disable-user-service-publishing=${yesNo (!publish.userServices)}
31 publish-addresses=${yesNo (publish.userServices || publish.addresses)}
32 publish-hinfo=${yesNo publish.hinfo}
33 publish-workstation=${yesNo publish.workstation}
34 publish-domain=${yesNo publish.domain}
37 enable-reflector=${yesNo reflector}
42 options.services.avahi = {
46 description = lib.mdDoc ''
47 Whether to run the Avahi daemon, which allows Avahi clients
48 to use Avahi's service discovery facilities and also allows
49 the local machine to advertise its presence and services
50 (through the mDNS responder implemented by `avahi-daemon').
56 default = config.networking.hostName;
57 defaultText = literalExpression "config.networking.hostName";
58 description = lib.mdDoc ''
59 Host name advertised on the LAN. If not set, avahi will use the value
60 of {option}`config.networking.hostName`.
64 domainName = mkOption {
67 description = lib.mdDoc ''
68 Domain name for all advertisements.
72 browseDomains = mkOption {
73 type = types.listOf types.str;
75 example = [ "0pointer.de" "zeroconf.org" ];
76 description = lib.mdDoc ''
77 List of non-local DNS domains to be browsed.
84 description = lib.mdDoc "Whether to use IPv4.";
89 default = config.networking.enableIPv6;
90 defaultText = literalExpression "config.networking.enableIPv6";
91 description = lib.mdDoc "Whether to use IPv6.";
94 interfaces = mkOption {
95 type = types.nullOr (types.listOf types.str);
97 description = lib.mdDoc ''
98 List of network interfaces that should be used by the {command}`avahi-daemon`.
99 Other interfaces will be ignored. If `null`, all local interfaces
100 except loopback and point-to-point will be used.
104 openFirewall = mkOption {
107 description = lib.mdDoc ''
108 Whether to open the firewall for UDP port 5353.
112 allowPointToPoint = mkOption {
115 description= lib.mdDoc ''
116 Whether to use POINTTOPOINT interfaces. Might make mDNS unreliable due to usually large
117 latencies with such links and opens a potential security hole by allowing mDNS access from Internet
122 wideArea = mkOption {
125 description = lib.mdDoc "Whether to enable wide-area service discovery.";
128 reflector = mkOption {
131 description = lib.mdDoc "Reflect incoming mDNS requests to all allowed network interfaces.";
134 extraServiceFiles = mkOption {
135 type = with types; attrsOf (either str path);
137 example = literalExpression ''
139 ssh = "''${pkgs.avahi}/etc/avahi/services/ssh.service";
141 <?xml version="1.0" standalone='no'?><!--*-nxml-*-->
142 <!DOCTYPE service-group SYSTEM "avahi-service.dtd">
144 <name replace-wildcards="yes">%h</name>
146 <type>_smb._tcp</type>
153 description = lib.mdDoc ''
154 Specify custom service definitions which are placed in the avahi service directory.
155 See the {manpage}`avahi.service(5)` manpage for detailed information.
163 description = lib.mdDoc "Whether to allow publishing in general.";
166 userServices = mkOption {
169 description = lib.mdDoc "Whether to publish user services. Will set `addresses=true`.";
172 addresses = mkOption {
175 description = lib.mdDoc "Whether to register mDNS address records for all local IP addresses.";
181 description = lib.mdDoc ''
182 Whether to register a mDNS HINFO record which contains information about the
183 local operating system and CPU.
187 workstation = mkOption {
190 description = lib.mdDoc ''
191 Whether to register a service of type "_workstation._tcp" on the local LAN.
198 description = lib.mdDoc "Whether to announce the locally used domain name for browsing by other hosts.";
205 description = lib.mdDoc ''
206 Whether to enable the mDNS NSS (Name Service Switch) plug-in.
207 Enabling it allows applications to resolve names in the `.local'
208 domain by transparently querying the Avahi daemon.
212 cacheEntriesMax = mkOption {
213 type = types.nullOr types.int;
215 description = lib.mdDoc ''
216 Number of resource records to be cached per interface. Use 0 to
217 disable caching. Avahi daemon defaults to 4096 if not set.
221 extraConfig = mkOption {
224 description = lib.mdDoc ''
225 Extra config to append to avahi-daemon.conf.
230 config = mkIf cfg.enable {
231 users.users.avahi = {
232 description = "avahi-daemon privilege separation user";
238 users.groups.avahi = {};
240 system.nssModules = optional cfg.nssmdns pkgs.nssmdns;
241 system.nssDatabases.hosts = optionals cfg.nssmdns (mkMerge [
242 (mkBefore [ "mdns_minimal [NOTFOUND=return]" ]) # before resolve
243 (mkAfter [ "mdns" ]) # after dns
246 environment.systemPackages = [ pkgs.avahi ];
248 environment.etc = (mapAttrs' (n: v: nameValuePair
249 "avahi/services/${n}.service"
250 { ${if types.path.check v then "source" else "text"} = v; }
251 ) cfg.extraServiceFiles);
253 systemd.sockets.avahi-daemon = {
254 description = "Avahi mDNS/DNS-SD Stack Activation Socket";
255 listenStreams = [ "/run/avahi-daemon/socket" ];
256 wantedBy = [ "sockets.target" ];
259 systemd.tmpfiles.rules = [ "d /run/avahi-daemon - avahi avahi -" ];
261 systemd.services.avahi-daemon = {
262 description = "Avahi mDNS/DNS-SD Stack";
263 wantedBy = [ "multi-user.target" ];
264 requires = [ "avahi-daemon.socket" ];
266 # Make NSS modules visible so that `avahi_nss_support ()' can
267 # return a sensible value.
268 environment.LD_LIBRARY_PATH = config.system.nssModules.path;
270 path = [ pkgs.coreutils pkgs.avahi ];
273 NotifyAccess = "main";
274 BusName = "org.freedesktop.Avahi";
276 ExecStart = "${pkgs.avahi}/sbin/avahi-daemon --syslog -f ${avahiDaemonConf}";
280 services.dbus.enable = true;
281 services.dbus.packages = [ pkgs.avahi ];
283 networking.firewall.allowedUDPPorts = mkIf cfg.openFirewall [ 5353 ];