zfs_unstable: 2.3.0-rc3 -> 2.3.0-rc4 (#365045)
[NixPkgs.git] / nixos / modules / services / networking / avahi-daemon.nix
blob47b707f213f0cb198d6fd6cef34a523f8027ebe4
1 { config, lib, pkgs, ... }:
2 let
3   cfg = config.services.avahi;
5   yesNo = yes: if yes then "yes" else "no";
7   avahiDaemonConf = with cfg; pkgs.writeText "avahi-daemon.conf" ''
8     [server]
9     ${# Users can set `networking.hostName' to the empty string, when getting
10       # a host name from DHCP.  In that case, let Avahi take whatever the
11       # current host name is; setting `host-name' to the empty string in
12       # `avahi-daemon.conf' would be invalid.
13       lib.optionalString (hostName != "") "host-name=${hostName}"}
14     browse-domains=${lib.concatStringsSep ", " browseDomains}
15     use-ipv4=${yesNo ipv4}
16     use-ipv6=${yesNo ipv6}
17     ${lib.optionalString (allowInterfaces!=null) "allow-interfaces=${lib.concatStringsSep "," allowInterfaces}"}
18     ${lib.optionalString (denyInterfaces!=null) "deny-interfaces=${lib.concatStringsSep "," denyInterfaces}"}
19     ${lib.optionalString (domainName!=null) "domain-name=${domainName}"}
20     allow-point-to-point=${yesNo allowPointToPoint}
21     ${lib.optionalString (cacheEntriesMax!=null) "cache-entries-max=${toString cacheEntriesMax}"}
23     [wide-area]
24     enable-wide-area=${yesNo wideArea}
26     [publish]
27     disable-publishing=${yesNo (!publish.enable)}
28     disable-user-service-publishing=${yesNo (!publish.userServices)}
29     publish-addresses=${yesNo (publish.userServices || publish.addresses)}
30     publish-hinfo=${yesNo publish.hinfo}
31     publish-workstation=${yesNo publish.workstation}
32     publish-domain=${yesNo publish.domain}
34     [reflector]
35     enable-reflector=${yesNo reflector}
36     ${extraConfig}
37   '';
40   imports = [
41     (lib.mkRenamedOptionModule [ "services" "avahi" "interfaces" ] [ "services" "avahi" "allowInterfaces" ])
42     (lib.mkRenamedOptionModule [ "services" "avahi" "nssmdns" ] [ "services" "avahi" "nssmdns4" ])
43   ];
45   options.services.avahi = {
46     enable = lib.mkOption {
47       type = lib.types.bool;
48       default = false;
49       description = ''
50         Whether to run the Avahi daemon, which allows Avahi clients
51         to use Avahi's service discovery facilities and also allows
52         the local machine to advertise its presence and services
53         (through the mDNS responder implemented by `avahi-daemon`).
54       '';
55     };
57     package = lib.mkPackageOption pkgs "avahi" { };
59     hostName = lib.mkOption {
60       type = lib.types.str;
61       default = config.networking.hostName;
62       defaultText = lib.literalExpression "config.networking.hostName";
63       description = ''
64         Host name advertised on the LAN. If not set, avahi will use the value
65         of {option}`config.networking.hostName`.
66       '';
67     };
69     domainName = lib.mkOption {
70       type = lib.types.str;
71       default = "local";
72       description = ''
73         Domain name for all advertisements.
74       '';
75     };
77     browseDomains = lib.mkOption {
78       type = lib.types.listOf lib.types.str;
79       default = [ ];
80       example = [ "0pointer.de" "zeroconf.org" ];
81       description = ''
82         List of non-local DNS domains to be browsed.
83       '';
84     };
86     ipv4 = lib.mkOption {
87       type = lib.types.bool;
88       default = true;
89       description = "Whether to use IPv4.";
90     };
92     ipv6 = lib.mkOption {
93       type = lib.types.bool;
94       default = true;
95       description = "Whether to use IPv6.";
96     };
98     allowInterfaces = lib.mkOption {
99       type = lib.types.nullOr (lib.types.listOf lib.types.str);
100       default = null;
101       description = ''
102         List of network interfaces that should be used by the {command}`avahi-daemon`.
103         Other interfaces will be ignored. If `null`, all local interfaces
104         except loopback and point-to-point will be used.
105       '';
106     };
108     denyInterfaces = lib.mkOption {
109       type = lib.types.nullOr (lib.types.listOf lib.types.str);
110       default = null;
111       description = ''
112         List of network interfaces that should be ignored by the
113         {command}`avahi-daemon`. Other unspecified interfaces will be used,
114         unless {option}`allowInterfaces` is set. This option takes precedence
115         over {option}`allowInterfaces`.
116       '';
117     };
119     openFirewall = lib.mkOption {
120       type = lib.types.bool;
121       default = true;
122       description = ''
123         Whether to open the firewall for UDP port 5353.
124         Disabling this setting also disables discovering of network devices.
125       '';
126     };
128     allowPointToPoint = lib.mkOption {
129       type = lib.types.bool;
130       default = false;
131       description = ''
132         Whether to use POINTTOPOINT interfaces. Might make mDNS unreliable due to usually large
133         latencies with such links and opens a potential security hole by allowing mDNS access from Internet
134         connections.
135       '';
136     };
138     wideArea = lib.mkOption {
139       type = lib.types.bool;
140       default = true;
141       description = "Whether to enable wide-area service discovery.";
142     };
144     reflector = lib.mkOption {
145       type = lib.types.bool;
146       default = false;
147       description = "Reflect incoming mDNS requests to all allowed network interfaces.";
148     };
150     extraServiceFiles = lib.mkOption {
151       type = with lib.types; attrsOf (either str path);
152       default = { };
153       example = lib.literalExpression ''
154         {
155           ssh = "''${pkgs.avahi}/etc/avahi/services/ssh.service";
156           smb = '''
157             <?xml version="1.0" standalone='no'?><!--*-nxml-*-->
158             <!DOCTYPE service-group SYSTEM "avahi-service.dtd">
159             <service-group>
160               <name replace-wildcards="yes">%h</name>
161               <service>
162                 <type>_smb._tcp</type>
163                 <port>445</port>
164               </service>
165             </service-group>
166           ''';
167         }
168       '';
169       description = ''
170         Specify custom service definitions which are placed in the avahi service directory.
171         See the {manpage}`avahi.service(5)` manpage for detailed information.
172       '';
173     };
175     publish = {
176       enable = lib.mkOption {
177         type = lib.types.bool;
178         default = false;
179         description = "Whether to allow publishing in general.";
180       };
182       userServices = lib.mkOption {
183         type = lib.types.bool;
184         default = false;
185         description = "Whether to publish user services. Will set `addresses=true`.";
186       };
188       addresses = lib.mkOption {
189         type = lib.types.bool;
190         default = false;
191         description = "Whether to register mDNS address records for all local IP addresses.";
192       };
194       hinfo = lib.mkOption {
195         type = lib.types.bool;
196         default = false;
197         description = ''
198           Whether to register a mDNS HINFO record which contains information about the
199           local operating system and CPU.
200         '';
201       };
203       workstation = lib.mkOption {
204         type = lib.types.bool;
205         default = false;
206         description = ''
207           Whether to register a service of type "_workstation._tcp" on the local LAN.
208         '';
209       };
211       domain = lib.mkOption {
212         type = lib.types.bool;
213         default = false;
214         description = "Whether to announce the locally used domain name for browsing by other hosts.";
215       };
216     };
218     nssmdns4 = lib.mkOption {
219       type = lib.types.bool;
220       default = false;
221       description = ''
222         Whether to enable the mDNS NSS (Name Service Switch) plug-in for IPv4.
223         Enabling it allows applications to resolve names in the `.local`
224         domain by transparently querying the Avahi daemon.
225       '';
226     };
228     nssmdns6 = lib.mkOption {
229       type = lib.types.bool;
230       default = false;
231       description = ''
232         Whether to enable the mDNS NSS (Name Service Switch) plug-in for IPv6.
233         Enabling it allows applications to resolve names in the `.local`
234         domain by transparently querying the Avahi daemon.
236         ::: {.note}
237         Due to the fact that most mDNS responders only register local IPv4 addresses,
238         most user want to leave this option disabled to avoid long timeouts when applications first resolve the none existing IPv6 address.
239         :::
240       '';
241     };
243     cacheEntriesMax = lib.mkOption {
244       type = lib.types.nullOr lib.types.int;
245       default = null;
246       description = ''
247         Number of resource records to be cached per interface. Use 0 to
248         disable caching. Avahi daemon defaults to 4096 if not set.
249       '';
250     };
252     extraConfig = lib.mkOption {
253       type = lib.types.lines;
254       default = "";
255       description = ''
256         Extra config to append to avahi-daemon.conf.
257       '';
258     };
259   };
261   config = lib.mkIf cfg.enable {
262     users.users.avahi = {
263       description = "avahi-daemon privilege separation user";
264       home = "/var/empty";
265       group = "avahi";
266       isSystemUser = true;
267     };
269     users.groups.avahi = { };
271     system.nssModules = lib.optional (cfg.nssmdns4 || cfg.nssmdns6) pkgs.nssmdns;
272     system.nssDatabases.hosts = let
273       mdns = if (cfg.nssmdns4 && cfg.nssmdns6) then
274         "mdns"
275       else if (!cfg.nssmdns4 && cfg.nssmdns6) then
276         "mdns6"
277       else if (cfg.nssmdns4 && !cfg.nssmdns6) then
278         "mdns4"
279       else
280         "";
281     in lib.optionals (cfg.nssmdns4 || cfg.nssmdns6) (lib.mkMerge [
282       (lib.mkBefore [ "${mdns}_minimal [NOTFOUND=return]" ]) # before resolve
283       (lib.mkAfter [ "${mdns}" ]) # after dns
284     ]);
286     environment.systemPackages = [ cfg.package ];
288     environment.etc = (lib.mapAttrs'
289       (n: v: lib.nameValuePair
290         "avahi/services/${n}.service"
291         { ${if lib.types.path.check v then "source" else "text"} = v; }
292       )
293       cfg.extraServiceFiles);
295     systemd.sockets.avahi-daemon = {
296       description = "Avahi mDNS/DNS-SD Stack Activation Socket";
297       listenStreams = [ "/run/avahi-daemon/socket" ];
298       wantedBy = [ "sockets.target" ];
299     };
301     systemd.tmpfiles.rules = [ "d /run/avahi-daemon - avahi avahi -" ];
303     systemd.services.avahi-daemon = {
304       description = "Avahi mDNS/DNS-SD Stack";
305       wantedBy = [ "multi-user.target" ];
306       requires = [ "avahi-daemon.socket" ];
308       # Make NSS modules visible so that `avahi_nss_support ()' can
309       # return a sensible value.
310       environment.LD_LIBRARY_PATH = config.system.nssModules.path;
312       path = [ pkgs.coreutils cfg.package ];
314       serviceConfig = {
315         NotifyAccess = "main";
316         BusName = "org.freedesktop.Avahi";
317         Type = "dbus";
318         ExecStart = "${cfg.package}/sbin/avahi-daemon --syslog -f ${avahiDaemonConf}";
319         ConfigurationDirectory = "avahi/services";
321         # Hardening
322         CapabilityBoundingSet = [
323           # https://github.com/avahi/avahi/blob/v0.9-rc1/avahi-daemon/caps.c#L38
324           "CAP_SYS_CHROOT"
325           "CAP_SETUID"
326           "CAP_SETGID"
327         ];
328         DevicePolicy = "closed";
329         LockPersonality = true;
330         MemoryDenyWriteExecute = true;
331         NoNewPrivileges = true;
332         PrivateDevices = true;
333         PrivateTmp = true;
334         PrivateUsers = false;
335         ProcSubset = "pid";
336         ProtectClock = true;
337         ProtectControlGroups = true;
338         ProtectHome = true;
339         ProtectHostname = true;
340         ProtectKernelLogs = true;
341         ProtectKernelModules = true;
342         ProtectKernelTunables = true;
343         ProtectProc = "invisible";
344         ProtectSystem = "strict";
345         RestrictAddressFamilies = [
346           "AF_INET"
347           "AF_INET6"
348           "AF_NETLINK"
349           "AF_UNIX"
350         ];
351         RestrictNamespaces = true;
352         RestrictRealtime = true;
353         RestrictSUIDSGID = true;
354         SystemCallArchitectures = "native";
355         SystemCallFilter = [
356           "@system-service"
357           "~@privileged"
358           "@chown setgroups setresuid"
359         ];
360         UMask = "0077";
361       };
362     };
364     services.dbus.enable = true;
365     services.dbus.packages = [ cfg.package ];
367     networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall [ 5353 ];
368   };