1 /*
2 ** Copyright (C) 2010 Seth Hall <seth@icir.org>
3 **
4 ** This program is free software; you can redistribute it and/or modify
5 ** it under the terms of the GNU General Public License Version 2 as
6 ** published by the Free Software Foundation.  You may not use, modify or
7 ** distribute this program under any other version of the GNU General
8 ** Public License.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19 /* $Id$ */
20 
21 /* spo_alert_Bro
22  *
23  * This module sends alerts to the Bro-IDS as Bro events using the Bro
24  * communications protocol.
25  *
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #ifdef BROCCOLI
33 
34 #include <string.h>
35 #include <sys/types.h>
36 #include <stdlib.h>
37 #ifdef HAVE_STRINGS_H
38 #include <strings.h>
39 #endif
40 
41 #include "broccoli.h"
42 
43 #include "barnyard2.h"
44 #include "decode.h"
45 #include "debug.h"
46 #include "map.h"
47 #include "mstring.h"
48 #include "parser.h"
49 #include "strlcatu.h"
50 #include "strlcpyu.h"
51 #include "plugbase.h"
52 #include "unified2.h"
53 #include "util.h"
54 #include "ipv6_port.h"
55 
56 extern OptTreeNode *otn_tmp;
57 
58 void AlertBroSetup(void);
59 void AlertBroInit(char *);
60 void AlertBro(Packet *, void *, u_int32_t, void *);
61 void AlertBroCleanExit(int, void *);
62 void AlertBroRestart(int, void *);
63 
64 static BroConn *bro_conn;
65 
66 /*
67  * Function: AlertBroSetup()
68  *
69  * Purpose: Registers the output plugin keyword and initialization
70  *          function into the output plugin list.  This is the function that
71  *          gets called from InitOutputPlugins() in plugbase.c.
72  *
73  * Arguments: None.
74  *
75  * Returns: void function
76  *
77  */
AlertBroSetup(void)78 void AlertBroSetup(void)
79 {
80     /* link the preprocessor keyword to the init function in
81        the preproc list */
82     RegisterOutputPlugin("alert_bro", OUTPUT_TYPE_FLAG__ALERT, AlertBroInit);
83     DEBUG_WRAP(DebugMessage(DEBUG_INIT,"Output plugin: Alert-Bro is setup...\n"););
84 }
85 
86 
87 /*
88  * Function: AlertBroInit(char *)
89  *
90  * Purpose: Makes the connection to Bro, links the preproc function
91  *          into the function list.
92  *
93  * Arguments: args => ptr to argument string
94  *
95  * Returns: void function
96  *
97  */
AlertBroInit(char * args)98 void AlertBroInit(char *args)
99 {
100     char *host_string = args;
101 
102     bro_init(NULL);
103     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Output: Alert-Bro Initialized\n"););
104 
105     if ( !(bro_conn = bro_conn_new_str(host_string,
106                             BRO_CFLAG_RECONNECT | BRO_CFLAG_ALWAYS_QUEUE )) )
107     {
108         FatalError("Could not get Bro connection handle.\n", host_string);
109     }
110     bro_conn_set_class(bro_conn, "barnyard");
111     LogMessage("alert_bro Connecting to Bro (%s)...", host_string);
112     if ( !bro_conn_connect(bro_conn) )
113     {
114         FatalError("failed!\nCould not connect to Bro!\n");
115     }
116     LogMessage("done.\n");
117 
118     DEBUG_WRAP(DebugMessage(DEBUG_INIT,"Linking Bro alert function to call list...\n"););
119     /* Set the preprocessor function into the function list */
120     AddFuncToOutputList(AlertBro, OUTPUT_TYPE__ALERT, 0);
121     AddFuncToCleanExitList(AlertBroCleanExit, 0);
122     AddFuncToRestartList(AlertBroRestart, 0);
123 }
124 
125 #ifdef SUP_IP6
map_broccoli_addr(BroAddr * a,const snort_ip_p i)126 static INLINE void map_broccoli_addr(BroAddr* a, const snort_ip_p i)
127 {
128     if ( i->family == AF_INET )
129     {
130         memcpy(a->addr, BRO_IPV4_MAPPED_PREFIX, sizeof(BRO_IPV4_MAPPED_PREFIX));
131         memcpy(&a->addr[3], i->ip.u6_addr32, sizeof(uint32_t));
132     }
133     else if ( i->family == AF_INET6 )
134         memcpy(a->addr, &i->ip, sizeof(a->addr));
135 }
136 #else
map_broccoli_addr(BroAddr * a,const struct in_addr i)137 static INLINE void map_broccoli_addr(BroAddr* a, const struct in_addr i)
138 {
139     memcpy(a->addr, BRO_IPV4_MAPPED_PREFIX, sizeof(BRO_IPV4_MAPPED_PREFIX));
140     memcpy(&a->addr[3], &i, sizeof(uint32_t));
141 }
142 #endif
143 
144 /*
145  * Function: AlertBro(Packet *)
146  *
147  * Arguments: p => pointer to the current packet data struct
148  *
149  * Returns: void function
150  *
151  */
AlertBro(Packet * p,void * event,u_int32_t event_type,void * arg)152 void AlertBro(Packet *p, void *event, u_int32_t event_type, void *arg)
153 {
154     BroEvent      *ev;
155     SigNode       *sn;
156     ClassType     *cn;
157     ReferenceNode *rn;
158 
159     Unified2EventCommon *uevent = (Unified2EventCommon *) event;
160     BroPort src_p;
161     BroPort dst_p;
162     BroAddr src_addr;
163     BroAddr dst_addr;
164 
165     if ( p == NULL || event == NULL )
166     {
167         return;
168     }
169 
170     sn = GetSigByGidSid(ntohl(uevent->generator_id),
171                         ntohl(uevent->signature_id),
172 	                ntohl(uevent->signature_revision));
173 
174     if(p && IPH_IS_VALID(p))
175     {
176         ev = bro_event_new("Barnyard2::barnyard_alert");
177 
178         // First value
179         BroRecord *packet_id = bro_record_new();
180         src_p.port_num = dst_p.port_num = 0;
181         // Broccoli's protocol handling is sort of broken at the moment
182         // it segfaults when doing bro_record_add_val if not tcp, udp, or icmp
183         // waiting on ticket: http://tracker.icir.org/bro/ticket/278
184         src_p.port_proto = dst_p.port_proto = IPPROTO_TCP;
185         if(GET_IPH_PROTO(p) != 255)
186         {
187             src_p.port_proto = dst_p.port_proto = GET_IPH_PROTO(p);
188             if((GET_IPH_PROTO(p) == IPPROTO_ICMP) && p->icmph)
189             {
190                 src_p.port_num = p->icmph->type;
191                 dst_p.port_num = p->icmph->code;
192             } else {
193                 src_p.port_num = p->sp;
194                 dst_p.port_num = p->dp;
195             }
196         }
197 
198         map_broccoli_addr(&src_addr, GET_SRC_ADDR(p));
199         bro_record_add_val(packet_id, "src_ip", BRO_TYPE_IPADDR, NULL, &src_addr);
200         bro_record_add_val(packet_id, "src_p",  BRO_TYPE_PORT,   NULL, &src_p);
201         map_broccoli_addr(&dst_addr, GET_DST_ADDR(p));
202         bro_record_add_val(packet_id, "dst_ip", BRO_TYPE_IPADDR, NULL, &dst_addr);
203         bro_record_add_val(packet_id, "dst_p",  BRO_TYPE_PORT,   NULL, &dst_p);
204         bro_event_add_val(ev, BRO_TYPE_RECORD, "Barnyard2::PacketID", packet_id);
205         bro_record_free(packet_id);
206 
207         // Second value
208         BroRecord *sad = bro_record_new();
209         uint64_t sensor_id_hl = ntohl(uevent->sensor_id);
210         bro_record_add_val(sad, "sensor_id",          BRO_TYPE_COUNT, NULL, &sensor_id_hl);
211         double ts = (double) ntohl(uevent->event_second) + (((double) ntohl(uevent->event_microsecond))/1000000);
212         bro_record_add_val(sad, "ts",                 BRO_TYPE_TIME,  NULL, &ts);
213         uint64_t signature_id_hl = ntohl(uevent->signature_id);
214         bro_record_add_val(sad, "signature_id",       BRO_TYPE_COUNT, NULL, &signature_id_hl);
215         uint64_t generator_id_hl = ntohl(uevent->generator_id);
216         bro_record_add_val(sad, "generator_id",       BRO_TYPE_COUNT, NULL, &generator_id_hl);
217         uint64_t signature_revision_hl = ntohl(uevent->signature_revision);
218         bro_record_add_val(sad, "signature_revision", BRO_TYPE_COUNT, NULL, &signature_revision_hl);
219         uint64_t classification_id_hl = ntohl(uevent->classification_id);
220         bro_record_add_val(sad, "classification_id",  BRO_TYPE_COUNT, NULL, &classification_id_hl);
221         BroString class_bs;
222         cn = ClassTypeLookupById(barnyard2_conf, ntohl(uevent->classification_id));
223         bro_string_init(&class_bs);
224         if ( cn )
225             bro_string_set(&class_bs, cn->name);
226         bro_record_add_val(sad, "classification",     BRO_TYPE_STRING, NULL, &class_bs);
227         bro_string_cleanup(&class_bs);
228         uint64_t priority_id_hl = ntohl(uevent->priority_id);
229         bro_record_add_val(sad, "priority_id",        BRO_TYPE_COUNT, NULL, &priority_id_hl);
230         uint64_t event_id_hl = ntohl(uevent->event_id);
231         bro_record_add_val(sad, "event_id",           BRO_TYPE_COUNT, NULL, &event_id_hl);
232         //BroSet *ref_set = bro_set_new();
233         //BroString ref_name_bs;
234         //rn = sn->refs;
235         //while(rn)
236         //{
237         //    bro_string_init(&ref_name_bs);
238         //    bro_string_set(&ref_name_bs, rn->system->name);
239         //    bro_set_insert(ref_set, BRO_TYPE_STRING, &ref_name_bs);
240         //    bro_string_cleanup(&ref_name_bs);
241         //    rn = rn->next;
242         //}
243         //bro_record_add_val(sad, "references", BRO_TYPE_SET, NULL, ref_set);
244         //bro_set_free(ref_set);
245 
246         bro_event_add_val(ev, BRO_TYPE_RECORD, "Barnyard2::AlertData", sad);
247         bro_record_free(sad);
248 
249         // Third value
250         BroString msg_bs;
251         bro_string_init(&msg_bs);
252         bro_string_set(&msg_bs, sn->msg);
253         bro_event_add_val(ev, BRO_TYPE_STRING, NULL, &msg_bs);
254         bro_string_cleanup(&msg_bs);
255 
256         // Fourth value
257         BroString contents_bs;
258         bro_string_init(&contents_bs);
259         bro_string_set_data(&contents_bs, (uchar *) p->data, p->dsize);
260         bro_event_add_val(ev, BRO_TYPE_STRING, NULL, &contents_bs);
261         bro_string_cleanup(&contents_bs);
262 
263         // send and free the event
264         bro_event_send(bro_conn, ev);
265         bro_event_free(ev);
266     }
267     else
268     {
269         // Not bothering with alerts using faked or undecodeable packets.
270         LogMessage("WARNING (Bro) faked or undecodeable packet: %s\n", sn->msg);
271     }
272 
273 }
274 
AlertBroCleanExit(int signal,void * arg)275 void AlertBroCleanExit(int signal, void *arg)
276 {
277     DEBUG_WRAP(DebugMessage(DEBUG_LOG, "AlertBroCleanExit\n"););
278     int remaining=0;
279     while (bro_event_queue_length(bro_conn) > 0)
280         {
281         remaining = bro_event_queue_flush(bro_conn);
282         LogMessage("(Bro) %d events left to flush.\n", remaining);
283         }
284     bro_conn_delete(bro_conn);
285 }
286 
AlertBroRestart(int signal,void * arg)287 void AlertBroRestart(int signal, void *arg)
288 {
289     DEBUG_WRAP(DebugMessage(DEBUG_LOG, "AlertBroRestartFunc\n"););
290     int remaining=0;
291     while (bro_event_queue_length(bro_conn) > 0)
292         {
293         remaining = bro_event_queue_flush(bro_conn);
294         LogMessage("(Bro) %d events left to flush.\n", remaining);
295         }
296     if(!bro_conn_reconnect(bro_conn))
297         FatalError("Could not connect to Bro!\n");
298 }
299 
300 #endif /* BROCCOLI */
301