1 /*
2 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 ** Copyright (C) 2002-2013 Sourcefire, Inc.
4 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
5 **
6 ** Author: Rahul Burman <rahburma@cisco.com>
7 **
8 ** This program is free software; you can redistribute it and/or modify
9 ** it under the terms of the GNU General Public License Version 2 as
10 ** published by the Free Software Foundation. You may not use, modify or
11 ** distribute this program under any other version of the GNU General
12 ** Public License.
13 **
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ** GNU General Public License for more details.
18 **
19 ** You should have received a copy of the GNU General Public License
20 ** along with this program; if not, write to the Free Software
21 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23 /* $Id$ */
24
25 /* spo_log_buffer_dump
26 *
27 * Purpose:
28 *
29 * This module is used to dump the buffers used by preprocessors during
30 * packet inspection
31 *
32 * Arguments: filename to which buffers are to be dumped
33 *
34 * Effect: None
35 *
36 * Comments:
37 *
38 */
39
40 #ifdef DUMP_BUFFER
41
42 #include <sys/types.h>
43
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47
48 #include "spo_log_buffer_dump.h"
49 #include "decode.h"
50 #include "event.h"
51 #include "plugbase.h"
52 #include "spo_plugbase.h"
53 #include "parser.h"
54 #include "snort_debug.h"
55 #include "preprocids.h"
56 #include "log_text.h"
57 #include "snort.h"
58 #include "strvec.h"
59
60 #define DEFAULT_FILE "stdout"
61 #define LIMIT (128*M_BYTES)
62 #define LOG_BUFFER (4*K_BYTES)
63
64 static int maxBuffers[MAX_BUFFER_DUMP_FUNC] = { MAX_HTTP_BUFFER_DUMP,
65 MAX_SMTP_BUFFER_DUMP,
66 MAX_SIP_BUFFER_DUMP,
67 MAX_DNP3_BUFFER_DUMP,
68 MAX_POP_BUFFER_DUMP,
69 MAX_MODBUS_BUFFER_DUMP,
70 MAX_SSH_BUFFER_DUMP,
71 MAX_DNS_BUFFER_DUMP,
72 MAX_DCERPC2_BUFFER_DUMP,
73 MAX_FTPTELNET_BUFFER_DUMP,
74 MAX_IMAP_BUFFER_DUMP,
75 MAX_SSL_BUFFER_DUMP,
76 MAX_GTP_BUFFER_DUMP };
77
78 typedef struct _SpoLogBufferDumpData
79 {
80 TextLog* log;
81 } SpoLogBufferDumpData;
82
83 /* list of function prototypes for this output plugin */
84 static void LogBufferDumpInit(struct _SnortConfig *, char *);
85 static SpoLogBufferDumpData *InitializeLogBufferDumpOutputStream(SnortConfig *);
86 static void LogBufferDump(Packet *, const char *, void *, Event *);
87 static void LogBufferDumpCleanExitFunc(int, void *);
88
LogBufferDumpSetup(void)89 void LogBufferDumpSetup(void)
90 {
91 /* link the preprocessor keyword to the init function in
92 the preproc list */
93 RegisterOutputPlugin("log_buffer_dump", OUTPUT_TYPE_FLAG__LOG, LogBufferDumpInit);
94
95 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Output plugin: LogBufferDump is setup...\n"););
96 }
97
98
LogBufferDumpInit(struct _SnortConfig * sc,char * args)99 static void LogBufferDumpInit(struct _SnortConfig *sc, char *args)
100 {
101 SpoLogBufferDumpData *data;
102 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Output: LogBufferDump Initialized\n"););
103
104 /* parse the argument list from the rules file */
105 data = InitializeLogBufferDumpOutputStream(sc);
106
107 /* Set the preprocessor function into the function list */
108 AddFuncToOutputList(sc, LogBufferDump, OUTPUT_TYPE__LOG, data);
109 AddBDFuncToOutputList(sc, LogBufferDump, OUTPUT_TYPE__LOG, data);
110 AddFuncToCleanExitList(LogBufferDumpCleanExitFunc, data);
111 }
112
113
114 /*
115 * Function: InitializeLogBufferDumpOutputStream(SnortConfig *)
116 *
117 * Purpose: Initialize the output stream to which buffers will be dumped.
118 *
119 * Arguments: args => SnortConfig
120 *
121 * Returns: SpoLogBufferDumpData
122 */
InitializeLogBufferDumpOutputStream(SnortConfig * sc)123 static SpoLogBufferDumpData *InitializeLogBufferDumpOutputStream(SnortConfig *sc)
124 {
125 SpoLogBufferDumpData *data;
126 char* filename = NULL;
127
128 DEBUG_WRAP(DebugMessage(DEBUG_LOG, "Output: LogBufferDump output stream initialized\n"););
129 data = (SpoLogBufferDumpData *)SnortAlloc(sizeof(SpoLogBufferDumpData));
130
131 if ( !data )
132 {
133 FatalError("log buffer dump: unable to allocate memory!\n");
134 }
135
136 const char** dump_file = StringVector_GetVector(sc->buffer_dump_file);
137
138 if (dump_file && dump_file[0])
139 filename = SnortStrdup(dump_file[0]);
140 else
141 filename = SnortStrdup(DEFAULT_FILE);
142
143 data->log = TextLog_Init(filename, LOG_BUFFER, LIMIT);
144
145 if (filename != NULL)
146 free(filename);
147
148 return data;
149 }
150
LogBufferDump(Packet * p,const char * msg,void * arg,Event * event)151 static void LogBufferDump(Packet *p, const char *msg, void *arg, Event *event)
152 {
153 // dump the buffers used during packet processing
154 dumped_state = true;
155 SpoLogBufferDumpData *data = (SpoLogBufferDumpData *)arg;
156 TextLog_Puts(data->log, "\n=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n");
157 if (ScOutputAppData() && (p->dsize > 0) && PacketWasCooked(p))
158 {
159 switch ( p->pseudo_type ) {
160 case PSEUDO_PKT_SMB_SEG:
161 TextLog_Print(data->log, "\n%s", "SMB desegmented packet:");
162 break;
163 case PSEUDO_PKT_DCE_SEG:
164 TextLog_Print(data->log, "\n%s", "DCE/RPC desegmented packet:");
165 break;
166 case PSEUDO_PKT_DCE_FRAG:
167 TextLog_Print(data->log, "\n%s", "DCE/RPC defragmented packet:");
168 break;
169 case PSEUDO_PKT_SMB_TRANS:
170 TextLog_Print(data->log, "\n%s", "SMB Transact reassembled packet:");
171 break;
172 case PSEUDO_PKT_DCE_RPKT:
173 TextLog_Print(data->log, "\n%s", "DCE/RPC reassembled packet:");
174 break;
175 case PSEUDO_PKT_TCP:
176 TextLog_Print(data->log, "\n%s", "Stream Reassembled Packet:\n");
177 break;
178 case PSEUDO_PKT_IP:
179 TextLog_Print(data->log, "\n%s", "Frag reassembled packet:");
180 break;
181 default:
182 // FIXTHIS do we get here for portscan or sdf?
183 break;
184 }
185 }
186 else
187 {
188 TextLog_Print(data->log, "\n%s", "Raw Packet:\n");
189 }
190 LogTimeStamp(data->log, p);
191 if(p && IPH_IS_VALID(p))
192 {
193 if (ScOutputDataLink())
194 {
195 Log2ndHeader(data->log, p);
196 }
197
198 LogIPHeader(data->log, p);
199
200 if(!p->frag_flag)
201 {
202 switch(GET_IPH_PROTO(p))
203 {
204 case IPPROTO_TCP:
205 LogTCPHeader(data->log, p);
206 break;
207
208 case IPPROTO_UDP:
209 LogUDPHeader(data->log, p);
210 break;
211
212 case IPPROTO_ICMP:
213 LogICMPHeader(data->log, p);
214 break;
215
216 default:
217 break;
218 }
219 }
220 LogXrefs(data->log, 1);
221
222 TextLog_Putc(data->log, '\n');
223 }
224 TextLog_Flush(data->log);
225
226 bool bufferDumpFlag = false;
227
228 if (p->dsize)
229 {
230 TraceBuffer *bufs;
231 int i, j;
232
233 for (i = 0; i < MAX_BUFFER_DUMP_FUNC; i++)
234 {
235 if ((bdmask & (UINT64_C(1) << i)) && getBuffers[i])
236 {
237 bufs = getBuffers[i]();
238 if (bufs != NULL)
239 {
240 for (j = 0; j < maxBuffers[i]; j++)
241 {
242 if (bufs[j].length != 0)
243 {
244 if (!bufferDumpFlag) // To Print Dumping Buffers string only once
245 {
246 bufferDumpFlag = true;
247 TextLog_Print(data->log, "\nDumping Buffers\n");
248 }
249
250 if (event != NULL)
251 {
252 TextLog_Print(data->log, "%s [%lu:%lu:%lu]\n",
253 (char *)"Event",
254 (unsigned long) event->sig_generator,
255 (unsigned long) event->sig_id,
256 (unsigned long) event->sig_rev);
257 }
258 LogBuffer(data->log, bufs[j].buf_name, bufs[j].buf_content, bufs[j].length);
259 // free the http buffers after logging
260 if (i == HTTP_BUFFER_DUMP_FUNC)
261 free(bufs[j].buf_content);
262 bufs[j].buf_content = NULL;
263 bufs[j].length = 0;
264 }
265 }
266 }
267 }
268 }
269 }
270
271 if (!bufferDumpFlag) // No data available in all the files
272 {
273 TextLog_Print(data->log, "\nNo Buffers to Dump\n");
274 }
275 }
276
LogBufferDumpCleanup(int signal,void * arg,const char * msg)277 static void LogBufferDumpCleanup(int signal, void *arg, const char* msg)
278 {
279 SpoLogBufferDumpData *data = (SpoLogBufferDumpData *)arg;
280 DEBUG_WRAP(DebugMessage(DEBUG_LOG, "%s\n", msg););
281
282 /* free memory from SpoLogBufferDumpData */
283 if ( data->log ) TextLog_Term(data->log);
284 free(data);
285
286 /* Checkout for any allocated HTTP buffers not freed yet */
287 TraceBuffer *bufs;
288 int j;
289
290 if ((bdmask & (UINT64_C(1) << HTTP_BUFFER_DUMP_FUNC)) && getBuffers[HTTP_BUFFER_DUMP_FUNC])
291 {
292 bufs = getBuffers[HTTP_BUFFER_DUMP_FUNC]();
293 if (bufs != NULL)
294 {
295 for (j = 0; j < maxBuffers[HTTP_BUFFER_DUMP_FUNC]; j++)
296 {
297 if (bufs[j].buf_content)
298 {
299 free(bufs[j].buf_content);
300 bufs[j].buf_content = NULL;
301 bufs[j].length = 0;
302 }
303 }
304 }
305 }
306 }
307
308
LogBufferDumpCleanExitFunc(int signal,void * arg)309 static void LogBufferDumpCleanExitFunc(int signal, void *arg)
310 {
311 LogBufferDumpCleanup(signal, arg, "LogBufferDumpCleanExit");
312 }
313
314 #endif
315