From 2145dbc4fcd3c512bb7ec6e0826fa3d2d2e80c4c Mon Sep 17 00:00:00 2001 From: pennae Date: Sat, 14 May 2022 07:54:19 +0200 Subject: [PATCH 1/2] nixos/mosquitto: add missing listener option bind_interface we expose it under settings instead of at the listener toplevel because mosquitto seems to pick the addresses it will listen on nondeterministically from the set of addresses configured on the interface being bound to. encouraging its use by putting it into the toplevel options for a listener seems inadvisable. --- .../modules/services/networking/mosquitto.nix | 4 ++- nixos/tests/mosquitto.nix | 28 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/nixos/modules/services/networking/mosquitto.nix b/nixos/modules/services/networking/mosquitto.nix index b41a2fd27be..1b61a3ee599 100644 --- a/nixos/modules/services/networking/mosquitto.nix +++ b/nixos/modules/services/networking/mosquitto.nix @@ -199,6 +199,7 @@ let allow_anonymous = 1; allow_zero_length_clientid = 1; auto_id_prefix = 1; + bind_interface = 1; cafile = 1; capath = 1; certfile = 1; @@ -629,9 +630,10 @@ in ])); RemoveIPC = true; RestrictAddressFamilies = [ - "AF_UNIX" # for sd_notify() call + "AF_UNIX" "AF_INET" "AF_INET6" + "AF_NETLINK" ]; RestrictNamespaces = true; RestrictRealtime = true; diff --git a/nixos/tests/mosquitto.nix b/nixos/tests/mosquitto.nix index 36cc8e3e3d9..d516d3373d9 100644 --- a/nixos/tests/mosquitto.nix +++ b/nixos/tests/mosquitto.nix @@ -4,6 +4,7 @@ let port = 1888; tlsPort = 1889; anonPort = 1890; + bindTestPort = 1891; password = "VERY_secret"; hashedPassword = "$7$101$/WJc4Mp+I+uYE9sR$o7z9rD1EYXHPwEP5GqQj6A7k4W1yVbePlb8TqNcuOLV9WNCiDgwHOB0JHC1WCtdkssqTBduBNUnUGd6kmZvDSw=="; topic = "test/foo"; @@ -125,6 +126,10 @@ in { }; }; } + { + settings.bind_interface = "eth0"; + port = bindTestPort; + } ]; }; }; @@ -134,6 +139,8 @@ in { }; testScript = '' + import json + def mosquitto_cmd(binary, user, topic, port): return ( "mosquitto_{} " @@ -162,6 +169,27 @@ in { start_all() server.wait_for_unit("mosquitto.service") + with subtest("bind_interface"): + addrs = dict() + for iface in json.loads(server.succeed("ip -json address show")): + for addr in iface['addr_info']: + # don't want to deal with multihoming here + assert addr['local'] not in addrs + addrs[addr['local']] = (iface['ifname'], addr['family']) + + # mosquitto grabs *one* random address per type for bind_interface + (has4, has6) = (False, False) + for line in server.succeed("ss -HlptnO sport = ${toString bindTestPort}").splitlines(): + items = line.split() + if "mosquitto" not in items[5]: continue + listener = items[3].rsplit(':', maxsplit=1)[0].strip('[]') + assert listener in addrs + assert addrs[listener][0] == "eth0" + has4 |= addrs[listener][1] == 'inet' + has6 |= addrs[listener][1] == 'inet6' + assert has4 + assert has6 + with subtest("check passwords"): client1.succeed(publish("-m test", "password_store")) client1.succeed(publish("-m test", "password_file")) From c1115d37ffd4f947dd110c1bfc8f1593eaa07928 Mon Sep 17 00:00:00 2001 From: pennae Date: Sat, 14 May 2022 08:01:30 +0200 Subject: [PATCH 2/2] nixos/mosquitto: fix attribute path display in assertions --- nixos/modules/services/networking/mosquitto.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nixos/modules/services/networking/mosquitto.nix b/nixos/modules/services/networking/mosquitto.nix index 1b61a3ee599..256d9457d39 100644 --- a/nixos/modules/services/networking/mosquitto.nix +++ b/nixos/modules/services/networking/mosquitto.nix @@ -296,7 +296,7 @@ let }; listenerAsserts = prefix: listener: - assertKeysValid prefix freeformListenerKeys listener.settings + assertKeysValid "${prefix}.settings" freeformListenerKeys listener.settings ++ userAsserts prefix listener.users ++ imap0 (i: v: authAsserts "${prefix}.authPlugins.${toString i}" v) @@ -398,7 +398,7 @@ let }; bridgeAsserts = prefix: bridge: - assertKeysValid prefix freeformBridgeKeys bridge.settings + assertKeysValid "${prefix}.settings" freeformBridgeKeys bridge.settings ++ [ { assertion = length bridge.addresses > 0; message = "Bridge ${prefix} needs remote broker addresses"; @@ -527,7 +527,7 @@ let globalAsserts = prefix: cfg: flatten [ - (assertKeysValid prefix freeformGlobalKeys cfg.settings) + (assertKeysValid "${prefix}.settings" freeformGlobalKeys cfg.settings) (imap0 (n: l: listenerAsserts "${prefix}.listener.${toString n}" l) cfg.listeners) (mapAttrsToList (n: b: bridgeAsserts "${prefix}.bridge.${n}" b) cfg.bridges) ];