/***** * * Copyright (C) 2003-2005 Nicolas Delon * All Rights Reserved * * This file is part of the Prelude program. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * *****/ #include #include #include #include #include #include #include #include #include #include #include #include "pflogger.h" #include "process_packet.h" #include "config.h" #define DEFAULT_SNAPLEN 96 #define DEFAULT_INTERFACE "pflog0" #define ANALYZER_CLASS "Firewall" #define ANALYZER_MODEL "Prelude PFlogger" #define ANALYZER_MANUFACTURER "The Prelude Team http://www.prelude-ids.org" static char *pid_file = NULL; static const char *conf_file = PRELUDE_PFLOGGER_CONF; static char *interface = DEFAULT_INTERFACE; static int bring_interface_down_at_shutdown = 0; static prelude_client_t *pflogger_client = NULL; static idmef_analyzer_t *pflogger_analyzer = NULL; static int print_help(prelude_option_t *opt, const char *arg, prelude_string_t *errmsg, void *context) { prelude_option_print(NULL, PRELUDE_OPTION_TYPE_CLI, 25, stderr); exit(0); } static int print_version(prelude_option_t *opt, const char *arg, prelude_string_t *errmsg, void *context) { printf("prelude-pflogger %s\n", VERSION); exit(0); } static int set_daemon_mode(prelude_option_t *opt, const char *arg, prelude_string_t *errmsg, void *context) { int ret; ret = prelude_daemonize(pid_file); if ( ret < 0 ) return ret; prelude_log_set_flags(prelude_log_get_flags()|PRELUDE_LOG_FLAGS_SYSLOG); return 0; } static int set_pid_file(prelude_option_t *opt, const char *arg, prelude_string_t *errmsg, void *context) { pid_file = strdup(arg); if ( ! pid_file ) return prelude_error_from_errno(errno); return 0; } static int set_conf_file(prelude_option_t *opt, const char *arg, prelude_string_t *errmsg, void *context) { conf_file = strdup(arg); if ( ! conf_file ) return prelude_error_from_errno(errno); return 0; } static int init_sensor_options(int *argc, char **argv) { prelude_option_t *ropt, *opt; prelude_string_t *errmsg; int ret; ret = prelude_option_new_root(&ropt); if ( ret < 0 ) return ret; prelude_option_add(ropt, &opt, PRELUDE_OPTION_TYPE_CLI, 'v', "version", "Print version number", PRELUDE_OPTION_ARGUMENT_NONE, print_version, NULL); prelude_option_set_priority(opt, PRELUDE_OPTION_PRIORITY_IMMEDIATE); prelude_option_add(ropt, &opt, PRELUDE_OPTION_TYPE_CLI, 'h', "help", "Print this help", PRELUDE_OPTION_ARGUMENT_NONE, print_help, NULL); prelude_option_set_priority(opt, PRELUDE_OPTION_PRIORITY_IMMEDIATE); prelude_option_add(ropt, &opt, PRELUDE_OPTION_TYPE_CLI|PRELUDE_OPTION_TYPE_CFG, 'd', "daemon", "Run in daemon mode", PRELUDE_OPTION_ARGUMENT_NONE, set_daemon_mode, NULL); prelude_option_set_priority(opt, PRELUDE_OPTION_PRIORITY_FIRST); prelude_option_add(ropt, &opt, PRELUDE_OPTION_TYPE_CLI, 'c', "config", "Configuration file to use", PRELUDE_OPTION_ARGUMENT_REQUIRED, set_conf_file, NULL); prelude_option_set_priority(opt, PRELUDE_OPTION_PRIORITY_IMMEDIATE); prelude_option_add(ropt, &opt, PRELUDE_OPTION_TYPE_CLI|PRELUDE_OPTION_TYPE_CFG, 'P', "pidfile", "Write Prelude PFlogger pid to the specified pidfile", PRELUDE_OPTION_ARGUMENT_REQUIRED, set_pid_file, NULL); prelude_option_set_priority(opt, PRELUDE_OPTION_PRIORITY_IMMEDIATE); ret = prelude_option_read(ropt, &conf_file, argc, argv, &errmsg, NULL); if ( ret < 0 && errmsg ) { prelude_log(PRELUDE_LOG_WARN, "Could not start Prelude PFlogger: %s.\n", prelude_string_get_string(errmsg)); exit(1); } return ret; } static int init_sensor_idmef_infos(void) { prelude_string_t *string; int ret; pflogger_analyzer = prelude_client_get_analyzer(pflogger_client); ret = idmef_analyzer_new_model(pflogger_analyzer, &string); if ( ret < 0 ) return ret; prelude_string_set_constant(string, ANALYZER_MODEL); ret = idmef_analyzer_new_class(pflogger_analyzer, &string); if ( ret < 0 ) return ret; prelude_string_set_constant(string, ANALYZER_CLASS); ret = idmef_analyzer_new_manufacturer(pflogger_analyzer, &string); if ( ret < 0 ) return ret; prelude_string_set_constant(string, ANALYZER_MANUFACTURER); ret = idmef_analyzer_new_version(pflogger_analyzer, &string); if ( ret < 0 ) return ret; prelude_string_set_constant(string, VERSION); return 0; } static int init_sensor(int *argc, char **argv) { int ret; prelude_init(argc, argv); ret = init_sensor_options(argc, argv); if ( ret < 0 ) return ret; ret = prelude_client_new(&pflogger_client, "prelude-pflogger"); if ( ret < 0 ) return ret; prelude_client_set_config_filename(pflogger_client, conf_file); ret = init_sensor_idmef_infos(); if ( ret < 0 ) return ret; ret = prelude_client_set_flags(pflogger_client, prelude_client_get_flags(pflogger_client) | PRELUDE_CLIENT_FLAGS_ASYNC_SEND|PRELUDE_CLIENT_FLAGS_ASYNC_TIMER); if ( ret < 0 ) return ret; return prelude_client_start(pflogger_client); } /* * Check if interface is up * if not, bring it up and set a flag so that * the interface will be brought down when pflogger shutdown */ static int init_interface(void) { int sock; struct ifreq ifreq; sock = socket(AF_INET, SOCK_DGRAM, 0); if ( sock < 0 ) return prelude_error_from_errno(errno); strncpy(ifreq.ifr_name, interface, sizeof (ifreq.ifr_name)); if ( ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0 ) { close(sock); return prelude_error_from_errno(errno); } if ( !(ifreq.ifr_flags & IFF_UP) ) { prelude_log(PRELUDE_LOG_INFO, "interface %s is down, bring it up\n", interface); ifreq.ifr_flags |= IFF_UP; if ( ioctl(sock, SIOCSIFFLAGS, &ifreq) ) return prelude_error_from_errno(errno); bring_interface_down_at_shutdown = 1; } close(sock); return 0; } static int shutdown_interface(void) { int sock; struct ifreq ifreq; if ( ! bring_interface_down_at_shutdown ) return 0; sock = socket(AF_INET, SOCK_DGRAM, 0); if ( sock < 0 ) return prelude_error_from_errno(errno); strncpy(ifreq.ifr_name, interface, sizeof (ifreq.ifr_name)); if ( ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0 ) { close(sock); return prelude_error_from_errno(errno); } ifreq.ifr_flags &= ~IFF_UP; if ( ioctl(sock, SIOCSIFFLAGS, &ifreq) ) return prelude_error_from_errno(errno); close(sock); return 0; } static void pflogger_shutdown(void) { process_packet_stop(); (void) shutdown_interface(); } static void signal_handler(int signo) { prelude_log(PRELUDE_LOG_INFO, "caught signal %d\n", signo); pflogger_shutdown(); exit(0); } static void init_signal_handlers(void) { signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGQUIT, signal_handler); signal(SIGHUP, signal_handler); } int pflogger_send_alert(idmef_message_t *message) { idmef_alert_t *alert = idmef_message_get_alert(message); idmef_time_t *create_time; int ret; ret = idmef_time_new_from_gettimeofday(&create_time); if ( ret < 0 ) return ret; idmef_alert_set_create_time(alert, create_time); idmef_alert_set_analyzer(alert, idmef_analyzer_ref(pflogger_analyzer), 0); prelude_client_send_idmef(pflogger_client, message); return 0; } int main(int argc, char **argv) { int ret; ret = init_sensor(&argc, argv); if ( ret < 0 ) goto error; ret = init_interface(); if ( ret < 0 ) goto error; ret = process_packet_init(interface, DEFAULT_SNAPLEN); if ( ret < 0 ) goto error; init_signal_handlers(); ret = process_packet_mainloop(); if ( ret < 0 ) goto error; pflogger_shutdown(); return 0; error: if ( ret != -1 ) prelude_perror(ret, "error"); return 1; }