1 /*
2 **
3 ** Copyright (C) 2008-2013 Ian Firns (SecurixLive) <dev@securixlive.com>
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License Version 2 as
7 ** published by the Free Software Foundation. You may not use, modify or
8 ** distribute this program under any other version of the GNU General
9 ** Public License.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 **
20 **
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <sys/types.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <dirent.h>
35 #include <sys/stat.h>
36
37 #include "barnyard2.h"
38 #include "debug.h"
39 #include "plugbase.h"
40 #include "spooler.h"
41 #include "unified2.h"
42 #include "util.h"
43
44
45
46 /*
47 ** PRIVATE FUNCTIONS
48 */
49 Spooler *spoolerOpen(const char *, const char *, uint32_t);
50 int spoolerClose(Spooler *);
51 int spoolerReadRecordHeader(Spooler *);
52 int spoolerReadRecord(Spooler *);
53 void spoolerProcessRecord(Spooler *, int);
54 void spoolerFreeRecord(Record *record);
55
56 int spoolerWriteWaldo(Waldo *, Spooler *);
57 int spoolerOpenWaldo(Waldo *, uint8_t);
58 int spoolerCloseWaldo(Waldo *);
59
60
61 int spoolerPacketCacheAdd(Spooler *, Packet *);
62 int spoolerPacketCacheClear(Spooler *);
63
64 int spoolerEventCachePush(Spooler *, uint32_t, void *);
65 EventRecordNode * spoolerEventCacheGetByEventID(Spooler *, uint32_t);
66 EventRecordNode * spoolerEventCacheGetHead(Spooler *);
67 uint8_t spoolerEventCacheHeadUsed(Spooler *);
68 int spoolerEventCacheClean(Spooler *);
69
70 /* Find the next spool file timestamp extension with a value equal to or
71 * greater than timet. If extension != NULL, the extension will be
72 * returned.
73 *
74 * @retval 0 file found
75 * @retval -1 error
76 * @retval 1 no file found
77 *
78 * Bugs: This function presumes a 1 character delimeter between the base
79 * filename and the extension
80 */
FindNextExtension(const char * dirpath,const char * filebase,uint32_t timestamp,uint32_t * extension)81 static int FindNextExtension(const char *dirpath, const char *filebase,
82 uint32_t timestamp, uint32_t *extension)
83 {
84 DIR *dir = NULL;
85 struct dirent *dir_entry;
86 size_t filebase_len;
87 uint32_t timestamp_min = 0;
88 char *endptr;
89
90 DEBUG_WRAP(DebugMessage(DEBUG_SPOOLER,"Looking in %s %s\n", dirpath, filebase););
91
92 /* peform sanity checks */
93 if (dirpath == NULL || filebase == NULL)
94 return SPOOLER_EXTENSION_EPARAM;
95
96 /* calculate filebase length */
97 filebase_len = strlen(filebase);
98
99 /* open the directory */
100 if ( !(dir=opendir(dirpath)) )
101 {
102 LogMessage("ERROR: Unable to open directory '%s' (%s)\n", dirpath,
103 strerror(errno));
104 return SPOOLER_EXTENSION_EOPEN;
105 }
106
107 /* step through each entry in the directory */
108 while ( (dir_entry=readdir(dir)) )
109 {
110 unsigned long file_timestamp;
111
112 if (strncmp(filebase, dir_entry->d_name, filebase_len) != 0)
113 continue;
114
115 /* this is a file we may want */
116 file_timestamp = strtol(dir_entry->d_name + filebase_len + 1, &endptr, 10);
117 if ((errno == ERANGE) || (*endptr != '\0'))
118 {
119 LogMessage("WARNING: Can't extract timestamp extension from '%s'"
120 "using base '%s'\n", dir_entry->d_name, filebase);
121
122 continue;
123 }
124
125 /* exact match */
126 if (timestamp != 0 && file_timestamp == timestamp)
127 {
128 timestamp_min = file_timestamp;
129 break;
130 }
131 /* possible overshoot */
132 else if (file_timestamp > timestamp)
133 {
134 /* realign the minimum timestamp threshold */
135 if ( timestamp_min == 0 || (file_timestamp < timestamp_min) )
136 timestamp_min = file_timestamp;
137 }
138 }
139
140 closedir(dir);
141
142 /* no newer extensions were found */
143 if (timestamp_min == 0)
144 return SPOOLER_EXTENSION_NONE;
145
146 /* update the extension variable if it exists */
147 if (extension != NULL)
148 *extension = timestamp_min;
149
150 return SPOOLER_EXTENSION_FOUND;
151 }
152
spoolerOpen(const char * dirpath,const char * filename,uint32_t extension)153 Spooler *spoolerOpen(const char *dirpath, const char *filename, uint32_t extension)
154 {
155 Spooler *spooler = NULL;
156 int ret;
157
158 /* perform sanity checks */
159 if ( filename == NULL )
160 return NULL;
161
162 /* create the spooler structure and allocate all memory */
163 spooler = (Spooler *)SnortAlloc(sizeof(Spooler));
164
165 RegisterSpooler(spooler);
166
167 /* allocate some extra structures required (ie. Packet) */
168
169 spooler->fd = -1;
170
171 /* build the full filepath */
172 if (extension == 0)
173 {
174 ret = SnortSnprintf(spooler->filepath, MAX_FILEPATH_BUF, "%s", filename);
175 }
176 else
177 {
178 ret = SnortSnprintf(spooler->filepath, MAX_FILEPATH_BUF, "%s/%s.%u", dirpath, filename,
179 extension);
180 }
181
182 /* sanity check the filepath */
183 if (ret != SNORT_SNPRINTF_SUCCESS)
184 {
185 UnRegisterSpooler(spooler);
186 spoolerClose(spooler);
187 FatalError("spooler: filepath too long!\n");
188 }
189
190 spooler->timestamp = extension;
191
192 LogMessage("Opened spool file '%s'\n", spooler->filepath);
193
194 /* open the file non-blocking */
195 if ( (spooler->fd=open(spooler->filepath, O_RDONLY | O_NONBLOCK, 0)) == -1 )
196 {
197 LogMessage("ERROR: Unable to open log spool file '%s' (%s)\n",
198 spooler->filepath, strerror(errno));
199 UnRegisterSpooler(spooler);
200 spoolerClose(spooler);
201 spooler = NULL;
202 return NULL;
203 }
204
205 /* set state to initially be open */
206 spooler->state = SPOOLER_STATE_OPENED;
207
208 spooler->ifn = GetInputPlugin("unified2");
209
210 if (spooler->ifn == NULL)
211 {
212 UnRegisterSpooler(spooler);
213 spoolerClose(spooler);
214 spooler = NULL;
215 FatalError("ERROR: No suitable input plugin found!\n");
216 }
217
218 return spooler;
219 }
220
spoolerClose(Spooler * spooler)221 int spoolerClose(Spooler *spooler)
222 {
223 /* perform sanity checks */
224 if (spooler == NULL)
225 return -1;
226
227 LogMessage("Closing spool file '%s'. Read %d records\n",
228 spooler->filepath, spooler->record_idx);
229
230 if (spooler->fd != -1)
231 close(spooler->fd);
232
233 /* free record */
234 spoolerFreeRecord(&spooler->record);
235
236 free(spooler);
237 spooler = NULL;
238
239 return 0;
240 }
241
RegisterSpooler(Spooler * spooler)242 void RegisterSpooler(Spooler *spooler)
243 {
244 Barnyard2Config *bc = BcGetConfig();
245
246 if(!bc)
247 return;
248
249
250 if(bc->spooler)
251 {
252 /* XXX */
253 FatalError("[%s()], can't register spooler. \n",
254 __FUNCTION__);
255 }
256 else
257 {
258 bc->spooler = spooler;
259 }
260
261 return;
262 }
263
UnRegisterSpooler(Spooler * spooler)264 void UnRegisterSpooler(Spooler *spooler)
265 {
266 Barnyard2Config *bc = BcGetConfig();
267
268 if(!bc)
269 return;
270
271 if(bc->spooler != spooler)
272 {
273 /* XXX */
274 FatalError("[%s()], can't un-register spooler. \n",
275 __FUNCTION__);
276 }
277 else
278 {
279 bc->spooler = NULL;
280 }
281
282 return;
283 }
284
285
286
spoolerReadRecordHeader(Spooler * spooler)287 int spoolerReadRecordHeader(Spooler *spooler)
288 {
289 int ret;
290
291 /* perform sanity checks */
292 if ( spooler == NULL )
293 return -1;
294
295 if (spooler->state != SPOOLER_STATE_OPENED && spooler->state != SPOOLER_STATE_RECORD_READ)
296 {
297 LogMessage("ERROR: Invalid attempt to read record header.\n");
298 return -1;
299 }
300
301 if (spooler->ifn->readRecordHeader)
302 {
303 ret = spooler->ifn->readRecordHeader(spooler);
304
305 if (ret != 0)
306 return ret;
307
308 spooler->state = SPOOLER_STATE_HEADER_READ;
309 spooler->offset = 0;
310 }
311 else
312 {
313 LogMessage("WARNING: No function defined to read header.\n");
314 return -1;
315 }
316
317 return 0;
318 }
319
spoolerReadRecord(Spooler * spooler)320 int spoolerReadRecord(Spooler *spooler)
321 {
322 int ret;
323
324 /* perform sanity checks */
325 if (spooler == NULL)
326 return -1;
327
328 if (spooler->state != SPOOLER_STATE_HEADER_READ)
329 {
330 LogMessage("ERROR: Invalid attempt to read record.\n");
331 return -1;
332 }
333
334 if (spooler->ifn->readRecord)
335 {
336 ret = spooler->ifn->readRecord(spooler);
337
338 if (ret != 0)
339 return ret;
340
341 spooler->state = SPOOLER_STATE_RECORD_READ;
342 spooler->record_idx++;
343 spooler->offset = 0;
344 }
345 else
346 {
347 LogMessage("WARNING: No function defined to read header.\n");
348 return -1;
349 }
350
351 return 0;
352 }
353
ProcessBatch(const char * dirpath,const char * filename)354 int ProcessBatch(const char *dirpath, const char *filename)
355 {
356 Spooler *spooler = NULL;
357 int ret = 0;
358 int pb_ret = 0;
359
360 /* Open the spool file */
361 if ( (spooler=spoolerOpen("", filename, 0)) == NULL)
362 {
363 FatalError("Unable to create spooler: %s\n", strerror(errno));
364 }
365
366 while (exit_signal == 0 && pb_ret == 0)
367 {
368 /* for SIGUSR1 / dropstats */
369 SignalCheck();
370
371 switch (spooler->state)
372 {
373 case SPOOLER_STATE_OPENED:
374 case SPOOLER_STATE_RECORD_READ:
375 ret = spoolerReadRecordHeader(spooler);
376
377 if (ret == BARNYARD2_READ_EOF)
378 {
379 pb_ret = -1;
380 }
381 else if (ret != 0)
382 {
383 LogMessage("ERROR: Input file '%s' is corrupted! (%u)\n",
384 spooler->filepath, ret);
385 pb_ret = -1;
386 }
387 break;
388
389 default:
390 ret = spoolerReadRecord(spooler);
391
392 if (ret == 0)
393 {
394 /* process record, firing output as required */
395 spoolerProcessRecord(spooler, 1);
396 }
397 else if (ret == BARNYARD2_READ_EOF)
398 {
399 pb_ret = -1;
400 }
401 else
402 {
403 LogMessage("ERROR: Input file '%s' is corrupted! (%u)\n",
404 spooler->filepath, ret);
405 pb_ret = -1;
406 }
407
408 spoolerFreeRecord(&spooler->record);
409 break;
410 }
411 }
412
413 /* we've finished with the spooler so destroy and cleanup */
414 spoolerClose(spooler);
415 spooler = NULL;
416
417 return pb_ret;
418 }
419
420 /*
421 ** ProcessContinuous(const char *dirpath, const char *filebase, uint32_t record_start, time_t timestamp)
422 **
423 **
424 **
425 */
ProcessContinuous(const char * dirpath,const char * filebase,uint32_t record_start,uint32_t timestamp)426 int ProcessContinuous(const char *dirpath, const char *filebase,
427 uint32_t record_start, uint32_t timestamp)
428 {
429 Spooler *spooler = NULL;
430 int ret = 0;
431 int pc_ret = 0;
432 int new_file_available = 0;
433 int waiting_logged = 0;
434 uint32_t skipped = 0;
435 uint32_t extension = 0;
436
437 u_int32_t waldo_timestamp = 0;
438 waldo_timestamp = timestamp; /* fix possible bug by keeping invocated timestamp at the time of the initial call */
439
440 if (BcProcessNewRecordsOnly())
441 {
442 LogMessage("Processing new records only.\n");
443
444 /* Find newest file extension */
445 while (FindNextExtension(dirpath, filebase, timestamp, &extension) == 0)
446 {
447 if (timestamp > 0 && BcLogVerbose())
448 LogMessage("Skipping file: %s/%s.%u\n", dirpath,
449 filebase, timestamp);
450
451 timestamp = extension + 1;
452 }
453
454 timestamp = extension;
455 }
456
457 /* Start the main process loop */
458 while (exit_signal == 0)
459 {
460 /* for SIGUSR1 / dropstats */
461 SignalCheck();
462
463 /* no spooler exists so let's create one */
464 if (spooler == NULL)
465 {
466 /* find the next file to spool */
467 ret = FindNextExtension(dirpath, filebase, timestamp, &extension);
468
469 /* The file found is not the same as specified in the waldo,
470 thus we need to reset record_start, since we are obviously not processing the same file*/
471 if(waldo_timestamp != extension)
472 {
473 record_start = 0; /* There is no danger to resetting record_start to 0
474 if called timestamp is not the same */
475 }
476
477
478 /* no new extensions found */
479 if (ret == SPOOLER_EXTENSION_NONE)
480 {
481 if (waiting_logged == 0)
482 {
483 if (BcProcessNewRecordsOnly())
484 LogMessage("Skipped %u old records\n", skipped);
485
486 LogMessage("Waiting for new spool file\n");
487 waiting_logged = 1;
488 barnyard2_conf->process_new_records_only_flag = 0;
489 }
490
491 sleep(1);
492 continue;
493 }
494 /* an error occured whilst looking for new extensions */
495 else if (ret != SPOOLER_EXTENSION_FOUND)
496 {
497 LogMessage("ERROR: Unable to find the next spool file!\n");
498 exit_signal = -1;
499 pc_ret = -1;
500 continue;
501 }
502
503 /* found a new extension so create a new spooler */
504 if ( (spooler=spoolerOpen(dirpath, filebase, extension)) == NULL )
505 {
506 LogMessage("ERROR: Unable to create spooler!\n");
507 exit_signal = -1;
508 pc_ret = -1;
509 continue;
510 }
511 else
512 {
513 /* Make sure we create a new waldo even if we did not have processed an event */
514 if(waldo_timestamp != extension)
515 {
516 spooler->record_idx = 0;
517 spoolerWriteWaldo(&barnyard2_conf->waldo, spooler);
518 }
519 waiting_logged = 0;
520
521 /* set timestamp to ensure we look for a newer file next time */
522 timestamp = extension + 1;
523 }
524
525 continue;
526 }
527
528 /* act according to current spooler state */
529 switch(spooler->state)
530 {
531 case SPOOLER_STATE_OPENED:
532 case SPOOLER_STATE_RECORD_READ:
533 ret = spoolerReadRecordHeader(spooler);
534 break;
535
536 case SPOOLER_STATE_HEADER_READ:
537 ret = spoolerReadRecord(spooler);
538 break;
539
540 default:
541 LogMessage("ERROR: Invalid spooler state (%i). Closing '%s'\n",
542 spooler->state, spooler->filepath);
543
544 #ifndef WIN32
545 /* archive the spool file */
546 if (BcArchiveDir() != NULL)
547 ArchiveFile(spooler->filepath, BcArchiveDir());
548 #endif
549
550 /* we've finished with the spooler so destroy and cleanup */
551 UnRegisterSpooler(spooler);
552 spoolerClose(spooler);
553 spooler = NULL;
554
555 record_start = 0;
556 break;
557 }
558
559 /* if no spooler exists, we are waiting for a newer file to arrive */
560 if (spooler == NULL)
561 continue;
562
563 if (ret == 0)
564 {
565 /* check for a successful record read */
566 if (spooler->state == SPOOLER_STATE_RECORD_READ)
567 {
568 if (record_start > 0)
569 {
570 /* skip this record */
571 record_start--;
572 DEBUG_WRAP(DebugMessage(DEBUG_SPOOLER,"Skipping due to record start offset (%lu)...\n",
573 (long unsigned)record_start););
574
575 /* process record to ensure correlation context, but DO NOT fire output*/
576 spoolerProcessRecord(spooler, 0);
577 }
578 else if (BcProcessNewRecordsOnly())
579 {
580 /* skip this record */
581 skipped++;
582 DEBUG_WRAP(DebugMessage(DEBUG_SPOOLER,"Skipping due to new records only flag...\n"););
583
584 /* process record to ensure correlation context, but DO NOT fire output*/
585 spoolerProcessRecord(spooler, 0);
586 }
587 else
588 {
589 /* process record, firing output as required */
590 spoolerProcessRecord(spooler, 1);
591 }
592 }
593
594 spoolerFreeRecord(&spooler->record);
595 }
596 else if (ret == BARNYARD2_FILE_ERROR)
597 {
598 LogMessage("ERROR: Reading current file!\n");
599 exit_signal = -3;
600 pc_ret = -1;
601 continue;
602 }
603 else
604 {
605 if (new_file_available)
606 {
607 switch(spooler->state)
608 {
609 case SPOOLER_STATE_OPENED:
610 case SPOOLER_STATE_HEADER_READ:
611 case SPOOLER_STATE_RECORD_READ:
612 if (ret == BARNYARD2_ETRUNC)
613 LogMessage("Truncated record in '%s'\n", spooler->filepath);
614 break;
615
616 default:
617 if (ret == BARNYARD2_READ_PARTIAL)
618 LogMessage("Partial read from '%s'\n",
619 spooler->filepath);
620 break;
621 }
622
623 /* archive the file */
624 if (BcArchiveDir() != NULL)
625 ArchiveFile(spooler->filepath, BcArchiveDir());
626
627 /* close (ie. destroy and cleanup) the spooler so we can rotate */
628 UnRegisterSpooler(spooler);
629 spoolerClose(spooler);
630 spooler = NULL;
631
632 record_start = 0;
633 new_file_available = 0;
634 }
635 else
636 {
637 ret = FindNextExtension(dirpath, filebase, timestamp, NULL);
638 if (ret == 0)
639 {
640 new_file_available = 1;
641 }
642 else if (ret == -1)
643 {
644 LogMessage("ERROR: Looking for next spool file!\n");
645 exit_signal = -3;
646 pc_ret = -1;
647 }
648 else
649 {
650 if (!waiting_logged)
651 {
652 if (BcProcessNewRecordsOnly())
653 LogMessage("Skipped %u old records\n", skipped);
654
655 LogMessage("Waiting for new data\n");
656 waiting_logged = 1;
657 barnyard2_conf->process_new_records_only_flag = 0;
658 }
659
660 sleep(1);
661 continue;
662 }
663 }
664 }
665 }
666
667 /* close waldo if appropriate */
668 if(barnyard2_conf)
669 spoolerCloseWaldo(&barnyard2_conf->waldo);
670
671 return pc_ret;
672 }
673
ProcessContinuousWithWaldo(Waldo * waldo)674 int ProcessContinuousWithWaldo(Waldo *waldo)
675 {
676 if (waldo == NULL)
677 return -1;
678
679 return ProcessContinuous(waldo->data.spool_dir, waldo->data.spool_filebase,
680 waldo->data.record_idx, waldo->data.timestamp);
681 }
682
683
684 /*
685 ** RECORD PROCESSING EVENTS
686 */
687
spoolerProcessRecord(Spooler * spooler,int fire_output)688 void spoolerProcessRecord(Spooler *spooler, int fire_output)
689 {
690 struct pcap_pkthdr pkth;
691 uint32_t type;
692 EventRecordNode *ernCache;
693
694 /* convert type once */
695 type = ntohl(((Unified2RecordHeader *)spooler->record.header)->type);
696
697 /* increment the stats */
698 pc.total_records++;
699 switch (type)
700 {
701 case UNIFIED2_PACKET:
702 pc.total_packets++;
703 break;
704 case UNIFIED2_IDS_EVENT:
705 case UNIFIED2_IDS_EVENT_IPV6:
706 case UNIFIED2_IDS_EVENT_MPLS:
707 case UNIFIED2_IDS_EVENT_IPV6_MPLS:
708 case UNIFIED2_IDS_EVENT_VLAN:
709 case UNIFIED2_IDS_EVENT_IPV6_VLAN:
710 pc.total_events++;
711 break;
712 default:
713 pc.total_unknown++;
714 }
715
716 /* check if it's packet */
717 if (type == UNIFIED2_PACKET)
718 {
719 /* convert event id once */
720 uint32_t event_id = ntohl(((Unified2Packet *)spooler->record.data)->event_id);
721
722 /* check if there is a previously cached event that matches this event id */
723 ernCache = spoolerEventCacheGetByEventID(spooler, event_id);
724
725 /* allocate space for the packet and construct the packet header */
726 spooler->record.pkt = SnortAlloc(sizeof(Packet));
727
728 pkth.caplen = ntohl(((Unified2Packet *)spooler->record.data)->packet_length);
729 pkth.len = pkth.caplen;
730 pkth.ts.tv_sec = ntohl(((Unified2Packet *)spooler->record.data)->packet_second);
731 pkth.ts.tv_usec = ntohl(((Unified2Packet *)spooler->record.data)->packet_microsecond);
732
733 /* decode the packet from the Unified2Packet information */
734 datalink = ntohl(((Unified2Packet *)spooler->record.data)->linktype);
735 DecodePacket(datalink, spooler->record.pkt, &pkth,
736 ((Unified2Packet *)spooler->record.data)->packet_data);
737
738 /* This is a fixup for portscan... */
739 if( (spooler->record.pkt->iph == NULL) &&
740 ((spooler->record.pkt->inner_iph != NULL) && (spooler->record.pkt->inner_iph->ip_proto == 255)))
741 {
742 spooler->record.pkt->iph = spooler->record.pkt->inner_iph;
743 }
744
745 /* check if it's been re-assembled */
746 if (spooler->record.pkt->packet_flags & PKT_REBUILT_STREAM)
747 {
748 DEBUG_WRAP(DebugMessage(DEBUG_SPOOLER,"Packet has been rebuilt from a stream\n"););
749 }
750
751 /* if the packet and cached event share the same id */
752 if ( ernCache != NULL )
753 {
754 /* call output plugins with a "SPECIAL" alert format (both Event and Packet information) */
755 DEBUG_WRAP(DebugMessage(DEBUG_SPOOLER,"Firing SPECIAL style (Packet+Event)\n"););
756
757 if ( fire_output &&
758 ((ernCache->used == 0) || BcAlertOnEachPacketInStream()) )
759 CallOutputPlugins(OUTPUT_TYPE__SPECIAL,
760 spooler->record.pkt,
761 ernCache->data,
762 ernCache->type);
763
764 /* indicate that the cached event has been used */
765 ernCache->used = 1;
766 }
767 else
768 {
769 /* fire the event cache head only if not already used (ie dirty) */
770 if ( spoolerEventCacheHeadUsed(spooler) == 0 )
771 {
772 ernCache = spoolerEventCacheGetHead(spooler);
773
774 /* call output plugins with an "ALERT" format (cached Event information only) */
775 DEBUG_WRAP(DebugMessage(DEBUG_SPOOLER,"Firing ALERT style (Event only)\n"););
776
777 if (fire_output)
778 CallOutputPlugins(OUTPUT_TYPE__ALERT,
779 NULL,
780 ernCache->data,
781 ernCache->type);
782
783 /* set the event cache used flag */
784 ernCache->used = 1;
785 }
786
787 /* call output plugins with a "LOG" format (Packet information only) */
788 DEBUG_WRAP(DebugMessage(DEBUG_SPOOLER,"Firing LOG style (Packet)\n"););
789
790 if (fire_output)
791 CallOutputPlugins(OUTPUT_TYPE__SPECIAL,
792 spooler->record.pkt,
793 NULL,
794 0);
795 }
796
797 /* free the memory allocated in this function */
798 free(spooler->record.pkt);
799 spooler->record.pkt = NULL;
800
801 /* waldo operations occur after the output plugins are called */
802 if (fire_output)
803 spoolerWriteWaldo(&barnyard2_conf->waldo, spooler);
804 }
805 /* check if it's an event of known sorts */
806 else if(type == UNIFIED2_IDS_EVENT || type == UNIFIED2_IDS_EVENT_IPV6 ||
807 type == UNIFIED2_IDS_EVENT_MPLS || type == UNIFIED2_IDS_EVENT_IPV6_MPLS ||
808 type == UNIFIED2_IDS_EVENT_VLAN || type == UNIFIED2_IDS_EVENT_IPV6_VLAN)
809 {
810 /* fire the cached event only if not already used (ie dirty) */
811 if ( spoolerEventCacheHeadUsed(spooler) == 0 )
812 {
813 /* call output plugins with an "ALERT" format (cached Event information only) */
814 DEBUG_WRAP(DebugMessage(DEBUG_SPOOLER,"Firing ALERT style (Event only)\n"););
815
816 ernCache = spoolerEventCacheGetHead(spooler);
817
818 if (fire_output)
819 CallOutputPlugins(OUTPUT_TYPE__ALERT,
820 NULL,
821 ernCache->data,
822 ernCache->type);
823
824 /* flush the event cache flag */
825 ernCache->used = 1;
826 }
827
828 /* cache new data */
829 spoolerEventCachePush(spooler, type, spooler->record.data);
830 spooler->record.data = NULL;
831
832 /* waldo operations occur after the output plugins are called */
833 if (fire_output)
834 spoolerWriteWaldo(&barnyard2_conf->waldo, spooler);
835 }
836 else if (type == UNIFIED2_EXTRA_DATA)
837 {
838 /* waldo operations occur after the output plugins are called */
839 if (fire_output)
840 spoolerWriteWaldo(&barnyard2_conf->waldo, spooler);
841 }
842 else
843 {
844 /* fire the cached event only if not already used (ie dirty) */
845 if ( spoolerEventCacheHeadUsed(spooler) == 0 )
846 {
847 /* call output plugins with an "ALERT" format (cached Event information only) */
848 DEBUG_WRAP(DebugMessage(DEBUG_SPOOLER,"Firing ALERT style (Event only)\n"););
849
850 ernCache = spoolerEventCacheGetHead(spooler);
851
852 if (fire_output)
853 CallOutputPlugins(OUTPUT_TYPE__ALERT,
854 NULL,
855 ernCache->data,
856 ernCache->type);
857
858 /* waldo operations occur after the output plugins are called */
859 if (fire_output)
860 spoolerWriteWaldo(&barnyard2_conf->waldo, spooler);
861 }
862 }
863
864 /* clean the cache out */
865 spoolerEventCacheClean(spooler);
866 }
867
spoolerEventCachePush(Spooler * spooler,uint32_t type,void * data)868 int spoolerEventCachePush(Spooler *spooler, uint32_t type, void *data)
869 {
870 EventRecordNode *ernNode;
871
872 DEBUG_WRAP(DebugMessage(DEBUG_SPOOLER,"Caching event...\n"););
873
874 /* allocate memory */
875 ernNode = (EventRecordNode *)SnortAlloc(sizeof(EventRecordNode));
876
877 /* create the new node */
878 ernNode->used = 0;
879 ernNode->type = type;
880 ernNode->data = data;
881
882 /* add new events to the front of the cache */
883 ernNode->next = spooler->event_cache;
884
885 spooler->event_cache = ernNode;
886 spooler->events_cached++;
887
888 DEBUG_WRAP(DebugMessage(DEBUG_SPOOLER,"Cached event: %d\n", spooler->events_cached););
889
890 return 0;
891 }
892
spoolerEventCacheGetByEventID(Spooler * spooler,uint32_t event_id)893 EventRecordNode *spoolerEventCacheGetByEventID(Spooler *spooler, uint32_t event_id)
894 {
895 EventRecordNode *ernCurrent = spooler->event_cache;
896
897 while (ernCurrent != NULL)
898 {
899 if ( ntohl(((Unified2EventCommon *)ernCurrent->data)->event_id) == event_id )
900 {
901 return ernCurrent;
902 }
903
904 ernCurrent = ernCurrent->next;
905 }
906
907 return NULL;
908 }
909
spoolerEventCacheGetHead(Spooler * spooler)910 EventRecordNode *spoolerEventCacheGetHead(Spooler *spooler)
911 {
912 if ( spooler == NULL )
913 return NULL;
914
915 return spooler->event_cache;
916 }
917
spoolerEventCacheHeadUsed(Spooler * spooler)918 uint8_t spoolerEventCacheHeadUsed(Spooler *spooler)
919 {
920 if ( spooler == NULL || spooler->event_cache == NULL )
921 return 255;
922
923 return spooler->event_cache->used;
924 }
925
spoolerEventCacheClean(Spooler * spooler)926 int spoolerEventCacheClean(Spooler *spooler)
927 {
928 EventRecordNode *ernCurrent = NULL;
929 EventRecordNode *ernPrev = NULL;
930 EventRecordNode *ernNext = NULL;
931
932 if (spooler == NULL || spooler->event_cache == NULL )
933 return 1;
934
935 ernPrev = spooler->event_cache;
936 ernCurrent = spooler->event_cache;
937
938 while (ernCurrent != NULL && spooler->events_cached > barnyard2_conf->event_cache_size )
939 {
940 ernNext = ernCurrent->next;
941
942 if ( ernCurrent->used == 1 )
943 {
944 /* Delete from list */
945 if (ernCurrent == spooler->event_cache)
946 {
947 spooler->event_cache = ernNext;
948 }
949 else
950 {
951 ernPrev->next = ernNext;
952 }
953
954 spooler->events_cached--;
955
956 if(ernCurrent->data != NULL)
957 {
958 free(ernCurrent->data);
959 }
960
961 if(ernCurrent != NULL)
962 {
963 free(ernCurrent);
964 }
965 }
966
967 if(ernCurrent != NULL)
968 {
969 ernPrev = ernCurrent;
970 }
971
972 ernCurrent = ernNext;
973
974 }
975
976 return 0;
977 }
978
spoolerEventCacheFlush(Spooler * spooler)979 void spoolerEventCacheFlush(Spooler *spooler)
980 {
981 EventRecordNode *next_ptr = NULL;
982 EventRecordNode *evt_ptr = NULL;
983
984 if (spooler == NULL || spooler->event_cache == NULL )
985 return;
986
987 evt_ptr = spooler->event_cache;
988
989 while(evt_ptr != NULL)
990 {
991 next_ptr = evt_ptr->next;
992
993 if(evt_ptr->data)
994 {
995 free(evt_ptr->data);
996 evt_ptr->data = NULL;
997 }
998
999 free(evt_ptr);
1000
1001 evt_ptr = next_ptr;
1002 }
1003
1004 spooler->event_cache = NULL;
1005
1006 return;
1007 }
1008
1009
spoolerFreeRecord(Record * record)1010 void spoolerFreeRecord(Record *record)
1011 {
1012 if (record->data)
1013 {
1014 free(record->data);
1015 }
1016
1017
1018 record->data = NULL;
1019 }
1020
1021 /*
1022 ** WALDO FILE OPERATIONS
1023 */
1024
1025 /*
1026 ** spoolerOpenWaldo(Waldo *waldo, uint8_t mode)
1027 **
1028 ** Description:
1029 ** Open the waldo file, non-blocking, defined in the Waldo structure
1030 */
spoolerOpenWaldo(Waldo * waldo,uint8_t mode)1031 int spoolerOpenWaldo(Waldo *waldo, uint8_t mode)
1032 {
1033 struct stat waldo_info;
1034 int waldo_file_flags = 0;
1035 mode_t waldo_file_mode = 0;
1036 int ret = 0;
1037
1038 /* check if waldo file is already open and in the correct mode */
1039 if ( (waldo->state & WALDO_STATE_OPEN) && (waldo->fd != -1) && (waldo->mode == mode) )
1040 {
1041 return WALDO_FILE_SUCCESS;
1042 }
1043
1044 /* check that a waldo file has been specified */
1045 if ( waldo->filepath[0] == '\0' )
1046 {
1047 return WALDO_FILE_EEXIST;
1048 }
1049
1050 /* stat the file to see it exists */
1051 ret = stat(waldo->filepath, &waldo_info);
1052
1053 if ( mode == WALDO_MODE_READ )
1054 waldo_file_flags = ( O_RDONLY );
1055 else if ( mode == WALDO_MODE_WRITE )
1056 {
1057 waldo_file_flags = ( O_CREAT | O_WRONLY );
1058 waldo_file_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) ;
1059 }
1060
1061 /* open the file non-blocking */
1062 if ( (waldo->fd=open(waldo->filepath, waldo_file_flags, waldo_file_mode)) == -1 )
1063 {
1064 LogMessage("WARNING: Unable to open waldo file '%s' (%s)\n", waldo->filepath,
1065 strerror(errno));
1066 return WALDO_FILE_EOPEN;
1067 }
1068
1069 if ( ret != 0 )
1070 return WALDO_FILE_EEXIST;
1071
1072 /* set waldo state and mode */
1073 waldo->state |= WALDO_STATE_OPEN;
1074 waldo->mode = mode;
1075
1076 return WALDO_FILE_SUCCESS;
1077 }
1078
1079 /*
1080 ** spoolerCloseWaldo(Waldo *waldo)
1081 **
1082 ** Description:
1083 ** Open the waldo file, non-blocking, defined in the Waldo structure
1084 **
1085 */
spoolerCloseWaldo(Waldo * waldo)1086 int spoolerCloseWaldo(Waldo *waldo)
1087 {
1088 if(waldo == NULL)
1089 return WALDO_STRUCT_EMPTY;
1090
1091 /* check we have a valid file descriptor */
1092 if (waldo->state & WALDO_STATE_OPEN)
1093 return WALDO_FILE_EOPEN;
1094
1095 /* close the file */
1096 if(waldo->fd > 0)
1097 close(waldo->fd);
1098
1099 waldo->fd = -1;
1100
1101 /* reset open state and mode */
1102 waldo->state &= ( ~WALDO_STATE_OPEN );
1103 waldo->mode = WALDO_MODE_NULL;
1104
1105 return WALDO_FILE_SUCCESS;
1106 }
1107
1108 /*
1109 ** spoolReadWaldo(Waldo *waldo)
1110 **
1111 ** Description:
1112 ** Read the waldo file defined in the Waldo structure and populate all values
1113 ** within.
1114 **
1115 */
spoolerReadWaldo(Waldo * waldo)1116 int spoolerReadWaldo(Waldo *waldo)
1117 {
1118 int ret;
1119 WaldoData wd;
1120
1121 /* check if we have a file in the correct mode (READ) */
1122 if ( waldo->mode != WALDO_MODE_READ )
1123 {
1124 /* close waldo if appropriate */
1125 if(barnyard2_conf)
1126 spoolerCloseWaldo(waldo);
1127
1128 if ( (ret=spoolerOpenWaldo(waldo, WALDO_MODE_READ)) != WALDO_FILE_SUCCESS )
1129 return ret;
1130 }
1131 else if ( ! (waldo->state & WALDO_STATE_OPEN) )
1132 {
1133 if ( (ret=spoolerOpenWaldo(waldo, WALDO_MODE_READ)) != WALDO_FILE_SUCCESS )
1134 return ret;
1135 }
1136 else
1137 {
1138 /* ensure we are at the beggining since we must be open and in read */
1139 lseek(waldo->fd, 0, SEEK_SET);
1140 }
1141
1142 /* read values into temporary WaldoData structure */
1143 ret = read(waldo->fd, &wd, sizeof(WaldoData));
1144
1145 /* TODO: additional checks on the waldo file data to test corruption */
1146 if ( ret != sizeof(WaldoData) )
1147 return WALDO_FILE_ETRUNC;
1148
1149 /* copy waldo file contents to the directory structure */
1150 memcpy(&waldo->data, &wd, sizeof(WaldoData));
1151
1152 DEBUG_WRAP(DebugMessage(DEBUG_SPOOLER,
1153 "Waldo read\n\tdir: %s\n\tbase: %s\n\ttime: %lu\n\tidx: %d\n",
1154 waldo->data.spool_dir, waldo->data.spool_filebase,
1155 waldo->data.timestamp, waldo->data.record_idx););
1156
1157
1158 /* close waldo if appropriate */
1159 if(barnyard2_conf)
1160 spoolerCloseWaldo(waldo);
1161
1162 return WALDO_FILE_SUCCESS;
1163 }
1164
1165 /*
1166 ** spoolerWriteWaldo(Waldo *waldo)
1167 **
1168 ** Description:
1169 ** Write to the waldo file
1170 **
1171 */
spoolerWriteWaldo(Waldo * waldo,Spooler * spooler)1172 int spoolerWriteWaldo(Waldo *waldo, Spooler *spooler)
1173 {
1174 int ret;
1175
1176 /* check if we are using waldo files */
1177 if ( ! (waldo->state & WALDO_STATE_ENABLED) )
1178 return WALDO_STRUCT_EMPTY;
1179
1180 /* check that a waldo file exists before continued */
1181 if (waldo == NULL)
1182 return WALDO_STRUCT_EMPTY;
1183
1184 /* update fields */
1185 waldo->data.timestamp = spooler->timestamp;
1186 waldo->data.record_idx = spooler->record_idx;
1187
1188 /* check if we have a file in the correct mode (READ) */
1189 if ( waldo->mode != WALDO_MODE_WRITE )
1190 {
1191 /* close waldo if appropriate */
1192 if(barnyard2_conf)
1193 spoolerCloseWaldo(waldo);
1194
1195
1196 spoolerOpenWaldo(waldo, WALDO_MODE_WRITE);
1197 }
1198 else if ( ! (waldo->state & WALDO_STATE_OPEN) )
1199 {
1200 spoolerOpenWaldo(waldo, WALDO_MODE_WRITE);
1201 }
1202 else
1203 {
1204 /* ensure we are at the start since we must be open and in write */
1205 lseek(waldo->fd, 0, SEEK_SET);
1206 }
1207
1208 /* write values */
1209 ret = write(waldo->fd, &waldo->data, sizeof(WaldoData));
1210
1211 if (ret != sizeof(WaldoData) )
1212 return WALDO_FILE_ETRUNC;
1213
1214 DEBUG_WRAP(DebugMessage(DEBUG_SPOOLER,
1215 "Waldo write\n\tdir: %s\n\tbase: %s\n\ttime: %lu\n\tidx: %d\n",
1216 waldo->data.spool_dir, waldo->data.spool_filebase,
1217 waldo->data.timestamp, waldo->data.record_idx););
1218
1219 return WALDO_FILE_SUCCESS;
1220 }
1221
1222