xref: /freebsd/usr.sbin/syslogd/tests/syslogd_test.sh (revision 96190b4fef3b4a0cc3ca0606b0c4e3e69a5e6717)
1#-
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2021, 2023 The FreeBSD Foundation
5#
6# This software was developed by Mark Johnston under sponsorship from
7# the FreeBSD Foundation.
8#
9# This software was developed by Jake Freeland under sponsorship from
10# the FreeBSD Foundation.
11#
12
13# Tests to-do:
14# actions: hostname, users
15
16readonly SYSLOGD_UDP_PORT="5140"
17readonly SYSLOGD_CONFIG="${PWD}/syslog.conf"
18readonly SYSLOGD_LOCAL_SOCKET="${PWD}/log.sock"
19readonly SYSLOGD_PIDFILE="${PWD}/syslogd.pid"
20readonly SYSLOGD_LOCAL_PRIVSOCKET="${PWD}/logpriv.sock"
21
22# Start a private syslogd instance.
23syslogd_start()
24{
25    local jail
26
27    if [ "$1" = "-j" ]; then
28        jail="jexec $2"
29        shift 2
30    fi
31    $jail syslogd \
32        -b ":${SYSLOGD_UDP_PORT}" \
33        -C \
34        -d \
35        -f "${SYSLOGD_CONFIG}" \
36        -H \
37        -p "${SYSLOGD_LOCAL_SOCKET}" \
38        -P "${SYSLOGD_PIDFILE}" \
39        -S "${SYSLOGD_LOCAL_PRIVSOCKET}" \
40        $@ \
41        &
42
43    # Give syslogd a bit of time to spin up.
44    while [ "$((i+=1))" -le 20 ]; do
45        [ -S "${SYSLOGD_LOCAL_SOCKET}" ] && return
46        sleep 0.1
47    done
48    atf_fail "timed out waiting for syslogd to start"
49}
50
51# Simple logger(1) wrapper.
52syslogd_log()
53{
54    atf_check -s exit:0 -o empty -e empty logger $*
55}
56
57# Make syslogd reload its configuration file.
58syslogd_reload()
59{
60    pkill -HUP -F "${SYSLOGD_PIDFILE}"
61}
62
63# Stop a private syslogd instance.
64syslogd_stop()
65{
66    pid=$(cat "${SYSLOGD_PIDFILE}")
67    if pkill -F "${SYSLOGD_PIDFILE}"; then
68        wait "${pid}"
69        rm -f "${SYSLOGD_PIDFILE}" "${SYSLOGD_LOCAL_SOCKET}" \
70            "${SYSLOGD_LOCAL_PRIVSOCKET}"
71    fi
72}
73
74atf_test_case "basic" "cleanup"
75basic_head()
76{
77    atf_set descr "Messages are logged via supported transports"
78}
79basic_body()
80{
81    logfile="${PWD}/basic.log"
82    printf "user.debug\t${logfile}\n" > "${SYSLOGD_CONFIG}"
83    syslogd_start
84
85    syslogd_log -p user.debug -t basic -h "${SYSLOGD_LOCAL_SOCKET}" \
86        "hello, world (unix)"
87    atf_check -s exit:0 -o match:"basic: hello, world \(unix\)" \
88        tail -n 1 "${logfile}"
89
90    # Grab kernel configuration file.
91    sysctl kern.conftxt > conf.txt
92
93    # We have INET transport; make sure we can use it.
94    if grep -qw "INET" conf.txt; then
95        syslogd_log -4 -p user.debug -t basic -h 127.0.0.1 -P "${SYSLOGD_UDP_PORT}" \
96            "hello, world (v4)"
97        atf_check -s exit:0 -o match:"basic: hello, world \(v4\)" \
98            tail -n 1 "${logfile}"
99    fi
100    # We have INET6 transport; make sure we can use it.
101    if grep -qw "INET6" conf.txt; then
102        syslogd_log -6 -p user.debug -t basic -h ::1 -P "${SYSLOGD_UDP_PORT}" \
103            "hello, world (v6)"
104        atf_check -s exit:0 -o match:"basic: hello, world \(v6\)" \
105            tail -n 1 "${logfile}"
106    fi
107}
108basic_cleanup()
109{
110    syslogd_stop
111}
112
113atf_test_case "reload" "cleanup"
114reload_head()
115{
116    atf_set descr "SIGHUP correctly refreshes configuration"
117}
118reload_body()
119{
120    logfile="${PWD}/reload.log"
121    printf "user.debug\t/${logfile}\n" > "${SYSLOGD_CONFIG}"
122    syslogd_start
123
124    syslogd_log -p user.debug -t reload -h "${SYSLOGD_LOCAL_SOCKET}" \
125        "pre-reload"
126    atf_check -s exit:0 -o match:"reload: pre-reload" tail -n 1 "${logfile}"
127
128    # Override the old rule.
129    truncate -s 0 "${logfile}"
130    printf "news.debug\t${logfile}\n" > "${SYSLOGD_CONFIG}"
131    syslogd_reload
132
133    syslogd_log -p user.debug -t reload -h "${SYSLOGD_LOCAL_SOCKET}" \
134        "post-reload user"
135    syslogd_log -p news.debug -t reload -h "${SYSLOGD_LOCAL_SOCKET}" \
136        "post-reload news"
137    atf_check -s exit:0 -o not-match:"reload: post-reload user" cat ${logfile}
138    atf_check -s exit:0 -o match:"reload: post-reload news" cat ${logfile}
139}
140reload_cleanup()
141{
142    syslogd_stop
143}
144
145atf_test_case "prog_filter" "cleanup"
146prog_filter_head()
147{
148    atf_set descr "Messages are only received from programs in the filter"
149}
150prog_filter_body()
151{
152    logfile="${PWD}/prog_filter.log"
153    printf "!prog1,prog2\nuser.debug\t${logfile}\n" > "${SYSLOGD_CONFIG}"
154    syslogd_start
155
156    for i in 1 2 3; do
157        syslogd_log -p user.debug -t "prog${i}" -h "${SYSLOGD_LOCAL_SOCKET}" \
158            "hello this is prog${i}"
159    done
160    atf_check -s exit:0 -o match:"prog1: hello this is prog1" cat "${logfile}"
161    atf_check -s exit:0 -o match:"prog2: hello this is prog2" cat "${logfile}"
162    atf_check -s exit:0 -o not-match:"prog3: hello this is prog3" cat "${logfile}"
163
164    # Override the old rule.
165    truncate -s 0 ${logfile}
166    printf "!-prog1,prog2\nuser.debug\t${logfile}\n" > "${SYSLOGD_CONFIG}"
167    syslogd_reload
168
169    for i in 1 2 3; do
170        syslogd_log -p user.debug -t "prog${i}" -h "${SYSLOGD_LOCAL_SOCKET}" \
171            "hello this is prog${i}"
172    done
173    atf_check -s exit:0 -o not-match:"prog1: hello this is prog1" cat "${logfile}"
174    atf_check -s exit:0 -o not-match:"prog2: hello this is prog2" cat "${logfile}"
175    atf_check -s exit:0 -o match:"prog3: hello this is prog3" cat "${logfile}"
176}
177prog_filter_cleanup()
178{
179    syslogd_stop
180}
181
182atf_test_case "host_filter" "cleanup"
183host_filter_head()
184{
185    atf_set descr "Messages are only received from hostnames in the filter"
186}
187host_filter_body()
188{
189    logfile="${PWD}/host_filter.log"
190    printf "+host1,host2\nuser.debug\t${logfile}\n" > "${SYSLOGD_CONFIG}"
191    syslogd_start
192
193    for i in 1 2 3; do
194        syslogd_log -p user.debug -t "host${i}" -H "host${i}" \
195            -h "${SYSLOGD_LOCAL_SOCKET}" "hello this is host${i}"
196    done
197    atf_check -s exit:0 -o match:"host1: hello this is host1" cat "${logfile}"
198    atf_check -s exit:0 -o match:"host2: hello this is host2" cat "${logfile}"
199    atf_check -s exit:0 -o not-match:"host3: hello this is host3" cat "${logfile}"
200
201    # Override the old rule.
202    truncate -s 0 ${logfile}
203    printf "\-host1,host2\nuser.debug\t${logfile}\n" > "${SYSLOGD_CONFIG}"
204    syslogd_reload
205
206    for i in 1 2 3; do
207        syslogd_log -p user.debug -t "host${i}" -H "host${i}" \
208        -h "${SYSLOGD_LOCAL_SOCKET}" "hello this is host${i}"
209    done
210    atf_check -s exit:0 -o not-match:"host1: hello this is host1" cat "${logfile}"
211    atf_check -s exit:0 -o not-match:"host2: hello this is host2" cat "${logfile}"
212    atf_check -s exit:0 -o match:"host3: hello this is host3" cat "${logfile}"
213}
214host_filter_cleanup()
215{
216    syslogd_stop
217}
218
219atf_test_case "prop_filter" "cleanup"
220prop_filter_head()
221{
222    atf_set descr "Messages are received based on conditions in the propery based filter"
223}
224prop_filter_body()
225{
226    logfile="${PWD}/prop_filter.log"
227    printf ":msg,contains,\"FreeBSD\"\nuser.debug\t${logfile}\n" \
228        > "${SYSLOGD_CONFIG}"
229    syslogd_start
230
231    syslogd_log -p user.debug -t "prop1" -h "${SYSLOGD_LOCAL_SOCKET}" "FreeBSD"
232    syslogd_log -p user.debug -t "prop2" -h "${SYSLOGD_LOCAL_SOCKET}" "freebsd"
233    atf_check -s exit:0 -o match:"prop1: FreeBSD" cat "${logfile}"
234    atf_check -s exit:0 -o not-match:"prop2: freebsd" cat "${logfile}"
235
236    truncate -s 0 ${logfile}
237    printf ":msg,!contains,\"FreeBSD\"\nuser.debug\t${logfile}\n" \
238        > "${SYSLOGD_CONFIG}"
239    syslogd_reload
240
241    syslogd_log -p user.debug -t "prop1" -h "${SYSLOGD_LOCAL_SOCKET}" "FreeBSD"
242    syslogd_log -p user.debug -t "prop2" -h "${SYSLOGD_LOCAL_SOCKET}" "freebsd"
243    atf_check -s exit:0 -o not-match:"prop1: FreeBSD" cat "${logfile}"
244    atf_check -s exit:0 -o match:"prop2: freebsd" cat "${logfile}"
245
246    truncate -s 0 ${logfile}
247    printf ":msg,icase_contains,\"FreeBSD\"\nuser.debug\t${logfile}\n" \
248        > "${SYSLOGD_CONFIG}"
249    syslogd_reload
250
251    syslogd_log -p user.debug -t "prop1" -h "${SYSLOGD_LOCAL_SOCKET}" "FreeBSD"
252    syslogd_log -p user.debug -t "prop2" -h "${SYSLOGD_LOCAL_SOCKET}" "freebsd"
253    atf_check -s exit:0 -o match:"prop1: FreeBSD" cat "${logfile}"
254    atf_check -s exit:0 -o match:"prop2: freebsd" cat "${logfile}"
255
256    truncate -s 0 ${logfile}
257    printf ":msg,!icase_contains,\"FreeBSD\"\nuser.debug\t${logfile}\n" \
258        > "${SYSLOGD_CONFIG}"
259    syslogd_reload
260
261    syslogd_log -p user.debug -t "prop1" -h "${SYSLOGD_LOCAL_SOCKET}" "FreeBSD"
262    syslogd_log -p user.debug -t "prop2" -h "${SYSLOGD_LOCAL_SOCKET}" "freebsd"
263    syslogd_log -p user.debug -t "prop3" -h "${SYSLOGD_LOCAL_SOCKET}" "Solaris"
264    atf_check -s exit:0 -o not-match:"prop1: FreeBSD" cat "${logfile}"
265    atf_check -s exit:0 -o not-match:"prop2: freebsd" cat "${logfile}"
266    atf_check -s exit:0 -o match:"prop3: Solaris" cat "${logfile}"
267}
268prop_filter_cleanup()
269{
270    syslogd_stop
271}
272
273atf_test_case "pipe_action" "cleanup"
274pipe_action_head()
275{
276    atf_set descr "The pipe action evaluates provided command in sh(1)"
277}
278pipe_action_body()
279{
280    logfile="${PWD}/pipe_action.log"
281    printf "\"While I'm digging in the tunnel, the elves will often come to me \
282        with solutions to my problem.\"\n-Saymore Crey" > ${logfile}
283
284    printf "!pipe\nuser.debug\t| sed -i '' -e 's/Saymore Crey/Seymour Cray/g' \
285        ${logfile}\n" > "${SYSLOGD_CONFIG}"
286    syslogd_start
287
288    syslogd_log -p user.debug -t "pipe" -h "${SYSLOGD_LOCAL_SOCKET}" \
289        "fix spelling error"
290    atf_check -s exit:0 -o match:"Seymour Cray" cat "${logfile}"
291}
292pipe_action_cleanup()
293{
294    syslogd_stop
295}
296
297atf_test_case "jail_noinet" "cleanup"
298jail_noinet_head()
299{
300    atf_set descr "syslogd -ss can be run in a jail without INET support"
301    atf_set require.user root
302}
303jail_noinet_body()
304{
305    local logfile
306
307    atf_check jail -c name=syslogd_noinet persist
308
309    logfile="${PWD}/jail_noinet.log"
310    printf "user.debug\t${logfile}\n" > "${SYSLOGD_CONFIG}"
311    syslogd_start -j syslogd_noinet -ss
312
313    syslogd_log -p user.debug -t "test" -h "${SYSLOGD_LOCAL_SOCKET}" \
314        "hello, world"
315    atf_check -s exit:0 -o match:"test: hello, world" cat "${logfile}"
316}
317jail_noinet_cleanup()
318{
319    jail -r syslogd_noinet
320}
321
322atf_init_test_cases()
323{
324    atf_add_test_case "basic"
325    atf_add_test_case "reload"
326    atf_add_test_case "prog_filter"
327    atf_add_test_case "host_filter"
328    atf_add_test_case "prop_filter"
329    atf_add_test_case "pipe_action"
330    atf_add_test_case "jail_noinet"
331}
332