diff --git a/nixos/modules/services/logging/ulogd.nix b/nixos/modules/services/logging/ulogd.nix index 065032b531c6..05c9797bb28b 100644 --- a/nixos/modules/services/logging/ulogd.nix +++ b/nixos/modules/services/logging/ulogd.nix @@ -3,7 +3,7 @@ with lib; let cfg = config.services.ulogd; - settingsFormat = pkgs.formats.ini { }; + settingsFormat = pkgs.formats.ini { listsAsDuplicateKeys = true; }; settingsFile = settingsFormat.generate "ulogd.conf" cfg.settings; in { options = { @@ -12,22 +12,34 @@ in { settings = mkOption { example = { - global.stack = "stack=log1:NFLOG,base1:BASE,pcap1:PCAP"; + global.stack = [ + "log1:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu1:LOGEMU" + "log1:NFLOG,base1:BASE,pcap1:PCAP" + ]; + log1.group = 2; + pcap1 = { - file = "/var/log/ulogd.pcap"; sync = 1; + file = "/var/log/ulogd.pcap"; + }; + + emu1 = { + sync = 1; + file = "/var/log/ulogd_pkts.log"; }; }; type = settingsFormat.type; default = { }; - description = lib.mdDoc "Configuration for ulogd. See {file}`/share/doc/ulogd/` in `pkgs.ulogd.doc`."; + description = lib.mdDoc + "Configuration for ulogd. See {file}`/share/doc/ulogd/` in `pkgs.ulogd.doc`."; }; logLevel = mkOption { type = types.enum [ 1 3 5 7 8 ]; default = 5; - description = lib.mdDoc "Log level (1 = debug, 3 = info, 5 = notice, 7 = error, 8 = fatal)"; + description = lib.mdDoc + "Log level (1 = debug, 3 = info, 5 = notice, 7 = error, 8 = fatal)"; }; }; }; @@ -40,7 +52,10 @@ in { before = [ "network-pre.target" ]; serviceConfig = { - ExecStart = "${pkgs.ulogd}/bin/ulogd -c ${settingsFile} --verbose --loglevel ${toString cfg.logLevel}"; + ExecStart = + "${pkgs.ulogd}/bin/ulogd -c ${settingsFile} --verbose --loglevel ${ + toString cfg.logLevel + }"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; }; }; diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 5b2e12a501bf..92389fdad55a 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -839,7 +839,7 @@ in { typesense = handleTest ./typesense.nix {}; ucarp = handleTest ./ucarp.nix {}; udisks2 = handleTest ./udisks2.nix {}; - ulogd = handleTest ./ulogd.nix {}; + ulogd = handleTest ./ulogd/ulogd.nix {}; unbound = handleTest ./unbound.nix {}; unifi = handleTest ./unifi.nix {}; unit-php = handleTest ./web-servers/unit-php.nix {}; diff --git a/nixos/tests/ulogd.nix b/nixos/tests/ulogd.nix deleted file mode 100644 index d351fdae7983..000000000000 --- a/nixos/tests/ulogd.nix +++ /dev/null @@ -1,82 +0,0 @@ -import ./make-test-python.nix ({ pkgs, lib, ... }: { - name = "ulogd"; - - meta.maintainers = with lib.maintainers; [ p-h ]; - - nodes.machine = { ... }: { - networking.firewall.enable = false; - networking.nftables.enable = true; - networking.nftables.ruleset = '' - table inet filter { - chain input { - type filter hook input priority 0; - log group 2 accept - } - - chain output { - type filter hook output priority 0; policy accept; - log group 2 accept - } - - chain forward { - type filter hook forward priority 0; policy drop; - log group 2 accept - } - - } - ''; - services.ulogd = { - enable = true; - settings = { - global = { - logfile = "/var/log/ulogd.log"; - stack = "log1:NFLOG,base1:BASE,pcap1:PCAP"; - }; - - log1.group = 2; - - pcap1 = { - file = "/var/log/ulogd.pcap"; - sync = 1; - }; - }; - }; - - environment.systemPackages = with pkgs; [ - tcpdump - ]; - }; - - testScript = '' - start_all() - machine.wait_for_unit("ulogd.service") - machine.wait_for_unit("network-online.target") - - with subtest("Ulogd is running"): - machine.succeed("pgrep ulogd >&2") - - # All packets show up twice in the logs - with subtest("Logs are collected"): - machine.succeed("ping -f 127.0.0.1 -c 5 >&2") - machine.succeed("sleep 2") - machine.wait_until_succeeds("du /var/log/ulogd.pcap >&2") - _, echo_request_packets = machine.execute("tcpdump -r /var/log/ulogd.pcap icmp[0] == 8 and host 127.0.0.1") - expected, actual = 5*2, len(echo_request_packets.splitlines()) - assert expected == actual, f"Expected {expected} packets, got: {actual}" - _, echo_reply_packets = machine.execute("tcpdump -r /var/log/ulogd.pcap icmp[0] == 0 and host 127.0.0.1") - expected, actual = 5*2, len(echo_reply_packets.splitlines()) - assert expected == actual, f"Expected {expected} packets, got: {actual}" - - with subtest("Reloading service reopens log file"): - machine.succeed("mv /var/log/ulogd.pcap /var/log/old_ulogd.pcap") - machine.succeed("systemctl reload ulogd.service") - machine.succeed("ping -f 127.0.0.1 -c 5 >&2") - machine.succeed("sleep 2") - _, echo_request_packets = machine.execute("tcpdump -r /var/log/ulogd.pcap icmp[0] == 8 and host 127.0.0.1") - expected, actual = 5*2, len(echo_request_packets.splitlines()) - assert expected == actual, f"Expected {expected} packets, got: {actual}" - _, echo_reply_packets = machine.execute("tcpdump -r /var/log/ulogd.pcap icmp[0] == 0 and host 127.0.0.1") - expected, actual = 5*2, len(echo_reply_packets.splitlines()) - assert expected == actual, f"Expected {expected} packets, got: {actual}" - ''; -}) diff --git a/nixos/tests/ulogd/ulogd.nix b/nixos/tests/ulogd/ulogd.nix new file mode 100644 index 000000000000..0fa92229a100 --- /dev/null +++ b/nixos/tests/ulogd/ulogd.nix @@ -0,0 +1,56 @@ +import ../make-test-python.nix ({ pkgs, lib, ... }: { + name = "ulogd"; + + meta.maintainers = with lib.maintainers; [ p-h ]; + + nodes.machine = { ... }: { + networking.firewall.enable = false; + networking.nftables.enable = true; + networking.nftables.ruleset = '' + table inet filter { + chain input { + type filter hook input priority 0; + icmp type { echo-request, echo-reply } log group 2 accept + } + + chain output { + type filter hook output priority 0; policy accept; + icmp type { echo-request, echo-reply } log group 2 accept + } + + chain forward { + type filter hook forward priority 0; policy drop; + } + + } + ''; + services.ulogd = { + enable = true; + settings = { + global = { + logfile = "/var/log/ulogd.log"; + stack = [ + "log1:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu1:LOGEMU" + "log1:NFLOG,base1:BASE,pcap1:PCAP" + ]; + }; + + log1.group = 2; + + pcap1 = { + sync = 1; + file = "/var/log/ulogd.pcap"; + }; + + emu1 = { + sync = 1; + file = "/var/log/ulogd_pkts.log"; + }; + }; + }; + + environment.systemPackages = with pkgs; [ tcpdump ]; + }; + + testScript = lib.readFile ./ulogd.py; +}) diff --git a/nixos/tests/ulogd/ulogd.py b/nixos/tests/ulogd/ulogd.py new file mode 100644 index 000000000000..d20daa4d733a --- /dev/null +++ b/nixos/tests/ulogd/ulogd.py @@ -0,0 +1,48 @@ +start_all() +machine.wait_for_unit("ulogd.service") +machine.wait_for_unit("network-online.target") + +with subtest("Ulogd is running"): + machine.succeed("pgrep ulogd >&2") + +# All packets show up twice in the logs +with subtest("Logs are collected"): + machine.succeed("ping -f 127.0.0.1 -c 5 >&2") + machine.succeed("sleep 2") + machine.wait_until_succeeds("du /var/log/ulogd.pcap") + _, echo_request_packets = machine.execute("tcpdump -r /var/log/ulogd.pcap icmp[0] == 8 and host 127.0.0.1") + expected, actual = 5 * 2, len(echo_request_packets.splitlines()) + assert expected == actual, f"Expected {expected} ICMP request packets from pcap, got: {actual}" + _, echo_reply_packets = machine.execute("tcpdump -r /var/log/ulogd.pcap icmp[0] == 0 and host 127.0.0.1") + expected, actual = 5 * 2, len(echo_reply_packets.splitlines()) + assert expected == actual, f"Expected {expected} ICMP reply packets from pcap, got: {actual}" + + machine.wait_until_succeeds("du /var/log/ulogd_pkts.log") + _, echo_request_packets = machine.execute("grep TYPE=8 /var/log/ulogd_pkts.log") + expected, actual = 5 * 2, len(echo_request_packets.splitlines()) + assert expected == actual, f"Expected {expected} ICMP request packets from logfile, got: {actual}" + _, echo_reply_packets = machine.execute("grep TYPE=0 /var/log/ulogd_pkts.log") + expected, actual = 5 * 2, len(echo_reply_packets.splitlines()) + assert expected == actual, f"Expected {expected} ICMP reply packets from logfile, got: {actual}" + +with subtest("Reloading service reopens log file"): + machine.succeed("mv /var/log/ulogd.pcap /var/log/old_ulogd.pcap") + machine.succeed("mv /var/log/ulogd_pkts.log /var/log/old_ulogd_pkts.log") + machine.succeed("systemctl reload ulogd.service") + machine.succeed("ping -f 127.0.0.1 -c 5 >&2") + machine.succeed("sleep 2") + machine.wait_until_succeeds("du /var/log/ulogd.pcap") + _, echo_request_packets = machine.execute("tcpdump -r /var/log/ulogd.pcap icmp[0] == 8 and host 127.0.0.1") + expected, actual = 5 * 2, len(echo_request_packets.splitlines()) + assert expected == actual, f"Expected {expected} packets, got: {actual}" + _, echo_reply_packets = machine.execute("tcpdump -r /var/log/ulogd.pcap icmp[0] == 0 and host 127.0.0.1") + expected, actual = 5 * 2, len(echo_reply_packets.splitlines()) + assert expected == actual, f"Expected {expected} packets, got: {actual}" + + machine.wait_until_succeeds("du /var/log/ulogd_pkts.log") + _, echo_request_packets = machine.execute("grep TYPE=8 /var/log/ulogd_pkts.log") + expected, actual = 5 * 2, len(echo_request_packets.splitlines()) + assert expected == actual, f"Expected {expected} ICMP request packets from logfile, got: {actual}" + _, echo_reply_packets = machine.execute("grep TYPE=0 /var/log/ulogd_pkts.log") + expected, actual = 5 * 2, len(echo_reply_packets.splitlines()) + assert expected == actual, f"Expected {expected} ICMP reply packets from logfile, got: {actual}"