diff --git a/nixos/doc/manual/from_md/release-notes/rl-2305.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2305.section.xml index 4837b29c585a..82f1751de1c3 100644 --- a/nixos/doc/manual/from_md/release-notes/rl-2305.section.xml +++ b/nixos/doc/manual/from_md/release-notes/rl-2305.section.xml @@ -67,6 +67,14 @@ <link xlink:href="options.html#opt-services.v2raya.enable">services.v2raya</link>. </para> </listitem> + <listitem> + <para> + <link xlink:href="https://www.netfilter.org/projects/ulogd/index.html">ulogd</link>, + a userspace logging daemon for netfilter/iptables related + logging. Available as + <link xlink:href="options.html#opt-services.ulogd.enable">services.ulogd</link>. + </para> + </listitem> </itemizedlist> </section> <section xml:id="sec-release-23.05-incompatibilities"> diff --git a/nixos/doc/manual/release-notes/rl-2305.section.md b/nixos/doc/manual/release-notes/rl-2305.section.md index b3354eec65fb..503ce59f6c40 100644 --- a/nixos/doc/manual/release-notes/rl-2305.section.md +++ b/nixos/doc/manual/release-notes/rl-2305.section.md @@ -26,6 +26,8 @@ In addition to numerous new and upgraded packages, this release has the followin - [v2rayA](https://v2raya.org), a Linux web GUI client of Project V which supports V2Ray, Xray, SS, SSR, Trojan and Pingtunnel. Available as [services.v2raya](options.html#opt-services.v2raya.enable). +- [ulogd](https://www.netfilter.org/projects/ulogd/index.html), a userspace logging daemon for netfilter/iptables related logging. Available as [services.ulogd](options.html#opt-services.ulogd.enable). + ## Backward Incompatibilities {#sec-release-23.05-incompatibilities} <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. --> diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index a1e7cf01882e..0c840a5d7ab8 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -520,6 +520,7 @@ ./services/logging/syslog-ng.nix ./services/logging/syslogd.nix ./services/logging/vector.nix + ./services/logging/ulogd.nix ./services/mail/clamsmtp.nix ./services/mail/davmail.nix ./services/mail/dkimproxy-out.nix diff --git a/nixos/modules/services/logging/ulogd.nix b/nixos/modules/services/logging/ulogd.nix new file mode 100644 index 000000000000..065032b531c6 --- /dev/null +++ b/nixos/modules/services/logging/ulogd.nix @@ -0,0 +1,48 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.services.ulogd; + settingsFormat = pkgs.formats.ini { }; + settingsFile = settingsFormat.generate "ulogd.conf" cfg.settings; +in { + options = { + services.ulogd = { + enable = mkEnableOption (lib.mdDoc "ulogd"); + + settings = mkOption { + example = { + global.stack = "stack=log1:NFLOG,base1:BASE,pcap1:PCAP"; + log1.group = 2; + pcap1 = { + file = "/var/log/ulogd.pcap"; + sync = 1; + }; + }; + type = settingsFormat.type; + default = { }; + 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)"; + }; + }; + }; + + config = mkIf cfg.enable { + systemd.services.ulogd = { + description = "Ulogd Daemon"; + wantedBy = [ "multi-user.target" ]; + wants = [ "network-pre.target" ]; + before = [ "network-pre.target" ]; + + serviceConfig = { + 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 e385dfebebf3..25f8994b131b 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -681,6 +681,7 @@ in { tuxguitar = handleTest ./tuxguitar.nix {}; ucarp = handleTest ./ucarp.nix {}; udisks2 = handleTest ./udisks2.nix {}; + ulogd = handleTest ./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 new file mode 100644 index 000000000000..ce52d855ffc2 --- /dev/null +++ b/nixos/tests/ulogd.nix @@ -0,0 +1,84 @@ +import ./make-test-python.nix ({ pkgs, lib, ... }: { + name = "ulogd"; + + meta = with lib; { + maintainers = with 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/pkgs/os-specific/linux/ulogd/default.nix b/pkgs/os-specific/linux/ulogd/default.nix index fb5fd465f1f3..cb48d20043fd 100644 --- a/pkgs/os-specific/linux/ulogd/default.nix +++ b/pkgs/os-specific/linux/ulogd/default.nix @@ -1,6 +1,6 @@ { stdenv, lib, fetchurl, gnumake, libnetfilter_acct, libnetfilter_conntrack , libnetfilter_log, libmnl, libnfnetlink, automake, autoconf, autogen, libtool -, pkg-config, libpcap, linuxdoc-tools, autoreconfHook }: +, pkg-config, libpcap, linuxdoc-tools, autoreconfHook, nixosTests }: stdenv.mkDerivation rec { version = "2.0.8"; @@ -49,6 +49,8 @@ stdenv.mkDerivation rec { linuxdoc-tools ]; + passthru.tests = { inherit (nixosTests) ulogd; }; + meta = with lib; { description = "Userspace logging daemon for netfilter/iptables";