1 /*
2 * Copyright (c) 2012-2018 Balabit
3 * Copyright (c) 2012 Balázs Scheidler
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * As an additional exemption you are allowed to compile & link against the
20 * OpenSSL libraries as published by the OpenSSL project. See the file
21 * COPYING for details.
22 *
23 */
24
25 #include "cr_template.h"
26 #include "timeutils/misc.h"
27 #include "stopwatch.h"
28 #include "logmsg/logmsg.h"
29 #include "gsockaddr.h"
30 #include "cfg.h"
31
32 #include <criterion/criterion.h>
33 #include <string.h>
34
35 #include "msg_parse_lib.h"
36
37 static MsgFormatOptions parse_options;
38
39 void
init_template_tests(void)40 init_template_tests(void)
41 {
42 init_parse_options_and_load_syslogformat(&parse_options);
43 }
44
45 void
deinit_template_tests(void)46 deinit_template_tests(void)
47 {
48 deinit_syslogformat_module();
49 }
50
51 LogMessage *
message_from_list(va_list ap)52 message_from_list(va_list ap)
53 {
54 char *key, *value;
55 LogMessage *msg = create_empty_message();
56
57 if (!msg)
58 return NULL;
59
60 key = va_arg(ap, char *);
61 while (key)
62 {
63 value = va_arg(ap, char *);
64 if (!value)
65 return msg;
66
67 log_msg_set_value_by_name(msg, key, value, -1);
68 key = va_arg(ap, char *);
69 }
70
71 return msg;
72 }
73
74 LogMessage *
create_empty_message(void)75 create_empty_message(void)
76 {
77 LogMessage *msg;
78 const char *msg_str = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]:árvíztűrőtükörfúrógép";
79
80 msg = log_msg_new(msg_str, strlen(msg_str), &parse_options);
81 log_msg_set_saddr_ref(msg, g_sockaddr_inet_new("10.11.12.13", 1010));
82 log_msg_set_daddr_ref(msg, g_sockaddr_inet_new("127.0.0.5", 6514));
83 log_msg_set_match(msg, 0, "whole-match", -1);
84 log_msg_set_match(msg, 1, "first-match", -1);
85 log_msg_set_tag_by_name(msg, "alma");
86 log_msg_set_tag_by_name(msg, "korte");
87 log_msg_clear_tag_by_name(msg, "narancs");
88 log_msg_set_tag_by_name(msg, "citrom");
89 log_msg_set_tag_by_name(msg, "tag,containing,comma");
90 msg->rcptid = 555;
91 msg->host_id = 0xcafebabe;
92 msg->proto = 33;
93
94 /* fix some externally or automatically defined values */
95 log_msg_set_value(msg, LM_V_HOST_FROM, "kismacska", -1);
96 msg->timestamps[LM_TS_RECVD].ut_sec = 1139684315;
97 msg->timestamps[LM_TS_RECVD].ut_usec = 639000;
98 msg->timestamps[LM_TS_RECVD].ut_gmtoff = get_local_timezone_ofs(1139684315);
99
100 return msg;
101 }
102
103 LogMessage *
create_sample_message(void)104 create_sample_message(void)
105 {
106 LogMessage *msg = create_empty_message();
107
108 log_msg_set_value_by_name(msg, "APP.VALUE", "value", -1);
109 log_msg_set_value_by_name(msg, "APP.VALUE2", "value", -1);
110 log_msg_set_value_by_name(msg, "APP.VALUE3", "value", -1);
111 log_msg_set_value_by_name(msg, "APP.VALUE4", "value", -1);
112 log_msg_set_value_by_name(msg, "APP.VALUE5", "value", -1);
113 log_msg_set_value_by_name(msg, "APP.VALUE6", "value", -1);
114 log_msg_set_value_by_name(msg, "APP.VALUE7", "value", -1);
115
116 log_msg_set_value_by_name(msg, "APP.STRIP1", " value", -1);
117 log_msg_set_value_by_name(msg, "APP.STRIP2", "value ", -1);
118 log_msg_set_value_by_name(msg, "APP.STRIP3", " value ", -1);
119 log_msg_set_value_by_name(msg, "APP.STRIP4", "value", -1);
120 log_msg_set_value_by_name(msg, "APP.STRIP5", "", -1);
121 log_msg_set_value_by_name(msg, "APP.QVALUE", "\"value\"", -1);
122 log_msg_set_value_by_name(msg, ".unix.uid", "1000", -1);
123 log_msg_set_value_by_name(msg, ".unix.gid", "1000", -1);
124 log_msg_set_value_by_name(msg, ".unix.cmd", "command", -1);
125 log_msg_set_value_by_name(msg, ".json.foo", "bar", -1);
126 log_msg_set_value_by_name(msg, ".json.sub.value1", "subvalue1", -1);
127 log_msg_set_value_by_name(msg, ".json.sub.value2", "subvalue2", -1);
128 log_msg_set_value_by_name(msg, "escaping", "binary stuff follows \"\xad árvíztűrőtükörfúrógép", -1);
129 log_msg_set_value_by_name(msg, "escaping2", "\xc3", -1);
130 log_msg_set_value_by_name(msg, "null", "binary\0stuff", 12);
131 log_msg_set_value_by_name(msg, "comma_value", "value,with,a,comma", -1);
132 log_msg_set_value_by_name(msg, "empty_value", "", -1);
133 log_msg_set_value_by_name(msg, "template_name", "dummy", -1);
134
135 return msg;
136 }
137
138 LogTemplate *
compile_template(const gchar * template,gboolean escaping)139 compile_template(const gchar *template, gboolean escaping)
140 {
141 LogTemplate *templ = log_template_new(configuration, NULL);
142 gboolean success;
143 GError *error = NULL;
144
145 log_template_set_escape(templ, escaping);
146 success = log_template_compile(templ, template, &error);
147 cr_assert(success, "template expected to compile cleanly,"
148 " but it didn't, template=%s, error=%s",
149 template, error ? error->message : "(none)");
150 g_clear_error(&error);
151
152 return templ;
153 }
154
155 void
assert_template_format_with_escaping_and_context_msgs(const gchar * template,gboolean escaping,const gchar * expected,gssize expected_len,LogMessage ** msgs,gint num_messages)156 assert_template_format_with_escaping_and_context_msgs(const gchar *template, gboolean escaping,
157 const gchar *expected, gssize expected_len,
158 LogMessage **msgs, gint num_messages)
159 {
160 LogTemplate *templ = compile_template(template, escaping);
161 const gchar *prefix = "somevoodooprefix/";
162 gint prefix_len = strlen(prefix);
163 if (!templ)
164 return;
165
166 GString *res = g_string_new(prefix);
167 const gchar *context_id = "test-context-id";
168
169 LogTemplateEvalOptions options = {NULL, LTZ_LOCAL, 999, context_id};
170 log_template_append_format_with_context(templ, msgs, num_messages, &options, res);
171 cr_assert(strncmp(res->str, prefix, prefix_len) == 0,
172 "the prefix was overwritten by the template, template=%s, res=%s, expected_prefix=%s",
173 template, res->str, prefix);
174
175 expected_len = (expected_len >= 0 ? expected_len : strlen(expected));
176 cr_assert_eq(res->len - prefix_len, expected_len,
177 "context template test failed, expected length mismatch, template=%s, actual=%.*s, expected=%.*s",
178 template, (gint) res->len - prefix_len, res->str + prefix_len, (gint) expected_len, expected);
179
180 cr_assert_arr_eq(res->str + prefix_len, expected, expected_len,
181 "context template test failed, template=%s, actual=%.*s, expected=%.*s",
182 template, (gint) res->len - prefix_len, res->str + prefix_len, (gint) expected_len, expected);
183 log_template_unref(templ);
184 g_string_free(res, TRUE);
185 }
186
187 void
assert_template_format_with_context_msgs(const gchar * template,const gchar * expected,LogMessage ** msgs,gint num_messages)188 assert_template_format_with_context_msgs(const gchar *template, const gchar *expected, LogMessage **msgs,
189 gint num_messages)
190 {
191 assert_template_format_with_escaping_and_context_msgs(template, FALSE, expected, -1, msgs, num_messages);
192 }
193
194
195 void
assert_template_format_with_escaping_msg(const gchar * template,gboolean escaping,const gchar * expected,LogMessage * msg)196 assert_template_format_with_escaping_msg(const gchar *template, gboolean escaping,
197 const gchar *expected,
198 LogMessage *msg)
199 {
200 assert_template_format_with_escaping_and_context_msgs(template, escaping, expected, -1, &msg, 1);
201 }
202
203 void
assert_template_format_with_escaping(const gchar * template,gboolean escaping,const gchar * expected)204 assert_template_format_with_escaping(const gchar *template, gboolean escaping, const gchar *expected)
205 {
206 LogMessage *msg = create_sample_message();
207
208 assert_template_format_with_escaping_msg(template, escaping, expected, msg);
209 log_msg_unref(msg);
210 }
211
212 void
assert_template_format_msg(const gchar * template,const gchar * expected,LogMessage * msg)213 assert_template_format_msg(const gchar *template, const gchar *expected, LogMessage *msg)
214 {
215 assert_template_format_with_escaping_msg(template, FALSE, expected, msg);
216 }
217
218 void
assert_template_format(const gchar * template,const gchar * expected)219 assert_template_format(const gchar *template, const gchar *expected)
220 {
221 assert_template_format_with_escaping(template, FALSE, expected);
222 }
223
224 void
assert_template_format_with_context(const gchar * template,const gchar * expected)225 assert_template_format_with_context(const gchar *template, const gchar *expected)
226 {
227 LogMessage *msg;
228 LogMessage *context[2];
229
230 msg = create_sample_message();
231 context[0] = context[1] = msg;
232
233 assert_template_format_with_context_msgs(template, expected, context, 2);
234
235 log_msg_unref(msg);
236 }
237
238 void
assert_template_format_with_len(const gchar * template,const gchar * expected,gssize expected_len)239 assert_template_format_with_len(const gchar *template, const gchar *expected, gssize expected_len)
240 {
241 LogMessage *msg = create_sample_message();
242
243 assert_template_format_with_escaping_and_context_msgs(template, FALSE, expected, expected_len, &msg, 1);
244 log_msg_unref(msg);
245 }
246
247 void
assert_template_failure(const gchar * template,const gchar * expected_error)248 assert_template_failure(const gchar *template, const gchar *expected_error)
249 {
250 LogTemplate *templ = log_template_new(configuration, NULL);
251 GError *error = NULL;
252
253 cr_assert_not(log_template_compile(templ, template, &error),
254 "compilation failure expected to template,"
255 " but success was returned, template=%s, expected_error=%s\n",
256 template, expected_error);
257 cr_assert(strstr(error ? error->message : "", expected_error) != NULL,
258 "FAIL: compilation error doesn't match, error=%s, expected_error=%s\n",
259 error->message, expected_error);
260 g_clear_error(&error);
261 log_template_unref(templ);
262 }
263
264 #define BENCHMARK_COUNT 100000
265
266 void
perftest_template(gchar * template)267 perftest_template(gchar *template)
268 {
269 LogTemplate *templ;
270 LogMessage *msg;
271 GString *res = g_string_sized_new(1024);
272 gint i;
273 GError *error = NULL;
274
275 templ = log_template_new(configuration, NULL);
276 if (!log_template_compile(templ, template, &error))
277 {
278 cr_assert(FALSE, "template expected to compile cleanly,"
279 " but it didn't, template=%s, error=%s",
280 template, error ? error->message : "(none)");
281 return;
282 }
283 msg = create_sample_message();
284
285 start_stopwatch();
286 for (i = 0; i < BENCHMARK_COUNT; i++)
287 {
288 log_template_format(templ, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, res);
289 }
290 stop_stopwatch_and_display_result(BENCHMARK_COUNT,
291 " %-90.*s",
292 (int) strlen(template) - 1,
293 template);
294
295 log_template_unref(templ);
296 g_string_free(res, TRUE);
297 log_msg_unref(msg);
298 }
299