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