From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp1.migadu.com ([2001:41d0:403:4876::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms13.migadu.com with LMTPS id 0IV4J2lwfWc/bwEA62LTzQ:P1 (envelope-from ) for ; Tue, 07 Jan 2025 18:20:25 +0000 Received: from aspmx1.migadu.com ([2001:41d0:403:4876::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp1.migadu.com with LMTPS id 0IV4J2lwfWc/bwEA62LTzQ (envelope-from ) for ; Tue, 07 Jan 2025 19:20:25 +0100 X-Envelope-To: larch@yhetil.org Authentication-Results: aspmx1.migadu.com; dkim=fail ("body hash did not verify") header.d=debbugs.gnu.org header.s=debbugs-gnu-org header.b=s30oFXU9; dkim=fail ("body hash did not verify") header.d=soeren-tempel.net header.s=opensmtpd header.b=Td9UT2JP; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=fail reason="SPF not aligned (relaxed)" header.from=soeren-tempel.net (policy=none) ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1736274025; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding:resent-cc: resent-from:resent-sender:resent-message-id:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=D3t+q31Vncr/nb24lU4kqrpyxXkTcJWS2RoRtwyM+kU=; b=qanePe7w345pf/h871tJIbZktQHa6mpDlxBrkD0UOOx3SB0dIy0opqzxr3uqhhZXSedajr TXCx/oeMPV71RLNZEfoW27ClyWDADmDUUfosa2d7J00HdruKsXEyNOxQ+rkQAgF5mGOjY2 XxYqwZhfRij63S92gqisrDg4EFoKV7BDEym3lxIexerDUHYE5B5OLkg1+kchi8FYlM91Y8 XcXTawNzd2hR8mkolaIwYu2q1MIyJDjQRMNQf5BYXa+MXf/VYsty5F23hlUNUqzLHpieiH 3Axkvj9T5CQnVDh40QkNYN6RSqNW5Yuk4eUOf3z46N63sMikhLi1ifsSyODzJA== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("body hash did not verify") header.d=debbugs.gnu.org header.s=debbugs-gnu-org header.b=s30oFXU9; dkim=fail ("body hash did not verify") header.d=soeren-tempel.net header.s=opensmtpd header.b=Td9UT2JP; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=fail reason="SPF not aligned (relaxed)" header.from=soeren-tempel.net (policy=none) ARC-Seal: i=1; s=key1; d=yhetil.org; t=1736274025; a=rsa-sha256; cv=none; b=M6Zw1Hm+dbpd5S2uOUj2HOV2CmhvwZRaGwD3Y+tSXZ/gRwtuh2B9aLkM3RSljktg3UU1dF Y8o3vJxlJYwEDPowEU2Uvypw14VS8vXp++g0ihXiIBFVh2aziHR8JKG1u3P1hmV+zGkfeH pDONBUydr+Bz5Zm84Rxzn3vZx6fq86R/P54wjDJ3tWMX6ZNqxaTVuAHABZR6uLgoac8XNk dBiPj5Vm0KMMZ+Cblf5ATok3/j7Np7nAmg6zX+F3+X1XpPJuWtQ19VZBbruRsTuXs3BRhJ RGv954PsSbe4l5mfy7gSRxIc2i6qMzUU5shXs8UIyGbZMZiM1mUyiBB6bXpIVw== Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 2D1459F684 for ; Tue, 07 Jan 2025 19:20:25 +0100 (CET) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tVEBS-0000U7-55; Tue, 07 Jan 2025 13:20:06 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tVEBP-0000Tr-E1 for guix-patches@gnu.org; Tue, 07 Jan 2025 13:20:03 -0500 Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1tVEBO-0000Cq-Jk for guix-patches@gnu.org; Tue, 07 Jan 2025 13:20:02 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debbugs.gnu.org; s=debbugs-gnu-org; h=MIME-Version:Date:From:To:In-Reply-To:References:Subject; bh=c3Ot32by1+tSeE9T5ZYxeXc5yCJW3CvhUaRBI//bRN0=; b=s30oFXU9kpJoHjakwy/ruCF95xaYWIWMtP82fLUd0YDsocta9Hqap2Dsd1aO58Stz+MoulCaD/tg7nvWBmsthUE04SItiMC2wKP64IjCan61/datbNzBlNLJHZ4M5E/OJwaOZlt0BYm8qMfOiFzFj9ah1XxRzkhjM0mO5bZ8D5jGwnYHQj1ZewcxuVXFWfr2e0Hdq+ftA9Z5MB+DSPVA/oRSdjifB+mEfoDEEuIXtxGX9egWJ4MjAYl5wDK0Orto3jUQOV2j1qyJQlN+7BQf3c8Pk7IEVQIUMugW8yd4k7B5uhPFBo6qfP+BLKOzmxcFjwCLdyhwHeUjOYEiCZK6xQ==; Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1tVEBO-0005nm-8J for guix-patches@gnu.org; Tue, 07 Jan 2025 13:20:02 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#68757] [PATCH v2 1/1] services: dns: Add unbound service References: <20240127121040.7156-2-soeren@soeren-tempel.net> In-Reply-To: <20240127121040.7156-2-soeren@soeren-tempel.net> Resent-From: soeren@soeren-tempel.net Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Tue, 07 Jan 2025 18:20:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 68757 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 68757@debbugs.gnu.org Cc: ludo@gnu.org Received: via spool by 68757-submit@debbugs.gnu.org id=B68757.173627398622255 (code B ref 68757); Tue, 07 Jan 2025 18:20:02 +0000 Received: (at 68757) by debbugs.gnu.org; 7 Jan 2025 18:19:46 +0000 Received: from localhost ([127.0.0.1]:44599 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tVEB7-0005mp-AB for submit@debbugs.gnu.org; Tue, 07 Jan 2025 13:19:46 -0500 Received: from magnesium.8pit.net ([45.76.88.171]:4835) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1tVEB3-0005mX-Uq; Tue, 07 Jan 2025 13:19:43 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; s=opensmtpd; bh=c3Ot32by 1+tSeE9T5ZYxeXc5yCJW3CvhUaRBI//bRN0=; h=date:subject:cc:to:from; d=soeren-tempel.net; b=Td9UT2JPIKzvVGjNclufRnzXWPANiah+lsedwjs3UVquX9v hYviTHfVslJT+Tn/eMIfhRTjWPTAWUInuFZWW8aOBavmtMLNBMGGE344/JsDbsFzxPLZiD 0QYCI0l4V2rfaN+fQXC6V3ncCU8Wm6grfueHI/q12HKmrrWpkEQ0LQ= Received: from localhost ( [2a02:560:4d3d:df00:553e:15:d1b3:1cf7]) by magnesium.8pit.net (OpenSMTPD) with ESMTPSA id 64b3f0d3 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:YES); Tue, 7 Jan 2025 19:19:38 +0100 (CET) From: soeren@soeren-tempel.net Date: Tue, 7 Jan 2025 19:17:30 +0100 Message-ID: <20250107181902.3982-1-soeren@soeren-tempel.net> X-Mailer: git-send-email 2.47.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+larch=yhetil.org@gnu.org Sender: guix-patches-bounces+larch=yhetil.org@gnu.org X-Migadu-Country: US X-Migadu-Flow: FLOW_IN X-Migadu-Spam-Score: 4.22 X-Spam-Score: 4.22 X-Migadu-Queue-Id: 2D1459F684 X-Migadu-Scanner: mx10.migadu.com X-TUID: CnstYfvU0q5r From: Sören Tempel This allows using Unbound as a local DNSSEC-enabled resolver. This commit also allows configuration of the Unbound DNS resolver via a Scheme API. The API currently provides very common options and includes an escape hatch to enable less common configurations. A sample configuration, which uses a DoT forwarder, looks as follows: (service unbound-service-type (unbound-configuration (forward-zone (list (unbound-zone (name ".") (forward-addr '("149.112.112.112#dns.quad9.net" "2620:fe::9#dns.quad9.net")) (forward-tls-upstream #t)))))) * gnu/service/dns.scm (unbound-serialize-field): New procedure. * gnu/service/dns.scm (unbound-serialize-alist): New procedure. * gnu/service/dns.scm (unbound-serialize-section): New procedure. * gnu/service/dns.scm (unbound-serialize-string): New procedure. * gnu/service/dns.scm (unbound-serialize-boolean): New procedure. * gnu/service/dns.scm (unbound-serialize-list-of-strings): New procedure. * gnu/service/dns.scm (unbound-zone): New record. * gnu/service/dns.scm (unbound-serialize-unbound-zone): New procedure. * gnu/service/dns.scm (unbound-serialize-list-of-unbound-zone): New procedure. * gnu/service/dns.scm (unbound-remote): New record. * gnu/service/dns.scm (unbound-serialize-unbound-remote): New procedure. * gnu/service/dns.scm (unbound-server): New record. * gnu/service/dns.scm (unbound-serialize-unbound-server): New procedure. * gnu/service/dns.scm (unbound-configuration): New record. * gnu/service/dns.scm (unbound-config-file): New procedure. * gnu/service/dns.scm (unbound-shepherd-service): New procedure. * gnu/service/dns.scm (unbound-account-service): New constant. * gnu/service/dns.scm (unbound-service-type): New services. Signed-off-by: Sören Tempel --- Changes since v1: This revision revises unbound-configuration to use record types with the most common options as record fields instead of association-list, as requested by ludo@. gnu/services/dns.scm | 192 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 191 insertions(+), 1 deletion(-) diff --git a/gnu/services/dns.scm b/gnu/services/dns.scm index 532e20e38a..efef5f0fed 100644 --- a/gnu/services/dns.scm +++ b/gnu/services/dns.scm @@ -3,6 +3,7 @@ ;;; Copyright © 2020 Pierre Langlois ;;; Copyright © 2021 Maxime Devos ;;; Copyright © 2022 Remco van 't Veer +;;; Copyright © 2024 Sören Tempel ;;; ;;; This file is part of GNU Guix. ;;; @@ -52,7 +53,21 @@ (define-module (gnu services dns) knot-resolver-configuration dnsmasq-service-type - dnsmasq-configuration)) + dnsmasq-configuration + + unbound-service-type + unbound-zone + unbound-server + unbound-configuration + unbound-configuration? + unbound-configuration-server + unbound-configuration-remote-control + unbound-configuration-forward-zone + unbound-configuration-stub-zone + unbound-configuration-auth-zone + unbound-configuration-view + unbound-configuration-python + unbound-configuration-dynlib)) ;;; ;;; Knot DNS. @@ -902,3 +917,178 @@ (define dnsmasq-service-type dnsmasq-activation))) (default-value (dnsmasq-configuration)) (description "Run the dnsmasq DNS server."))) + + +;;; +;;; Unbound. +;;; + +(define (unbound-serialize-field field-name value) + (let ((field (object->string field-name)) + (value (cond + ((boolean? value) (if value "yes" "no")) + ((string? value) value) + (else (object->string value))))) + (if (string=? field "extra-content") + #~(string-append #$value "\n") + #~(format #f " ~a: ~a~%" #$field #$value)))) + +(define (unbound-serialize-alist field-name value) + #~(string-append #$@(generic-serialize-alist list + unbound-serialize-field + value))) + +(define (unbound-serialize-section section-name value fields) + #~(format #f "~a:~%~a" + #$(object->string section-name) + #$(serialize-configuration value fields))) + +(define unbound-serialize-string unbound-serialize-field) +(define unbound-serialize-boolean unbound-serialize-field) + +(define-maybe string (prefix unbound-)) +(define-maybe list-of-strings (prefix unbound-)) +(define-maybe boolean (prefix unbound-)) + +(define (unbound-serialize-list-of-strings field-name value) + #~(string-append #$@(map (cut unbound-serialize-string field-name <>) value))) + +(define-configuration unbound-zone + (name + string + "Zone name.") + + (forward-addr + maybe-list-of-strings + "IP address of server to forward to.") + + (forward-tls-upstream + maybe-boolean + "Whether the queries to this forwarder use TLS for transport.") + + (extra-options + (alist '()) + "An association list of options to append.") + + (prefix unbound-)) + +(define (unbound-serialize-unbound-zone field-name value) + (unbound-serialize-section field-name value unbound-zone-fields)) + +(define (unbound-serialize-list-of-unbound-zone field-name value) + #~(string-append #$@(map (cut unbound-serialize-unbound-zone field-name <>) + value))) + +(define list-of-unbound-zone? (list-of unbound-zone?)) + +(define-configuration unbound-remote + (control-enable + maybe-boolean + "Enable remote control.") + + (control-interface + maybe-string + "IP address or local socket path to listen on for remote control.") + + (extra-options + (alist '()) + "An association list of options to append.") + + (prefix unbound-)) + +(define (unbound-serialize-unbound-remote field-name value) + (unbound-serialize-section field-name value unbound-remote-fields)) + +(define-configuration unbound-server + (interface + maybe-list-of-strings + "Interfaces listened on for queries from clients.") + + (hide-version + maybe-boolean + "Refuse the version.server and version.bind queries.") + + (hide-identity + maybe-boolean + "Refuse the id.server and hostname.bind queries.") + + (tls-cert-bundle + maybe-string + "Certificate bundle file, used for DNS over TLS.") + + (extra-options + (alist '()) + "An association list of options to append.") + + (prefix unbound-)) + +(define (unbound-serialize-unbound-server field-name value) + (unbound-serialize-section field-name value unbound-server-fields)) + +(define-configuration unbound-configuration + (server + (unbound-server + (unbound-server + (interface '("127.0.0.1" "::1")) + + (hide-version #t) + (hide-identity #t) + + (tls-cert-bundle "/etc/ssl/certs/ca-certificates.crt"))) + "General options for the Unbound server.") + + (remote-control + (unbound-remote + (unbound-remote + (control-enable #t) + (control-interface "/run/unbound.sock"))) + "Remote control options for the daemon.") + + (forward-zone + (list-of-unbound-zone '()) + "A zone for which queries should be forwarded to another resolver.") + + (extra-content + maybe-string + "Raw content to add to the configuration file.") + + (prefix unbound-)) + +(define (unbound-config-file config) + (mixed-text-file "unbound.conf" + (serialize-configuration + config + unbound-configuration-fields))) + +(define (unbound-shepherd-service config) + (let ((config-file (unbound-config-file config))) + (list (shepherd-service + (documentation "Unbound daemon.") + (provision '(unbound dns)) + (requirement '(networking)) + (actions (list (shepherd-configuration-action config-file))) + (start #~(make-forkexec-constructor + (list (string-append #$unbound "/sbin/unbound") + "-d" "-p" "-c" #$config-file))) + (stop #~(make-kill-destructor)))))) + +(define unbound-account-service + (list (user-group (name "unbound") (system? #t)) + (user-account + (name "unbound") + (group "unbound") + (system? #t) + (comment "Unbound daemon user") + (home-directory "/var/empty") + (shell "/run/current-system/profile/sbin/nologin")))) + +(define unbound-service-type + (service-type (name 'unbound) + (description "Run the unbound DNS resolver.") + (extensions + (list (service-extension account-service-type + (const unbound-account-service)) + (service-extension shepherd-root-service-type + unbound-shepherd-service))) + (compose concatenate) + (default-value (unbound-configuration))))