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