Unverified Commit abffff44 authored by Martin Weinelt's avatar Martin Weinelt Committed by GitHub
Browse files

nixos/getaddrinfo: init (#413986)

parents c8a2be1d f1eed27d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@

- [FileBrowser](https://filebrowser.org/), a web application for managing and sharing files. Available as [services.filebrowser](#opt-services.filebrowser.enable).

- Options under [networking.getaddrinfo](#opt-networking.getaddrinfo.enable) are now allowed to declaratively configure address selection and sorting behavior of `getaddrinfo` in dual-stack networks.

- [LACT](https://github.com/ilya-zlobintsev/LACT), a GPU monitoring and configuration tool, can now be enabled through [services.lact.enable](#opt-services.lact.enable).
  Note that for LACT to work properly on AMD GPU systems, you need to enable [hardware.amdgpu.overdrive.enable](#opt-hardware.amdgpu.overdrive.enable).

+120 −0
Original line number Diff line number Diff line
{
  pkgs,
  lib,
  config,
  ...
}:
let
  cfg = config.networking.getaddrinfo;

  formatTableEntries =
    tableName: table:
    if table == null then
      [ ]
    else
      lib.mapAttrsToList (cidr: val: "${tableName} ${cidr} ${toString val}") table;

  gaiConfText = lib.concatStringsSep "\n" (
    [
      "# Generated by NixOS module networking.getaddrinfo"
      "# Do not edit manually!"
      "reload ${if cfg.reload then "yes" else "no"}"
    ]
    ++ formatTableEntries "label" cfg.label
    ++ formatTableEntries "precedence" cfg.precedence
    ++ formatTableEntries "scopev4" cfg.scopev4
  );
in
{
  options.networking.getaddrinfo = {
    enable = lib.mkOption {
      type = lib.types.bool;
      default = pkgs.stdenv.hostPlatform.libc == "glibc";
      defaultText = lib.literalExpression ''
        pkgs.stdenv.hostPlatform.libc == "glibc"
      '';
      description = ''
        Enables custom address sorting configuration for {manpage}`getaddrinfo(3)` according to RFC 3484.

        This option generates a {file}`/etc/gai.conf` file to override the default address sorting tables,
        as described in {manpage}`gai.conf(5)`.

        This setting is only applicable when using the GNU C Library (glibc).
        It has no effect with other libc implementations.
      '';
    };

    reload = lib.mkOption {
      type = lib.types.bool;
      default = false;
      description = ''
        Determines whether a process should detect changes to the configuration file since it was last read.

        If enabled, the file is re-read automatically. This may cause issues in multithreaded applications
        and is generally discouraged.
      '';
    };

    label = lib.mkOption {
      type = lib.types.nullOr (lib.types.attrsOf lib.types.int);
      default = null;
      description = ''
        Adds entries to the label table, as described in section 2.1 of RFC 3484.

        If any label entries are provided, the glibc’s default label table is ignored.
      '';
      example = {
        "::/0" = 1;
        "2002::/16" = 2;
        "::/96" = 3;
        "::ffff:0:0/96" = 4;
        "fec0::/10" = 5;
        "fc00::/7" = 6;
        "2001:0::/32" = 7;
      };
    };

    precedence = lib.mkOption {
      type = lib.types.nullOr (lib.types.attrsOf lib.types.int);
      default = null;
      description = ''
        Similar to {option}`networking.getaddrinfo.label`, but this option
        defines entries for the precedence table instead.

        See sections 2.1 and 10.3 of RFC 3484 for details.

        Providing any value will disable the glibc's default precedence table.
      '';
      example = {
        "::1/128" = 50;
        "::/0" = 40;
        "2002::/16" = 30;
        "::/96" = 20;
        "::ffff:0:0/96" = 10;
      };
    };

    scopev4 = lib.mkOption {
      type = lib.types.nullOr (lib.types.attrsOf lib.types.int);
      default = null;
      description = ''
        Adds custom rules to the IPv4 scope table.

        By default, the scope IDs described in section 3.2 of RFC 6724 are used.

        Modifying these values is rarely necessary.
      '';
      example = {
        "::ffff:169.254.0.0/112" = 2;
        "::ffff:127.0.0.0/104" = 2;
        "::ffff:0.0.0.0/96" = 14;
      };
    };
  };

  config = lib.mkIf cfg.enable {
    environment.etc."gai.conf".text = gaiConfText;
  };

  meta.maintainers = with lib.maintainers; [ moraxyc ];
}
+1 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
  ./config/fonts/fontdir.nix
  ./config/fonts/ghostscript.nix
  ./config/fonts/packages.nix
  ./config/getaddrinfo.nix
  ./config/gtk/gtk-icon-cache.nix
  ./config/i18n.nix
  ./config/iproute2.nix
+1 −0
Original line number Diff line number Diff line
@@ -537,6 +537,7 @@ in
  gancio = runTest ./gancio.nix;
  garage = handleTest ./garage { };
  gatus = runTest ./gatus.nix;
  getaddrinfo = runTest ./getaddrinfo.nix;
  gemstash = handleTest ./gemstash.nix { };
  geoclue2 = runTest ./geoclue2.nix;
  geoserver = runTest ./geoserver.nix;
+68 −0
Original line number Diff line number Diff line
{ lib, ... }:
let
  ip4 = "192.0.2.1";
  ip6 = "2001:db8::1";

  precedence = {
    "::1/128" = 50;
    "::/0" = 40;
    "2002::/16" = 30;
    "::/96" = 20;
    "::ffff:0:0/96" = 100;
  };
in
{
  name = "getaddrinfo";
  meta.maintainers = with lib.maintainers; [ moraxyc ];

  nodes.server = _: {
    networking.firewall.enable = false;
    networking.useDHCP = false;

    services.dnsmasq = {
      enable = true;
      settings = {
        address = [
          "/nixos.test/${ip4}"
          "/nixos.test/${ip6}"
        ];
      };
    };
  };

  nodes.client =
    { pkgs, nodes, ... }:
    {
      networking.nameservers = [
        (lib.head nodes.server.networking.interfaces.eth1.ipv4.addresses).address
      ];
      networking.getaddrinfo = {
        reload = true;
        inherit precedence;
      };
      networking.useDHCP = false;
      environment.systemPackages = [
        (pkgs.writers.writePython3Bin "request-addr" { } ''
          import socket

          results = socket.getaddrinfo("nixos.test", None)
          print(results[0][4][0])
        '')
      ];
    };

  testScript =
    { ... }:
    ''
      server.wait_for_unit("dnsmasq.service")
      client.wait_for_unit("network.target")

      assert "${ip4}" in client.succeed("request-addr")

      client.succeed("""
        sed 's/100/10/' /etc/gai.conf > /etc/gai.conf.new && \
        mv /etc/gai.conf.new /etc/gai.conf
      """)
      assert "${ip6}" in client.succeed("request-addr")
    '';
}