at 21.11-pre 8.8 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.avahi; 7 8 yesNo = yes : if yes then "yes" else "no"; 9 10 avahiDaemonConf = with cfg; pkgs.writeText "avahi-daemon.conf" '' 11 [server] 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}"} 24 25 [wide-area] 26 enable-wide-area=${yesNo wideArea} 27 28 [publish] 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} 35 36 [reflector] 37 enable-reflector=${yesNo reflector} 38 ${extraConfig} 39 ''; 40in 41{ 42 options.services.avahi = { 43 enable = mkOption { 44 type = types.bool; 45 default = false; 46 description = '' 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'). 51 ''; 52 }; 53 54 hostName = mkOption { 55 type = types.str; 56 default = config.networking.hostName; 57 defaultText = literalExample "config.networking.hostName"; 58 description = '' 59 Host name advertised on the LAN. If not set, avahi will use the value 60 of <option>config.networking.hostName</option>. 61 ''; 62 }; 63 64 domainName = mkOption { 65 type = types.str; 66 default = "local"; 67 description = '' 68 Domain name for all advertisements. 69 ''; 70 }; 71 72 browseDomains = mkOption { 73 type = types.listOf types.str; 74 default = [ ]; 75 example = [ "0pointer.de" "zeroconf.org" ]; 76 description = '' 77 List of non-local DNS domains to be browsed. 78 ''; 79 }; 80 81 ipv4 = mkOption { 82 type = types.bool; 83 default = true; 84 description = "Whether to use IPv4."; 85 }; 86 87 ipv6 = mkOption { 88 type = types.bool; 89 default = config.networking.enableIPv6; 90 defaultText = "config.networking.enableIPv6"; 91 description = "Whether to use IPv6."; 92 }; 93 94 interfaces = mkOption { 95 type = types.nullOr (types.listOf types.str); 96 default = null; 97 description = '' 98 List of network interfaces that should be used by the <command>avahi-daemon</command>. 99 Other interfaces will be ignored. If <literal>null</literal>, all local interfaces 100 except loopback and point-to-point will be used. 101 ''; 102 }; 103 104 openFirewall = mkOption { 105 type = types.bool; 106 default = true; 107 description = '' 108 Whether to open the firewall for UDP port 5353. 109 ''; 110 }; 111 112 allowPointToPoint = mkOption { 113 type = types.bool; 114 default = false; 115 description= '' 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 118 connections. 119 ''; 120 }; 121 122 wideArea = mkOption { 123 type = types.bool; 124 default = true; 125 description = "Whether to enable wide-area service discovery."; 126 }; 127 128 reflector = mkOption { 129 type = types.bool; 130 default = false; 131 description = "Reflect incoming mDNS requests to all allowed network interfaces."; 132 }; 133 134 extraServiceFiles = mkOption { 135 type = with types; attrsOf (either str path); 136 default = {}; 137 example = literalExample '' 138 { 139 ssh = "''${pkgs.avahi}/etc/avahi/services/ssh.service"; 140 smb = ''' 141 <?xml version="1.0" standalone='no'?><!--*-nxml-*--> 142 <!DOCTYPE service-group SYSTEM "avahi-service.dtd"> 143 <service-group> 144 <name replace-wildcards="yes">%h</name> 145 <service> 146 <type>_smb._tcp</type> 147 <port>445</port> 148 </service> 149 </service-group> 150 '''; 151 } 152 ''; 153 description = '' 154 Specify custom service definitions which are placed in the avahi service directory. 155 See the <citerefentry><refentrytitle>avahi.service</refentrytitle> 156 <manvolnum>5</manvolnum></citerefentry> manpage for detailed information. 157 ''; 158 }; 159 160 publish = { 161 enable = mkOption { 162 type = types.bool; 163 default = false; 164 description = "Whether to allow publishing in general."; 165 }; 166 167 userServices = mkOption { 168 type = types.bool; 169 default = false; 170 description = "Whether to publish user services. Will set <literal>addresses=true</literal>."; 171 }; 172 173 addresses = mkOption { 174 type = types.bool; 175 default = false; 176 description = "Whether to register mDNS address records for all local IP addresses."; 177 }; 178 179 hinfo = mkOption { 180 type = types.bool; 181 default = false; 182 description = '' 183 Whether to register a mDNS HINFO record which contains information about the 184 local operating system and CPU. 185 ''; 186 }; 187 188 workstation = mkOption { 189 type = types.bool; 190 default = false; 191 description = '' 192 Whether to register a service of type "_workstation._tcp" on the local LAN. 193 ''; 194 }; 195 196 domain = mkOption { 197 type = types.bool; 198 default = false; 199 description = "Whether to announce the locally used domain name for browsing by other hosts."; 200 }; 201 }; 202 203 nssmdns = mkOption { 204 type = types.bool; 205 default = false; 206 description = '' 207 Whether to enable the mDNS NSS (Name Service Switch) plug-in. 208 Enabling it allows applications to resolve names in the `.local' 209 domain by transparently querying the Avahi daemon. 210 ''; 211 }; 212 213 cacheEntriesMax = mkOption { 214 type = types.nullOr types.int; 215 default = null; 216 description = '' 217 Number of resource records to be cached per interface. Use 0 to 218 disable caching. Avahi daemon defaults to 4096 if not set. 219 ''; 220 }; 221 222 extraConfig = mkOption { 223 type = types.lines; 224 default = ""; 225 description = '' 226 Extra config to append to avahi-daemon.conf. 227 ''; 228 }; 229 }; 230 231 config = mkIf cfg.enable { 232 users.users.avahi = { 233 description = "avahi-daemon privilege separation user"; 234 home = "/var/empty"; 235 group = "avahi"; 236 isSystemUser = true; 237 }; 238 239 users.groups.avahi = {}; 240 241 system.nssModules = optional cfg.nssmdns pkgs.nssmdns; 242 system.nssDatabases.hosts = optionals cfg.nssmdns (mkMerge [ 243 (mkOrder 900 [ "mdns_minimal [NOTFOUND=return]" ]) # must be before resolve 244 (mkOrder 1501 [ "mdns" ]) # 1501 to ensure it's after dns 245 ]); 246 247 environment.systemPackages = [ pkgs.avahi ]; 248 249 environment.etc = (mapAttrs' (n: v: nameValuePair 250 "avahi/services/${n}.service" 251 { ${if types.path.check v then "source" else "text"} = v; } 252 ) cfg.extraServiceFiles); 253 254 systemd.sockets.avahi-daemon = { 255 description = "Avahi mDNS/DNS-SD Stack Activation Socket"; 256 listenStreams = [ "/run/avahi-daemon/socket" ]; 257 wantedBy = [ "sockets.target" ]; 258 }; 259 260 systemd.tmpfiles.rules = [ "d /run/avahi-daemon - avahi avahi -" ]; 261 262 systemd.services.avahi-daemon = { 263 description = "Avahi mDNS/DNS-SD Stack"; 264 wantedBy = [ "multi-user.target" ]; 265 requires = [ "avahi-daemon.socket" ]; 266 267 # Make NSS modules visible so that `avahi_nss_support ()' can 268 # return a sensible value. 269 environment.LD_LIBRARY_PATH = config.system.nssModules.path; 270 271 path = [ pkgs.coreutils pkgs.avahi ]; 272 273 serviceConfig = { 274 NotifyAccess = "main"; 275 BusName = "org.freedesktop.Avahi"; 276 Type = "dbus"; 277 ExecStart = "${pkgs.avahi}/sbin/avahi-daemon --syslog -f ${avahiDaemonConf}"; 278 }; 279 }; 280 281 services.dbus.enable = true; 282 services.dbus.packages = [ pkgs.avahi ]; 283 284 networking.firewall.allowedUDPPorts = mkIf cfg.openFirewall [ 5353 ]; 285 }; 286}