1import ../make-test-python.nix ({ lib, pkgs, ... }:
2
3let
4 dnstapSocket = "/var/run/vector/dnstap.sock";
5in
6{
7 name = "vector-dnstap";
8 meta.maintainers = [ pkgs.lib.maintainers.happysalada ];
9
10 nodes = {
11 unbound = { config, pkgs, ... }: {
12 networking.firewall.allowedUDPPorts = [ 53 ];
13
14 services.vector = {
15 enable = true;
16
17 settings = {
18 sources = {
19 dnstap = {
20 type = "dnstap";
21 multithreaded = true;
22 mode = "unix";
23 lowercase_hostnames = true;
24 socket_file_mode = 504;
25 socket_path = "${dnstapSocket}";
26 };
27 };
28
29 sinks = {
30 file = {
31 type = "file";
32 inputs = [ "dnstap" ];
33 path = "/var/lib/vector/logs.log";
34 encoding = { codec = "json"; };
35 };
36 };
37 };
38 };
39
40 systemd.services.vector.serviceConfig = {
41 RuntimeDirectory = "vector";
42 RuntimeDirectoryMode = "0770";
43 };
44
45 services.unbound = {
46 enable = true;
47 enableRootTrustAnchor = false;
48 package = pkgs.unbound-full;
49 settings = {
50 server = {
51 interface = [ "0.0.0.0" "::" ];
52 access-control = [ "192.168.1.0/24 allow" ];
53
54 domain-insecure = "local";
55 private-domain = "local";
56
57 local-zone = "local. static";
58 local-data = [
59 ''"test.local. 10800 IN A 192.168.123.5"''
60 ];
61 };
62
63 dnstap = {
64 dnstap-enable = "yes";
65 dnstap-socket-path = "${dnstapSocket}";
66 dnstap-send-identity = "yes";
67 dnstap-send-version = "yes";
68 dnstap-log-client-query-messages = "yes";
69 dnstap-log-client-response-messages = "yes";
70 };
71 };
72 };
73
74 systemd.services.unbound = {
75 after = [ "vector.service" ];
76 wants = [ "vector.service" ];
77 serviceConfig = {
78 # DNSTAP access
79 ReadWritePaths = [ "/var/run/vector" ];
80 SupplementaryGroups = [ "vector" ];
81 };
82 };
83 };
84
85 dnsclient = { config, pkgs, ... }: {
86 environment.systemPackages = [ pkgs.dig ];
87 };
88 };
89
90 testScript = ''
91 unbound.wait_for_unit("unbound")
92 unbound.wait_for_unit("vector")
93
94 unbound.wait_until_succeeds(
95 "journalctl -o cat -u vector.service | grep 'Socket permissions updated to 0o770'"
96 )
97 unbound.wait_until_succeeds(
98 "journalctl -o cat -u vector.service | grep 'component_type=dnstap' | grep 'Listening... path=\"${dnstapSocket}\"'"
99 )
100
101 unbound.wait_for_file("${dnstapSocket}")
102 unbound.succeed("test 770 -eq $(stat -c '%a' ${dnstapSocket})")
103
104 dnsclient.wait_for_unit("network-online.target")
105 dnsclient.succeed(
106 "dig @unbound test.local"
107 )
108
109 unbound.wait_for_file("/var/lib/vector/logs.log")
110
111 unbound.wait_until_succeeds(
112 "grep ClientQuery /var/lib/vector/logs.log | grep '\"domainName\":\"test.local.\"' | grep '\"rcodeName\":\"NoError\"'"
113 )
114 unbound.wait_until_succeeds(
115 "grep ClientResponse /var/lib/vector/logs.log | grep '\"domainName\":\"test.local.\"' | grep '\"rData\":\"192.168.123.5\"'"
116 )
117 '';
118})