commit 9214b6481528e14b5c9e19cb7d4b7d0f259aedb3
parent 0334ccd8fbd811a714e12361f33ee8ef75a1ccb2
Author: Kirill Elagin <kirelagin@gmail.com>
Date: Mon, 31 Aug 2020 15:06:03 -0400
parent 0334ccd8fbd811a714e12361f33ee8ef75a1ccb2
Author: Kirill Elagin <kirelagin@gmail.com>
Date: Mon, 31 Aug 2020 15:06:03 -0400
Merge branch 'flake'
7 files changed, 204 insertions(+), 5 deletions(-)
A
|
105
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff --git a/README.md b/README.md @@ -72,8 +72,55 @@ Why? * Modularity: records defined in different modules get magically merged. -Use ----- +## Use + +### Importing + +There are two ways to import `nix-dns`. + +#### As a flake (new way) + +Add it as an input to your flake: + +```nix +# flake.nix + +{ + inputs = { + # ... + + dns = { + url = "github:kirelagin/nix-dns"; + inputs.nixpkgs.follows = "nixpkgs"; # (optionally) + }; + }; + + outputs = { self, nixpkgs, dns }: { + # All functions from `nix-dns` are available in `dns.lib`. + # ... + }; +} +``` + +All examples below assume the old way of importing, but they should work with +just one change: replace `dns` with `dns.lib` everywhere. + +#### Importing directly (old way) + +Always get the latest version from GitHub: + +```nix +let + dns = import (builtins.fetchTarball "https://github.com/kirelagin/nix-dns/archive/master.zip"); +in { + # ... +} +``` + +To make your setup more reliable, you should pin the version used by specifying +a commit hash or using a submodule. This is all a little clumsy and nowadays it +is probably best to simply switch to flakes. + ### In your NixOS configuration
diff --git a/dns/combinators.nix b/dns/combinators.nix @@ -82,4 +82,14 @@ spf = google = "include:_spf.google.com"; }; +dmarc = { + postmarkapp = rua: { + p = "none"; + pct = 100; + inherit rua; + sp = "none"; + aspf = "relaxed"; + }; +}; + }
diff --git a/dns/types/records/DMARC.nix b/dns/types/records/DMARC.nix @@ -0,0 +1,105 @@ +# +# © 2020 Kirill Elagin <kirelagin@gmail.com> +# +# SPDX-License-Identifier: MIT +# + +# This is a “fake” record type, not actually part of DNS. +# It gets compiled down to a TXT record. + +{ pkgs }: + +let + inherit (pkgs) lib; + inherit (lib) mkOption types; + +in + +rec { + rtype = "TXT"; + options = { + adkim = mkOption { + type = types.enum ["relaxed" "strict"]; + default = "relaxed"; + example = "strict"; + description = "DKIM Identifier Alignment mode"; + apply = builtins.substring 0 1; + }; + aspf = mkOption { + type = types.enum ["relaxed" "strict"]; + default = "relaxed"; + example = "strict"; + description = "SPF Identifier Alignment mode"; + apply = builtins.substring 0 1; + }; + fo = mkOption { + type = types.listOf (types.enum ["0" "1" "d" "s"]); + default = ["0"]; + example = ["0" "1" "s"]; + description = "Failure reporting options"; + apply = lib.concatStringsSep ":"; + }; + p = mkOption { + type = types.enum ["none" "quarantine" "reject"]; + example = "quarantine"; + description = "Requested Mail Receiver policy"; + }; + pct = mkOption { + type = types.ints.between 0 100; + default = 100; + example = 30; + description = "Percentage of messages to which the DMARC policy is to be applied"; + apply = builtins.toString; + }; + rf = mkOption { + type = types.listOf (types.enum ["afrf"]); + default = ["afrf"]; + example = ["afrf"]; + description = "Format to be used for message-specific failure reports"; + apply = lib.concatStringsSep ":"; + }; + ri = mkOption { + type = types.ints.unsigned; # FIXME: u32 + default = 86400; + example = 12345; + description = "Interval requested between aggregate reports"; + apply = builtins.toString; + }; + rua = mkOption { + type = types.oneOf [types.str (types.listOf types.str)]; + default = []; + example = "mailto:dmarc+rua@example.com"; + description = "Addresses to which aggregate feedback is to be sent"; + apply = val: # FIXME: need to encode commas in URIs + if builtins.isList val + then lib.concatStringsSep "," val + else val; + }; + ruf = mkOption { + type = types.listOf types.str; + default = []; + example = ["mailto:dmarc+ruf@example.com" "mailto:another+ruf@example.com"]; + description = "Addresses to which message-specific failure information is to be reported"; + apply = val: # FIXME: need to encode commas in URIs + if builtins.isList val + then lib.concatStringsSep "," val + else val; + }; + sp = mkOption { + type = types.nullOr (types.enum ["none" "quarantine" "reject"]); + default = null; + example = "quarantine"; + description = "Requested Mail Receiver policy for all subdomains"; + }; + }; + dataToString = data: + let + items = ["v=DMARC1"] ++ lib.pipe data [ + (builtins.intersectAttrs options) # remove garbage list `_module` + (lib.filterAttrs (_k: v: v != null && v != "")) + (lib.mapAttrsToList (k: v: "${k}=${v}")) + ]; + in ''"${lib.concatStringsSep "; " items + ";"}"''; + nameFixup = name: _self: + "_dmarc.${name}"; +}
diff --git a/dns/types/records/default.nix b/dns/types/records/default.nix @@ -19,6 +19,9 @@ let "SOA" "SRV" "TXT" + + # Pseudo types + "DMARC" ]; in
diff --git a/dns/types/zone.nix b/dns/types/zone.nix @@ -45,9 +45,9 @@ let writeSubzone = name: zone: let - groupToString = subt: - concatMapStringsSep "\n" (writeRecord name subt) (zone."${subt.rtype}"); - groups = map groupToString (attrValues rsubtypes'); + groupToString = pseudo: subt: + concatMapStringsSep "\n" (writeRecord name subt) (zone."${pseudo}"); + groups = mapAttrsToList groupToString rsubtypes'; groups' = filter (s: s != "") groups; writeSubzone' = subname: writeSubzone "${subname}.${name}";
diff --git a/flake.lock b/flake.lock @@ -0,0 +1,25 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1587398327, + "narHash": "sha256-mEKkeLgUrzAsdEaJ/1wdvYn0YZBAKEG3AN21koD2AgU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "5272327b81ed355bbed5659b8d303cf2979b6953", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +}
diff --git a/flake.nix b/flake.nix @@ -0,0 +1,9 @@ +{ + description = "Nix DSL for defining DNS zones"; + + outputs = { self, nixpkgs }: { + + lib = import ./default.nix { pkgs = nixpkgs; }; + + }; +}