mirror of
				https://github.com/optim-enterprises-bv/nDPId.git
				synced 2025-10-31 18:27:47 +00:00 
			
		
		
		
	 33560d64d2
			
		
	
	33560d64d2
	
	
	
		
			
			* CI: build against libnDPI with `-DNDPI_NO_PKGCONFIG=ON` and `-DSTATIC_LIBNDPI_INSTALLDIR=/usr` * CI: `ENABLE_DBUS=ON` for most builds Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
		
			
				
	
	
		
			669 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			669 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <dbus-1.0/dbus/dbus.h>
 | |
| #include <signal.h>
 | |
| #include <stdint.h>
 | |
| #include <syslog.h>
 | |
| 
 | |
| #include "nDPIsrvd.h"
 | |
| #include "utstring.h"
 | |
| #include "utils.h"
 | |
| 
 | |
| #define SLEEP_TIME_IN_S (3)
 | |
| 
 | |
| struct flow_user_data
 | |
| {
 | |
|     nDPIsrvd_ull detected_risks;
 | |
| };
 | |
| 
 | |
| enum dbus_level
 | |
| {
 | |
|     DBUS_LOW = 0,
 | |
|     DBUS_NORMAL,
 | |
|     DBUS_CRITICAL
 | |
| };
 | |
| 
 | |
| static char const * const flow_severities[] = {"Low", "Medium", "High", "Severe", "Critical", "Emergency"};
 | |
| static char const * const flow_breeds[] = {
 | |
|     "Safe", "Acceptable", "Fun", "Unsafe", "Potentially Dangerous", "Tracker\\/Ads", "Dangerous", "Unrated", "???"};
 | |
| static char const * const flow_categories[] = {"Unspecified",
 | |
|                                                "Media",
 | |
|                                                "VPN",
 | |
|                                                "Email",
 | |
|                                                "DataTransfer",
 | |
|                                                "Web",
 | |
|                                                "SocialNetwork",
 | |
|                                                "Download",
 | |
|                                                "Game",
 | |
|                                                "Chat",
 | |
|                                                "VoIP",
 | |
|                                                "Database",
 | |
|                                                "RemoteAccess",
 | |
|                                                "Cloud",
 | |
|                                                "Network",
 | |
|                                                "Collaborative",
 | |
|                                                "RPC",
 | |
|                                                "Streaming",
 | |
|                                                "System",
 | |
|                                                "SoftwareUpdate",
 | |
|                                                "Music",
 | |
|                                                "Video",
 | |
|                                                "Shopping",
 | |
|                                                "Productivity",
 | |
|                                                "FileSharing",
 | |
|                                                "ConnCheck",
 | |
|                                                "IoT-Scada",
 | |
|                                                "VirtAssistant",
 | |
|                                                "Cybersecurity",
 | |
|                                                "AdultContent",
 | |
|                                                "Mining",
 | |
|                                                "Malware",
 | |
|                                                "Advertisement",
 | |
|                                                "Banned_Site",
 | |
|                                                "Site_Unavailable",
 | |
|                                                "Allowed_Site",
 | |
|                                                "Antimalware",
 | |
|                                                "Crypto_Currency"};
 | |
| 
 | |
| static uint8_t desired_flow_severities[nDPIsrvd_ARRAY_LENGTH(flow_severities)] = {};
 | |
| static uint8_t desired_flow_breeds[nDPIsrvd_ARRAY_LENGTH(flow_breeds)] = {};
 | |
| static uint8_t desired_flow_categories[nDPIsrvd_ARRAY_LENGTH(flow_categories)] = {};
 | |
| 
 | |
| static unsigned int id = 0;
 | |
| static char const * const application = "nDPIsrvd.notifyd";
 | |
| 
 | |
| static int main_thread_shutdown = 0;
 | |
| 
 | |
| static char * pidfile = NULL;
 | |
| static char * serv_optarg = NULL;
 | |
| 
 | |
| #ifdef ENABLE_MEMORY_PROFILING
 | |
| void nDPIsrvd_memprof_log_alloc(size_t alloc_size)
 | |
| {
 | |
|     (void)alloc_size;
 | |
| }
 | |
| 
 | |
| void nDPIsrvd_memprof_log_free(size_t free_size)
 | |
| {
 | |
|     (void)free_size;
 | |
| }
 | |
| 
 | |
| void nDPIsrvd_memprof_log(char const * const format, ...)
 | |
| {
 | |
|     va_list ap;
 | |
| 
 | |
|     va_start(ap, format);
 | |
|     fprintf(stderr, "%s", "nDPIsrvd MemoryProfiler: ");
 | |
|     vfprintf(stderr, format, ap);
 | |
|     fprintf(stderr, "%s\n", "");
 | |
|     va_end(ap);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static void send_to_dbus(char const * const icon,
 | |
|                          char const * const urgency,
 | |
|                          enum dbus_level level,
 | |
|                          char const * const summary,
 | |
|                          char const * const body,
 | |
|                          int timeout)
 | |
| {
 | |
|     DBusConnection * connection = dbus_bus_get(DBUS_BUS_SESSION, 0);
 | |
|     DBusMessage * message = dbus_message_new_method_call("org.freedesktop.Notifications",
 | |
|                                                          "/org/freedesktop/Notifications",
 | |
|                                                          "org.freedesktop.Notifications",
 | |
|                                                          "Notify");
 | |
|     DBusMessageIter iter[4];
 | |
|     dbus_message_iter_init_append(message, iter);
 | |
|     dbus_message_iter_append_basic(iter, 's', &application);
 | |
|     dbus_message_iter_append_basic(iter, 'u', &id);
 | |
|     dbus_message_iter_append_basic(iter, 's', &icon);
 | |
|     dbus_message_iter_append_basic(iter, 's', &summary);
 | |
|     dbus_message_iter_append_basic(iter, 's', &body);
 | |
|     dbus_message_iter_open_container(iter, 'a', "s", iter + 1);
 | |
|     dbus_message_iter_close_container(iter, iter + 1);
 | |
|     dbus_message_iter_open_container(iter, 'a', "{sv}", iter + 1);
 | |
|     dbus_message_iter_open_container(iter + 1, 'e', 0, iter + 2);
 | |
|     dbus_message_iter_append_basic(iter + 2, 's', &urgency);
 | |
|     dbus_message_iter_open_container(iter + 2, 'v', "y", iter + 3);
 | |
|     dbus_message_iter_append_basic(iter + 3, 'y', &level);
 | |
|     dbus_message_iter_close_container(iter + 2, iter + 3);
 | |
|     dbus_message_iter_close_container(iter + 1, iter + 2);
 | |
|     dbus_message_iter_close_container(iter, iter + 1);
 | |
|     dbus_message_iter_append_basic(iter, 'i', &timeout);
 | |
|     dbus_connection_send(connection, message, 0);
 | |
|     dbus_connection_flush(connection);
 | |
|     dbus_message_unref(message);
 | |
|     dbus_connection_unref(connection);
 | |
| 
 | |
|     id++;
 | |
| }
 | |
| 
 | |
| static void notify(enum dbus_level level, char const * const summary, int timeout, char const * const body)
 | |
| {
 | |
|     send_to_dbus("dialog-information", "urgency", level, summary, body, timeout);
 | |
| }
 | |
| 
 | |
| __attribute__((format(printf, 4, 5))) static void notifyf(
 | |
|     enum dbus_level level, char const * const summary, int timeout, char const * const body_fmt, ...)
 | |
| {
 | |
|     va_list ap;
 | |
|     char buf[BUFSIZ];
 | |
| 
 | |
|     va_start(ap, body_fmt);
 | |
|     if (vsnprintf(buf, sizeof(buf), body_fmt, ap) > 0)
 | |
|     {
 | |
|         notify(level, summary, timeout, buf);
 | |
|     }
 | |
|     va_end(ap);
 | |
| }
 | |
| 
 | |
| static ssize_t get_value_index(char const * const possible_values[],
 | |
|                                size_t possible_values_size,
 | |
|                                char const * const needle,
 | |
|                                size_t needle_len)
 | |
| {
 | |
|     size_t i;
 | |
| 
 | |
|     for (i = 0; i < possible_values_size; ++i)
 | |
|     {
 | |
|         if (strncmp(needle, possible_values[i], needle_len) == 0)
 | |
|         {
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (i == possible_values_size)
 | |
|     {
 | |
|         return -1;
 | |
|     }
 | |
| 
 | |
|     return i;
 | |
| }
 | |
| 
 | |
| static void check_value(char const * const possible_values[],
 | |
|                         size_t possible_values_size,
 | |
|                         char const * const needle,
 | |
|                         size_t needle_len)
 | |
| {
 | |
|     if (get_value_index(possible_values, possible_values_size, needle, needle_len) == -1)
 | |
|     {
 | |
|         syslog(LOG_DAEMON | LOG_ERR, "BUG: Unknown value: %.*s", (int)needle_len, needle);
 | |
|         notifyf(DBUS_CRITICAL, "BUG", 5000, "Unknown value: %.*s", (int)needle_len, needle);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static enum nDPIsrvd_callback_return notifyd_json_callback(struct nDPIsrvd_socket * const sock,
 | |
|                                                            struct nDPIsrvd_instance * const instance,
 | |
|                                                            struct nDPIsrvd_thread_data * const thread_data,
 | |
|                                                            struct nDPIsrvd_flow * const flow)
 | |
| {
 | |
|     (void)instance;
 | |
|     (void)thread_data;
 | |
| 
 | |
|     struct nDPIsrvd_json_token const * const flow_event_name = TOKEN_GET_SZ(sock, "flow_event_name");
 | |
|     struct flow_user_data * flow_user_data = NULL;
 | |
| 
 | |
|     if (flow != NULL)
 | |
|     {
 | |
|         flow_user_data = (struct flow_user_data *)flow->flow_user_data;
 | |
|     }
 | |
| 
 | |
|     if (TOKEN_VALUE_EQUALS_SZ(sock, flow_event_name, "detected") != 0 ||
 | |
|         TOKEN_VALUE_EQUALS_SZ(sock, flow_event_name, "detection-update") != 0 ||
 | |
|         TOKEN_VALUE_EQUALS_SZ(sock, flow_event_name, "update") != 0)
 | |
|     {
 | |
|         struct nDPIsrvd_json_token const * const flow_risks = TOKEN_GET_SZ(sock, "ndpi", "flow_risk");
 | |
|         struct nDPIsrvd_json_token const * current = NULL;
 | |
|         int next_child_index = -1, desired_severity_found = 0;
 | |
|         UT_string risks;
 | |
| 
 | |
|         utstring_init(&risks);
 | |
| 
 | |
|         if (flow_risks != NULL)
 | |
|         {
 | |
|             while ((current = nDPIsrvd_get_next_token(sock, flow_risks, &next_child_index)) != NULL)
 | |
|             {
 | |
|                 nDPIsrvd_ull numeric_risk_value = (nDPIsrvd_ull)-1;
 | |
|                 size_t flow_risk_key_len = 0;
 | |
|                 char const * const flow_risk_key = TOKEN_GET_KEY(sock, current, &flow_risk_key_len);
 | |
| 
 | |
|                 if (flow_risk_key == NULL || flow_risk_key_len == 0)
 | |
|                 {
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 if (str_value_to_ull(flow_risk_key, &numeric_risk_value) == CONVERSION_OK && flow_user_data != NULL &&
 | |
|                     (flow_user_data->detected_risks & (1ull << numeric_risk_value)) == 0)
 | |
|                 {
 | |
|                     flow_user_data->detected_risks |= (1ull << (numeric_risk_value - 1));
 | |
| 
 | |
|                     char flow_risk_sz[flow_risk_key_len + 1];
 | |
|                     snprintf(flow_risk_sz, sizeof(flow_risk_sz), "%llu", numeric_risk_value);
 | |
|                     size_t flow_risk_len = 0;
 | |
|                     size_t flow_severity_len = 0;
 | |
|                     char const * const flow_risk_str =
 | |
|                         TOKEN_GET_VALUE(sock,
 | |
|                                         TOKEN_GET_SZ(sock, "ndpi", "flow_risk", flow_risk_sz, "risk"),
 | |
|                                         &flow_risk_len);
 | |
|                     char const * const flow_severity_str =
 | |
|                         TOKEN_GET_VALUE(sock,
 | |
|                                         TOKEN_GET_SZ(sock, "ndpi", "flow_risk", flow_risk_sz, "severity"),
 | |
|                                         &flow_severity_len);
 | |
| 
 | |
|                     if (flow_risk_str == NULL || flow_risk_len == 0 || flow_severity_str == NULL ||
 | |
|                         flow_severity_len == 0)
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
| 
 | |
|                     ssize_t severity_index = get_value_index(flow_severities,
 | |
|                                                              nDPIsrvd_ARRAY_LENGTH(flow_severities),
 | |
|                                                              flow_severity_str,
 | |
|                                                              flow_severity_len);
 | |
|                     if (severity_index != -1 && desired_flow_severities[severity_index] != 0)
 | |
|                     {
 | |
|                         desired_severity_found = 1;
 | |
|                     }
 | |
|                     utstring_printf(&risks,
 | |
|                                     "Risk: '%.*s'\n"
 | |
|                                     "Severity: '%.*s'\n",
 | |
|                                     (int)flow_risk_len,
 | |
|                                     flow_risk_str,
 | |
|                                     (int)flow_severity_len,
 | |
|                                     flow_severity_str);
 | |
|                     check_value(flow_severities,
 | |
|                                 nDPIsrvd_ARRAY_LENGTH(flow_severities),
 | |
|                                 flow_severity_str,
 | |
|                                 flow_severity_len);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         {
 | |
|             size_t flow_srcip_len = 0;
 | |
|             size_t flow_dstip_len = 0;
 | |
|             size_t flow_breed_len = 0;
 | |
|             size_t flow_category_len = 0;
 | |
|             size_t flow_hostname_len = 0;
 | |
| 
 | |
|             char const * const flow_srcip = TOKEN_GET_VALUE(sock, TOKEN_GET_SZ(sock, "src_ip"), &flow_srcip_len);
 | |
|             char const * const flow_dstip = TOKEN_GET_VALUE(sock, TOKEN_GET_SZ(sock, "dst_ip"), &flow_dstip_len);
 | |
|             char const * const flow_breed_str =
 | |
|                 TOKEN_GET_VALUE(sock, TOKEN_GET_SZ(sock, "ndpi", "breed"), &flow_breed_len);
 | |
|             char const * const flow_category_str =
 | |
|                 TOKEN_GET_VALUE(sock, TOKEN_GET_SZ(sock, "ndpi", "category"), &flow_category_len);
 | |
|             char const * const flow_hostname =
 | |
|                 TOKEN_GET_VALUE(sock, TOKEN_GET_SZ(sock, "ndpi", "hostname"), &flow_hostname_len);
 | |
| 
 | |
|             if (flow_breed_str != NULL && flow_breed_len != 0 && flow_category_str != NULL && flow_category_len != 0)
 | |
|             {
 | |
|                 ssize_t breed_index =
 | |
|                     get_value_index(flow_breeds, nDPIsrvd_ARRAY_LENGTH(flow_breeds), flow_breed_str, flow_breed_len);
 | |
|                 ssize_t category_index = get_value_index(flow_categories,
 | |
|                                                          nDPIsrvd_ARRAY_LENGTH(flow_categories),
 | |
|                                                          flow_category_str,
 | |
|                                                          flow_category_len);
 | |
| 
 | |
|                 if ((breed_index != -1 && desired_flow_breeds[breed_index] != 0) ||
 | |
|                     (category_index != -1 && desired_flow_categories[category_index] != 0) ||
 | |
|                     desired_severity_found != 0)
 | |
|                 {
 | |
|                     notifyf(DBUS_CRITICAL,
 | |
|                             "Flow Notification",
 | |
|                             5000,
 | |
|                             "%.*s -> %.*s (%.*s)\nBreed: '%.*s', Category: '%.*s'\n%s",
 | |
|                             (int)flow_srcip_len,
 | |
|                             flow_srcip,
 | |
|                             (int)flow_dstip_len,
 | |
|                             flow_dstip,
 | |
|                             (flow_hostname_len > 0 ? (int)flow_hostname_len : 1),
 | |
|                             (flow_hostname_len > 0 ? flow_hostname : "-"),
 | |
|                             (int)flow_breed_len,
 | |
|                             flow_breed_str,
 | |
|                             (int)flow_category_len,
 | |
|                             flow_category_str,
 | |
|                             (utstring_len(&risks) > 0 ? utstring_body(&risks) : "No flow risks detected\n"));
 | |
|                 }
 | |
| 
 | |
|                 check_value(flow_breeds, nDPIsrvd_ARRAY_LENGTH(flow_breeds), flow_breed_str, flow_breed_len);
 | |
|                 check_value(flow_categories,
 | |
|                             nDPIsrvd_ARRAY_LENGTH(flow_categories),
 | |
|                             flow_category_str,
 | |
|                             flow_category_len);
 | |
|             }
 | |
|             else if (desired_severity_found != 0)
 | |
|             {
 | |
|                 notifyf(DBUS_CRITICAL,
 | |
|                         "Risky Flow",
 | |
|                         5000,
 | |
|                         "%.*s -> %.*s (%.*s)\n%s",
 | |
|                         (int)flow_srcip_len,
 | |
|                         flow_srcip,
 | |
|                         (int)flow_dstip_len,
 | |
|                         flow_dstip,
 | |
|                         (flow_hostname_len > 0 ? (int)flow_hostname_len : 1),
 | |
|                         (flow_hostname_len > 0 ? flow_hostname : "-"),
 | |
|                         utstring_body(&risks));
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         utstring_done(&risks);
 | |
|     }
 | |
| 
 | |
|     return CALLBACK_OK;
 | |
| }
 | |
| 
 | |
| static void print_usage(char const * const arg0)
 | |
| {
 | |
|     static char const usage[] =
 | |
|         "Usage: %s "
 | |
|         "[-s host] [-C category...] [-B breed...] [-S severity...]\n\n"
 | |
|         "\t-s\tDestination where nDPIsrvd is listening on.\n"
 | |
|         "\t-C\tDesired nDPI category which fires a notificiation.\n"
 | |
|         "\t  \tCan be specified multiple times.\n"
 | |
|         "\t-B\tDesired nDPI breed which fires a notification.\n"
 | |
|         "\t  \tCan be specified multiple times.\n"
 | |
|         "\t-S\tDesired nDPI risk severity which fires a notification.\n"
 | |
|         "\t  \tCan be specified multiple times.\n"
 | |
|         "\n"
 | |
|         "Possible values for `-C': %s\n"
 | |
|         "Possible values for `-B': %s\n"
 | |
|         "Possible values for `-S': %s\n"
 | |
|         "\n";
 | |
| 
 | |
|     UT_string flow_categories_str, flow_breeds_str, flow_severities_str;
 | |
|     utstring_init(&flow_categories_str);
 | |
|     utstring_init(&flow_breeds_str);
 | |
|     utstring_init(&flow_severities_str);
 | |
|     for (size_t i = 0; i < nDPIsrvd_ARRAY_LENGTH(flow_categories); ++i)
 | |
|     {
 | |
|         utstring_printf(&flow_categories_str, "%s, ", flow_categories[i]);
 | |
|     }
 | |
|     flow_categories_str.d[flow_categories_str.i - 2] = '\0';
 | |
|     for (size_t i = 0; i < nDPIsrvd_ARRAY_LENGTH(flow_breeds); ++i)
 | |
|     {
 | |
|         utstring_printf(&flow_breeds_str, "%s, ", flow_breeds[i]);
 | |
|     }
 | |
|     flow_breeds_str.d[flow_breeds_str.i - 2] = '\0';
 | |
|     for (size_t i = 0; i < nDPIsrvd_ARRAY_LENGTH(flow_severities); ++i)
 | |
|     {
 | |
|         utstring_printf(&flow_severities_str, "%s, ", flow_severities[i]);
 | |
|     }
 | |
|     flow_severities_str.d[flow_severities_str.i - 2] = '\0';
 | |
|     fprintf(stderr,
 | |
|             usage,
 | |
|             arg0,
 | |
|             utstring_body(&flow_categories_str),
 | |
|             utstring_body(&flow_breeds_str),
 | |
|             utstring_body(&flow_severities_str));
 | |
|     utstring_done(&flow_severities_str);
 | |
|     utstring_done(&flow_breeds_str);
 | |
|     utstring_done(&flow_categories_str);
 | |
| }
 | |
| 
 | |
| static int set_defaults(void)
 | |
| {
 | |
|     char const * const default_severities[] = {"High", "Severe", "Critical", "Emergency"};
 | |
|     char const * const default_breeds[] = {"Unsafe", "Potentially Dangerous", "Dangerous", "Unrated"};
 | |
|     char const * const default_categories[] = {"Mining", "Malware", "Banned_Site", "Crypto_Currency"};
 | |
| 
 | |
|     for (size_t i = 0; i < nDPIsrvd_ARRAY_LENGTH(default_severities); ++i)
 | |
|     {
 | |
|         ssize_t index = get_value_index(flow_severities,
 | |
|                                         nDPIsrvd_ARRAY_LENGTH(flow_severities),
 | |
|                                         default_severities[i],
 | |
|                                         strlen(default_severities[i]));
 | |
|         if (index == -1)
 | |
|         {
 | |
|             return 1;
 | |
|         }
 | |
|         desired_flow_severities[index] = 1;
 | |
|     }
 | |
| 
 | |
|     for (size_t i = 0; i < nDPIsrvd_ARRAY_LENGTH(default_breeds); ++i)
 | |
|     {
 | |
|         ssize_t index = get_value_index(flow_breeds,
 | |
|                                         nDPIsrvd_ARRAY_LENGTH(flow_breeds),
 | |
|                                         default_breeds[i],
 | |
|                                         strlen(default_breeds[i]));
 | |
|         if (index == -1)
 | |
|         {
 | |
|             return 1;
 | |
|         }
 | |
|         desired_flow_breeds[index] = 1;
 | |
|     }
 | |
| 
 | |
|     for (size_t i = 0; i < nDPIsrvd_ARRAY_LENGTH(default_categories); ++i)
 | |
|     {
 | |
|         ssize_t index = get_value_index(flow_categories,
 | |
|                                         nDPIsrvd_ARRAY_LENGTH(flow_categories),
 | |
|                                         default_categories[i],
 | |
|                                         strlen(default_categories[i]));
 | |
|         if (index == -1)
 | |
|         {
 | |
|             return 1;
 | |
|         }
 | |
|         desired_flow_categories[index] = 1;
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static int parse_options(int argc, char ** argv, struct nDPIsrvd_socket * const sock)
 | |
| {
 | |
|     int opt, force_defaults = 1;
 | |
| 
 | |
|     while ((opt = getopt(argc, argv, "hdp:s:C:B:S:")) != -1)
 | |
|     {
 | |
|         switch (opt)
 | |
|         {
 | |
|             case 'd':
 | |
|                 daemonize_enable();
 | |
|                 break;
 | |
|             case 'p':
 | |
|                 free(pidfile);
 | |
|                 pidfile = strdup(optarg);
 | |
|                 break;
 | |
|             case 's':
 | |
|                 free(serv_optarg);
 | |
|                 serv_optarg = strdup(optarg);
 | |
|                 break;
 | |
|             case 'C':
 | |
|             {
 | |
|                 ssize_t index =
 | |
|                     get_value_index(flow_categories, nDPIsrvd_ARRAY_LENGTH(flow_categories), optarg, strlen(optarg));
 | |
|                 if (index == -1)
 | |
|                 {
 | |
|                     fprintf(stderr, "Invalid argument for `-C': %s\n", optarg);
 | |
|                     return 1;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     desired_flow_categories[index] = 1;
 | |
|                 }
 | |
|                 force_defaults = 0;
 | |
|                 break;
 | |
|             }
 | |
|             case 'B':
 | |
|             {
 | |
|                 ssize_t index =
 | |
|                     get_value_index(flow_breeds, nDPIsrvd_ARRAY_LENGTH(flow_breeds), optarg, strlen(optarg));
 | |
|                 if (index == -1)
 | |
|                 {
 | |
|                     fprintf(stderr, "Invalid argument for `-B': %s\n", optarg);
 | |
|                     return 1;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     desired_flow_breeds[index] = 1;
 | |
|                 }
 | |
|                 force_defaults = 0;
 | |
|                 break;
 | |
|             }
 | |
|             case 'S':
 | |
|             {
 | |
|                 ssize_t index =
 | |
|                     get_value_index(flow_severities, nDPIsrvd_ARRAY_LENGTH(flow_severities), optarg, strlen(optarg));
 | |
|                 if (index == -1)
 | |
|                 {
 | |
|                     fprintf(stderr, "Invalid argument for `-S': %s\n", optarg);
 | |
|                     return 1;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     desired_flow_severities[index] = 1;
 | |
|                 }
 | |
|                 force_defaults = 0;
 | |
|                 break;
 | |
|             }
 | |
|             default:
 | |
|                 print_usage(argv[0]);
 | |
|                 return 1;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (force_defaults != 0 && set_defaults() != 0)
 | |
|     {
 | |
|         fprintf(stderr, "%s\n", "BUG: Could not set default values.");
 | |
|         syslog(LOG_DAEMON | LOG_ERR, "%s\n", "BUG: Could not set default values.");
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     if (serv_optarg == NULL)
 | |
|     {
 | |
|         serv_optarg = strdup(DISTRIBUTOR_UNIX_SOCKET);
 | |
|     }
 | |
| 
 | |
|     if (nDPIsrvd_setup_address(&sock->address, serv_optarg) != 0)
 | |
|     {
 | |
|         syslog(LOG_DAEMON | LOG_ERR, "Could not parse address `%s'", serv_optarg);
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     if (optind < argc)
 | |
|     {
 | |
|         syslog(LOG_DAEMON | LOG_ERR, "%s", "Unexpected argument after options");
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static void sighandler(int signum)
 | |
| {
 | |
|     switch (signum)
 | |
|     {
 | |
|         case SIGINT:
 | |
|             notify(DBUS_LOW, "nDPIsrvd-notifyd", 3000, "Received SIGINT, shutdown.");
 | |
|             break;
 | |
|         case SIGTERM:
 | |
|             notify(DBUS_LOW, "nDPIsrvd-notifyd", 3000, "Received SIGTERM, shutdown.");
 | |
|             break;
 | |
|         default:
 | |
|             notify(DBUS_LOW, "nDPIsrvd-notifyd", 3000, "Received unknown signal, shutdown.");
 | |
|             break;
 | |
|     }
 | |
| 
 | |
|     main_thread_shutdown++;
 | |
| }
 | |
| 
 | |
| int main(int argc, char ** argv)
 | |
| {
 | |
|     signal(SIGINT, sighandler);
 | |
|     signal(SIGTERM, sighandler);
 | |
|     signal(SIGPIPE, SIG_IGN);
 | |
| 
 | |
|     openlog("nDPIsrvd-notifyd", LOG_CONS, LOG_DAEMON);
 | |
| 
 | |
|     struct nDPIsrvd_socket * sock =
 | |
|         nDPIsrvd_socket_init(0, 0, 0, sizeof(struct flow_user_data), notifyd_json_callback, NULL, NULL);
 | |
|     if (sock == NULL)
 | |
|     {
 | |
|         syslog(LOG_DAEMON | LOG_ERR, "%s", "nDPIsrvd socket memory allocation failed!");
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     if (parse_options(argc, argv, sock) != 0)
 | |
|     {
 | |
|         goto failure;
 | |
|     }
 | |
| 
 | |
|     if (daemonize_with_pidfile(pidfile) != 0)
 | |
|     {
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     int previous_connect_succeeded = 1;
 | |
|     do
 | |
|     {
 | |
|         if (nDPIsrvd_connect(sock) != CONNECT_OK)
 | |
|         {
 | |
|             if (main_thread_shutdown != 0)
 | |
|             {
 | |
|                 break;
 | |
|             }
 | |
|             if (previous_connect_succeeded != 0)
 | |
|             {
 | |
|                 notifyf(DBUS_CRITICAL, "nDPIsrvd-notifyd", 3000, "nDPIsrvd socket connect to %s failed!", serv_optarg);
 | |
|                 syslog(LOG_DAEMON | LOG_ERR, "nDPIsrvd socket connect to %s failed!", serv_optarg);
 | |
|                 previous_connect_succeeded = 0;
 | |
|             }
 | |
|             nDPIsrvd_socket_close(sock);
 | |
|             sleep(SLEEP_TIME_IN_S);
 | |
|             continue;
 | |
|         }
 | |
|         previous_connect_succeeded = 1;
 | |
| 
 | |
|         if (nDPIsrvd_set_read_timeout(sock, 3, 0) != 0)
 | |
|         {
 | |
|             syslog(LOG_DAEMON | LOG_ERR, "nDPIsrvd set read timeout failed: %s", strerror(errno));
 | |
|             goto failure;
 | |
|         }
 | |
| 
 | |
|         notifyf(DBUS_NORMAL, "nDPIsrvd-notifyd", 3000, "Connected to '%s'", serv_optarg);
 | |
|         syslog(LOG_DAEMON | LOG_NOTICE, "%s", "Initialization succeeded.");
 | |
| 
 | |
|         while (main_thread_shutdown == 0)
 | |
|         {
 | |
|             enum nDPIsrvd_read_return read_ret = nDPIsrvd_read(sock);
 | |
|             if (errno == EINTR)
 | |
|             {
 | |
|                 continue;
 | |
|             }
 | |
|             if (read_ret == READ_TIMEOUT)
 | |
|             {
 | |
|                 continue;
 | |
|             }
 | |
|             if (read_ret != READ_OK)
 | |
|             {
 | |
|                 notifyf(DBUS_CRITICAL, "nDPIsrvd-notifyd", 3000, "nDPIsrvd socket read from %s failed!", serv_optarg);
 | |
|                 syslog(LOG_DAEMON | LOG_ERR, "nDPIsrvd socket read from %s failed!", serv_optarg);
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             enum nDPIsrvd_parse_return parse_ret = nDPIsrvd_parse_all(sock);
 | |
|             if (parse_ret != PARSE_NEED_MORE_DATA)
 | |
|             {
 | |
|                 syslog(LOG_DAEMON | LOG_ERR,
 | |
|                        "Could not parse JSON message %s: %.*s\n",
 | |
|                        nDPIsrvd_enum_to_string(parse_ret),
 | |
|                        nDPIsrvd_json_buffer_length(sock),
 | |
|                        nDPIsrvd_json_buffer_string(sock));
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         nDPIsrvd_socket_close(sock);
 | |
|         notifyf(DBUS_NORMAL, "nDPIsrvd-notifyd", 3000, "Disconnected from '%s'.", serv_optarg);
 | |
|         if (main_thread_shutdown == 0)
 | |
|         {
 | |
|             sleep(SLEEP_TIME_IN_S);
 | |
|         }
 | |
|     } while (main_thread_shutdown == 0);
 | |
| 
 | |
| failure:
 | |
|     nDPIsrvd_socket_free(&sock);
 | |
|     daemonize_shutdown(pidfile);
 | |
|     closelog();
 | |
| 
 | |
|     return 0;
 | |
| }
 |