1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.services.unbound; 8 9 stateDir = "/var/lib/unbound"; 10 11 access = concatMapStrings (x: " access-control: ${x} allow\n") cfg.allowedAccess; 12 13 interfaces = concatMapStrings (x: " interface: ${x}\n") cfg.interfaces; 14 15 forward = optionalString (length cfg.forwardAddresses != 0) 16 "forward-zone:\n name: .\n" + 17 concatMapStrings (x: " forward-addr: ${x}\n") cfg.forwardAddresses; 18 19 rootTrustAnchorFile = "${stateDir}/root.key"; 20 21 trustAnchor = optionalString cfg.enableRootTrustAnchor 22 "auto-trust-anchor-file: ${rootTrustAnchorFile}"; 23 24 confFile = pkgs.writeText "unbound.conf" '' 25 server: 26 directory: "${stateDir}" 27 username: unbound 28 chroot: "${stateDir}" 29 pidfile: "" 30 ${interfaces} 31 ${access} 32 ${trustAnchor} 33 ${cfg.extraConfig} 34 ${forward} 35 ''; 36 37in 38 39{ 40 41 ###### interface 42 43 options = { 44 services.unbound = { 45 46 enable = mkOption { 47 default = false; 48 type = types.bool; 49 description = "Whether to enable the Unbound domain name server."; 50 }; 51 52 allowedAccess = mkOption { 53 default = ["127.0.0.0/24"]; 54 type = types.listOf types.str; 55 description = "What networks are allowed to use unbound as a resolver."; 56 }; 57 58 interfaces = mkOption { 59 default = [ "127.0.0.1" "::1" ]; 60 type = types.listOf types.str; 61 description = "What addresses the server should listen on."; 62 }; 63 64 forwardAddresses = mkOption { 65 default = [ ]; 66 type = types.listOf types.str; 67 description = "What servers to forward queries to."; 68 }; 69 70 enableRootTrustAnchor = mkOption { 71 default = true; 72 type = types.bool; 73 description = "Use and update root trust anchor for DNSSEC validation."; 74 }; 75 76 extraConfig = mkOption { 77 default = ""; 78 type = types.str; 79 description = "Extra lines of unbound config."; 80 }; 81 82 }; 83 }; 84 85 ###### implementation 86 87 config = mkIf cfg.enable { 88 89 environment.systemPackages = [ pkgs.unbound ]; 90 91 users.extraUsers = singleton { 92 name = "unbound"; 93 uid = config.ids.uids.unbound; 94 description = "unbound daemon user"; 95 home = stateDir; 96 createHome = true; 97 }; 98 99 systemd.services.unbound = { 100 description="Unbound recursive Domain Name Server"; 101 after = [ "network.target" ]; 102 before = [ "nss-lookup.target" ]; 103 wants = [" nss-lookup.target" ]; 104 wantedBy = [ "multi-user.target" ]; 105 106 preStart = '' 107 mkdir -m 0755 -p ${stateDir}/dev/ 108 cp ${confFile} ${stateDir}/unbound.conf 109 ${pkgs.unbound}/bin/unbound-anchor -a ${rootTrustAnchorFile} 110 chown unbound ${stateDir} ${rootTrustAnchorFile} 111 touch ${stateDir}/dev/random 112 ${pkgs.utillinux}/bin/mount --bind -n /dev/random ${stateDir}/dev/random 113 ''; 114 115 serviceConfig = { 116 ExecStart = "${pkgs.unbound}/sbin/unbound -d -c ${stateDir}/unbound.conf"; 117 ExecStopPost="${pkgs.utillinux}/bin/umount ${stateDir}/dev/random"; 118 }; 119 }; 120 121 }; 122 123}