1 /*
2 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 ** Copyright (C) 2003-2013 Sourcefire, Inc.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 /* $Id$ */
22
23 /* We use some Linux only socket capabilities */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #ifdef LINUX
30
31 #include "sf_types.h"
32 #include "spo_plugbase.h"
33 #include "plugbase.h"
34
35 #include "event.h"
36 #include "rules.h"
37 #include "treenodes.h"
38 #include "snort_debug.h"
39 #include "util.h"
40 #include "sfPolicy.h"
41 #include <sys/socket.h>
42 #include <sys/un.h>
43 #include <errno.h>
44 #include <stdlib.h>
45 #include "generators.h"
46 #include "snort.h"
47 #include "parser.h"
48
49 /* error result codes */
50 #define SNORT_SUCCESS 0
51 #define SNORT_EINVAL 1
52 #define SNORT_ENOENT 2
53 #define SNORT_ENOMEM 3
54
55 static int configured = 0;
56 static int connected = 0;
57 static int sock = -1;
58 static struct sockaddr_un sockAddr;
59
60 typedef struct _SnortActionRequest
61 {
62 uint32_t event_id;
63 uint32_t tv_sec;
64 uint32_t generator;
65 uint32_t sid;
66 uint32_t src_ip;
67 uint32_t dest_ip;
68 uint16_t sport;
69 uint16_t dport;
70 uint8_t protocol;
71 } SnortActionRequest;
72
73 /* For the list of GID/SIDs that are used by the
74 * Finalize routine.
75 */
76 typedef struct _AlertSFSocketGidSid
77 {
78 uint32_t sidValue;
79 uint32_t gidValue;
80 struct _AlertSFSocketGidSid *next;
81 } AlertSFSocketGidSid;
82 static AlertSFSocketGidSid *sid_list = NULL;
83
84 static void AlertSFSocket_Init(struct _SnortConfig *, char *args);
85 static void AlertSFSocketSid_Init(struct _SnortConfig *, char *args);
86 void AlertSFSocketSid_InitFinalize(struct _SnortConfig *sc, int unused, void *also_unused);
87 void AlertSFSocket(Packet *packet, const char *msg, void *arg, Event *event);
88
89 static int AlertSFSocket_Connect(void);
90 static OptTreeNode *OptTreeNode_Search(uint32_t gid, uint32_t sid);
91 static int SignatureAddOutputFunc(uint32_t gid, uint32_t sid,
92 void (*outputFunc)(Packet *, const char *, void *, Event *),
93 void *args);
94 int String2ULong(char *string, unsigned long *result);
95
AlertSFSocket_Setup(void)96 void AlertSFSocket_Setup(void)
97 {
98 RegisterOutputPlugin("alert_sf_socket", OUTPUT_TYPE_FLAG__ALERT,
99 AlertSFSocket_Init);
100
101 RegisterOutputPlugin("alert_sf_socket_sid", OUTPUT_TYPE_FLAG__ALERT,
102 AlertSFSocketSid_Init);
103
104 DEBUG_WRAP(DebugMessage(DEBUG_INIT,"Output plugin: AlertSFSocket "
105 "registered\n"););
106 }
107
108 /* this is defined in linux/un.h (see aldo sys/un.h) */
109 #ifndef UNIX_PATH_MAX
110 #define UNIX_PATH_MAX 108
111 #endif
112
AlertSFSocket_Init(struct _SnortConfig * sc,char * args)113 static void AlertSFSocket_Init(struct _SnortConfig *sc, char *args)
114 {
115 /* process argument */
116 char *sockname;
117
118 if(!args)
119 FatalError("AlertSFSocket: must specify a socket name\n");
120
121 sockname = (char*)args;
122
123 if(strlen(sockname) == 0)
124 FatalError("AlertSFSocket: must specify a socket name\n");
125
126 if(strlen(sockname) > UNIX_PATH_MAX - 1)
127 FatalError("AlertSFSocket: socket name must be less than %i "
128 "characters\n", UNIX_PATH_MAX - 1);
129
130 /* create socket */
131 if((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
132 {
133 FatalError("Unable to create socket: %s\n", strerror(errno));
134 }
135
136 memset(&sockAddr, 0, sizeof(sockAddr));
137 sockAddr.sun_family = AF_UNIX;
138 memcpy(sockAddr.sun_path + 1, sockname, strlen(sockname));
139
140 if(AlertSFSocket_Connect() == 0)
141 connected = 1;
142
143 configured = 1;
144 }
145
146 /*
147 * Parse 'sidValue' or 'gidValue:sidValue'
148 */
GidSid2UInt(char * args,uint32_t * sidValue,uint32_t * gidValue)149 int GidSid2UInt(char * args, uint32_t * sidValue, uint32_t * gidValue)
150 {
151 char gbuff[80];
152 char sbuff[80];
153 int i;
154 unsigned long glong,slong;
155
156 *gidValue=GENERATOR_SNORT_ENGINE;
157 *sidValue=0;
158
159 i=0;
160 while( args && *args && (i < 20) )
161 {
162 sbuff[i]=*args;
163 if( sbuff[i]==':' ) break;
164 args++;
165 i++;
166 }
167 sbuff[i]=0;
168
169 if( i >= 20 )
170 {
171 return SNORT_EINVAL;
172 }
173
174 if( *args == ':' )
175 {
176 memcpy(gbuff,sbuff,i);
177 gbuff[i]=0;
178
179 if(String2ULong(gbuff,&glong))
180 {
181 return SNORT_EINVAL;
182 }
183 *gidValue = (uint32_t)glong;
184
185 args++;
186 i=0;
187 while( args && *args && i < 20 )
188 {
189 sbuff[i]=*args;
190 args++;
191 i++;
192 }
193 sbuff[i]=0;
194
195 if( i >= 20 )
196 {
197 return SNORT_EINVAL;
198 }
199
200 if(String2ULong(sbuff,&slong))
201 {
202 return SNORT_EINVAL;
203 }
204 *sidValue = (uint32_t)slong;
205 }
206 else
207 {
208 if(String2ULong(sbuff,&slong))
209 {
210 return SNORT_EINVAL;
211 }
212 *sidValue=(uint32_t)slong;
213 }
214
215 return SNORT_SUCCESS;
216 }
217
AlertSFSocketSid_Init(struct _SnortConfig * sc,char * args)218 static void AlertSFSocketSid_Init(struct _SnortConfig *sc, char *args)
219 {
220 uint32_t sidValue;
221 uint32_t gidValue;
222 AlertSFSocketGidSid *new_sid = NULL;
223
224 /* check configured value */
225 if(!configured)
226 FatalError("AlertSFSocket must be configured before attaching it to a "
227 "sid");
228
229 if (GidSid2UInt((char*)args, &sidValue, &gidValue) )
230 FatalError("Invalid argument '%s' to alert_sf_socket_sid\n", args);
231
232 new_sid = (AlertSFSocketGidSid *)SnortAlloc(sizeof(AlertSFSocketGidSid));
233
234 new_sid->sidValue = sidValue;
235 new_sid->gidValue = gidValue;
236
237 if (sid_list)
238 {
239 /* Add this one to the front. */
240 new_sid->next = sid_list;
241 }
242 else
243 {
244 AddFuncToPostConfigList(sc, AlertSFSocketSid_InitFinalize, NULL);
245 }
246 sid_list = new_sid;
247 }
248
AlertSFSocketSid_InitFinalize(struct _SnortConfig * sc,int unused,void * also_unused)249 void AlertSFSocketSid_InitFinalize(struct _SnortConfig *sc, int unused, void *also_unused)
250 {
251 AlertSFSocketGidSid *new_sid = sid_list;
252 AlertSFSocketGidSid *next_sid;
253 uint32_t sidValue;
254 uint32_t gidValue;
255 int rval = 0;
256
257 while (new_sid)
258 {
259 sidValue = new_sid->sidValue;
260 gidValue = new_sid->gidValue;
261
262 rval = SignatureAddOutputFunc( (uint32_t)gidValue, (uint32_t)sidValue, AlertSFSocket, NULL );
263
264 switch(rval)
265 {
266 case SNORT_SUCCESS:
267 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "SFSocket output enabled for "
268 "sid %u.\n", sidValue););
269 break;
270 case SNORT_EINVAL:
271 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Invalid argument "
272 "attempting to attach output for sid %u.\n",
273 sidValue););
274 break;
275 case SNORT_ENOENT:
276 LogMessage("No entry found. SFSocket output not enabled for "
277 "sid %u.\n", sidValue);
278 break;
279 case SNORT_ENOMEM:
280 FatalError("Out of memory");
281 break;
282 }
283
284 /* Save ptr to next one in the list */
285 next_sid = new_sid->next;
286 /* Free the current one, not needed any more */
287 free(new_sid);
288 /* Reset the list */
289 sid_list = new_sid = next_sid;
290 }
291 }
292
AlertSFSocket_Connect(void)293 static int AlertSFSocket_Connect(void)
294 {
295 /* check sock value */
296 if(sock == -1)
297 FatalError("AlertSFSocket: Invalid socket\n");
298
299 if(connect(sock, (struct sockaddr *)&sockAddr, sizeof(sockAddr)) == -1)
300 {
301 if(errno == ECONNREFUSED || errno == ENOENT)
302 {
303 LogMessage("WARNING: AlertSFSocket: Unable to connect to socket: "
304 "%s.\n", strerror(errno));
305 return 1;
306 }
307 else
308 {
309 FatalError("AlertSFSocket: Unable to connect to socket "
310 "(%i): %s\n", errno, strerror(errno));
311 }
312 }
313 return 0;
314 }
315
316
317 static SnortActionRequest sar;
318
AlertSFSocket(Packet * packet,const char * msg,void * arg,Event * event)319 void AlertSFSocket(Packet *packet, const char *msg, void *arg, Event *event)
320 {
321 int tries = 0;
322
323 if(!event || !packet || !IPH_IS_VALID(packet))
324 return;
325
326 // for now, only support ip4
327 if ( !IS_IP4(packet) )
328 return;
329
330 /* construct the action request */
331 sar.event_id = event->event_id;
332 sar.tv_sec = packet->pkth->ts.tv_sec;
333 sar.generator = event->sig_generator;
334 sar.sid = event->sig_id;
335
336 // when ip6 is supported:
337 // * suggest TLV format where T == family, L is implied by
338 // T (and not sent), and V is just the address octets in
339 // network order
340 // * if T is made the 1st octet of struct, bytes to read
341 // can be determined by reading 1 byte
342 // * addresses could be moved to end of struct in uint8_t[32]
343 // and only 1st 8 used for ip4
344 sar.src_ip = ntohl(sfaddr_get_ip4_value(GET_SRC_IP(packet)));
345 sar.dest_ip = ntohl(sfaddr_get_ip4_value(GET_DST_IP(packet)));
346 sar.protocol = GET_IPH_PROTO(packet);
347
348 if(sar.protocol == IPPROTO_UDP || sar.protocol == IPPROTO_TCP)
349 {
350 sar.sport = packet->sp;
351 sar.dport = packet->dp;
352 }
353 else
354 {
355 sar.sport = 0;
356 sar.dport = 0;
357 }
358
359 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"AlertSFSocket fired for sid %u\n",
360 event->sig_id););
361
362 do
363 {
364 tries++;
365 /* connect as needed */
366 if(!connected)
367 {
368 if(AlertSFSocket_Connect() != 0)
369 break;
370 connected = 1;
371 }
372
373 /* send request */
374 if(send(sock, &sar, sizeof(sar), 0) == sizeof(sar))
375 {
376 /* success */
377 return;
378 }
379 /* send failed */
380 if(errno == ENOBUFS)
381 {
382 LogMessage("ERROR: AlertSFSocket: out of buffer space\n");
383 break;
384 }
385 else if(errno == ECONNRESET)
386 {
387 connected = 0;
388 LogMessage("WARNING: AlertSFSocket: connection reset, will attempt "
389 "to reconnect.\n");
390 }
391 else if(errno == ECONNREFUSED)
392 {
393 LogMessage("WARNING: AlertSFSocket: connection refused, "
394 "will attempt to reconnect.\n");
395 connected = 0;
396 }
397 else if(errno == ENOTCONN)
398 {
399 LogMessage("WARNING: AlertSFSocket: not connected, "
400 "will attempt to reconnect.\n");
401 connected = 0;
402 }
403 else
404 {
405 LogMessage("ERROR: AlertSFSocket: unhandled error '%i' in send(): "
406 "%s\n", errno, strerror(errno));
407 connected = 0;
408 }
409 } while(tries <= 1);
410 LogMessage("ERROR: AlertSFSocket: Alert not sent\n");
411 return;
412 }
413
SignatureAddOutputFunc(uint32_t gid,uint32_t sid,void (* outputFunc)(Packet *,const char *,void *,Event *),void * args)414 static int SignatureAddOutputFunc( uint32_t gid, uint32_t sid,
415 void (*outputFunc)(Packet *, const char *, void *, Event *),
416 void *args)
417 {
418 OptTreeNode *optTreeNode = NULL;
419 OutputFuncNode *outputFuncs = NULL;
420
421 if(!outputFunc)
422 return SNORT_EINVAL; /* Invalid argument */
423
424 if(!(optTreeNode = OptTreeNode_Search(gid,sid)))
425 {
426 LogMessage("Unable to find OptTreeNode for SID %u\n", sid);
427 return SNORT_ENOENT;
428 }
429
430 if(!(outputFuncs = (OutputFuncNode *)calloc(1, sizeof(OutputFuncNode))))
431 {
432 LogMessage("Out of memory adding output function to SID %u\n", sid);
433 return SNORT_ENOMEM;
434 }
435
436 outputFuncs->func = outputFunc;
437 outputFuncs->arg = args;
438
439 outputFuncs->next = optTreeNode->outputFuncs;
440
441 optTreeNode->outputFuncs = outputFuncs;
442
443 return SNORT_SUCCESS;
444 }
445
446
447 /* search for an OptTreeNode by sid in specific policy*/
OptTreeNode_Search(uint32_t gid,uint32_t sid)448 static OptTreeNode *OptTreeNode_Search(uint32_t gid, uint32_t sid)
449 {
450 SFGHASH_NODE *hashNode;
451 OptTreeNode *otn = NULL;
452 RuleTreeNode *rtn = NULL;
453
454 if(sid == 0)
455 return NULL;
456
457 for (hashNode = sfghash_findfirst(snort_conf->otn_map);
458 hashNode;
459 hashNode = sfghash_findnext(snort_conf->otn_map))
460 {
461 otn = (OptTreeNode *)hashNode->data;
462 rtn = getRuntimeRtnFromOtn(otn);
463 if (rtn)
464 {
465 if ((rtn->proto == IPPROTO_TCP) || (rtn->proto == IPPROTO_UDP)
466 || (rtn->proto == IPPROTO_ICMP) || (rtn->proto == ETHERNET_TYPE_IP))
467 {
468 if (otn->sigInfo.id == sid)
469 {
470 return otn;
471 }
472 }
473 }
474 }
475
476 return NULL;
477 }
478
String2ULong(char * string,unsigned long * result)479 int String2ULong(char *string, unsigned long *result)
480 {
481 unsigned long value;
482 char *endptr;
483 if(!string)
484 return -1;
485
486 value = strtoul(string, &endptr, 10);
487 if(*endptr != '\0')
488 return -1;
489
490 *result = value;
491
492 return 0;
493 }
494
495
496 #endif /* LINUX */
497
498