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