1 /*
2  * Copyright (c) 2002-2012 Balabit
3  * Copyright (c) 1998-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 "parser/parser-expr.h"
26 #include "template/templates.h"
27 #include "logmatcher.h"
28 
29 #include <string.h>
30 
31 /* NOTE: consumes template */
32 void
log_parser_set_template(LogParser * self,LogTemplate * template)33 log_parser_set_template(LogParser *self, LogTemplate *template)
34 {
35   log_template_unref(self->template);
36   self->template = template;
37 }
38 
39 gboolean
log_parser_process_message(LogParser * self,LogMessage ** pmsg,const LogPathOptions * path_options)40 log_parser_process_message(LogParser *self, LogMessage **pmsg, const LogPathOptions *path_options)
41 {
42   LogMessage *msg = *pmsg;
43   gboolean success;
44 
45   if (G_LIKELY(!self->template))
46     {
47       NVTable *payload = nv_table_ref(msg->payload);
48       const gchar *value;
49       gssize value_len;
50 
51       /* NOTE: the process function may set values in the LogMessage
52        * instance, which in turn can trigger nv_table_realloc() to be
53        * called.  However in case nv_table_realloc() finds a refcounter > 1,
54        * it'll always _move_ the structure and leave the old one intact,
55        * until its refcounter drops to zero.  If that wouldn't be the case,
56        * nv_table_realloc() could make our payload pointer and the
57        * LM_V_MESSAGE pointer we pass to process() go stale.
58        */
59 
60       value = log_msg_get_value(msg, LM_V_MESSAGE, &value_len);
61       success = self->process(self, pmsg, path_options, value, value_len);
62       nv_table_unref(payload);
63     }
64   else
65     {
66       GString *input = g_string_sized_new(256);
67 
68       log_template_format(self->template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, input);
69       success = self->process(self, pmsg, path_options, input->str, input->len);
70       g_string_free(input, TRUE);
71     }
72 
73   if (!success)
74     stats_counter_inc(self->super.discarded_messages);
75 
76   return success;
77 }
78 
79 static void
log_parser_queue(LogPipe * s,LogMessage * msg,const LogPathOptions * path_options)80 log_parser_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options)
81 {
82   LogParser *self = (LogParser *) s;
83   gboolean success;
84   gchar *parser_result;
85 
86   msg_trace(">>>>>> parser rule evaluation begin",
87             evt_tag_str("rule", self->name),
88             log_pipe_location_tag(s),
89             evt_tag_printf("msg", "%p", msg));
90 
91   success = log_parser_process_message(self, &msg, path_options);
92 
93   if (success)
94     {
95       parser_result = "Forwarding message to the next LogPipe";
96       log_pipe_forward_msg(s, msg, path_options);
97     }
98   else
99     {
100       parser_result = "Dropping message from LogPipe";
101       if (path_options->matched)
102         (*path_options->matched) = FALSE;
103       log_msg_drop(msg, path_options, AT_PROCESSED);
104     }
105   msg_trace("<<<<<< parser rule evaluation result",
106             evt_tag_str("result", parser_result),
107             evt_tag_str("rule", self->name),
108             log_pipe_location_tag(s),
109             evt_tag_printf("msg", "%p", msg));
110 }
111 
112 gboolean
log_parser_init_method(LogPipe * s)113 log_parser_init_method(LogPipe *s)
114 {
115   LogParser *self = (LogParser *) s;
116   GlobalConfig *cfg = log_pipe_get_config(s);
117 
118   if (!self->name && s->expr_node)
119     self->name = cfg_tree_get_rule_name(&cfg->tree, ENC_PARSER, s->expr_node);
120 
121   stats_lock();
122   StatsClusterKey sc_key;
123   stats_cluster_logpipe_key_set(&sc_key, SCS_PARSER, self->name, NULL );
124   stats_register_counter(1, &sc_key, SC_TYPE_DISCARDED, &self->super.discarded_messages);
125   stats_unlock();
126 
127   return TRUE;
128 }
129 
130 void
log_parser_free_method(LogPipe * s)131 log_parser_free_method(LogPipe *s)
132 {
133   LogParser *self = (LogParser *) s;
134 
135   stats_lock();
136   StatsClusterKey sc_key;
137   stats_cluster_logpipe_key_set(&sc_key, SCS_PARSER, self->name, NULL );
138   stats_unregister_counter(&sc_key, SC_TYPE_DISCARDED, &self->super.discarded_messages);
139   stats_unlock();
140 
141   g_free(self->name);
142   log_template_unref(self->template);
143   log_pipe_free_method(s);
144 
145 }
146 
147 void
log_parser_init_instance(LogParser * self,GlobalConfig * cfg)148 log_parser_init_instance(LogParser *self, GlobalConfig *cfg)
149 {
150   log_pipe_init_instance(&self->super, cfg);
151   self->super.init = log_parser_init_method;
152   self->super.deinit = log_parser_deinit_method;
153   self->super.free_fn = log_parser_free_method;
154   self->super.queue = log_parser_queue;
155 }
156