json_object *Normalize_Liblognorm(char *syslog_msg, struct _SaganNormalizeLiblognorm *SaganNormalizeLiblognorm) { char buf[10*1024] = { 0 }; char tmp_host[254] = { 0 }; int rc_normalize = 0; const char *cstr = NULL; const char *tmp = NULL; struct json_object *json = NULL; json_object *string_obj; SaganNormalizeLiblognorm->ip_src[0] = '0'; SaganNormalizeLiblognorm->ip_src[1] = '\0'; SaganNormalizeLiblognorm->ip_dst[0] = '0'; SaganNormalizeLiblognorm->ip_dst[1] = '\0'; SaganNormalizeLiblognorm->username[0] = '\0'; SaganNormalizeLiblognorm->src_host[0] = '\0'; SaganNormalizeLiblognorm->dst_host[0] = '\0'; SaganNormalizeLiblognorm->hash_sha1[0] = '\0'; SaganNormalizeLiblognorm->hash_sha256[0] = '\0'; SaganNormalizeLiblognorm->hash_md5[0] = '\0'; SaganNormalizeLiblognorm->http_uri[0] = '\0'; SaganNormalizeLiblognorm->http_hostname[0] = '\0'; SaganNormalizeLiblognorm->src_port = 0; SaganNormalizeLiblognorm->dst_port = 0; snprintf(buf, sizeof(buf),"%s", syslog_msg); /* int ln_normalize(ln_ctx ctx, const char *str, size_t strLen, struct json_object **json_p); */ rc_normalize = ln_normalize(ctx, buf, strlen(buf), &json); if (json == NULL) { return NULL; } cstr = (char*)json_object_to_json_string(json); /* Get source address information */ json_object_object_get_ex(json, "src-ip", &string_obj); tmp = json_object_get_string(string_obj); if ( tmp != NULL) { snprintf(SaganNormalizeLiblognorm->ip_src, sizeof(SaganNormalizeLiblognorm->ip_src), "%s", tmp); } json_object_object_get_ex(json, "dst-ip", &string_obj); tmp = json_object_get_string(string_obj); if ( tmp != NULL ) { snprintf(SaganNormalizeLiblognorm->ip_dst, sizeof(SaganNormalizeLiblognorm->ip_dst), "%s", tmp); } /* Get username information - Will be used in the future */ json_object_object_get_ex(json, "username", &string_obj); tmp = json_object_get_string(string_obj); if ( tmp != NULL ) { snprintf(SaganNormalizeLiblognorm->username, sizeof(SaganNormalizeLiblognorm->username), "%s", tmp); } /* Do DNS lookup for source hostname */ json_object_object_get_ex(json, "src-host", &string_obj); tmp = json_object_get_string(string_obj); if ( tmp != NULL ) { strlcpy(SaganNormalizeLiblognorm->src_host, tmp, sizeof(SaganNormalizeLiblognorm->src_host)); if ( SaganNormalizeLiblognorm->ip_src[0] == '0' && config->syslog_src_lookup) { if (!DNS_Lookup(SaganNormalizeLiblognorm->src_host, tmp_host, sizeof(tmp_host))) { strlcpy(SaganNormalizeLiblognorm->ip_src, tmp_host, sizeof(SaganNormalizeLiblognorm->ip_src)); } } } json_object_object_get_ex(json, "dst-host", &string_obj); tmp = json_object_get_string(string_obj); if ( tmp != NULL ) { strlcpy(SaganNormalizeLiblognorm->dst_host, tmp, sizeof(SaganNormalizeLiblognorm->dst_host)); if ( SaganNormalizeLiblognorm->ip_dst[0] == '0' && config->syslog_src_lookup) { if (!DNS_Lookup(SaganNormalizeLiblognorm->dst_host, tmp_host, sizeof(tmp_host))) { strlcpy(SaganNormalizeLiblognorm->ip_dst, tmp_host, sizeof(SaganNormalizeLiblognorm->ip_dst)); } } } /* Get port information */ json_object_object_get_ex(json, "src-port", &string_obj); tmp = json_object_get_string(string_obj); if ( tmp != NULL ) { SaganNormalizeLiblognorm->src_port = atoi(tmp); } json_object_object_get_ex(json, "dst-port", &string_obj); tmp = json_object_get_string(string_obj); if ( tmp != NULL ) { SaganNormalizeLiblognorm->dst_port = atoi(tmp); } json_object_object_get_ex(json, "hash-md5", &string_obj); tmp = json_object_get_string(string_obj); if ( tmp != NULL ) { strlcpy(SaganNormalizeLiblognorm->hash_md5, tmp, sizeof(SaganNormalizeLiblognorm->hash_md5)); } json_object_object_get_ex(json, "hash-sha1", &string_obj); tmp = json_object_get_string(string_obj); if ( tmp != NULL ) { strlcpy(SaganNormalizeLiblognorm->hash_sha1, tmp, sizeof(SaganNormalizeLiblognorm->hash_sha1)); } json_object_object_get_ex(json, "hash-sha256", &string_obj); tmp = json_object_get_string(string_obj); if ( tmp != NULL ) { strlcpy(SaganNormalizeLiblognorm->hash_sha256, tmp, sizeof(SaganNormalizeLiblognorm->hash_sha256)); } json_object_object_get_ex(json, "http_uri", &string_obj); tmp = json_object_get_string(string_obj); if ( tmp != NULL ) { strlcpy(SaganNormalizeLiblognorm->http_uri, tmp, sizeof(SaganNormalizeLiblognorm->http_uri)); } json_object_object_get_ex(json, "http_hostname", &string_obj); tmp = json_object_get_string(string_obj); if ( tmp != NULL ) { strlcpy(SaganNormalizeLiblognorm->http_hostname, tmp, sizeof(SaganNormalizeLiblognorm->http_hostname)); } json_object_object_get_ex(json, "filename", &string_obj); tmp = json_object_get_string(string_obj); if ( tmp != NULL ) { strlcpy(SaganNormalizeLiblognorm->filename, tmp, sizeof(SaganNormalizeLiblognorm->filename)); } if ( debug->debugnormalize ) { Sagan_Log(DEBUG, "Liblognorm DEBUG output: %d", rc_normalize); Sagan_Log(DEBUG, "---------------------------------------------------"); Sagan_Log(DEBUG, "Log message to normalize: |%s|", syslog_msg); Sagan_Log(DEBUG, "Parsed: %s", cstr); Sagan_Log(DEBUG, "Source IP: %s", SaganNormalizeLiblognorm->ip_src); Sagan_Log(DEBUG, "Destination IP: %s", SaganNormalizeLiblognorm->ip_dst); Sagan_Log(DEBUG, "Source Port: %d", SaganNormalizeLiblognorm->src_port); Sagan_Log(DEBUG, "Destination Port: %d", SaganNormalizeLiblognorm->dst_port); Sagan_Log(DEBUG, "Source Host: %s", SaganNormalizeLiblognorm->src_host); Sagan_Log(DEBUG, "Destination Host: %s", SaganNormalizeLiblognorm->dst_host); Sagan_Log(DEBUG, "Username: %s", SaganNormalizeLiblognorm->username); Sagan_Log(DEBUG, "MD5 Hash: %s", SaganNormalizeLiblognorm->hash_md5); Sagan_Log(DEBUG, "SHA1 Hash: %s", SaganNormalizeLiblognorm->hash_sha1); Sagan_Log(DEBUG, "SHA265 Hash: %s", SaganNormalizeLiblognorm->hash_sha256); Sagan_Log(DEBUG, "HTTP URI: %s", SaganNormalizeLiblognorm->http_uri); Sagan_Log(DEBUG, "HTTP HOSTNAME: %s", SaganNormalizeLiblognorm->http_hostname); Sagan_Log(DEBUG, "Filename: %s", SaganNormalizeLiblognorm->filename); Sagan_Log(DEBUG, ""); } if (0 != rc_normalize && json) { json_object_put(json); json = NULL; } return json; }
int main(int argc, char **argv) { const struct option long_options[] = { { "help", no_argument, NULL, 'h' }, { "debug", required_argument, NULL, 'd' }, { "daemon", no_argument, NULL, 'D' }, { "user", required_argument, NULL, 'u' }, { "chroot", required_argument, NULL, 'c' }, { "credits", no_argument, NULL, 'C' }, { "config", required_argument, NULL, 'f' }, { "log", required_argument, NULL, 'l' }, { "file", required_argument, NULL, 'F' }, {0, 0, 0, 0} }; static const char *short_options = "l:f:u:d:c:pDhC"; int option_index = 0; /****************************************************************************/ /* libpcap/PLOG (syslog sniffer) local variables */ /****************************************************************************/ #ifdef HAVE_LIBPCAP pthread_t pcap_thread; pthread_attr_t thread_pcap_attr; pthread_attr_init(&thread_pcap_attr); pthread_attr_setdetachstate(&thread_pcap_attr, PTHREAD_CREATE_DETACHED); #endif /****************************************************************************/ /* Perfmonitor local variables */ /****************************************************************************/ pthread_t perfmonitor_thread; pthread_attr_t thread_perfmonitor_attr; pthread_attr_init(&thread_perfmonitor_attr); pthread_attr_setdetachstate(&thread_perfmonitor_attr, PTHREAD_CREATE_DETACHED); /****************************************************************************/ /* Various local variables */ /****************************************************************************/ /* Block all signals, we create a signal handling thread */ sigset_t signal_set; pthread_t sig_thread; sigfillset( &signal_set ); pthread_sigmask( SIG_BLOCK, &signal_set, NULL ); /* Key board handler (displays stats, etc */ pthread_t key_thread; pthread_attr_t key_thread_attr; pthread_attr_init(&key_thread_attr); pthread_attr_setdetachstate(&key_thread_attr, PTHREAD_CREATE_DETACHED); struct sockaddr_in sa; char src_dns_lookup[20]; int dns_flag=0; sbool fifoerr=0; char *syslog_host=NULL; char *syslog_facility=NULL; char *syslog_priority=NULL; char *syslog_level=NULL; char *syslog_tag=NULL; char *syslog_date=NULL; char *syslog_time=NULL; char *syslog_program=NULL; char *syslog_msg=NULL; char syslogstring[MAX_SYSLOGMSG]; signed char c; char *tok; int rc=0; int i; time_t t; struct tm *run; sbool debugflag=0; /* Allocate and clear memory for global structs */ /* Allocate memory for global struct _SaganDebug */ debug = malloc(sizeof(_SaganDebug)); memset(debug, 0, sizeof(_SaganDebug)); /* Allocate memroy for global struct _SaganConfig */ config = malloc(sizeof(_SaganConfig)); memset(config, 0, sizeof(_SaganConfig)); struct _SaganSigArgs *sigargs; sigargs = malloc(sizeof(_SaganSigArgs)); memset(sigargs, 0, sizeof(_SaganSigArgs)); struct _SaganDNSCache *dnscache; dnscache = malloc(sizeof(_SaganDNSCache)); memset(dnscache, 0, sizeof(_SaganDNSCache)); counters = malloc(sizeof(_SaganCounters)); memset(counters, 0, sizeof(_SaganCounters)); flowbit = malloc(sizeof(_Sagan_Flowbit)); memset(flowbit, 0, sizeof(_Sagan_Flowbit)); t = time(NULL); run=localtime(&t); strftime(config->sagan_startutime, sizeof(config->sagan_startutime), "%s", run); strlcpy(config->sagan_config, CONFIG_FILE_PATH, sizeof(config->sagan_config)); /* We set the config->sagan_log_filepath to the system default. It'll be fopen'ed shortly - 06/03/2011 - Champ Clark III */ strlcpy(config->sagan_log_filepath, SAGANLOG, sizeof(config->sagan_log_filepath)); config->sagan_runas = RUNAS; /* Get command line arg's */ while ((c = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1) { switch(c) { if (c == -1) break; case 'h': Sagan_Usage(); exit(0); break; case 'C': Sagan_Credits(); exit(0); break; case 'd': if (Sagan_strstr(optarg, "malformed")) { debug->debugmalformed=1; debugflag=1; } if (Sagan_strstr(optarg, "limits")) { debug->debuglimits=1; debugflag=1; } if (Sagan_strstr(optarg, "syslog")) { debug->debugsyslog=1; debugflag=1; } if (Sagan_strstr(optarg, "load")) { debug->debugload=1; debugflag=1; } if (Sagan_strstr(optarg, "fwsam")) { debug->debugfwsam=1; debugflag=1; } if (Sagan_strstr(optarg, "external")) { debug->debugexternal=1; debugflag=1; } if (Sagan_strstr(optarg, "threads")) { debug->debugthreads=1; debugflag=1; } if (Sagan_strstr(optarg, "flowbit")) { debug->debugflowbit=1; debugflag=1; } if (Sagan_strstr(optarg, "engine")) { debug->debugengine=1; debugflag=1; } if (Sagan_strstr(optarg, "brointel")) { debug->debugbrointel=1; debugflag=1; } #ifdef HAVE_LIBGEOIP if (Sagan_strstr(optarg, "geoip")) { debug->debuggeoip=1; debugflag=1; } #endif #ifdef HAVE_LIBLOGNORM if (Sagan_strstr(optarg, "normalize" )) { debug->debugnormalize=1; debugflag=1; } #endif #ifdef HAVE_LIBESMTP if (Sagan_strstr(optarg, "smtp")) { debug->debugesmtp=1; debugflag=1; } #endif #ifdef HAVE_LIBPCAP if (Sagan_strstr(optarg, "plog")) { debug->debugplog=1; debugflag=1; } #endif #ifdef WITH_WEBSENSE if (Sagan_strstr(optarg, "websense")) { debug->debugwebsense=1; debugflag=1; } #endif /* If option is unknown */ if ( debugflag == 0 ) { fprintf(stderr, "Unknown debug option %s!\n", optarg); exit(1); } break; case 'D': daemonize=1; break; case 'u': config->sagan_runas=optarg; break; case 'c': Sagan_Chroot(optarg); break; case 'F': config->sagan_fifo_flag=1; strlcpy(config->sagan_fifo,optarg,sizeof(config->sagan_fifo) - 1); break; case 'f': strlcpy(config->sagan_config,optarg,sizeof(config->sagan_config) - 1); break; case 'l': strlcpy(config->sagan_log_filepath,optarg,sizeof(config->sagan_log_filepath) - 1); break; default: fprintf(stderr, "Invalid argument! See below for command line switches.\n"); Sagan_Usage(); exit(0); break; } } Sagan_Open_Log_File(OPEN, SAGAN_LOG); Load_Config(); Sagan_Engine_Init(); #ifdef HAVE_LIBLOGNORM Sagan_Liblognorm_Load(); #endif /* Load/init liblognorm definitions. I tried to move this into a subroutine, * but that ended up causing segfaults on ln_normalize() or causing * liblognorm not to function correctly (not parsing fields). Make reloading * a SIGHUP a issue as well. * 12/17/2010 - Champ */ SaganProcSyslog = malloc(config->max_processor_threads * sizeof(struct _Sagan_Proc_Syslog)); pthread_t processor_id[config->max_processor_threads]; pthread_attr_t thread_processor_attr; pthread_attr_init(&thread_processor_attr); pthread_attr_setdetachstate(&thread_processor_attr, PTHREAD_CREATE_DETACHED); Sagan_Log(S_NORMAL, "Configuration file %s loaded and %d rules loaded.", config->sagan_config, counters->rulecount); Sagan_Log(S_NORMAL, "Out of %d rules, %d Flowbit(s) are in use.", counters->rulecount, counters->flowbit_total_counter); Sagan_Log(S_NORMAL, "Sagan version %s is firing up!", VERSION); /* We go ahead and assign values to SaganSigArgs (struct sig_thread_args). This * struct is always used by the sig_handler thread, and sometimes used by the * plog_handler (below). So we assign values now */ sigargs->daemonize = daemonize; #ifdef HAVE_LIBPCAP /* Spawn a thread to 'sniff' syslog traffic (sagan-plog.c). This redirects syslog traffic to the /dev/log socket. This needs "root" access, so we drop priv's after this thread is started */ if ( config->plog_flag ) { rc = pthread_create( &pcap_thread, NULL, (void *)plog_handler, sigargs ); if ( rc != 0 ) { Remove_Lock_File(); Sagan_Log(S_ERROR, "[%s, line %d] Error creating libpcap handler thread [error: %d].", __FILE__, __LINE__, rc); } sleep(1); /* Sleep to avoid race between main() and plog thread plog thread needs "root" rights before sagan_droppriv(). In some cases main() run sagan_droppriv() before thread can complete - Champ Clark - 07/20/2011 */ } #endif Sagan_Droppriv(); /* Become the Sagan user */ Sagan_Log(S_NORMAL, "---------------------------------------------------------------------------"); if ( config->perfmonitor_flag ) { if (( config->perfmonitor_file_stream = fopen(config->perfmonitor_file_name, "a" )) == NULL ) { Remove_Lock_File(); Sagan_Log(S_ERROR, "[%s, line %d] Can't open %s - %s!", __FILE__, __LINE__, config->perfmonitor_file_name, strerror(errno)); } rc = pthread_create( &perfmonitor_thread, NULL, (void *)Sagan_Perfmonitor_Handler, sigargs ); if ( rc != 0 ) { Remove_Lock_File(); Sagan_Log(S_ERROR, "[%s, line %d] Error creating Perfmonitor thread [error: %d].", __FILE__, __LINE__, rc); } } /* Open sagan alert file */ Sagan_Open_Log_File(OPEN, ALERT_LOG); /**************************************************************************** * Display processor information as we load ****************************************************************************/ /* Sagan_Track_Clients processor ********************************************/ if ( config->sagan_track_clients_flag) { if ( config->pp_sagan_track_clients ) Sagan_Log(S_NORMAL, "Client Tracking Processor: %d minute(s)", config->pp_sagan_track_clients); Sagan_Track_Clients_Init(); Sagan_Load_Tracking_Cache(); } /* Sagan Blacklist IP processor *********************************************/ if ( config->blacklist_flag) { Sagan_Blacklist_Init(); Sagan_Blacklist_Load(); } /* Sagan Websense processor ************************************************/ #ifdef WITH_WEBSENSE if ( config->websense_flag ) { curl_global_init(CURL_GLOBAL_ALL); config->websense_last_time = atol(config->sagan_startutime); Sagan_Websense_Init(); Sagan_Log(S_NORMAL, ""); Sagan_Log(S_NORMAL, "Websense URL: %s", config->websense_url); Sagan_Log(S_NORMAL, "Websense Auth: %s", config->websense_auth); Sagan_Log(S_NORMAL, "Websense Device ID: %s", config->websense_device_id); Sagan_Log(S_NORMAL, "Websense Categories File: %s", config->websense_cat); Sagan_Log(S_NORMAL, "Websense Max Cache: %d", config->websense_max_cache); Sagan_Log(S_NORMAL, "Websense Cache Timeout: %d minutes.", config->websense_timeout / 60); Sagan_Log(S_NORMAL, "Websense loaded %d categories.", counters->websense_cat_count); } #endif /* Sagan Bro Intel processor *******************************************/ if ( config->brointel_flag ) { Sagan_Log(S_NORMAL, ""); Sagan_BroIntel_Init(); Sagan_BroIntel_Load_File(); Sagan_Log(S_NORMAL, "Bro Intel::ADDR Loaded: %d", counters->brointel_addr_count); Sagan_Log(S_NORMAL, "Bro Intel::DOMAIN Loaded: %d", counters->brointel_domain_count); Sagan_Log(S_NORMAL, "Bro Intel::FILE_HASH Loaded: %d", counters->brointel_file_hash_count); Sagan_Log(S_NORMAL, "Bro Intel::URL Loaded: %d", counters->brointel_url_count); Sagan_Log(S_NORMAL, "Bro Intel::SOFTWARE Loaded: %d", counters->brointel_software_count); Sagan_Log(S_NORMAL, "Bro Intel::EMAIL Loaded: %d", counters->brointel_email_count); Sagan_Log(S_NORMAL, "Bro Intel::USER_NAME Loaded: %d", counters->brointel_user_name_count); Sagan_Log(S_NORMAL, "Bro Intel::FILE_NAME Loaded: %d", counters->brointel_file_name_count); Sagan_Log(S_NORMAL, "Bro Intel::CERT_HASH Loaded: %d", counters->brointel_cert_hash_count); Sagan_Log(S_NORMAL, "Bro Intel Duplicates Detected: %d", counters->brointel_dups); } /*************************************************************************** * Output plugins ***************************************************************************/ #ifdef HAVE_LIBESMTP if ( config->sagan_esmtp_flag ) { Sagan_Log(S_NORMAL, ""); if ( config->min_email_priority ) Sagan_Log(S_NORMAL, "E-mail on priority %d or higher.", config->min_email_priority); Sagan_Log(S_NORMAL, "E-Mail will be sent from: %s", config->sagan_esmtp_from); Sagan_Log(S_NORMAL, "SMTP server is set to: %s", config->sagan_esmtp_server); } #endif #ifdef WITH_SNORTSAM if ( config->sagan_fwsam_flag ) { Sagan_Log(S_NORMAL, ""); Sagan_Log(S_NORMAL, "Snortsam output plug in enabled."); } #endif if ( config->sagan_external_output_flag ) { Sagan_Log(S_NORMAL, ""); Sagan_Log(S_NORMAL, "External program to be called: %s", config->sagan_extern); } /* Unified2 ****************************************************************/ #if defined(HAVE_DNET_H) || defined(HAVE_DUMBNET_H) if ( config->sagan_unified2_flag ) { Sagan_Log(S_NORMAL, ""); Sagan_Log(S_NORMAL, "Unified2 file: %s", config->unified2_filepath); Sagan_Log(S_NORMAL, "Unified2 limit: %dM", config->unified2_limit / 1024 / 1024 ); Unified2InitFile(); } #endif /*************************************************************************** * Non-Processor/Output option ***************************************************************************/ /* What to "ignore" ********************************************************/ if ( config->sagan_droplist_flag ) { Load_Ignore_List(); Sagan_Log(S_NORMAL, ""); Sagan_Log(S_NORMAL, "Loaded %d ignore/drop list item(s).", counters->droplist_count); } /*************************************************************************** * Continue with normal startup! ***************************************************************************/ Sagan_Log(S_NORMAL, ""); Sagan_Log(S_NORMAL, " ,-._,-. -*> Sagan! <*-"); Sagan_Log(S_NORMAL, " \\/)\"(\\/ Version %s", VERSION); Sagan_Log(S_NORMAL, " (_o_) Champ Clark III & The Quadrant InfoSec Team [quadrantsec.com]"); Sagan_Log(S_NORMAL, " / \\/) Copyright (C) 2009-2015 Quadrant Information Security, et al."); Sagan_Log(S_NORMAL, " (|| ||) Using PCRE version: %s", pcre_version()); Sagan_Log(S_NORMAL, " oo-oo Sagan is processing events....."); Sagan_Log(S_NORMAL, ""); /* Become a daemon if requested */ if ( daemonize ) { Sagan_Log(S_NORMAL, "Becoming a daemon!"); pid_t pid = 0; setsid(); pid = fork(); if (pid == 0) {} else { exit(0); } } /* Create the signal handlers thread _after_ the fork() so it can properly * handly signals - Champ Clark III - 06/13/2011 */ rc = pthread_create( &sig_thread, NULL, (void *)Sig_Handler, sigargs ); if ( rc != 0 ) { Remove_Lock_File(); Sagan_Log(S_ERROR, "[%s, line %d] Error creating signal handler thread. [error: %d]", __FILE__, __LINE__, rc); } /* We don't want the key_handler() if we're in daemon mode! */ if (!daemonize) { rc = pthread_create( &key_thread, NULL, (void *)key_handler, NULL ); if ( rc != 0 ) { Remove_Lock_File(); Sagan_Log(S_ERROR, "[%s, line %d] Error creating key_handler thread. [error: %d]", __FILE__, __LINE__, rc); } } /* We do this after forking so init scripts can complete */ /* Check lock file _after_ thread. If you don't it'll retreive the wrong pid * and incorrectly believe there is a stale lock file if --daemon */ checklockfile(); Sagan_Log(S_NORMAL, "Spawning %d Processor Threads.", config->max_processor_threads); for (i = 0; i < config->max_processor_threads; i++) { rc = pthread_create ( &processor_id[i], &thread_processor_attr, (void *)Sagan_Processor, NULL ); if ( rc != 0 ) { Remove_Lock_File(); Sagan_Log(S_ERROR, "Could not pthread_create() for I/O processors [error: %d]", rc); } } Sagan_Log(S_NORMAL, ""); if ( config->sagan_fifo_flag == 0 ) { Sagan_Log(S_NORMAL, "Attempting to open syslog FIFO (%s).", config->sagan_fifo); } else { Sagan_Log(S_NORMAL, "Attempting to open syslog FILE (%s).", config->sagan_fifo); } while(1) { FILE *fd; fd = fopen(config->sagan_fifo, "r"); if ( config->sagan_fifo_flag == 0 ) { Sagan_Log(S_NORMAL, "Successfully opened FIFO (%s).", config->sagan_fifo); } else { Sagan_Log(S_NORMAL, "Successfully opened FILE (%s) and processing events.....", config->sagan_fifo); } while(fd != NULL) { while(fgets(syslogstring, sizeof(syslogstring), fd) != NULL) { /* If the FIFO was in a error state, let user know the FIFO writer has resumed */ if ( fifoerr == 1 ) { Sagan_Log(S_NORMAL, "FIFO writer has restarted. Processing events."); fifoerr=0; } counters->sagantotal++; syslog_host = strtok_r(syslogstring, "|", &tok); /* If we're using DNS (and we shouldn't be!), we start DNS checks and lookups * here. We cache both good and bad lookups to not over load our DNS server(s). * The only way DNS cache can be cleared is to restart Sagan */ if (config->syslog_src_lookup ) { if ( inet_pton(AF_INET, syslog_host, &(sa.sin_addr)) == 0 ) /* Is inbound a valid IP? */ { dns_flag=0; for(i=0; i <= counters->dns_cache_count ; i++) /* Check cache first */ { if (!strcmp( dnscache[i].hostname, syslog_host)) { syslog_host = dnscache[i].src_ip; dns_flag=1; } } /* If entry was not found in cache, look it up */ if ( dns_flag == 0 ) { /* Do a DNS lookup */ strlcpy(src_dns_lookup, DNS_Lookup(syslog_host), sizeof(src_dns_lookup)); /* Invalid lookups get the config->sagan_host value */ if (src_dns_lookup[0] == '0' ) { strlcpy(src_dns_lookup, config->sagan_host, sizeof(src_dns_lookup)); counters->dns_miss_count++; } /* Add entry to DNS Cache */ dnscache = (_SaganDNSCache *) realloc(dnscache, (counters->dns_cache_count+1) * sizeof(_SaganDNSCache)); strlcpy(dnscache[counters->dns_cache_count].hostname, syslog_host, sizeof(dnscache[counters->dns_cache_count].hostname)); strlcpy(dnscache[counters->dns_cache_count].src_ip, src_dns_lookup, sizeof(dnscache[counters->dns_cache_count].src_ip)); counters->dns_cache_count++; syslog_host = src_dns_lookup; } } } else { /* We check to see if values from our FIFO are valid. If we aren't doing DNS related * stuff (above), we start basic check with the syslog_host */ if (syslog_host == NULL || inet_pton(AF_INET, syslog_host, &(sa.sin_addr)) == 0 ) { syslog_host = config->sagan_host; pthread_mutex_lock(&SaganMalformedCounter); counters->malformed_host++; pthread_mutex_unlock(&SaganMalformedCounter); if ( debug->debugmalformed ) { Sagan_Log(S_WARN, "Sagan received a malformed 'host' (replaced with %s)", config->sagan_host); } } } // if ( config->home_any == 1) { /* We know check the rest of the values */ syslog_facility=strtok_r(NULL, "|", &tok); if ( syslog_facility == NULL ) { syslog_facility = "SAGAN: FACILITY ERROR"; pthread_mutex_lock(&SaganMalformedCounter); counters->malformed_facility++; pthread_mutex_unlock(&SaganMalformedCounter); if ( debug->debugmalformed ) { Sagan_Log(S_WARN, "Sagan received a malformed 'facility'"); } } syslog_priority=strtok_r(NULL, "|", &tok); if ( syslog_priority == NULL ) { syslog_priority = "SAGAN: PRIORITY ERROR"; pthread_mutex_lock(&SaganMalformedCounter); counters->malformed_priority++; pthread_mutex_unlock(&SaganMalformedCounter); if ( debug->debugmalformed ) { Sagan_Log(S_WARN, "Sagan received a malformed 'priority'"); } } syslog_level=strtok_r(NULL, "|", &tok); if ( syslog_level == NULL ) { syslog_level = "SAGAN: LEVEL ERROR"; pthread_mutex_lock(&SaganMalformedCounter); counters->malformed_level++; pthread_mutex_unlock(&SaganMalformedCounter); if ( debug->debugmalformed ) { Sagan_Log(S_WARN, "Sagan received a malformed 'level'"); } } syslog_tag=strtok_r(NULL, "|", &tok); if ( syslog_tag == NULL ) { syslog_tag = "SAGAN: TAG ERROR"; pthread_mutex_lock(&SaganMalformedCounter); counters->malformed_tag++; pthread_mutex_unlock(&SaganMalformedCounter); if ( debug->debugmalformed ) { Sagan_Log(S_WARN, "Sagan received a malformed 'tag'"); } } syslog_date=strtok_r(NULL, "|", &tok); if ( syslog_date == NULL ) { syslog_date = "SAGAN: DATE ERROR"; pthread_mutex_lock(&SaganMalformedCounter); counters->malformed_date++; pthread_mutex_unlock(&SaganMalformedCounter); if ( debug->debugmalformed ) { Sagan_Log(S_WARN, "Sagan received a malformed 'date'"); } } syslog_time=strtok_r(NULL, "|", &tok); if ( syslog_time == NULL ) { syslog_time = "SAGAN: TIME ERROR"; pthread_mutex_lock(&SaganMalformedCounter); counters->malformed_time++; pthread_mutex_unlock(&SaganMalformedCounter); if ( debug->debugmalformed ) { Sagan_Log(S_WARN, "Sagan received a malformed 'time'"); } } syslog_program=strtok_r(NULL, "|", &tok); if ( syslog_program == NULL ) { syslog_program = "SAGAN: PROGRAM ERROR"; pthread_mutex_lock(&SaganMalformedCounter); counters->malformed_program++; pthread_mutex_unlock(&SaganMalformedCounter); if ( debug->debugmalformed ) { Sagan_Log(S_WARN, "Sagan received a malformed 'program'"); } } syslog_msg=strtok_r(NULL, "", &tok); /* In case the message has | in it, we delimit on "" */ if ( syslog_msg == NULL ) { syslog_msg = "SAGAN: MESSAGE ERROR"; pthread_mutex_lock(&SaganMalformedCounter); counters->malformed_message++; pthread_mutex_unlock(&SaganMalformedCounter); if ( debug->debugmalformed ) { Sagan_Log(S_WARN, "Sagan received a malformed 'message' [Syslog Host: %s]", syslog_host); } /* If the message is lost, all is lost. Typically, you don't lose part of the message, * it's more likely to lose all - Champ Clark III 11/17/2011 */ counters->sagan_log_drop++; } /* Strip any \n or \r from the syslog_msg */ if ( strcspn ( syslog_msg, "\n" ) < strlen(syslog_msg) ) syslog_msg[strcspn ( syslog_msg, "\n" )] = '\0'; if ( proc_msgslot < config->max_processor_threads ) { pthread_mutex_lock(&SaganProcWorkMutex); strlcpy(SaganProcSyslog[proc_msgslot].syslog_host, syslog_host, sizeof(SaganProcSyslog[proc_msgslot].syslog_host)); strlcpy(SaganProcSyslog[proc_msgslot].syslog_facility, syslog_facility, sizeof(SaganProcSyslog[proc_msgslot].syslog_facility)); strlcpy(SaganProcSyslog[proc_msgslot].syslog_priority, syslog_priority, sizeof(SaganProcSyslog[proc_msgslot].syslog_priority)); strlcpy(SaganProcSyslog[proc_msgslot].syslog_level, syslog_level, sizeof(SaganProcSyslog[proc_msgslot].syslog_level)); strlcpy(SaganProcSyslog[proc_msgslot].syslog_tag, syslog_tag, sizeof(SaganProcSyslog[proc_msgslot].syslog_tag)); strlcpy(SaganProcSyslog[proc_msgslot].syslog_date, syslog_date, sizeof(SaganProcSyslog[proc_msgslot].syslog_date)); strlcpy(SaganProcSyslog[proc_msgslot].syslog_time, syslog_time, sizeof(SaganProcSyslog[proc_msgslot].syslog_time)); strlcpy(SaganProcSyslog[proc_msgslot].syslog_program, syslog_program, sizeof(SaganProcSyslog[proc_msgslot].syslog_program)); strlcpy(SaganProcSyslog[proc_msgslot].syslog_message, syslog_msg, sizeof(SaganProcSyslog[proc_msgslot].syslog_message)); proc_msgslot++; pthread_cond_signal(&SaganProcDoWork); pthread_mutex_unlock(&SaganProcWorkMutex); } else { counters->worker_thread_exhaustion++; counters->sagan_log_drop++; } if (debug->debugthreads) Sagan_Log(S_DEBUG, "Current \"proc_msgslot\": %d", proc_msgslot); if (debug->debugsyslog) { Sagan_Log(S_DEBUG, "[%s, line %d] **[RAW Syslog]*********************************", __FILE__, __LINE__); Sagan_Log(S_DEBUG, "[%s, line %d] Host: %s | Program: %s | Facility: %s | Priority: %s | Level: %s | Tag: %s", __FILE__, __LINE__, syslog_host, syslog_program, syslog_facility, syslog_priority, syslog_level, syslog_tag); Sagan_Log(S_DEBUG, "[%s, line %d] Raw message: %s", __FILE__, __LINE__, syslog_msg); } } /* while(fgets) */ /* fgets() has returned a error, likely due to the FIFO writer leaving */ /* DEBUG : set a kill flag and join */ /* RMEOVE LOCK */ if ( fifoerr == 0 ) { if ( config->sagan_fifo_flag != 0 ) { Sagan_Log(S_NORMAL, "EOF reached. Waiting for threads to catch up"); sleep(5); fclose(fd); Sagan_Log(S_NORMAL, "Exiting."); /* DEBUG: Rejoin threads */ exit(0); } else { Sagan_Log(S_WARN, "FIFO writer closed. Waiting for FIFO writer to restart...."); fifoerr=1; /* Set flag so our wile(fgets) knows */ } } sleep(1); /* So we don't eat 100% CPU */ } /* while(fd != NULL) */ fclose(fd); /* ???? */ } /* End of while(1) */ } /* End of main */