ulogd: add support for multiple logging stacks

fixes #244469
This commit is contained in:
Philippe Hürlimann 2023-09-18 00:09:25 +02:00
parent fdebb755af
commit 7ae1eab886
5 changed files with 126 additions and 89 deletions

View file

@ -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";
};
};

View file

@ -830,7 +830,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 {};

View file

@ -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}"
'';
})

View file

@ -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;
})

View file

@ -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}"