1 /*
2 ** Copyright (C) 2002-2009 Sourcefire, Inc.
3 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
4 ** Copyright (C) 2000,2001 Andrew R. Baker <andrewb@uab.edu>
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License Version 2 as
8 ** published by the Free Software Foundation.  You may not use, modify or
9 ** distribute this program under any other version of the GNU General
10 ** Public License.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software
19 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21 
22 /* $Id$ */
23 
24 /* spo_alert_fast
25  *
26  * Purpose:  output plugin for fast alerting
27  *
28  * Arguments:  alert file
29  *
30  * Effect:
31  *
32  * Alerts are written to a file in the snort fast alert format
33  *
34  * Comments:   Allows use of fast alerts with other output plugin types
35  *
36  */
37 
38 /* output plugin header file */
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42 
43 #ifdef HAVE_STRINGS_H
44 #include <strings.h>
45 #endif
46 
47 #include <sys/types.h>
48 
49 #ifndef WIN32
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #endif /* !WIN32 */
54 
55 #include "barnyard2.h"
56 #include "decode.h"
57 #include "debug.h"
58 #include "plugbase.h"
59 #include "parser.h"
60 #include "util.h"
61 #include "log.h"
62 #include "mstring.h"
63 #include "unified2.h"
64 
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <string.h>
68 
69 #include "sfutil/sf_textlog.h"
70 #include "log_text.h"
71 #include "ipv6_port.h"
72 
73 
74 /* full buf was chosen to allow printing max size packets
75  * in hex/ascii mode:
76  * each byte => 2 nibbles + space + ascii + overhead
77  */
78 #define FULL_BUF  (4*IP_MAXPACKET)
79 #define FAST_BUF  (4*K_BYTES)
80 
81 /*
82  * not defined for backwards compatibility
83  * (default is produced by OpenAlertFile()
84 #define DEFAULT_FILE  "alert.fast"
85  */
86 #define DEFAULT_LIMIT (128*M_BYTES)
87 
88 typedef struct _SpoAlertFastData
89 {
90     TextLog* log;
91     uint8_t packet_flag;
92 } SpoAlertFastData;
93 
94 static void AlertFastInit(char *);
95 static SpoAlertFastData *ParseAlertFastArgs(char *);
96 static void AlertFastCleanExitFunc(int, void *);
97 static void AlertFastRestartFunc(int, void *);
98 static void AlertFast(Packet *, void *, uint32_t, void *);
99 
100 /*
101  * Function: SetupAlertFast()
102  *
103  * Purpose: Registers the output plugin keyword and initialization
104  *          function into the output plugin list.  This is the function that
105  *          gets called from InitOutputPlugins() in plugbase.c.
106  *
107  * Arguments: None.
108  *
109  * Returns: void function
110  *
111  */
AlertFastSetup(void)112 void AlertFastSetup(void)
113 {
114     /* link the preprocessor keyword to the init function in
115        the preproc list */
116     RegisterOutputPlugin("alert_fast", OUTPUT_TYPE_FLAG__ALERT, AlertFastInit);
117     DEBUG_WRAP(DebugMessage(DEBUG_INIT,"Output plugin: AlertFast is setup...\n"););
118 }
119 
120 
121 /*
122  * Function: AlertFastInit(char *)
123  *
124  * Purpose: Calls the argument parsing function, performs final setup on data
125  *          structs, links the preproc function into the function list.
126  *
127  * Arguments: args => ptr to argument string
128  *
129  * Returns: void function
130  *
131  */
AlertFastInit(char * args)132 static void AlertFastInit(char *args)
133 {
134     SpoAlertFastData *data;
135 
136     DEBUG_WRAP(DebugMessage(DEBUG_INIT,"Output: AlertFast Initialized\n"););
137 
138     /* parse the argument list from the rules file */
139     data = ParseAlertFastArgs(args);
140 
141     DEBUG_WRAP(DebugMessage(DEBUG_INIT,"Linking AlertFast functions to call lists...\n"););
142 
143     /* Set the preprocessor function into the function list */
144     AddFuncToOutputList(AlertFast, OUTPUT_TYPE__ALERT, data);
145     AddFuncToCleanExitList(AlertFastCleanExitFunc, data);
146     AddFuncToRestartList(AlertFastRestartFunc, data);
147 }
148 
AlertFast(Packet * p,void * event,uint32_t event_type,void * arg)149 static void AlertFast(Packet *p, void *event, uint32_t event_type, void *arg)
150 {
151     SpoAlertFastData    *data;
152     SigNode             *sn;
153 
154     if( p == NULL || event == NULL || arg == NULL )
155     {
156         return;
157     }
158 
159     data = (SpoAlertFastData *)arg;
160     sn = GetSigByGidSid(ntohl(((Unified2EventCommon *)event)->generator_id),
161                         ntohl(((Unified2EventCommon *)event)->signature_id),
162 			ntohl(((Unified2EventCommon *)event)->signature_revision));
163 
164     LogTimeStamp(data->log, p);
165 
166     if( p != NULL && p->packet_flags & PKT_INLINE_DROP )
167         TextLog_Puts(data->log, " [Drop]");
168 
169     if(sn != NULL)
170     {
171 #ifdef MARK_TAGGED
172         char c=' ';
173         if ((p != NULL) && (p->packet_flags & PKT_REBUILT_STREAM))
174             c = 'R';
175         else if ((p != NULL) && (p->packet_flags & PKT_REBUILT_FRAG))
176             c = 'F';
177         TextLog_Print(data->log, " [**] %c ", c);
178 #else
179         TextLog_Puts(data->log, " [**] ");
180 #endif
181 
182         TextLog_Print(data->log, "[%lu:%lu:%lu] ",
183                 (unsigned long) ntohl(((Unified2EventCommon *)event)->generator_id),
184                 (unsigned long) ntohl(((Unified2EventCommon *)event)->signature_id),
185                 (unsigned long) ntohl(((Unified2EventCommon *)event)->signature_revision));
186 
187         if(BcAlertInterface())
188         {
189             TextLog_Print(data->log, "<%s> ", PRINT_INTERFACE(barnyard2_conf->interface));
190         }
191 
192         TextLog_Puts(data->log, sn->msg);
193         TextLog_Puts(data->log, " [**] ");
194     }
195 
196     /* print the packet header to the alert file */
197     if(p && IPH_IS_VALID(p))
198     {
199         LogPriorityData(data->log,
200                         ntohl(((Unified2EventCommon *)event)->classification_id),
201                         ntohl(((Unified2EventCommon *)event)->priority_id),
202                         0);
203 
204         TextLog_Print(data->log, "{%s} ", protocol_names[GET_IPH_PROTO(p)]);
205 
206         if(p->frag_flag)
207         {
208             /* just print the straight IP header */
209             if(!BcObfuscate())
210             {
211                 TextLog_Puts(data->log, inet_ntoa(GET_SRC_ADDR(p)));
212                 TextLog_Puts(data->log, " -> ");
213                 TextLog_Puts(data->log, inet_ntoa(GET_DST_ADDR(p)));
214             }
215             else
216             {
217                 /* print the header complete with port information */
218                 if(IS_IP4(p))
219                     TextLog_Print(data->log, "xxx.xxx.xxx.xxx:%d -> xxx.xxx.xxx.xxx:%d", p->sp, p->dp);
220                 else if(IS_IP6(p))
221                     TextLog_Print(data->log, "x:x:x:x::x:x:x:x:%d -> x:x:x:x:x:x:x:x:%d", p->sp, p->dp);
222             }
223         }
224         else
225         {
226             switch(GET_IPH_PROTO(p))
227             {
228                 case IPPROTO_UDP:
229                 case IPPROTO_TCP:
230                     /* print the header complete with port information */
231                     if(!BcObfuscate())
232                     {
233                         TextLog_Puts(data->log, inet_ntoa(GET_SRC_ADDR(p)));
234                         TextLog_Print(data->log, ":%d -> ", p->sp);
235                         TextLog_Puts(data->log, inet_ntoa(GET_DST_ADDR(p)));
236                         TextLog_Print(data->log, ":%d", p->dp);
237                     }
238                     else
239                     {
240                         /* print the header complete with port information */
241                         if(IS_IP4(p))
242                             TextLog_Print(data->log, "xxx.xxx.xxx.xxx:%d -> xxx.xxx.xxx.xxx:%d", p->sp, p->dp);
243                         else if(IS_IP6(p))
244                             TextLog_Print(data->log, "x:x:x:x::x:x:x:x:%d -> x:x:x:x:x:x:x:x:%d", p->sp, p->dp);
245                     }
246                     break;
247                 case IPPROTO_ICMP:
248                 default:
249                     /* just print the straight IP header */
250                     if(!BcObfuscate())
251                     {
252                         TextLog_Puts(data->log, inet_ntoa(GET_SRC_ADDR(p)));
253                         TextLog_Puts(data->log, " -> ");
254                         TextLog_Puts(data->log, inet_ntoa(GET_DST_ADDR(p)));
255                     }
256                     else
257                     {
258                         /* print the header complete with port information */
259                         if(IS_IP4(p))
260                             TextLog_Print(data->log, "xxx.xxx.xxx.xxx:%d -> xxx.xxx.xxx.xxx:%d", p->sp, p->dp);
261                         else if(IS_IP6(p))
262                             TextLog_Print(data->log, "x:x:x:x::x:x:x:x:%d -> x:x:x:x:x:x:x:x:%d", p->sp, p->dp);
263                     }
264             }
265         }
266     }               /* end of if (p) */
267 
268     if(p && data->packet_flag)
269     {
270         /* Log whether or not this is reassembled data - only indicate
271          * if we're actually going to show any of the payload */
272         if (BcOutputAppData() && (p->dsize > 0))
273         {
274             if (p->packet_flags &
275                 (PKT_DCE_RPKT | PKT_REBUILT_STREAM | PKT_REBUILT_FRAG |
276                  PKT_SMB_SEG | PKT_DCE_SEG | PKT_DCE_FRAG | PKT_SMB_TRANS))
277             {
278                 TextLog_NewLine(data->log);
279             }
280 
281             if (p->packet_flags & PKT_SMB_SEG)
282                 TextLog_Print(data->log, "%s", "SMB desegmented packet");
283             else if (p->packet_flags & PKT_DCE_SEG)
284                 TextLog_Print(data->log, "%s", "DCE/RPC desegmented packet");
285             else if (p->packet_flags & PKT_DCE_FRAG)
286                 TextLog_Print(data->log, "%s", "DCE/RPC defragmented packet");
287             else if (p->packet_flags & PKT_SMB_TRANS)
288                 TextLog_Print(data->log, "%s", "SMB Transact reassembled packet");
289             else if (p->packet_flags & PKT_DCE_RPKT)
290                 TextLog_Print(data->log, "%s", "DCE/RPC reassembled packet");
291             else if (p->packet_flags & PKT_REBUILT_STREAM)
292                 TextLog_Print(data->log, "%s", "Stream reassembled packet");
293             else if (p->packet_flags & PKT_REBUILT_FRAG)
294                 TextLog_Print(data->log, "%s", "Frag reassembled packet");
295         }
296 
297         TextLog_NewLine(data->log);
298 
299         if(IPH_IS_VALID(p))
300             LogIPPkt(data->log, GET_IPH_PROTO(p), p);
301 #ifndef NO_NON_ETHER_DECODER
302         else if(p->ah)
303             LogArpHeader(data->log, p);
304 #endif
305     }
306     TextLog_NewLine(data->log);
307     TextLog_Flush(data->log);
308 }
309 
310 /*
311  * Function: ParseAlertFastArgs(char *)
312  *
313  * Purpose: Process positional args, if any.  Syntax is:
314  * output alert_fast: [<logpath> ["packet"] [<limit>]]
315  * limit ::= <number>('G'|'M'|K')
316  *
317  * Arguments: args => argument list
318  *
319  * Returns: void function
320  *
321  */
ParseAlertFastArgs(char * args)322 static SpoAlertFastData *ParseAlertFastArgs(char *args)
323 {
324     char **toks;
325     int num_toks;
326     SpoAlertFastData *data;
327     char* filename = NULL;
328     unsigned long limit = DEFAULT_LIMIT;
329     unsigned int bufSize = FAST_BUF;
330     int i;
331 
332     DEBUG_WRAP(DebugMessage(DEBUG_LOG, "ParseAlertFastArgs: %s\n", args););
333     data = (SpoAlertFastData *)SnortAlloc(sizeof(SpoAlertFastData));
334 
335     if ( !data )
336     {
337         FatalError("alert_fast: unable to allocate memory!\n");
338     }
339     if ( !args ) args = "";
340     toks = mSplit((char *)args, " \t", 0, &num_toks, '\\');
341 
342     for (i = 0; i < num_toks; i++)
343     {
344         const char* tok = toks[i];
345         char *end;
346 
347         switch (i)
348         {
349             case 0:
350                 if ( !strcasecmp(tok, "stdout") )
351                     filename = SnortStrdup(tok);
352 
353                 else
354                     filename = ProcessFileOption(barnyard2_conf_for_parsing, tok);
355                 break;
356 
357             case 1:
358                 if ( !strcasecmp("packet", tok) )
359                 {
360                     data->packet_flag = 1;
361                     bufSize = FULL_BUF;
362                     break;
363                 }
364                 /* in this case, only 2 options allowed */
365                 else i++;
366                 /* fall thru so "packet" is optional ... */
367 
368             case 2:
369                 limit = strtol(tok, &end, 10);
370 
371                 if ( tok == end )
372                     FatalError("alert_fast error in %s(%i): %s\n",
373                         file_name, file_line, tok);
374 
375                 if ( end && toupper(*end) == 'G' )
376                     limit <<= 30; /* GB */
377 
378                 else if ( end && toupper(*end) == 'M' )
379                     limit <<= 20; /* MB */
380 
381                 else if ( end && toupper(*end) == 'K' )
382                     limit <<= 10; /* KB */
383                 break;
384 
385             case 3:
386                 FatalError("alert_fast: error in %s(%i): %s\n",
387                     file_name, file_line, tok);
388                 break;
389         }
390     }
391     mSplitFree(&toks, num_toks);
392 
393 #ifdef DEFAULT_FILE
394     if ( !filename ) filename = ProcessFileOption(barnyard2_conf_for_parsing, DEFAULT_FILE);
395 #endif
396 
397     DEBUG_WRAP(DebugMessage(
398         DEBUG_INIT, "alert_fast: '%s' %d %ld\n",
399         filename?filename:"alert", data->packet_flag, limit
400     ););
401     data->log = TextLog_Init(filename, bufSize, limit);
402     if ( filename ) free(filename);
403 
404     return data;
405 }
406 
AlertFastCleanup(int signal,void * arg,const char * msg)407 static void AlertFastCleanup(int signal, void *arg, const char* msg)
408 {
409     SpoAlertFastData *data = (SpoAlertFastData *)arg;
410     DEBUG_WRAP(DebugMessage(DEBUG_LOG, "%s\n", msg););
411 
412     /*free memory from SpoAlertFastData */
413     if ( data->log )
414     {
415 	TextLog_Term(data->log);
416     }
417 
418     if(data)
419 	free(data);
420 
421     return;
422 }
423 
AlertFastCleanExitFunc(int signal,void * arg)424 static void AlertFastCleanExitFunc(int signal, void *arg)
425 {
426     AlertFastCleanup(signal, arg, "AlertFastCleanExitFunc");
427 }
428 
AlertFastRestartFunc(int signal,void * arg)429 static void AlertFastRestartFunc(int signal, void *arg)
430 {
431     AlertFastCleanup(signal, arg, "AlertFastRestartFunc");
432 }
433 
434