1 /* Copyright (C) 2013-2020 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  * Logs vars in JSON format.
24  *
25  */
26 
27 #include "suricata-common.h"
28 #include "debug.h"
29 #include "detect.h"
30 #include "flow.h"
31 #include "conf.h"
32 
33 #include "threads.h"
34 #include "tm-threads.h"
35 #include "threadvars.h"
36 #include "util-debug.h"
37 
38 #include "util-misc.h"
39 #include "util-unittest.h"
40 #include "util-unittest-helper.h"
41 
42 #include "detect-parse.h"
43 #include "detect-engine.h"
44 #include "detect-engine-mpm.h"
45 #include "detect-reference.h"
46 #include "app-layer-parser.h"
47 #include "app-layer-dnp3.h"
48 #include "app-layer-htp.h"
49 #include "app-layer-htp-xff.h"
50 #include "util-classification-config.h"
51 #include "util-syslog.h"
52 #include "util-logopenfile.h"
53 
54 #include "output.h"
55 #include "output-json.h"
56 #include "output-json-metadata.h"
57 
58 #include "util-byte.h"
59 #include "util-privs.h"
60 #include "util-print.h"
61 #include "util-proto-name.h"
62 #include "util-optimize.h"
63 #include "util-buffer.h"
64 #include "util-crypt.h"
65 
66 #define MODULE_NAME "JsonMetadataLog"
67 
68 typedef struct MetadataJsonOutputCtx_ {
69     LogFileCtx* file_ctx;
70     OutputJsonCommonSettings cfg;
71 } MetadataJsonOutputCtx;
72 
73 typedef struct JsonMetadataLogThread_ {
74     /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */
75     LogFileCtx* file_ctx;
76     MemBuffer *json_buffer;
77     MetadataJsonOutputCtx* json_output_ctx;
78 } JsonMetadataLogThread;
79 
MetadataJson(ThreadVars * tv,JsonMetadataLogThread * aft,const Packet * p)80 static int MetadataJson(ThreadVars *tv, JsonMetadataLogThread *aft, const Packet *p)
81 {
82     JsonBuilder *js = CreateEveHeader(p, LOG_DIR_PACKET, "metadata", NULL);
83     if (unlikely(js == NULL))
84         return TM_ECODE_OK;
85 
86     EveAddCommonOptions(&aft->json_output_ctx->cfg, p, p->flow, js);
87     OutputJsonBuilderBuffer(js, aft->file_ctx, &aft->json_buffer);
88 
89     jb_free(js);
90     return TM_ECODE_OK;
91 }
92 
JsonMetadataLogger(ThreadVars * tv,void * thread_data,const Packet * p)93 static int JsonMetadataLogger(ThreadVars *tv, void *thread_data, const Packet *p)
94 {
95     JsonMetadataLogThread *aft = thread_data;
96 
97     return MetadataJson(tv, aft, p);
98 }
99 
JsonMetadataLogCondition(ThreadVars * tv,const Packet * p)100 static int JsonMetadataLogCondition(ThreadVars *tv, const Packet *p)
101 {
102     if (p->pktvar) {
103         return TRUE;
104     }
105     return FALSE;
106 }
107 
JsonMetadataLogThreadInit(ThreadVars * t,const void * initdata,void ** data)108 static TmEcode JsonMetadataLogThreadInit(ThreadVars *t, const void *initdata, void **data)
109 {
110     JsonMetadataLogThread *aft = SCCalloc(1, sizeof(JsonMetadataLogThread));
111     if (unlikely(aft == NULL))
112         return TM_ECODE_FAILED;
113 
114     if(initdata == NULL) {
115         SCLogDebug("Error getting context for EveLogMetadata.  \"initdata\" argument NULL");
116         goto error_exit;
117     }
118 
119     aft->json_buffer = MemBufferCreateNew(JSON_OUTPUT_BUFFER_SIZE);
120     if (aft->json_buffer == NULL) {
121         goto error_exit;
122     }
123 
124     /** Use the Output Context (file pointer and mutex) */
125     MetadataJsonOutputCtx *json_output_ctx = ((OutputCtx *)initdata)->data;
126     aft->file_ctx = LogFileEnsureExists(json_output_ctx->file_ctx, t->id);
127     if (!aft->file_ctx) {
128         goto error_exit;
129     }
130     aft->json_output_ctx = json_output_ctx;
131 
132     *data = (void *)aft;
133     return TM_ECODE_OK;
134 
135 error_exit:
136     if (aft->json_buffer != NULL) {
137         MemBufferFree(aft->json_buffer);
138     }
139     SCFree(aft);
140     return TM_ECODE_FAILED;
141 }
142 
JsonMetadataLogThreadDeinit(ThreadVars * t,void * data)143 static TmEcode JsonMetadataLogThreadDeinit(ThreadVars *t, void *data)
144 {
145     JsonMetadataLogThread *aft = (JsonMetadataLogThread *)data;
146     if (aft == NULL) {
147         return TM_ECODE_OK;
148     }
149 
150     MemBufferFree(aft->json_buffer);
151 
152     /* clear memory */
153     memset(aft, 0, sizeof(JsonMetadataLogThread));
154 
155     SCFree(aft);
156     return TM_ECODE_OK;
157 }
158 
JsonMetadataLogDeInitCtxSub(OutputCtx * output_ctx)159 static void JsonMetadataLogDeInitCtxSub(OutputCtx *output_ctx)
160 {
161     SCLogDebug("cleaning up sub output_ctx %p", output_ctx);
162 
163     MetadataJsonOutputCtx *json_output_ctx = (MetadataJsonOutputCtx *) output_ctx->data;
164 
165     if (json_output_ctx != NULL) {
166         SCFree(json_output_ctx);
167     }
168     SCFree(output_ctx);
169 }
170 
171 /**
172  * \brief Create a new LogFileCtx for "fast" output style.
173  * \param conf The configuration node for this output.
174  * \return A LogFileCtx pointer on success, NULL on failure.
175  */
JsonMetadataLogInitCtxSub(ConfNode * conf,OutputCtx * parent_ctx)176 static OutputInitResult JsonMetadataLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx)
177 {
178     OutputInitResult result = { NULL, false };
179     OutputJsonCtx *ajt = parent_ctx->data;
180     MetadataJsonOutputCtx *json_output_ctx = NULL;
181 
182     OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
183     if (unlikely(output_ctx == NULL))
184         return result;
185 
186     json_output_ctx = SCMalloc(sizeof(MetadataJsonOutputCtx));
187     if (unlikely(json_output_ctx == NULL)) {
188         goto error;
189     }
190     memset(json_output_ctx, 0, sizeof(MetadataJsonOutputCtx));
191 
192     json_output_ctx->file_ctx = ajt->file_ctx;
193     json_output_ctx->cfg = ajt->cfg;
194     /* override config setting as this logger is about metadata */
195     json_output_ctx->cfg.include_metadata = true;
196 
197     output_ctx->data = json_output_ctx;
198     output_ctx->DeInit = JsonMetadataLogDeInitCtxSub;
199 
200     result.ctx = output_ctx;
201     result.ok = true;
202     return result;
203 
204 error:
205     if (json_output_ctx != NULL) {
206         SCFree(json_output_ctx);
207     }
208     if (output_ctx != NULL) {
209         SCFree(output_ctx);
210     }
211 
212     return result;
213 }
214 
JsonMetadataLogRegister(void)215 void JsonMetadataLogRegister (void)
216 {
217     OutputRegisterPacketSubModule(LOGGER_JSON_METADATA, "eve-log", MODULE_NAME,
218         "eve-log.metadata", JsonMetadataLogInitCtxSub, JsonMetadataLogger,
219         JsonMetadataLogCondition, JsonMetadataLogThreadInit,
220         JsonMetadataLogThreadDeinit, NULL);
221 
222     /* Kept for compatibility. */
223     OutputRegisterPacketSubModule(LOGGER_JSON_METADATA, "eve-log", MODULE_NAME,
224         "eve-log.vars", JsonMetadataLogInitCtxSub, JsonMetadataLogger,
225         JsonMetadataLogCondition, JsonMetadataLogThreadInit,
226         JsonMetadataLogThreadDeinit, NULL);
227 }
228