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