Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

spo_alert_prelude.c

Go to the documentation of this file.
00001 /*****
00002 *
00003 * Copyright (C) 2005 PreludeIDS Technologies. All Rights Reserved.
00004 * Author: Yoann Vandoorselaere <yoann.v@prelude-ids.com>
00005 *
00006 * This file is part of the Snort program.
00007 *
00008 * This program is free software; you can redistribute it and/or modify
00009 * it under the terms of the GNU General Public License as published by
00010 * the Free Software Foundation; either version 2, or (at your option)
00011 * any later version.
00012 *
00013 * This program is distributed in the hope that it will be useful,
00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 * GNU General Public License for more details.
00017 *
00018 * You should have received a copy of the GNU General Public License
00019 * along with this program; see the file COPYING.  If not, write to
00020 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
00021 *
00022 *****/
00023 
00024 #ifdef HAVE_CONFIG_H
00025  #include "config.h"
00026 #endif
00027 
00028 #ifdef HAVE_LIBPRELUDE
00029 
00030 #include <stdio.h>
00031 #include <sys/types.h>
00032 #include <sys/socket.h>
00033 #include <netinet/in.h>
00034 #include <arpa/inet.h>
00035 
00036 #include <libprelude/prelude.h>
00037 
00038 #include "event.h"
00039 #include "decode.h"
00040 #include "plugbase.h"
00041 #include "spo_plugbase.h"
00042 #include "parser.h"
00043 #include "debug.h"
00044 #include "util.h"
00045 #include "mstring.h"
00046 
00047 #include "snort.h"
00048 
00049 #define ANALYZER_CLASS "NIDS"
00050 #define ANALYZER_MODEL "Snort"
00051 #define ANALYZER_MANUFACTURER "http://www.snort.org"
00052 
00053 #define DEFAULT_ANALYZER_NAME "snort"
00054 
00055 
00056 extern PV pv;
00057 extern OptTreeNode *otn_tmp;
00058 
00059 static char *init_args = NULL;
00060 static unsigned int info_priority = 4;
00061 static unsigned int low_priority  = 3;
00062 static unsigned int mid_priority  = 2;
00063 static prelude_bool_t initialized = FALSE;
00064 
00065 
00066 static int setup_analyzer(idmef_analyzer_t *analyzer)
00067 {
00068         int ret;
00069         prelude_string_t *string;
00070         
00071         ret = idmef_analyzer_new_model(analyzer, &string);
00072         if ( ret < 0 )
00073                 return ret;
00074         prelude_string_set_constant(string, ANALYZER_MODEL);
00075 
00076         ret = idmef_analyzer_new_class(analyzer, &string);
00077         if ( ret < 0 )
00078                 return ret;
00079         prelude_string_set_constant(string, ANALYZER_CLASS);
00080 
00081         ret = idmef_analyzer_new_manufacturer(analyzer, &string);
00082         if ( ret < 0 ) 
00083                 return ret;
00084         prelude_string_set_constant(string, ANALYZER_MANUFACTURER);
00085 
00086         ret = idmef_analyzer_new_version(analyzer, &string);
00087         if ( ret < 0 )
00088                 return ret;
00089         prelude_string_set_constant(string, VERSION);
00090 
00091         return 0;
00092 }
00093 
00094 
00095 
00096 static idmef_reference_origin_t reference_to_origin(const char *name)
00097 {
00098         int i, ret;
00099         struct {
00100                 const char *name;
00101                 idmef_reference_origin_t origin;
00102         } tbl[] = {
00103                 { "cve", IDMEF_REFERENCE_ORIGIN_CVE             },
00104                 { "bugtraq", IDMEF_REFERENCE_ORIGIN_BUGTRAQID   },
00105                 { "osvdb", IDMEF_REFERENCE_ORIGIN_OSVDB         },
00106                 { NULL, 0                                       }
00107         };
00108 
00109         for ( i = 0; tbl[i].name; i++ ) {
00110                 ret = strcmp(tbl[i].name, name);
00111                 if ( ret == 0 )
00112                         return tbl[i].origin;
00113         }
00114 
00115         return IDMEF_REFERENCE_ORIGIN_VENDOR_SPECIFIC;
00116 }
00117 
00118 
00119 
00120 static int event_to_source_target(Packet *p, idmef_alert_t *alert)
00121 {
00122         int ret;
00123         idmef_node_t *node;
00124         idmef_source_t *source;
00125         idmef_target_t *target;
00126         idmef_address_t *address;
00127         idmef_service_t *service;
00128         prelude_string_t *string;
00129         static char saddr[128], daddr[128];
00130 
00131         if ( !p )
00132             return 0;
00133 
00134         if ( ! p->iph )
00135                 return 0;
00136         
00137         ret = idmef_alert_new_source(alert, &source, -1);
00138         if ( ret < 0 )
00139                 return ret;
00140 
00141         ret = idmef_source_new_service(source, &service);
00142         if ( ret < 0 )
00143                 return ret;
00144 
00145         if ( p->tcph || p->udph )
00146                 idmef_service_set_port(service, p->sp);
00147         
00148         idmef_service_set_ip_version(service, IP_VER(p->iph));
00149         idmef_service_set_iana_protocol_number(service, p->iph->ip_proto);
00150         
00151         ret = idmef_source_new_node(source, &node);
00152         if ( ret < 0 )
00153                 return ret;
00154 
00155         ret = idmef_node_new_address(node, &address, -1);
00156         if ( ret < 0 )
00157                 return ret;
00158 
00159         ret = idmef_address_new_address(address, &string);
00160         if ( ret < 0 )
00161                 return ret;
00162         
00163         snprintf(saddr, sizeof(saddr), "%s", inet_ntoa(p->iph->ip_src));
00164         prelude_string_set_ref(string, saddr);
00165 
00166         ret = idmef_alert_new_target(alert, &target, -1);
00167         if ( ret < 0 )
00168                 return ret;
00169 
00170         ret = idmef_target_new_service(target, &service);
00171         if ( ! ret < 0 )
00172                 return ret;
00173         
00174         if ( p->tcph || p->udph )                
00175                 idmef_service_set_port(service, p->dp);
00176         
00177         idmef_service_set_ip_version(service, IP_VER(p->iph));
00178         idmef_service_set_iana_protocol_number(service, p->iph->ip_proto);
00179         
00180         ret = idmef_target_new_node(target, &node);
00181         if ( ret < 0 )
00182                 return ret;
00183         
00184         ret = idmef_node_new_address(node, &address, -1);
00185         if ( ret < 0 )
00186                 return ret;
00187         
00188         ret = idmef_address_new_address(address, &string);
00189         if ( ret < 0 )
00190                 return ret;
00191                 
00192         snprintf(daddr, sizeof(daddr), "%s", inet_ntoa(p->iph->ip_dst));
00193         prelude_string_set_ref(string, daddr);
00194         
00195         return 0;
00196 }
00197 
00198 
00199 
00200 static int add_byte_data(idmef_alert_t *alert, const char *meaning, const unsigned char *data, size_t size)
00201 {
00202         int ret;
00203         prelude_string_t *str;
00204         idmef_additional_data_t *ad;
00205 
00206         if ( ! data || ! size )
00207                 return 0;
00208         
00209         ret = idmef_alert_new_additional_data(alert, &ad, -1);
00210         if ( ret < 0 )
00211                 return ret;
00212 
00213         ret = idmef_additional_data_set_byte_string_ref(ad, data, size);
00214         if ( ret < 0 ) {
00215                 ErrorMessage("%s: error setting byte string data: %s.\n",
00216                              prelude_strsource(ret), prelude_strerror(ret));
00217                 return -1;
00218         }
00219 
00220         ret = idmef_additional_data_new_meaning(ad, &str);
00221         if ( ret < 0 ) {
00222                 ErrorMessage("%s: error creating additional-data meaning: %s.\n",
00223                              prelude_strsource(ret), prelude_strerror(ret));
00224                 return -1;
00225         }
00226         
00227         ret = prelude_string_set_ref(str, meaning);
00228         if ( ret < 0 ) {
00229                 ErrorMessage("%s: error setting byte string data meaning: %s.\n",
00230                              prelude_strsource(ret), prelude_strerror(ret));
00231         }
00232                 
00233         return -1;
00234 }
00235 
00236 
00237 
00238 static int add_int_data(idmef_alert_t *alert, const char *meaning, uint32_t data)
00239 {
00240         int ret;
00241         prelude_string_t *str;
00242         idmef_additional_data_t *ad;
00243         
00244         ret = idmef_alert_new_additional_data(alert, &ad, -1);
00245         if ( ret < 0 )
00246                 return ret;
00247         
00248         idmef_additional_data_set_integer(ad, data);
00249 
00250         ret = idmef_additional_data_new_meaning(ad, &str);
00251         if ( ret < 0 ) {
00252                 ErrorMessage("%s: error creating additional-data meaning: %s.\n",
00253                              prelude_strsource(ret), prelude_strerror(ret));
00254                 return -1;
00255         }
00256         
00257         ret = prelude_string_set_ref(str, meaning);
00258         if ( ret < 0 ) {
00259                 ErrorMessage("%s: error setting integer data meaning: %s.\n",
00260                              prelude_strsource(ret), prelude_strerror(ret));
00261                 return -1;
00262         }
00263         
00264         return 0;
00265 }
00266 
00267 
00268 
00269 
00270 static int packet_to_data(Packet *p, Event *event, idmef_alert_t *alert)
00271 {
00272         if ( !p )
00273             return 0;
00274 
00275         add_int_data(alert, "sid", event->sig_id);
00276         
00277         if ( p->iph ) {
00278                 add_int_data(alert, "ip_mf", p->mf);
00279                 add_int_data(alert, "ip_df", p->df);
00280                 add_int_data(alert, "ip_rf", p->rf);
00281                 add_int_data(alert, "ip_off", p->frag_offset);
00282                 add_int_data(alert, "ip_hlen", IP_HLEN(p->iph));
00283                 add_int_data(alert, "ip_tos", p->iph->ip_tos);
00284                 add_int_data(alert, "ip_len", ntohs(p->iph->ip_len));
00285                 add_int_data(alert, "ip_id", ntohs(p->iph->ip_id));
00286                 add_int_data(alert, "ip_flags", p->frag_flag);
00287                 add_int_data(alert, "ip_off", ntohs(p->frag_offset));
00288                 add_int_data(alert, "ip_ttl", p->iph->ip_ttl);
00289                 add_int_data(alert, "ip_proto", p->iph->ip_proto);
00290                 add_int_data(alert, "ip_csum", ntohs(p->iph->ip_csum));
00291         }
00292         
00293         if ( p->tcph ) {
00294                 add_int_data(alert, "th_seq", ntohl(p->tcph->th_seq));
00295                 add_int_data(alert, "th_ack", ntohl(p->tcph->th_ack));
00296                 add_int_data(alert, "tcp_off", TCP_OFFSET(p->tcph));
00297                 add_int_data(alert, "tcp_res", TCP_X2(p->tcph));
00298                 add_int_data(alert, "tcp_flags", p->tcph->th_flags);
00299                 add_int_data(alert, "tcp_win", ntohs(p->tcph->th_win));
00300                 add_int_data(alert, "tcp_sum", ntohs(p->tcph->th_sum));
00301                 add_int_data(alert, "tcp_urp", ntohs(p->tcph->th_urp));
00302         }
00303 
00304         else if ( p->udph ) {
00305                 add_int_data(alert, "udp_len", ntohl(p->udph->uh_len));
00306                 add_int_data(alert, "udp_chk", ntohl(p->udph->uh_chk));
00307         }
00308 
00309         add_byte_data(alert, "payload", p->data, p->dsize);
00310         
00311         return 0;
00312 }
00313 
00314 
00315 
00316 static int event_to_impact(Event *event, idmef_alert_t *alert)
00317 {
00318         int ret;
00319         ClassType *classtype;
00320         prelude_string_t *str;
00321         idmef_impact_t *impact;
00322         idmef_assessment_t *assessment;
00323         idmef_impact_severity_t severity;
00324         
00325         ret = idmef_alert_new_assessment(alert, &assessment);
00326         if ( ret < 0 )
00327                 return ret;
00328 
00329         ret = idmef_assessment_new_impact(assessment, &impact);
00330         if ( ret < 0 )
00331                 return ret;
00332 
00333         if ( event->priority < mid_priority )
00334                 severity = IDMEF_IMPACT_SEVERITY_HIGH;
00335 
00336         else if ( event->priority < low_priority )
00337                 severity = IDMEF_IMPACT_SEVERITY_MEDIUM;
00338 
00339         else if ( event->priority < info_priority )
00340                 severity = IDMEF_IMPACT_SEVERITY_LOW;
00341 
00342         else    severity = IDMEF_IMPACT_SEVERITY_INFO;
00343 
00344         idmef_impact_set_severity(impact, severity);
00345 
00346         if ( ! otn_tmp )
00347                 return 0;
00348         
00349         classtype = otn_tmp->sigInfo.classType;
00350         if ( classtype ) {
00351                 ret = idmef_impact_new_description(impact, &str);
00352                 if ( ret < 0 )
00353                         return ret;
00354 
00355                 prelude_string_set_ref(str, classtype->name);
00356         }
00357         
00358         return 0;
00359 }
00360 
00361 
00362 
00363 
00364 static int event_to_reference(Event *event, idmef_classification_t *class)
00365 {
00366         int ret;
00367         ReferenceNode *refs;
00368         prelude_string_t *str;
00369         idmef_reference_t *ref;
00370         ReferenceSystemNode *system;
00371 
00372         ret = idmef_classification_new_ident(class, &str);
00373         if ( ret < 0 )
00374                 return ret;
00375 
00376         ret = prelude_string_sprintf(str, "%u", event->sig_id);
00377         if ( ret < 0 )
00378                 return ret;
00379         
00380         /*
00381          * return if we have no information about the rule.
00382          */
00383         if ( ! otn_tmp )
00384                 return 0;
00385 
00386         for ( refs = otn_tmp->sigInfo.refs; refs != NULL; refs = refs->next ) {
00387 
00388                 system = refs->system;
00389                 if ( ! system )
00390                         continue;
00391                 
00392                 ret = idmef_classification_new_reference(class, &ref, -1);
00393                 if ( ret < 0 )
00394                         return ret;
00395 
00396                 ret = idmef_reference_new_name(ref, &str);
00397                 if ( ret < 0 )
00398                         return ret;
00399                 
00400                 idmef_reference_set_origin(ref, reference_to_origin(system->name));
00401                 if ( idmef_reference_get_origin(ref) != IDMEF_REFERENCE_ORIGIN_VENDOR_SPECIFIC )
00402                         prelude_string_set_ref(str, refs->id);
00403                 else
00404                         prelude_string_set_constant(str, "url");
00405 
00406                 ret = idmef_reference_new_url(ref, &str);
00407                 if ( ret < 0 )
00408                         return ret;
00409                 
00410                 prelude_string_sprintf(str, "%s%s", system->url, refs->id);
00411         }        
00412 
00413         return 0;
00414 }
00415 
00416 
00417 
00418 void snort_alert_prelude(Packet *p, char *msg, void *data, Event *event)
00419 {
00420         int ret;
00421         idmef_time_t *time;
00422         idmef_alert_t *alert;
00423         prelude_string_t *str;
00424         idmef_message_t *idmef;
00425         idmef_classification_t *class;
00426         prelude_client_t *client = data;
00427 
00428         if ( !p )
00429             return;
00430 
00431         ret = idmef_message_new(&idmef);
00432         if ( ret < 0 )
00433                 return;
00434 
00435         ret = idmef_message_new_alert(idmef, &alert);
00436         if ( ret < 0 )
00437                 goto err;
00438 
00439         ret = idmef_alert_new_classification(alert, &class);
00440         if ( ret < 0 )
00441                 goto err;
00442 
00443         ret = idmef_classification_new_text(class, &str);
00444         if ( ret < 0 )
00445                 goto err;
00446 
00447         prelude_string_set_ref(str, msg);
00448 
00449         ret = event_to_impact(event, alert);
00450         if ( ret < 0 )
00451                 goto err;
00452 
00453         ret = event_to_reference(event, class);
00454         if ( ret < 0 )
00455                 goto err;
00456         
00457         ret = event_to_source_target(p, alert);
00458         if ( ret < 0 )
00459                 goto err;
00460         
00461         ret = packet_to_data(p, event, alert);
00462         if ( ret < 0 )
00463                 goto err;
00464         
00465         ret = idmef_alert_new_detect_time(alert, &time);
00466         if ( ret < 0 )
00467                 goto err;
00468         idmef_time_set_from_timeval(time, &p->pkth->ts);
00469         
00470         ret = idmef_time_new_from_gettimeofday(&time);
00471         if ( ret < 0 )
00472                 goto err; 
00473         idmef_alert_set_create_time(alert, time);
00474                 
00475         idmef_alert_set_analyzer(alert, idmef_analyzer_ref(prelude_client_get_analyzer(client)), 0);
00476         prelude_client_send_idmef(client, idmef);
00477                 
00478  err:
00479         idmef_message_destroy(idmef);
00480 }
00481 
00482 
00483 
00484 void snort_alert_prelude_clean_exit(int signal, void *data)
00485 {
00486         
00487 }
00488 
00489 
00490 void snort_alert_prelude_restart(int signal, void *data)
00491 {
00492         /*
00493          * This function might be called from a signal handler,
00494          * and there is no way to know about it since signal is
00495          * always SIGQUIT.
00496          *
00497          * As calling a function from a signal handler is not secure
00498          * we won't do it.
00499          */
00500 }
00501 
00502 
00503 
00504 static void parse_args(char *args, char **profile)
00505 {
00506         int i, tokens, ret;
00507         char **args_table, *value, *key;
00508                 
00509         args_table = mSplit(args, " ", 4, &tokens, '\\');
00510         for ( i = 0; i < tokens; i++ ) {
00511                 
00512                 key = args_table[i];
00513                 strtok(key, "=");
00514                 
00515                 value = strtok(NULL, "");
00516                 if ( ! value )
00517                         FatalError("spo_alert_prelude: missing value for keyword '%s'.\n", key);
00518                 
00519                 ret = strcasecmp("profile", key);
00520                 if ( ret == 0 ) {
00521                         if ( *profile )
00522                                 free(*profile);
00523                         
00524                         *profile = strdup(value);
00525                         continue;
00526                 }
00527                 
00528                 ret = strcasecmp("info", key);
00529                 if ( ret == 0 ) {
00530                         info_priority = atoi(value);
00531                         continue;
00532                 }
00533 
00534                 ret = strcasecmp("low", key);
00535                 if ( ret == 0 ) {
00536                         low_priority = atoi(value);
00537                         continue;
00538                 }
00539 
00540                 ret = strcasecmp("medium", key);
00541                 if ( ret == 0 ) {
00542                         mid_priority = atoi(value);
00543                         continue;
00544                 }
00545 
00546                 FatalError("spo_alert_prelude: Invalid parameter found: '%s'.\n", key);
00547         }
00548 
00549         mSplitFree(&args_table, tokens);
00550 }
00551 
00552 
00553 void AlertPreludeSetupAfterSetuid(void)
00554 {
00555         int ret;
00556         char *profile = NULL;
00557         prelude_client_t *client;
00558         prelude_client_flags_t flags;
00559 
00560         if ( ! initialized )
00561                 return;
00562         
00563         parse_args(init_args, &profile);
00564         free(init_args);
00565 
00566         ret = prelude_thread_init(NULL);
00567         if ( ret < 0 )
00568                 FatalError("%s: Unable to initialize the Prelude thread subsystem: %s.\n",
00569                            prelude_strsource(ret), prelude_strerror(ret));
00570         
00571         ret = prelude_init(NULL, NULL);
00572         if ( ret < 0 )
00573                 FatalError("%s: Unable to initialize the Prelude library: %s.\n",
00574                            prelude_strsource(ret), prelude_strerror(ret));
00575         
00576         ret = prelude_client_new(&client, profile ? profile : DEFAULT_ANALYZER_NAME);
00577         if ( profile )
00578                 free(profile);
00579         
00580         if ( ret < 0 )
00581                 FatalError("%s: Unable to create a prelude client object: %s.\n",
00582                            prelude_strsource(ret), prelude_strerror(ret));
00583 
00584         
00585         flags = PRELUDE_CLIENT_FLAGS_ASYNC_SEND|PRELUDE_CLIENT_FLAGS_ASYNC_TIMER;
00586         
00587         ret = prelude_client_set_flags(client, prelude_client_get_flags(client) | flags);
00588         if ( ret < 0 )
00589                 FatalError("%s: Unable to set asynchronous send and timer: %s.\n",
00590                            prelude_strsource(ret), prelude_strerror(ret));
00591 
00592         
00593         setup_analyzer(prelude_client_get_analyzer(client));
00594         
00595         ret = prelude_client_start(client);
00596         if ( ret < 0 ) {
00597                 if ( prelude_client_is_setup_needed(ret) )
00598                         prelude_client_print_setup_error(client);
00599 
00600                 FatalError("%s: Unable to initialize prelude client: %s.\n",
00601                            prelude_strsource(ret), prelude_strerror(ret));
00602         }
00603                 
00604         AddFuncToOutputList(snort_alert_prelude, NT_OUTPUT_ALERT, client);
00605 
00606         /*
00607          * The CleanExit and Restart callback function are not registed
00608          * since theses might be called from a signal handler, and there
00609          * is no way to know about it since their signal argument is set to an
00610          * unsignificant value.
00611          *
00612          * As calling function other than the very restricted set of function
00613          * guaranteed to be reentrant defined in POSIX.1 from a signal handler
00614          * is not safe, we can't do it.
00615          *
00616          * Snort should really check for the signal to be set from the main program
00617          * loop and call the signal handling function from there, rather than doing
00618          * it in the signal handler itself, which could easily lead to crash since
00619          * most of the preprocessor function use non reentrant function from the
00620          * callback in question.
00621          */
00622 }
00623 
00624 
00625 void snort_alert_prelude_init(unsigned char *args)
00626 {
00627         /*
00628          * Do nothing here. Wait until AlertPreludeSetupAfterSetuid is called.
00629          */
00630         if ( args )
00631                 init_args = strdup((char *) args);
00632 
00633         initialized = TRUE;
00634 }
00635 
00636 
00637 void AlertPreludeSetup(void)
00638 {
00639         RegisterOutputPlugin("alert_prelude", NT_OUTPUT_ALERT, snort_alert_prelude_init);
00640 }
00641 
00642 
00643 #endif /* HAVE_LIBPRELUDE */

Generated on Sun May 14 14:51:14 2006 by  doxygen 1.4.2