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