From b324ef282494280f463a4f549e10363e6abdfdb1 Mon Sep 17 00:00:00 2001 From: Evgeny Kurnevsky Date: Thu, 27 Jul 2023 11:48:44 +0300 Subject: [PATCH] modules/environment/networking: implement /etc/hosts options --- AUTHORS | 1 + CHANGELOG.md | 5 ++ modules/environment/networking.nix | 80 +++++++++++++++++-- .../config-flake-hosts-localhost.cfg.nix | 7 ++ tests/on-device/config-flake-hosts.bats | 37 +++++++++ tests/on-device/config-flake-hosts.cfg.nix | 19 +++++ 6 files changed, 143 insertions(+), 6 deletions(-) create mode 100644 tests/on-device/config-flake-hosts-localhost.cfg.nix create mode 100644 tests/on-device/config-flake-hosts.bats create mode 100644 tests/on-device/config-flake-hosts.cfg.nix diff --git a/AUTHORS b/AUTHORS index b745465a..95a3b729 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,3 +1,4 @@ Alexander Sosedkin Tobias Happ Bruno Bigras +Evgeny Kurnevsky diff --git a/CHANGELOG.md b/CHANGELOG.md index 678b8d20..24418298 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## Release 23.11 (unreleased) +### New Options + +* New options `networking.hosts`, `networking.hostFiles` and + `networking.extraHosts` for `/etc/hosts` configuration. + ## Release 23.05 ### New Options diff --git a/modules/environment/networking.nix b/modules/environment/networking.nix index 61a46ccd..1c16b0f3 100644 --- a/modules/environment/networking.nix +++ b/modules/environment/networking.nix @@ -1,20 +1,91 @@ -# Copyright (c) 2019-2021, see AUTHORS. Licensed under MIT License, see LICENSE. +# Copyright (c) 2019-2023, see AUTHORS. Licensed under MIT License, see LICENSE. + +# Inspired by +# https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/config/networking.nix +# (Copyright (c) 2003-2023 Eelco Dolstra and the Nixpkgs/NixOS contributors, +# licensed under MIT License as well) { config, lib, pkgs, ... }: with lib; +let + cfg = config.networking; + + localhostMultiple = any (elem "localhost") (attrValues (removeAttrs cfg.hosts [ "127.0.0.1" "::1" ])); +in + { ###### interface - options = { }; + options = { + + networking.hosts = lib.mkOption { + type = types.attrsOf (types.listOf types.str); + default = { }; + example = literalExpression '' + { + "127.0.0.1" = [ "foo.bar.baz" ]; + "192.168.0.2" = [ "fileserver.local" "nameserver.local" ]; + }; + ''; + description = lib.mdDoc '' + Locally defined maps of hostnames to IP addresses. + ''; + }; + + networking.hostFiles = lib.mkOption { + type = types.listOf types.path; + defaultText = literalMD "Hosts from {option}`networking.hosts` and {option}`networking.extraHosts`"; + example = literalExpression ''[ "''${pkgs.my-blocklist-package}/share/my-blocklist/hosts" ]''; + description = lib.mdDoc '' + Files that should be concatenated together to form {file}`/etc/hosts`. + ''; + }; + + networking.extraHosts = lib.mkOption { + type = types.lines; + default = ""; + example = "192.168.0.1 lanlocalhost"; + description = lib.mdDoc '' + Additional verbatim entries to be appended to {file}`/etc/hosts`. + For adding hosts from derivation results, use {option}`networking.hostFiles` instead. + ''; + }; + + }; ###### implementation config = { + assertions = [{ + assertion = !localhostMultiple; + message = '' + `networking.hosts` maps "localhost" to something other than "127.0.0.1" + or "::1". This will break some applications. Please use + `networking.extraHosts` if you really want to add such a mapping. + ''; + }]; + + networking.hostFiles = + let + localhostHosts = pkgs.writeText "localhost-hosts" '' + 127.0.0.1 localhost + ::1 localhost + ''; + stringHosts = + let + oneToString = set: ip: ip + " " + concatStringsSep " " set.${ip} + "\n"; + allToString = set: concatMapStrings (oneToString set) (attrNames set); + in + pkgs.writeText "string-hosts" (allToString (filterAttrs (_: v: v != [ ]) cfg.hosts)); + extraHosts = pkgs.writeText "extra-hosts" cfg.extraHosts; + in + mkBefore [ localhostHosts stringHosts extraHosts ]; + environment.etc = { # /etc/services: TCP/UDP port assignments. services.source = pkgs.iana-etc + "/etc/services"; @@ -23,10 +94,7 @@ with lib; protocols.source = pkgs.iana-etc + "/etc/protocols"; # /etc/hosts: Hostname-to-IP mappings. - hosts.text = '' - 127.0.0.1 localhost - ::1 localhost - ''; + hosts.source = pkgs.concatText "hosts" cfg.hostFiles; "resolv.conf".text = '' nameserver 1.1.1.1 diff --git a/tests/on-device/config-flake-hosts-localhost.cfg.nix b/tests/on-device/config-flake-hosts-localhost.cfg.nix new file mode 100644 index 00000000..f32e6e88 --- /dev/null +++ b/tests/on-device/config-flake-hosts-localhost.cfg.nix @@ -0,0 +1,7 @@ +{ pkgs, ... }: + +{ + system.stateVersion = "23.05"; + + networking.hosts."127.0.0.2" = [ "localhost" ]; +} diff --git a/tests/on-device/config-flake-hosts.bats b/tests/on-device/config-flake-hosts.bats new file mode 100644 index 00000000..4625927c --- /dev/null +++ b/tests/on-device/config-flake-hosts.bats @@ -0,0 +1,37 @@ +# Copyright (c) 2023, see AUTHORS. Licensed under MIT License, see LICENSE. + +load lib + +@test 'hosts can be configured' { + # set up / build / activate the configuration + cat "$ON_DEVICE_TESTS_DIR/config-flake-hosts.cfg.nix" \ + > ~/.config/nixpkgs/nix-on-droid.nix + _sed "s|<>|$FLAKE_URL|g" \ + "$ON_DEVICE_TESTS_DIR/config-flake.nix" \ + > ~/.config/nixpkgs/flake.nix + + nix-on-droid switch --flake ~/.config/nixpkgs#device + + # check that /etc/hosts contains configured hosts + for entry in '::1 localhost' \ + '127.0.0.1 localhost' \ + '127.0.0.2 a b' \ + '127.0.0.3 c' \ + '127.0.0.4 d' + do + grep "$entry" /etc/hosts + done +} + +@test 'hosts can not map localhost' { + # set up / build / activate the configuration + cat "$ON_DEVICE_TESTS_DIR/config-flake-hosts-localhost.cfg.nix" \ + > ~/.config/nixpkgs/nix-on-droid.nix + _sed "s|<>|$FLAKE_URL|g" \ + "$ON_DEVICE_TESTS_DIR/config-flake.nix" \ + > ~/.config/nixpkgs/flake.nix + + # check that networking.hosts can't map localhost + run nix-on-droid switch --flake ~/.config/nixpkgs#device + [ "$status" -eq 1 ] +} diff --git a/tests/on-device/config-flake-hosts.cfg.nix b/tests/on-device/config-flake-hosts.cfg.nix new file mode 100644 index 00000000..b2f3ad08 --- /dev/null +++ b/tests/on-device/config-flake-hosts.cfg.nix @@ -0,0 +1,19 @@ +{ pkgs, ... }: + +{ + system.stateVersion = "23.05"; + + networking = { + hosts."127.0.0.2" = [ "a" "b" ]; + + extraHosts = '' + 127.0.0.3 c + ''; + + hostFiles = [ + (pkgs.writeText "hosts" '' + 127.0.0.4 d + '') + ]; + }; +}