static int runner_process_envelope(u_int64_t evpid) { struct envelope envelope; size_t mta_av, mda_av, bnc_av; struct scheduler_info si; mta_av = env->sc_maxconn - stat_get(STATS_MTA_SESSION, STAT_ACTIVE); mda_av = env->sc_maxconn - stat_get(STATS_MDA_SESSION, STAT_ACTIVE); bnc_av = env->sc_maxconn - stat_get(STATS_RUNNER_BOUNCES, STAT_ACTIVE); if (! queue_envelope_load(evpid, &envelope)) return 0; if (envelope.type == D_MDA) if (mda_av == 0) { env->sc_flags |= SMTPD_MDA_BUSY; return 0; } if (envelope.type == D_MTA) if (mta_av == 0) { env->sc_flags |= SMTPD_MTA_BUSY; return 0; } if (envelope.type == D_BOUNCE) if (bnc_av == 0) { env->sc_flags |= SMTPD_BOUNCE_BUSY; return 0; } if (runner_check_loop(&envelope)) { struct envelope bounce; envelope_set_errormsg(&envelope, "loop has been detected"); if (bounce_record_message(&envelope, &bounce)) { scheduler_info(&si, &bounce); scheduler->insert(&si); } scheduler->remove(evpid); queue_envelope_delete(&envelope); runner_reset_events(); return 0; } return runner_process_batch(envelope.type, evpid); }
int stat_open(struct pk_state *state, const char *name) { gchar *buf; int fh; buf = stat_get(state, name); if (buf == NULL) return -ENOENT; g_mutex_lock(state->fuse->stat_buffer_lock); /* Find the next available file handle */ for (fh = 1; g_hash_table_lookup(state->fuse->stat_buffers, GINT_TO_POINTER(fh)); fh++); g_hash_table_insert(state->fuse->stat_buffers, GINT_TO_POINTER(fh), buf); g_mutex_unlock(state->fuse->stat_buffer_lock); return fh; }
static void stat_print(int stat, int what) { static const char *names[STATS_MAX] = { "smtp.sessions", "smtp.sessions.inet4", "smtp.sessions.inet6", "smtp.sessions.smtps", "smtp.sessions.starttls", "mta.sessions", "mda.sessions", "control.sessions", "lka.sessions", "lka.sessions.mx", "lka.sessions.host", "lka.sessions.cname", "lka.sessions.failure", "scheduler", "scheduler.bounces", "queue.inserts.local", "queue.inserts.remote", "ramqueue.envelopes", "ramqueue.messages", "ramqueue.batches", "ramqueue.hosts", }; const char *sfx; if (what == STAT_ACTIVE) sfx = ".active"; else if (what == STAT_MAXACTIVE) sfx = ".maxactive"; else sfx = ""; printf("%s%s=%zd\n", names[stat], sfx, stat_get(stat, what)); }
void stat_shutdown(struct pk_state *state, gboolean normal) { gchar **stats; gchar **cur; gchar *value; if (normal) { /* Log statistics */ for (stats = cur = stat_list(state); *cur != NULL; cur++) { value = stat_get(state, *cur); g_strchomp(value); pk_log(LOG_STATS, "%s: %s", *cur, value); g_free(value); } g_strfreev(stats); } g_hash_table_destroy(state->fuse->stat_buffers); g_mutex_free(state->fuse->stat_buffer_lock); }
void runner_imsg(struct imsgev *iev, struct imsg *imsg) { struct envelope *e, bounce; struct scheduler_info si; log_imsg(PROC_RUNNER, iev->proc, imsg); switch (imsg->hdr.type) { case IMSG_QUEUE_COMMIT_MESSAGE: e = imsg->data; runner_message_to_scheduler(evpid_to_msgid(e->id)); runner_reset_events(); return; case IMSG_QUEUE_DELIVERY_OK: stat_decrement(STATS_RUNNER); e = imsg->data; log_debug("queue_delivery_ok: %016"PRIx64, e->id); scheduler->remove(e->id); queue_envelope_delete(e); return; case IMSG_QUEUE_DELIVERY_TEMPFAIL: stat_decrement(STATS_RUNNER); e = imsg->data; e->retry++; queue_envelope_update(e); log_debug("queue_delivery_tempfail: %016"PRIx64, e->id); scheduler_info(&si, e); scheduler->insert(&si); runner_reset_events(); return; case IMSG_QUEUE_DELIVERY_PERMFAIL: stat_decrement(STATS_RUNNER); e = imsg->data; if (e->type != D_BOUNCE && e->sender.user[0] != '\0') { bounce_record_message(e, &bounce); log_debug("queue_delivery_permfail: %016"PRIx64, bounce.id); scheduler_info(&si, &bounce); scheduler->insert(&si); runner_reset_events(); } scheduler->remove(e->id); queue_envelope_delete(e); return; case IMSG_MDA_SESS_NEW: stat_decrement(STATS_MDA_SESSION); if (env->sc_maxconn - stat_get(STATS_MDA_SESSION, STAT_ACTIVE)) env->sc_flags &= ~SMTPD_MDA_BUSY; runner_reset_events(); return; case IMSG_BATCH_DONE: stat_decrement(STATS_MTA_SESSION); if (env->sc_maxconn - stat_get(STATS_MTA_SESSION, STAT_ACTIVE)) env->sc_flags &= ~SMTPD_MTA_BUSY; runner_reset_events(); return; case IMSG_SMTP_ENQUEUE: e = imsg->data; if (imsg->fd < 0 || !bounce_session(imsg->fd, e)) { queue_envelope_update(e); log_debug("smtp_enqueue: %016"PRIx64, e->id); scheduler_info(&si, e); scheduler->insert(&si); runner_reset_events(); return; } return; case IMSG_QUEUE_PAUSE_MDA: env->sc_flags |= SMTPD_MDA_PAUSED; return; case IMSG_QUEUE_RESUME_MDA: env->sc_flags &= ~SMTPD_MDA_PAUSED; runner_reset_events(); return; case IMSG_QUEUE_PAUSE_MTA: env->sc_flags |= SMTPD_MTA_PAUSED; return; case IMSG_QUEUE_RESUME_MTA: env->sc_flags &= ~SMTPD_MTA_PAUSED; runner_reset_events(); return; case IMSG_CTL_VERBOSE: log_verbose(*(int *)imsg->data); return; case IMSG_RUNNER_SCHEDULE: scheduler->force(*(u_int64_t *)imsg->data); runner_reset_events(); return; case IMSG_RUNNER_REMOVE: { runner_remove(*(u_int64_t *)imsg->data); runner_reset_events(); return; } } errx(1, "runner_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type)); }
int main(int argc, char **argv) { int arg,ret; char *configfile; char pcapfile[256]; // Load default config init_config(); // Set the signal handlers signal(SIGHUP, sighup_handler); signal(SIGINT, sigquit_handler); signal(SIGQUIT,sigquit_handler); // Parse command-line options while ((arg = getopt(argc, argv, "IP:i:c:f:DqvdTsr:l:u:S:")) != -1){ switch (arg){ case 'f': strncpy(CONFIG_PCAP_FILTER,optarg,CONFIG_MAX_CHAR); break; case 'r': strncpy(pcapfile,optarg,256); mode_offline=1; break; case 'c': configfile = optarg; read_config(configfile); //dump_config(); break; case 'i': // Start the pcap thread strncpy(CONFIG_PCAP_DEV,optarg,CONFIG_MAX_CHAR); break; case 'P': CONFIG_DIVERT_PORT=atoi(optarg); break; case 'I': CONFIG_DIVERT_ENABLE=1; break; case 'q': CONFIG_LOG_STDOUT = 0; break; case 'u': strncpy(CONFIG_USER,optarg,CONFIG_MAX_CHAR); break; case 'l': strncpy(CONFIG_LOGDIR,optarg,CONFIG_MAX_CHAR); if(strlen(CONFIG_LOGDIR) > 64) { fatal_error("Log directory is too long!"); } if (access(CONFIG_LOGDIR, F_OK) == -1){ fatal_error("Log directory does not exist"); } break; case 's': CONFIG_LOG_SYSLOG = 1; break; case 'S': strncpy(CONFIG_SIGFILE,optarg,CONFIG_MAX_CHAR); break; case 'T': CONFIG_TCP_STRICT = 0; break; case 'v': CONFIG_LOG_VERBOSE++; break; case 'd': CONFIG_SHOW_TRAFFIC = 1; break; case 'D': fork_to_background(); break; default: usage(); exit(1); break; } } // Initialize the stats structure and the streams stats_init(); // Create the list, this is to store the IP packets in which can then // be read by another thread. TODO: add maximum list size trafficlist = getRingBuffer(CONFIG_RINGBUFFER_SIZE); // Register the destructor registerListDestructor(destructor_callback,trafficlist); registerListIterator(traffic_analyzer,trafficlist); // Create the control thread first for message logging pthread_create(&t_control,NULL,(void*)control_loop,NULL); //Initialize the detection hooks detect_hook_init(); tcp_stream_init(); //Initialize the timers timer_init(); timer_register_function(CONFIG_TIMER_STATS,"Stats printer",stats_show_cnt_line,NULL); timer_register_function(CONFIG_TIMER_TCP_CLEANER,"TCP session cleaner", tcp_clean_sessions,NULL); timer_register_function(CONFIG_TIMER_IPFRAG_CLEANER,"IP fragment cleaner", ip_frag_cleaner,NULL); //Load the signatures if(load_signatures(CONFIG_SIGFILE) == 1){ usage(); exit(1); } // Make signature index; init_signature_indexes(); log_info("Signatures loaded: %d, not loaded: %d", stat_get(CNT_SIG_LOADED), stat_get(CNT_SIG_NOT_LOADED)); // Check if root privileges are required if(mode_offline == 0 && getuid() != 0) { fprintf(stderr, "Root privileges are required, unless you specify a\n"); fprintf(stderr, "pcap file with the '-r' option..\n"); exit(1); } if(CONFIG_DIVERT_ENABLE) { log_info("Opening DIVERT socket port: %d\n",CONFIG_DIVERT_PORT); divert_open_socket(CONFIG_DIVERT_PORT); // Start the divert_listen loop pthread_create(&t_listener,NULL,(void*)divert_listen_loop,handle); } else if(mode_offline != 1) { // If no device was specified AND not configured then the only // option is to pick one using the cap library (not recommended) if(*CONFIG_PCAP_DEV == '0') { if(pcap_return_device() != NULL) { log_info("Picking random interface (overrule -i)"); strncpy(CONFIG_PCAP_DEV,pcap_return_device(),CONFIG_MAX_CHAR); } else { usage(); exit(1); } } // Start the sniffer thread handle = pcap_open_device(CONFIG_PCAP_DEV,CONFIG_PCAP_FILTER); pthread_create(&t_listener,NULL,(void*)pcap_listen_loop,handle); } else { // Open the file handle = pcap_open_file(pcapfile,CONFIG_PCAP_FILTER); pthread_create(&t_listener,NULL,(void*)pcap_listen_loop,handle); } // Chroot if needed if(CONFIG_CHROOT_ENABLE == 1) { if((ret = chroot(CONFIG_CHROOT_DIR)) != 0) { fatal_error("Chroot to \"%s\" failed: %s !",CONFIG_CHROOT_DIR, strerror(errno)); } else { log_info("Chroot to directory: \"%s\" done",CONFIG_CHROOT_DIR); } } // Drop privileges if needed if(*CONFIG_USER != '0' && drop_privileges(CONFIG_USER) != 0) { fatal_error("Unable to drop privileges, quitting for security reasons",CONFIG_USER); } // Set the time gettimeofday(&startuptime,NULL); pthread_create(&t_analyzer,NULL,(void*)pcap_analyzer,NULL); if(mode_offline == 1) { pthread_join(t_analyzer, NULL); } else { pthread_join(t_listener,NULL); } // Control thread loop_control = 0; pthread_join(t_control, NULL); // And bail out dump_stats(stdout); return 0; }