network plugin: Change the license to LGPL 2.1.
[collectd.git] / src / network.c
1 /**
2  * collectd - src/network.c
3  * Copyright (C) 2005-2009  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation; only version 2.1 of the License is
8  * applicable.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  * Authors:
20  *   Florian octo Forster <octo at verplant.org>
21  **/
22
23 #define _BSD_SOURCE /* For struct ip_mreq */
24
25 #include "collectd.h"
26 #include "plugin.h"
27 #include "common.h"
28 #include "configfile.h"
29 #include "utils_fbhash.h"
30 #include "utils_avltree.h"
31
32 #include "network.h"
33
34 #if HAVE_PTHREAD_H
35 # include <pthread.h>
36 #endif
37 #if HAVE_SYS_SOCKET_H
38 # include <sys/socket.h>
39 #endif
40 #if HAVE_NETDB_H
41 # include <netdb.h>
42 #endif
43 #if HAVE_NETINET_IN_H
44 # include <netinet/in.h>
45 #endif
46 #if HAVE_ARPA_INET_H
47 # include <arpa/inet.h>
48 #endif
49 #if HAVE_POLL_H
50 # include <poll.h>
51 #endif
52
53 #if HAVE_LIBGCRYPT
54 # include <gcrypt.h>
55 GCRY_THREAD_OPTION_PTHREAD_IMPL;
56 #endif
57
58 /* 1500 - 40 - 8  =  Ethernet packet - IPv6 header - UDP header */
59 /* #define BUFF_SIZE 1452 */
60
61 #ifndef IPV6_ADD_MEMBERSHIP
62 # ifdef IPV6_JOIN_GROUP
63 #  define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
64 # else
65 #  error "Neither IP_ADD_MEMBERSHIP nor IPV6_JOIN_GROUP is defined"
66 # endif
67 #endif /* !IP_ADD_MEMBERSHIP */
68
69 /* Buffer size to allocate. */
70 #define BUFF_SIZE 1024
71
72 /*
73  * Maximum size required for encryption / signing:
74  *
75  *    42 bytes for the encryption header
76  * +  64 bytes for the username
77  * -----------
78  * = 106 bytes
79  */
80 #define BUFF_SIG_SIZE 106
81
82 /*
83  * Private data types
84  */
85 #define SECURITY_LEVEL_NONE     0
86 #if HAVE_LIBGCRYPT
87 # define SECURITY_LEVEL_SIGN    1
88 # define SECURITY_LEVEL_ENCRYPT 2
89 #endif
90 struct sockent_client
91 {
92         int fd;
93         struct sockaddr_storage *addr;
94         socklen_t                addrlen;
95 #if HAVE_LIBGCRYPT
96         int security_level;
97         char *username;
98         char *password;
99         gcry_cipher_hd_t cypher;
100         unsigned char password_hash[32];
101 #endif
102 };
103
104 struct sockent_server
105 {
106         int *fd;
107         size_t fd_num;
108 #if HAVE_LIBGCRYPT
109         int security_level;
110         char *auth_file;
111         fbhash_t *userdb;
112         gcry_cipher_hd_t cypher;
113 #endif
114 };
115
116 typedef struct sockent
117 {
118 #define SOCKENT_TYPE_CLIENT 1
119 #define SOCKENT_TYPE_SERVER 2
120         int type;
121
122         char *node;
123         char *service;
124
125         union
126         {
127                 struct sockent_client client;
128                 struct sockent_server server;
129         } data;
130
131         struct sockent *next;
132 } sockent_t;
133
134 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
135  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
136  * +-------+-----------------------+-------------------------------+
137  * ! Ver.  !                       ! Length                        !
138  * +-------+-----------------------+-------------------------------+
139  */
140 struct part_header_s
141 {
142         uint16_t type;
143         uint16_t length;
144 };
145 typedef struct part_header_s part_header_t;
146
147 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
148  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
149  * +-------------------------------+-------------------------------+
150  * ! Type                          ! Length                        !
151  * +-------------------------------+-------------------------------+
152  * : (Length - 4) Bytes                                            :
153  * +---------------------------------------------------------------+
154  */
155 struct part_string_s
156 {
157         part_header_t *head;
158         char *value;
159 };
160 typedef struct part_string_s part_string_t;
161
162 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
163  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
164  * +-------------------------------+-------------------------------+
165  * ! Type                          ! Length                        !
166  * +-------------------------------+-------------------------------+
167  * : (Length - 4 == 2 || 4 || 8) Bytes                             :
168  * +---------------------------------------------------------------+
169  */
170 struct part_number_s
171 {
172         part_header_t *head;
173         uint64_t *value;
174 };
175 typedef struct part_number_s part_number_t;
176
177 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
178  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
179  * +-------------------------------+-------------------------------+
180  * ! Type                          ! Length                        !
181  * +-------------------------------+---------------+---------------+
182  * ! Num of values                 ! Type0         ! Type1         !
183  * +-------------------------------+---------------+---------------+
184  * ! Value0                                                        !
185  * !                                                               !
186  * +---------------------------------------------------------------+
187  * ! Value1                                                        !
188  * !                                                               !
189  * +---------------------------------------------------------------+
190  */
191 struct part_values_s
192 {
193         part_header_t *head;
194         uint16_t *num_values;
195         uint8_t  *values_types;
196         value_t  *values;
197 };
198 typedef struct part_values_s part_values_t;
199
200 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
201  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
202  * +-------------------------------+-------------------------------+
203  * ! Type                          ! Length                        !
204  * +-------------------------------+-------------------------------+
205  * ! Hash (Bits   0 -  31)                                         !
206  * : :                                                             :
207  * ! Hash (Bits 224 - 255)                                         !
208  * +---------------------------------------------------------------+
209  */
210 /* Minimum size */
211 #define PART_SIGNATURE_SHA256_SIZE 36
212 struct part_signature_sha256_s
213 {
214   part_header_t head;
215   unsigned char hash[32];
216   char *username;
217 };
218 typedef struct part_signature_sha256_s part_signature_sha256_t;
219
220 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
221  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
222  * +-------------------------------+-------------------------------+
223  * ! Type                          ! Length                        !
224  * +-------------------------------+-------------------------------+
225  * ! Original length               ! Padding (0 - 15 bytes)        !
226  * +-------------------------------+-------------------------------+
227  * ! Hash (Bits   0 -  31)                                         !
228  * : :                                                             :
229  * ! Hash (Bits 128 - 159)                                         !
230  * +---------------------------------------------------------------+
231  */
232 /* Minimum size */
233 #define PART_ENCRYPTION_AES256_SIZE 42
234 struct part_encryption_aes256_s
235 {
236   part_header_t head;
237   uint16_t username_length;
238   char *username;
239   unsigned char iv[16];
240   /* <encrypted> */
241   unsigned char hash[20];
242   /*   <payload /> */
243   /* </encrypted> */
244 };
245 typedef struct part_encryption_aes256_s part_encryption_aes256_t;
246
247 struct receive_list_entry_s
248 {
249   char data[BUFF_SIZE];
250   int  data_len;
251   int  fd;
252   struct receive_list_entry_s *next;
253 };
254 typedef struct receive_list_entry_s receive_list_entry_t;
255
256 /*
257  * Private variables
258  */
259 static int network_config_ttl = 0;
260 static int network_config_forward = 0;
261
262 static sockent_t *sending_sockets = NULL;
263
264 static receive_list_entry_t *receive_list_head = NULL;
265 static receive_list_entry_t *receive_list_tail = NULL;
266 static pthread_mutex_t       receive_list_lock = PTHREAD_MUTEX_INITIALIZER;
267 static pthread_cond_t        receive_list_cond = PTHREAD_COND_INITIALIZER;
268
269 static sockent_t     *listen_sockets = NULL;
270 static struct pollfd *listen_sockets_pollfd = NULL;
271 static size_t         listen_sockets_num = 0;
272
273 /* The receive and dispatch threads will run as long as `listen_loop' is set to
274  * zero. */
275 static int       listen_loop = 0;
276 static int       receive_thread_running = 0;
277 static pthread_t receive_thread_id;
278 static int       dispatch_thread_running = 0;
279 static pthread_t dispatch_thread_id;
280
281 /* Buffer in which to-be-sent network packets are constructed. */
282 static char             send_buffer[BUFF_SIZE];
283 static char            *send_buffer_ptr;
284 static int              send_buffer_fill;
285 static value_list_t     send_buffer_vl = VALUE_LIST_STATIC;
286 static pthread_mutex_t  send_buffer_lock = PTHREAD_MUTEX_INITIALIZER;
287
288 /* In this cache we store all the values we received, so we can send out only
289  * those values which were *not* received via the network plugin, too. This is
290  * used for the `Forward false' option. */
291 static c_avl_tree_t    *cache_tree = NULL;
292 static pthread_mutex_t  cache_lock = PTHREAD_MUTEX_INITIALIZER;
293 static time_t           cache_flush_last = 0;
294 static int              cache_flush_interval = 1800;
295
296 /*
297  * Private functions
298  */
299 static int cache_flush (void)
300 {
301         char **keys = NULL;
302         int    keys_num = 0;
303
304         char **tmp;
305         int    i;
306
307         char   *key;
308         time_t *value;
309         c_avl_iterator_t *iter;
310
311         time_t curtime = time (NULL);
312
313         iter = c_avl_get_iterator (cache_tree);
314         while (c_avl_iterator_next (iter, (void *) &key, (void *) &value) == 0)
315         {
316                 if ((curtime - *value) <= cache_flush_interval)
317                         continue;
318                 tmp = (char **) realloc (keys,
319                                 (keys_num + 1) * sizeof (char *));
320                 if (tmp == NULL)
321                 {
322                         sfree (keys);
323                         c_avl_iterator_destroy (iter);
324                         ERROR ("network plugin: cache_flush: realloc"
325                                         " failed.");
326                         return (-1);
327                 }
328                 keys = tmp;
329                 keys[keys_num] = key;
330                 keys_num++;
331         } /* while (c_avl_iterator_next) */
332         c_avl_iterator_destroy (iter);
333
334         for (i = 0; i < keys_num; i++)
335         {
336                 if (c_avl_remove (cache_tree, keys[i], (void *) &key,
337                                         (void *) &value) != 0)
338                 {
339                         WARNING ("network plugin: cache_flush: c_avl_remove"
340                                         " (%s) failed.", keys[i]);
341                         continue;
342                 }
343
344                 sfree (key);
345                 sfree (value);
346         }
347
348         sfree (keys);
349
350         DEBUG ("network plugin: cache_flush: Removed %i %s",
351                         keys_num, (keys_num == 1) ? "entry" : "entries");
352         cache_flush_last = curtime;
353         return (0);
354 } /* int cache_flush */
355
356 static int cache_check (const value_list_t *vl)
357 {
358         char key[1024];
359         time_t *value = NULL;
360         int retval = -1;
361
362         if (cache_tree == NULL)
363                 return (-1);
364
365         if (format_name (key, sizeof (key), vl->host, vl->plugin,
366                                 vl->plugin_instance, vl->type, vl->type_instance))
367                 return (-1);
368
369         pthread_mutex_lock (&cache_lock);
370
371         if (c_avl_get (cache_tree, key, (void *) &value) == 0)
372         {
373                 if (*value < vl->time)
374                 {
375                         *value = vl->time;
376                         retval = 0;
377                 }
378                 else
379                 {
380                         DEBUG ("network plugin: cache_check: *value = %i >= vl->time = %i",
381                                         (int) *value, (int) vl->time);
382                         retval = 1;
383                 }
384         }
385         else
386         {
387                 char *key_copy = strdup (key);
388                 value = malloc (sizeof (time_t));
389                 if ((key_copy != NULL) && (value != NULL))
390                 {
391                         *value = vl->time;
392                         c_avl_insert (cache_tree, key_copy, value);
393                         retval = 0;
394                 }
395                 else
396                 {
397                         sfree (key_copy);
398                         sfree (value);
399                 }
400         }
401
402         if ((time (NULL) - cache_flush_last) > cache_flush_interval)
403                 cache_flush ();
404
405         pthread_mutex_unlock (&cache_lock);
406
407         return (retval);
408 } /* int cache_check */
409
410 #if HAVE_LIBGCRYPT
411 static gcry_cipher_hd_t network_get_aes256_cypher (sockent_t *se, /* {{{ */
412     const void *iv, size_t iv_size, const char *username)
413 {
414   gcry_error_t err;
415   gcry_cipher_hd_t *cyper_ptr;
416   unsigned char password_hash[32];
417
418   if (se->type == SOCKENT_TYPE_CLIENT)
419   {
420           cyper_ptr = &se->data.client.cypher;
421           memcpy (password_hash, se->data.client.password_hash,
422                           sizeof (password_hash));
423   }
424   else
425   {
426           char *secret;
427
428           cyper_ptr = &se->data.server.cypher;
429
430           if (username == NULL)
431                   return (NULL);
432
433           secret = fbh_get (se->data.server.userdb, username);
434           if (secret == NULL)
435                   return (NULL);
436
437           gcry_md_hash_buffer (GCRY_MD_SHA256,
438                           password_hash,
439                           secret, strlen (secret));
440
441           sfree (secret);
442   }
443
444   if (*cyper_ptr == NULL)
445   {
446     err = gcry_cipher_open (cyper_ptr,
447         GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, /* flags = */ 0);
448     if (err != 0)
449     {
450       ERROR ("network plugin: gcry_cipher_open returned: %s",
451           gcry_strerror (err));
452       *cyper_ptr = NULL;
453       return (NULL);
454     }
455   }
456   else
457   {
458     gcry_cipher_reset (*cyper_ptr);
459   }
460   assert (*cyper_ptr != NULL);
461
462   err = gcry_cipher_setkey (*cyper_ptr,
463       password_hash, sizeof (password_hash));
464   if (err != 0)
465   {
466     ERROR ("network plugin: gcry_cipher_setkey returned: %s",
467         gcry_strerror (err));
468     gcry_cipher_close (*cyper_ptr);
469     *cyper_ptr = NULL;
470     return (NULL);
471   }
472
473   err = gcry_cipher_setiv (*cyper_ptr, iv, iv_size);
474   if (err != 0)
475   {
476     ERROR ("network plugin: gcry_cipher_setkey returned: %s",
477         gcry_strerror (err));
478     gcry_cipher_close (*cyper_ptr);
479     *cyper_ptr = NULL;
480     return (NULL);
481   }
482
483   return (*cyper_ptr);
484 } /* }}} int network_get_aes256_cypher */
485 #endif /* HAVE_LIBGCRYPT */
486
487 static int write_part_values (char **ret_buffer, int *ret_buffer_len,
488                 const data_set_t *ds, const value_list_t *vl)
489 {
490         char *packet_ptr;
491         int packet_len;
492         int num_values;
493
494         part_header_t pkg_ph;
495         uint16_t      pkg_num_values;
496         uint8_t      *pkg_values_types;
497         value_t      *pkg_values;
498
499         int offset;
500         int i;
501
502         num_values = vl->values_len;
503         packet_len = sizeof (part_header_t) + sizeof (uint16_t)
504                 + (num_values * sizeof (uint8_t))
505                 + (num_values * sizeof (value_t));
506
507         if (*ret_buffer_len < packet_len)
508                 return (-1);
509
510         pkg_values_types = (uint8_t *) malloc (num_values * sizeof (uint8_t));
511         if (pkg_values_types == NULL)
512         {
513                 ERROR ("network plugin: write_part_values: malloc failed.");
514                 return (-1);
515         }
516
517         pkg_values = (value_t *) malloc (num_values * sizeof (value_t));
518         if (pkg_values == NULL)
519         {
520                 free (pkg_values_types);
521                 ERROR ("network plugin: write_part_values: malloc failed.");
522                 return (-1);
523         }
524
525         pkg_ph.type = htons (TYPE_VALUES);
526         pkg_ph.length = htons (packet_len);
527
528         pkg_num_values = htons ((uint16_t) vl->values_len);
529
530         for (i = 0; i < num_values; i++)
531         {
532                 if (ds->ds[i].type == DS_TYPE_COUNTER)
533                 {
534                         pkg_values_types[i] = DS_TYPE_COUNTER;
535                         pkg_values[i].counter = htonll (vl->values[i].counter);
536                 }
537                 else
538                 {
539                         pkg_values_types[i] = DS_TYPE_GAUGE;
540                         pkg_values[i].gauge = htond (vl->values[i].gauge);
541                 }
542         }
543
544         /*
545          * Use `memcpy' to write everything to the buffer, because the pointer
546          * may be unaligned and some architectures, such as SPARC, can't handle
547          * that.
548          */
549         packet_ptr = *ret_buffer;
550         offset = 0;
551         memcpy (packet_ptr + offset, &pkg_ph, sizeof (pkg_ph));
552         offset += sizeof (pkg_ph);
553         memcpy (packet_ptr + offset, &pkg_num_values, sizeof (pkg_num_values));
554         offset += sizeof (pkg_num_values);
555         memcpy (packet_ptr + offset, pkg_values_types, num_values * sizeof (uint8_t));
556         offset += num_values * sizeof (uint8_t);
557         memcpy (packet_ptr + offset, pkg_values, num_values * sizeof (value_t));
558         offset += num_values * sizeof (value_t);
559
560         assert (offset == packet_len);
561
562         *ret_buffer = packet_ptr + packet_len;
563         *ret_buffer_len -= packet_len;
564
565         free (pkg_values_types);
566         free (pkg_values);
567
568         return (0);
569 } /* int write_part_values */
570
571 static int write_part_number (char **ret_buffer, int *ret_buffer_len,
572                 int type, uint64_t value)
573 {
574         char *packet_ptr;
575         int packet_len;
576
577         part_header_t pkg_head;
578         uint64_t pkg_value;
579         
580         int offset;
581
582         packet_len = sizeof (pkg_head) + sizeof (pkg_value);
583
584         if (*ret_buffer_len < packet_len)
585                 return (-1);
586
587         pkg_head.type = htons (type);
588         pkg_head.length = htons (packet_len);
589         pkg_value = htonll (value);
590
591         packet_ptr = *ret_buffer;
592         offset = 0;
593         memcpy (packet_ptr + offset, &pkg_head, sizeof (pkg_head));
594         offset += sizeof (pkg_head);
595         memcpy (packet_ptr + offset, &pkg_value, sizeof (pkg_value));
596         offset += sizeof (pkg_value);
597
598         assert (offset == packet_len);
599
600         *ret_buffer = packet_ptr + packet_len;
601         *ret_buffer_len -= packet_len;
602
603         return (0);
604 } /* int write_part_number */
605
606 static int write_part_string (char **ret_buffer, int *ret_buffer_len,
607                 int type, const char *str, int str_len)
608 {
609         char *buffer;
610         int buffer_len;
611
612         uint16_t pkg_type;
613         uint16_t pkg_length;
614
615         int offset;
616
617         buffer_len = 2 * sizeof (uint16_t) + str_len + 1;
618         if (*ret_buffer_len < buffer_len)
619                 return (-1);
620
621         pkg_type = htons (type);
622         pkg_length = htons (buffer_len);
623
624         buffer = *ret_buffer;
625         offset = 0;
626         memcpy (buffer + offset, (void *) &pkg_type, sizeof (pkg_type));
627         offset += sizeof (pkg_type);
628         memcpy (buffer + offset, (void *) &pkg_length, sizeof (pkg_length));
629         offset += sizeof (pkg_length);
630         memcpy (buffer + offset, str, str_len);
631         offset += str_len;
632         memset (buffer + offset, '\0', 1);
633         offset += 1;
634
635         assert (offset == buffer_len);
636
637         *ret_buffer = buffer + buffer_len;
638         *ret_buffer_len -= buffer_len;
639
640         return (0);
641 } /* int write_part_string */
642
643 static int parse_part_values (void **ret_buffer, size_t *ret_buffer_len,
644                 value_t **ret_values, int *ret_num_values)
645 {
646         char *buffer = *ret_buffer;
647         size_t buffer_len = *ret_buffer_len;
648
649         uint16_t tmp16;
650         size_t exp_size;
651         int   i;
652
653         uint16_t pkg_length;
654         uint16_t pkg_type;
655         uint16_t pkg_numval;
656
657         uint8_t *pkg_types;
658         value_t *pkg_values;
659
660         if (buffer_len < 15)
661         {
662                 NOTICE ("network plugin: packet is too short: "
663                                 "buffer_len = %zu", buffer_len);
664                 return (-1);
665         }
666
667         memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
668         buffer += sizeof (tmp16);
669         pkg_type = ntohs (tmp16);
670
671         memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
672         buffer += sizeof (tmp16);
673         pkg_length = ntohs (tmp16);
674
675         memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
676         buffer += sizeof (tmp16);
677         pkg_numval = ntohs (tmp16);
678
679         assert (pkg_type == TYPE_VALUES);
680
681         exp_size = 3 * sizeof (uint16_t)
682                 + pkg_numval * (sizeof (uint8_t) + sizeof (value_t));
683         if ((buffer_len < 0) || (buffer_len < exp_size))
684         {
685                 WARNING ("network plugin: parse_part_values: "
686                                 "Packet too short: "
687                                 "Chunk of size %zu expected, "
688                                 "but buffer has only %zu bytes left.",
689                                 exp_size, buffer_len);
690                 return (-1);
691         }
692
693         if (pkg_length != exp_size)
694         {
695                 WARNING ("network plugin: parse_part_values: "
696                                 "Length and number of values "
697                                 "in the packet don't match.");
698                 return (-1);
699         }
700
701         pkg_types = (uint8_t *) malloc (pkg_numval * sizeof (uint8_t));
702         pkg_values = (value_t *) malloc (pkg_numval * sizeof (value_t));
703         if ((pkg_types == NULL) || (pkg_values == NULL))
704         {
705                 sfree (pkg_types);
706                 sfree (pkg_values);
707                 ERROR ("network plugin: parse_part_values: malloc failed.");
708                 return (-1);
709         }
710
711         memcpy ((void *) pkg_types, (void *) buffer, pkg_numval * sizeof (uint8_t));
712         buffer += pkg_numval * sizeof (uint8_t);
713         memcpy ((void *) pkg_values, (void *) buffer, pkg_numval * sizeof (value_t));
714         buffer += pkg_numval * sizeof (value_t);
715
716         for (i = 0; i < pkg_numval; i++)
717         {
718                 if (pkg_types[i] == DS_TYPE_COUNTER)
719                         pkg_values[i].counter = ntohll (pkg_values[i].counter);
720                 else if (pkg_types[i] == DS_TYPE_GAUGE)
721                         pkg_values[i].gauge = ntohd (pkg_values[i].gauge);
722         }
723
724         *ret_buffer     = buffer;
725         *ret_buffer_len = buffer_len - pkg_length;
726         *ret_num_values = pkg_numval;
727         *ret_values     = pkg_values;
728
729         sfree (pkg_types);
730
731         return (0);
732 } /* int parse_part_values */
733
734 static int parse_part_number (void **ret_buffer, size_t *ret_buffer_len,
735                 uint64_t *value)
736 {
737         char *buffer = *ret_buffer;
738         size_t buffer_len = *ret_buffer_len;
739
740         uint16_t tmp16;
741         uint64_t tmp64;
742         size_t exp_size = 2 * sizeof (uint16_t) + sizeof (uint64_t);
743
744         uint16_t pkg_length;
745         uint16_t pkg_type;
746
747         if ((buffer_len < 0) || ((size_t) buffer_len < exp_size))
748         {
749                 WARNING ("network plugin: parse_part_number: "
750                                 "Packet too short: "
751                                 "Chunk of size %zu expected, "
752                                 "but buffer has only %zu bytes left.",
753                                 exp_size, buffer_len);
754                 return (-1);
755         }
756
757         memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
758         buffer += sizeof (tmp16);
759         pkg_type = ntohs (tmp16);
760
761         memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
762         buffer += sizeof (tmp16);
763         pkg_length = ntohs (tmp16);
764
765         memcpy ((void *) &tmp64, buffer, sizeof (tmp64));
766         buffer += sizeof (tmp64);
767         *value = ntohll (tmp64);
768
769         *ret_buffer = buffer;
770         *ret_buffer_len = buffer_len - pkg_length;
771
772         return (0);
773 } /* int parse_part_number */
774
775 static int parse_part_string (void **ret_buffer, size_t *ret_buffer_len,
776                 char *output, int output_len)
777 {
778         char *buffer = *ret_buffer;
779         size_t buffer_len = *ret_buffer_len;
780
781         uint16_t tmp16;
782         size_t header_size = 2 * sizeof (uint16_t);
783
784         uint16_t pkg_length;
785         uint16_t pkg_type;
786
787         if ((buffer_len < 0) || (buffer_len < header_size))
788         {
789                 WARNING ("network plugin: parse_part_string: "
790                                 "Packet too short: "
791                                 "Chunk of at least size %zu expected, "
792                                 "but buffer has only %zu bytes left.",
793                                 header_size, buffer_len);
794                 return (-1);
795         }
796
797         memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
798         buffer += sizeof (tmp16);
799         pkg_type = ntohs (tmp16);
800
801         memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
802         buffer += sizeof (tmp16);
803         pkg_length = ntohs (tmp16);
804
805         /* Check that packet fits in the input buffer */
806         if (pkg_length > buffer_len)
807         {
808                 WARNING ("network plugin: parse_part_string: "
809                                 "Packet too big: "
810                                 "Chunk of size %"PRIu16" received, "
811                                 "but buffer has only %zu bytes left.",
812                                 pkg_length, buffer_len);
813                 return (-1);
814         }
815
816         /* Check that pkg_length is in the valid range */
817         if (pkg_length <= header_size)
818         {
819                 WARNING ("network plugin: parse_part_string: "
820                                 "Packet too short: "
821                                 "Header claims this packet is only %hu "
822                                 "bytes long.", pkg_length);
823                 return (-1);
824         }
825
826         /* Check that the package data fits into the output buffer.
827          * The previous if-statement ensures that:
828          * `pkg_length > header_size' */
829         if ((output_len < 0)
830                         || ((size_t) output_len < ((size_t) pkg_length - header_size)))
831         {
832                 WARNING ("network plugin: parse_part_string: "
833                                 "Output buffer too small.");
834                 return (-1);
835         }
836
837         /* All sanity checks successfull, let's copy the data over */
838         output_len = pkg_length - header_size;
839         memcpy ((void *) output, (void *) buffer, output_len);
840         buffer += output_len;
841
842         /* For some very weird reason '\0' doesn't do the trick on SPARC in
843          * this statement. */
844         if (output[output_len - 1] != 0)
845         {
846                 WARNING ("network plugin: parse_part_string: "
847                                 "Received string does not end "
848                                 "with a NULL-byte.");
849                 return (-1);
850         }
851
852         *ret_buffer = buffer;
853         *ret_buffer_len = buffer_len - pkg_length;
854
855         return (0);
856 } /* int parse_part_string */
857
858 /* Forward declaration: parse_part_sign_sha256 and parse_part_encr_aes256 call
859  * parse_packet and vice versa. */
860 #define PP_SIGNED    0x01
861 #define PP_ENCRYPTED 0x02
862 static int parse_packet (sockent_t *se,
863                 void *buffer, size_t buffer_size, int flags);
864
865 #define BUFFER_READ(p,s) do { \
866   memcpy ((p), buffer + buffer_offset, (s)); \
867   buffer_offset += (s); \
868 } while (0)
869
870 #if HAVE_LIBGCRYPT
871 static int parse_part_sign_sha256 (sockent_t *se, /* {{{ */
872     void **ret_buffer, size_t *ret_buffer_len, int flags)
873 {
874   char *buffer;
875   size_t buffer_len;
876   size_t buffer_offset;
877
878   size_t username_len;
879   char *secret;
880
881   part_signature_sha256_t pss;
882   uint16_t pss_head_length;
883   char hash[sizeof (pss.hash)];
884
885   gcry_md_hd_t hd;
886   gcry_error_t err;
887   unsigned char *hash_ptr;
888
889   buffer = *ret_buffer;
890   buffer_len = *ret_buffer_len;
891   buffer_offset = 0;
892
893   if (se->data.server.userdb == NULL)
894   {
895     NOTICE ("network plugin: Received signed network packet but can't verify "
896         "it because no user DB has been configured. Will accept it.");
897     return (0);
898   }
899
900   /* Check if the buffer has enough data for this structure. */
901   if (buffer_len <= PART_SIGNATURE_SHA256_SIZE)
902     return (-ENOMEM);
903
904   /* Read type and length header */
905   BUFFER_READ (&pss.head.type, sizeof (pss.head.type));
906   BUFFER_READ (&pss.head.length, sizeof (pss.head.length));
907   pss_head_length = ntohs (pss.head.length);
908
909   /* Check if the `pss_head_length' is within bounds. */
910   if ((pss_head_length <= PART_SIGNATURE_SHA256_SIZE)
911       || (pss_head_length > buffer_len))
912   {
913     ERROR ("network plugin: HMAC-SHA-256 with invalid length received.");
914     return (-1);
915   }
916
917   /* Copy the hash. */
918   BUFFER_READ (pss.hash, sizeof (pss.hash));
919
920   /* Calculate username length (without null byte) and allocate memory */
921   username_len = pss_head_length - PART_SIGNATURE_SHA256_SIZE;
922   pss.username = malloc (username_len + 1);
923   if (pss.username == NULL)
924     return (-ENOMEM);
925
926   /* Read the username */
927   BUFFER_READ (pss.username, username_len);
928   pss.username[username_len] = 0;
929
930   assert (buffer_offset == pss_head_length);
931
932   /* Query the password */
933   secret = fbh_get (se->data.server.userdb, pss.username);
934   if (secret == NULL)
935   {
936     ERROR ("network plugin: Unknown user: %s", pss.username);
937     sfree (pss.username);
938     return (-ENOENT);
939   }
940
941   /* Create a hash device and check the HMAC */
942   hd = NULL;
943   err = gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
944   if (err != 0)
945   {
946     ERROR ("network plugin: Creating HMAC-SHA-256 object failed: %s",
947         gcry_strerror (err));
948     sfree (secret);
949     sfree (pss.username);
950     return (-1);
951   }
952
953   err = gcry_md_setkey (hd, secret, strlen (secret));
954   if (err != 0)
955   {
956     ERROR ("network plugin: gcry_md_setkey failed: %s", gcry_strerror (err));
957     gcry_md_close (hd);
958     return (-1);
959   }
960
961   gcry_md_write (hd,
962       buffer     + PART_SIGNATURE_SHA256_SIZE,
963       buffer_len - PART_SIGNATURE_SHA256_SIZE);
964   hash_ptr = gcry_md_read (hd, GCRY_MD_SHA256);
965   if (hash_ptr == NULL)
966   {
967     ERROR ("network plugin: gcry_md_read failed.");
968     gcry_md_close (hd);
969     sfree (secret);
970     sfree (pss.username);
971     return (-1);
972   }
973   memcpy (hash, hash_ptr, sizeof (hash));
974
975   /* Clean up */
976   gcry_md_close (hd);
977   hd = NULL;
978
979   sfree (secret);
980   sfree (pss.username);
981
982   if (memcmp (pss.hash, hash, sizeof (pss.hash)) != 0)
983   {
984     WARNING ("network plugin: Verifying HMAC-SHA-256 signature failed: "
985         "Hash mismatch.");
986   }
987   else
988   {
989     parse_packet (se, buffer + buffer_offset, buffer_len - buffer_offset,
990         flags | PP_SIGNED);
991   }
992
993   *ret_buffer = buffer + buffer_len;
994   *ret_buffer_len = 0;
995
996   return (0);
997 } /* }}} int parse_part_sign_sha256 */
998 /* #endif HAVE_LIBGCRYPT */
999
1000 #else /* if !HAVE_LIBGCRYPT */
1001 static int parse_part_sign_sha256 (sockent_t *se, /* {{{ */
1002     void **ret_buffer, size_t *ret_buffer_size, int flags)
1003 {
1004   static int warning_has_been_printed = 0;
1005
1006   char *buffer;
1007   size_t buffer_size;
1008   size_t buffer_offset;
1009   uint16_t part_len;
1010
1011   part_signature_sha256_t pss;
1012
1013   buffer = *ret_buffer;
1014   buffer_size = *ret_buffer_size;
1015   buffer_offset = 0;
1016
1017   if (buffer_size <= PART_SIGNATURE_SHA256_SIZE)
1018     return (-ENOMEM);
1019
1020   BUFFER_READ (&pss.head.type, sizeof (pss.head.type));
1021   BUFFER_READ (&pss.head.length, sizeof (pss.head.length));
1022   part_len = ntohs (pss.head.length);
1023
1024   if ((part_len <= PART_SIGNATURE_SHA256_SIZE)
1025       || (part_len > buffer_size))
1026     return (-EINVAL);
1027
1028   if (warning_has_been_printed == 0)
1029   {
1030     WARNING ("network plugin: Received signed packet, but the network "
1031         "plugin was not linked with libgcrypt, so I cannot "
1032         "verify the signature. The packet will be accepted.");
1033     warning_has_been_printed = 1;
1034   }
1035
1036   parse_packet (se, buffer + part_len, buffer_size - part_len, flags);
1037
1038   *ret_buffer = buffer + buffer_size;
1039   *ret_buffer_size = 0;
1040
1041   return (0);
1042 } /* }}} int parse_part_sign_sha256 */
1043 #endif /* !HAVE_LIBGCRYPT */
1044
1045 #if HAVE_LIBGCRYPT
1046 static int parse_part_encr_aes256 (sockent_t *se, /* {{{ */
1047                 void **ret_buffer, size_t *ret_buffer_len,
1048                 int flags)
1049 {
1050   char  *buffer = *ret_buffer;
1051   size_t buffer_len = *ret_buffer_len;
1052   size_t payload_len;
1053   size_t part_size;
1054   size_t buffer_offset;
1055   uint16_t username_len;
1056   part_encryption_aes256_t pea;
1057   unsigned char hash[sizeof (pea.hash)];
1058
1059   gcry_cipher_hd_t cypher;
1060   gcry_error_t err;
1061
1062   /* Make sure at least the header if available. */
1063   if (buffer_len <= PART_ENCRYPTION_AES256_SIZE)
1064   {
1065     NOTICE ("network plugin: parse_part_encr_aes256: "
1066         "Discarding short packet.");
1067     return (-1);
1068   }
1069
1070   buffer_offset = 0;
1071
1072   /* Copy the unencrypted information into `pea'. */
1073   BUFFER_READ (&pea.head.type, sizeof (pea.head.type));
1074   BUFFER_READ (&pea.head.length, sizeof (pea.head.length));
1075
1076   /* Check the `part size'. */
1077   part_size = ntohs (pea.head.length);
1078   if ((part_size <= PART_ENCRYPTION_AES256_SIZE)
1079       || (part_size > buffer_len))
1080   {
1081     NOTICE ("network plugin: parse_part_encr_aes256: "
1082         "Discarding part with invalid size.");
1083     return (-1);
1084   }
1085
1086   /* Read the username */
1087   BUFFER_READ (&username_len, sizeof (username_len));
1088   username_len = ntohs (username_len);
1089
1090   if ((username_len <= 0)
1091       || (username_len > (part_size - (PART_ENCRYPTION_AES256_SIZE + 1))))
1092   {
1093     NOTICE ("network plugin: parse_part_encr_aes256: "
1094         "Discarding part with invalid username length.");
1095     return (-1);
1096   }
1097
1098   assert (username_len > 0);
1099   pea.username = malloc (username_len + 1);
1100   if (pea.username == NULL)
1101     return (-ENOMEM);
1102   BUFFER_READ (pea.username, username_len);
1103   pea.username[username_len] = 0;
1104
1105   /* Last but not least, the initialization vector */
1106   BUFFER_READ (pea.iv, sizeof (pea.iv));
1107
1108   /* Make sure we are at the right position */
1109   assert (buffer_offset == (username_len +
1110         PART_ENCRYPTION_AES256_SIZE - sizeof (pea.hash)));
1111
1112   cypher = network_get_aes256_cypher (se, pea.iv, sizeof (pea.iv),
1113       pea.username);
1114   if (cypher == NULL)
1115     return (-1);
1116
1117   payload_len = part_size - (PART_ENCRYPTION_AES256_SIZE + username_len);
1118   assert (payload_len > 0);
1119
1120   /* Decrypt the packet in-place */
1121   err = gcry_cipher_decrypt (cypher,
1122       buffer    + buffer_offset,
1123       part_size - buffer_offset,
1124       /* in = */ NULL, /* in len = */ 0);
1125   if (err != 0)
1126   {
1127     ERROR ("network plugin: gcry_cipher_decrypt returned: %s",
1128         gcry_strerror (err));
1129     return (-1);
1130   }
1131
1132   /* Read the hash */
1133   BUFFER_READ (pea.hash, sizeof (pea.hash));
1134
1135   /* Make sure we're at the right position - again */
1136   assert (buffer_offset == (username_len + PART_ENCRYPTION_AES256_SIZE));
1137   assert (buffer_offset == (part_size - payload_len));
1138
1139   /* Check hash sum */
1140   memset (hash, 0, sizeof (hash));
1141   gcry_md_hash_buffer (GCRY_MD_SHA1, hash,
1142       buffer + buffer_offset, payload_len);
1143   if (memcmp (hash, pea.hash, sizeof (hash)) != 0)
1144   {
1145     ERROR ("network plugin: Decryption failed: Checksum mismatch.");
1146     return (-1);
1147   }
1148
1149   parse_packet (se, buffer + buffer_offset, payload_len,
1150       flags | PP_ENCRYPTED);
1151
1152   /* Update return values */
1153   *ret_buffer =     buffer     + part_size;
1154   *ret_buffer_len = buffer_len - part_size;
1155
1156   return (0);
1157 } /* }}} int parse_part_encr_aes256 */
1158 /* #endif HAVE_LIBGCRYPT */
1159
1160 #else /* if !HAVE_LIBGCRYPT */
1161 static int parse_part_encr_aes256 (sockent_t *se, /* {{{ */
1162     void **ret_buffer, size_t *ret_buffer_size, int flags)
1163 {
1164   static int warning_has_been_printed = 0;
1165
1166   char *buffer;
1167   size_t buffer_size;
1168   size_t buffer_offset;
1169
1170   part_header_t ph;
1171   size_t ph_length;
1172
1173   buffer = *ret_buffer;
1174   buffer_size = *ret_buffer_size;
1175   buffer_offset = 0;
1176
1177   /* parse_packet assures this minimum size. */
1178   assert (buffer_size >= (sizeof (ph.type) + sizeof (ph.length)));
1179
1180   BUFFER_READ (&ph.type, sizeof (ph.type));
1181   BUFFER_READ (&ph.length, sizeof (ph.length));
1182   ph_length = ntohs (ph.length);
1183
1184   if ((ph_length <= PART_ENCRYPTION_AES256_SIZE)
1185       || (ph_length > buffer_size))
1186   {
1187     ERROR ("network plugin: AES-256 encrypted part "
1188         "with invalid length received.");
1189     return (-1);
1190   }
1191
1192   if (warning_has_been_printed == 0)
1193   {
1194     WARNING ("network plugin: Received encrypted packet, but the network "
1195         "plugin was not linked with libgcrypt, so I cannot "
1196         "decrypt it. The part will be discarded.");
1197     warning_has_been_printed = 1;
1198   }
1199
1200   *ret_buffer += ph_length;
1201   *ret_buffer_size -= ph_length;
1202
1203   return (0);
1204 } /* }}} int parse_part_encr_aes256 */
1205 #endif /* !HAVE_LIBGCRYPT */
1206
1207 #undef BUFFER_READ
1208
1209 static int parse_packet (sockent_t *se, /* {{{ */
1210                 void *buffer, size_t buffer_size, int flags)
1211 {
1212         int status;
1213
1214         value_list_t vl = VALUE_LIST_INIT;
1215         notification_t n;
1216
1217 #if HAVE_LIBGCRYPT
1218         int packet_was_signed = (flags & PP_SIGNED);
1219         int packet_was_encrypted = (flags & PP_ENCRYPTED);
1220         int printed_ignore_warning = 0;
1221 #endif /* HAVE_LIBGCRYPT */
1222
1223
1224         memset (&vl, '\0', sizeof (vl));
1225         memset (&n, '\0', sizeof (n));
1226         status = 0;
1227
1228         while ((status == 0) && (0 < buffer_size)
1229                         && ((unsigned int) buffer_size > sizeof (part_header_t)))
1230         {
1231                 uint16_t pkg_length;
1232                 uint16_t pkg_type;
1233
1234                 memcpy ((void *) &pkg_type,
1235                                 (void *) buffer,
1236                                 sizeof (pkg_type));
1237                 memcpy ((void *) &pkg_length,
1238                                 (void *) (buffer + sizeof (pkg_type)),
1239                                 sizeof (pkg_length));
1240
1241                 pkg_length = ntohs (pkg_length);
1242                 pkg_type = ntohs (pkg_type);
1243
1244                 if (pkg_length > buffer_size)
1245                         break;
1246                 /* Ensure that this loop terminates eventually */
1247                 if (pkg_length < (2 * sizeof (uint16_t)))
1248                         break;
1249
1250                 if (pkg_type == TYPE_ENCR_AES256)
1251                 {
1252                         status = parse_part_encr_aes256 (se,
1253                                         &buffer, &buffer_size, flags);
1254                         if (status != 0)
1255                         {
1256                                 ERROR ("network plugin: Decrypting AES256 "
1257                                                 "part failed "
1258                                                 "with status %i.", status);
1259                                 break;
1260                         }
1261                 }
1262 #if HAVE_LIBGCRYPT
1263                 else if ((se->data.server.security_level == SECURITY_LEVEL_ENCRYPT)
1264                                 && (packet_was_encrypted == 0))
1265                 {
1266                         if (printed_ignore_warning == 0)
1267                         {
1268                                 INFO ("network plugin: Unencrypted packet or "
1269                                                 "part has been ignored.");
1270                                 printed_ignore_warning = 1;
1271                         }
1272                         buffer = ((char *) buffer) + pkg_length;
1273                         continue;
1274                 }
1275 #endif /* HAVE_LIBGCRYPT */
1276                 else if (pkg_type == TYPE_SIGN_SHA256)
1277                 {
1278                         status = parse_part_sign_sha256 (se,
1279                                         &buffer, &buffer_size, flags);
1280                         if (status != 0)
1281                         {
1282                                 ERROR ("network plugin: Verifying HMAC-SHA-256 "
1283                                                 "signature failed "
1284                                                 "with status %i.", status);
1285                                 break;
1286                         }
1287                 }
1288 #if HAVE_LIBGCRYPT
1289                 else if ((se->data.server.security_level == SECURITY_LEVEL_SIGN)
1290                                 && (packet_was_encrypted == 0)
1291                                 && (packet_was_signed == 0))
1292                 {
1293                         if (printed_ignore_warning == 0)
1294                         {
1295                                 INFO ("network plugin: Unsigned packet or "
1296                                                 "part has been ignored.");
1297                                 printed_ignore_warning = 1;
1298                         }
1299                         buffer = ((char *) buffer) + pkg_length;
1300                         continue;
1301                 }
1302 #endif /* HAVE_LIBGCRYPT */
1303                 else if (pkg_type == TYPE_VALUES)
1304                 {
1305                         status = parse_part_values (&buffer, &buffer_size,
1306                                         &vl.values, &vl.values_len);
1307
1308                         if (status != 0)
1309                                 break;
1310
1311                         if ((vl.time > 0)
1312                                         && (strlen (vl.host) > 0)
1313                                         && (strlen (vl.plugin) > 0)
1314                                         && (strlen (vl.type) > 0)
1315                                         && (cache_check (&vl) == 0))
1316                         {
1317                                 plugin_dispatch_values (&vl);
1318                         }
1319                         else
1320                         {
1321                                 DEBUG ("network plugin: parse_packet:"
1322                                                 " NOT dispatching values");
1323                         }
1324
1325                         sfree (vl.values);
1326                 }
1327                 else if (pkg_type == TYPE_TIME)
1328                 {
1329                         uint64_t tmp = 0;
1330                         status = parse_part_number (&buffer, &buffer_size,
1331                                         &tmp);
1332                         if (status == 0)
1333                         {
1334                                 vl.time = (time_t) tmp;
1335                                 n.time = (time_t) tmp;
1336                         }
1337                 }
1338                 else if (pkg_type == TYPE_INTERVAL)
1339                 {
1340                         uint64_t tmp = 0;
1341                         status = parse_part_number (&buffer, &buffer_size,
1342                                         &tmp);
1343                         if (status == 0)
1344                                 vl.interval = (int) tmp;
1345                 }
1346                 else if (pkg_type == TYPE_HOST)
1347                 {
1348                         status = parse_part_string (&buffer, &buffer_size,
1349                                         vl.host, sizeof (vl.host));
1350                         if (status == 0)
1351                                 sstrncpy (n.host, vl.host, sizeof (n.host));
1352                 }
1353                 else if (pkg_type == TYPE_PLUGIN)
1354                 {
1355                         status = parse_part_string (&buffer, &buffer_size,
1356                                         vl.plugin, sizeof (vl.plugin));
1357                         if (status == 0)
1358                                 sstrncpy (n.plugin, vl.plugin,
1359                                                 sizeof (n.plugin));
1360                 }
1361                 else if (pkg_type == TYPE_PLUGIN_INSTANCE)
1362                 {
1363                         status = parse_part_string (&buffer, &buffer_size,
1364                                         vl.plugin_instance,
1365                                         sizeof (vl.plugin_instance));
1366                         if (status == 0)
1367                                 sstrncpy (n.plugin_instance,
1368                                                 vl.plugin_instance,
1369                                                 sizeof (n.plugin_instance));
1370                 }
1371                 else if (pkg_type == TYPE_TYPE)
1372                 {
1373                         status = parse_part_string (&buffer, &buffer_size,
1374                                         vl.type, sizeof (vl.type));
1375                         if (status == 0)
1376                                 sstrncpy (n.type, vl.type, sizeof (n.type));
1377                 }
1378                 else if (pkg_type == TYPE_TYPE_INSTANCE)
1379                 {
1380                         status = parse_part_string (&buffer, &buffer_size,
1381                                         vl.type_instance,
1382                                         sizeof (vl.type_instance));
1383                         if (status == 0)
1384                                 sstrncpy (n.type_instance, vl.type_instance,
1385                                                 sizeof (n.type_instance));
1386                 }
1387                 else if (pkg_type == TYPE_MESSAGE)
1388                 {
1389                         status = parse_part_string (&buffer, &buffer_size,
1390                                         n.message, sizeof (n.message));
1391
1392                         if (status != 0)
1393                         {
1394                                 /* do nothing */
1395                         }
1396                         else if ((n.severity != NOTIF_FAILURE)
1397                                         && (n.severity != NOTIF_WARNING)
1398                                         && (n.severity != NOTIF_OKAY))
1399                         {
1400                                 INFO ("network plugin: "
1401                                                 "Ignoring notification with "
1402                                                 "unknown severity %i.",
1403                                                 n.severity);
1404                         }
1405                         else if (n.time <= 0)
1406                         {
1407                                 INFO ("network plugin: "
1408                                                 "Ignoring notification with "
1409                                                 "time == 0.");
1410                         }
1411                         else if (strlen (n.message) <= 0)
1412                         {
1413                                 INFO ("network plugin: "
1414                                                 "Ignoring notification with "
1415                                                 "an empty message.");
1416                         }
1417                         else
1418                         {
1419                                 plugin_dispatch_notification (&n);
1420                         }
1421                 }
1422                 else if (pkg_type == TYPE_SEVERITY)
1423                 {
1424                         uint64_t tmp = 0;
1425                         status = parse_part_number (&buffer, &buffer_size,
1426                                         &tmp);
1427                         if (status == 0)
1428                                 n.severity = (int) tmp;
1429                 }
1430                 else
1431                 {
1432                         DEBUG ("network plugin: parse_packet: Unknown part"
1433                                         " type: 0x%04hx", pkg_type);
1434                         buffer = ((char *) buffer) + pkg_length;
1435                 }
1436         } /* while (buffer_size > sizeof (part_header_t)) */
1437
1438         return (status);
1439 } /* }}} int parse_packet */
1440
1441 static void free_sockent_client (struct sockent_client *sec) /* {{{ */
1442 {
1443   if (sec->fd >= 0)
1444   {
1445     close (sec->fd);
1446     sec->fd = -1;
1447   }
1448   sfree (sec->addr);
1449 #if HAVE_LIBGCRYPT
1450   sfree (sec->username);
1451   sfree (sec->password);
1452   if (sec->cypher != NULL)
1453     gcry_cipher_close (sec->cypher);
1454 #endif
1455 } /* }}} void free_sockent_client */
1456
1457 static void free_sockent_server (struct sockent_server *ses) /* {{{ */
1458 {
1459   size_t i;
1460
1461   for (i = 0; i < ses->fd_num; i++)
1462   {
1463     if (ses->fd[i] >= 0)
1464     {
1465       close (ses->fd[i]);
1466       ses->fd[i] = -1;
1467     }
1468   }
1469
1470   sfree (ses->fd);
1471 #if HAVE_LIBGCRYPT
1472   sfree (ses->auth_file);
1473   fbh_destroy (ses->userdb);
1474   if (ses->cypher != NULL)
1475     gcry_cipher_close (ses->cypher);
1476 #endif
1477 } /* }}} void free_sockent_server */
1478
1479 static void sockent_destroy (sockent_t *se) /* {{{ */
1480 {
1481   sockent_t *next;
1482
1483   DEBUG ("network plugin: sockent_destroy (se = %p);", (void *) se);
1484
1485   while (se != NULL)
1486   {
1487     next = se->next;
1488
1489     sfree (se->node);
1490     sfree (se->service);
1491
1492     if (se->type == SOCKENT_TYPE_CLIENT)
1493       free_sockent_client (&se->data.client);
1494     else
1495       free_sockent_server (&se->data.server);
1496
1497     sfree (se);
1498     se = next;
1499   }
1500 } /* }}} void sockent_destroy */
1501
1502 /*
1503  * int network_set_ttl
1504  *
1505  * Set the `IP_MULTICAST_TTL', `IP_TTL', `IPV6_MULTICAST_HOPS' or
1506  * `IPV6_UNICAST_HOPS', depending on which option is applicable.
1507  *
1508  * The `struct addrinfo' is used to destinguish between unicast and multicast
1509  * sockets.
1510  */
1511 static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai)
1512 {
1513         DEBUG ("network plugin: network_set_ttl: network_config_ttl = %i;",
1514                         network_config_ttl);
1515
1516         assert (se->type == SOCKENT_TYPE_CLIENT);
1517
1518         if ((network_config_ttl < 1) || (network_config_ttl > 255))
1519                 return (-1);
1520
1521         if (ai->ai_family == AF_INET)
1522         {
1523                 struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr;
1524                 int optname;
1525
1526                 if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr)))
1527                         optname = IP_MULTICAST_TTL;
1528                 else
1529                         optname = IP_TTL;
1530
1531                 if (setsockopt (se->data.client.fd, IPPROTO_IP, optname,
1532                                         &network_config_ttl,
1533                                         sizeof (network_config_ttl)) == -1)
1534                 {
1535                         char errbuf[1024];
1536                         ERROR ("setsockopt: %s",
1537                                         sstrerror (errno, errbuf, sizeof (errbuf)));
1538                         return (-1);
1539                 }
1540         }
1541         else if (ai->ai_family == AF_INET6)
1542         {
1543                 /* Useful example: http://gsyc.escet.urjc.es/~eva/IPv6-web/examples/mcast.html */
1544                 struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai->ai_addr;
1545                 int optname;
1546
1547                 if (IN6_IS_ADDR_MULTICAST (&addr->sin6_addr))
1548                         optname = IPV6_MULTICAST_HOPS;
1549                 else
1550                         optname = IPV6_UNICAST_HOPS;
1551
1552                 if (setsockopt (se->data.client.fd, IPPROTO_IPV6, optname,
1553                                         &network_config_ttl,
1554                                         sizeof (network_config_ttl)) == -1)
1555                 {
1556                         char errbuf[1024];
1557                         ERROR ("setsockopt: %s",
1558                                         sstrerror (errno, errbuf,
1559                                                 sizeof (errbuf)));
1560                         return (-1);
1561                 }
1562         }
1563
1564         return (0);
1565 } /* int network_set_ttl */
1566
1567 static int network_bind_socket (int fd, const struct addrinfo *ai)
1568 {
1569         int loop = 0;
1570         int yes  = 1;
1571
1572         /* allow multiple sockets to use the same PORT number */
1573         if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR,
1574                                 &yes, sizeof(yes)) == -1) {
1575                 char errbuf[1024];
1576                 ERROR ("setsockopt: %s", 
1577                                 sstrerror (errno, errbuf, sizeof (errbuf)));
1578                 return (-1);
1579         }
1580
1581         DEBUG ("fd = %i; calling `bind'", fd);
1582
1583         if (bind (fd, ai->ai_addr, ai->ai_addrlen) == -1)
1584         {
1585                 char errbuf[1024];
1586                 ERROR ("bind: %s",
1587                                 sstrerror (errno, errbuf, sizeof (errbuf)));
1588                 return (-1);
1589         }
1590
1591         if (ai->ai_family == AF_INET)
1592         {
1593                 struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr;
1594                 if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr)))
1595                 {
1596                         struct ip_mreq mreq;
1597
1598                         DEBUG ("fd = %i; IPv4 multicast address found", fd);
1599
1600                         mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
1601                         mreq.imr_interface.s_addr = htonl (INADDR_ANY);
1602
1603                         if (setsockopt (fd, IPPROTO_IP, IP_MULTICAST_LOOP,
1604                                                 &loop, sizeof (loop)) == -1)
1605                         {
1606                                 char errbuf[1024];
1607                                 ERROR ("setsockopt: %s",
1608                                                 sstrerror (errno, errbuf,
1609                                                         sizeof (errbuf)));
1610                                 return (-1);
1611                         }
1612
1613                         if (setsockopt (fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
1614                                                 &mreq, sizeof (mreq)) == -1)
1615                         {
1616                                 char errbuf[1024];
1617                                 ERROR ("setsockopt: %s",
1618                                                 sstrerror (errno, errbuf,
1619                                                         sizeof (errbuf)));
1620                                 return (-1);
1621                         }
1622                 }
1623         }
1624         else if (ai->ai_family == AF_INET6)
1625         {
1626                 /* Useful example: http://gsyc.escet.urjc.es/~eva/IPv6-web/examples/mcast.html */
1627                 struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai->ai_addr;
1628                 if (IN6_IS_ADDR_MULTICAST (&addr->sin6_addr))
1629                 {
1630                         struct ipv6_mreq mreq;
1631
1632                         DEBUG ("fd = %i; IPv6 multicast address found", fd);
1633
1634                         memcpy (&mreq.ipv6mr_multiaddr,
1635                                         &addr->sin6_addr,
1636                                         sizeof (addr->sin6_addr));
1637
1638                         /* http://developer.apple.com/documentation/Darwin/Reference/ManPages/man4/ip6.4.html
1639                          * ipv6mr_interface may be set to zeroes to
1640                          * choose the default multicast interface or to
1641                          * the index of a particular multicast-capable
1642                          * interface if the host is multihomed.
1643                          * Membership is associ-associated with a
1644                          * single interface; programs running on
1645                          * multihomed hosts may need to join the same
1646                          * group on more than one interface.*/
1647                         mreq.ipv6mr_interface = 0;
1648
1649                         if (setsockopt (fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
1650                                                 &loop, sizeof (loop)) == -1)
1651                         {
1652                                 char errbuf[1024];
1653                                 ERROR ("setsockopt: %s",
1654                                                 sstrerror (errno, errbuf,
1655                                                         sizeof (errbuf)));
1656                                 return (-1);
1657                         }
1658
1659                         if (setsockopt (fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
1660                                                 &mreq, sizeof (mreq)) == -1)
1661                         {
1662                                 char errbuf[1024];
1663                                 ERROR ("setsockopt: %s",
1664                                                 sstrerror (errno, errbuf,
1665                                                         sizeof (errbuf)));
1666                                 return (-1);
1667                         }
1668                 }
1669         }
1670
1671         return (0);
1672 } /* int network_bind_socket */
1673
1674 /* Initialize a sockent structure. `type' must be either `SOCKENT_TYPE_CLIENT'
1675  * or `SOCKENT_TYPE_SERVER' */
1676 static int sockent_init (sockent_t *se, int type) /* {{{ */
1677 {
1678         if (se == NULL)
1679                 return (-1);
1680
1681         memset (se, 0, sizeof (*se));
1682
1683         se->type = SOCKENT_TYPE_CLIENT;
1684         se->node = NULL;
1685         se->service = NULL;
1686         se->next = NULL;
1687
1688         if (type == SOCKENT_TYPE_SERVER)
1689         {
1690                 se->type = SOCKENT_TYPE_SERVER;
1691                 se->data.server.fd = NULL;
1692 #if HAVE_LIBGCRYPT
1693                 se->data.server.security_level = SECURITY_LEVEL_NONE;
1694                 se->data.server.auth_file = NULL;
1695                 se->data.server.userdb = NULL;
1696                 se->data.server.cypher = NULL;
1697 #endif
1698         }
1699         else
1700         {
1701                 se->data.client.fd = -1;
1702                 se->data.client.addr = NULL;
1703 #if HAVE_LIBGCRYPT
1704                 se->data.client.security_level = SECURITY_LEVEL_NONE;
1705                 se->data.client.username = NULL;
1706                 se->data.client.password = NULL;
1707                 se->data.client.cypher = NULL;
1708 #endif
1709         }
1710
1711         return (0);
1712 } /* }}} int sockent_init */
1713
1714 /* Open the file descriptors for a initialized sockent structure. */
1715 static int sockent_open (sockent_t *se) /* {{{ */
1716 {
1717         struct addrinfo  ai_hints;
1718         struct addrinfo *ai_list, *ai_ptr;
1719         int              ai_return;
1720
1721         const char *node;
1722         const char *service;
1723
1724         if (se == NULL)
1725                 return (-1);
1726
1727         /* Set up the security structures. */
1728 #if HAVE_LIBGCRYPT /* {{{ */
1729         if (se->type == SOCKENT_TYPE_CLIENT)
1730         {
1731                 if (se->data.client.security_level > SECURITY_LEVEL_NONE)
1732                 {
1733                         if ((se->data.client.username == NULL)
1734                                         || (se->data.client.password == NULL))
1735                         {
1736                                 ERROR ("network plugin: Client socket with "
1737                                                 "security requested, but no "
1738                                                 "credentials are configured.");
1739                                 return (-1);
1740                         }
1741                         gcry_md_hash_buffer (GCRY_MD_SHA256,
1742                                         se->data.client.password_hash,
1743                                         se->data.client.password,
1744                                         strlen (se->data.client.password));
1745                 }
1746         }
1747         else /* (se->type == SOCKENT_TYPE_SERVER) */
1748         {
1749                 if (se->data.server.security_level > SECURITY_LEVEL_NONE)
1750                 {
1751                         if (se->data.server.auth_file == NULL)
1752                         {
1753                                 ERROR ("network plugin: Server socket with "
1754                                                 "security requested, but no "
1755                                                 "password file is configured.");
1756                                 return (-1);
1757                         }
1758                 }
1759                 if (se->data.server.auth_file != NULL)
1760                 {
1761                         se->data.server.userdb = fbh_create (se->data.server.auth_file);
1762                         if (se->data.server.userdb == NULL)
1763                         {
1764                                 ERROR ("network plugin: Reading password file "
1765                                                 "`%s' failed.",
1766                                                 se->data.server.auth_file);
1767                                 if (se->data.server.security_level > SECURITY_LEVEL_NONE)
1768                                         return (-1);
1769                         }
1770                 }
1771         }
1772 #endif /* }}} HAVE_LIBGCRYPT */
1773
1774         node = se->node;
1775         service = se->service;
1776
1777         if (service == NULL)
1778           service = NET_DEFAULT_PORT;
1779
1780         DEBUG ("network plugin: sockent_open: node = %s; service = %s;",
1781             node, service);
1782
1783         memset (&ai_hints, 0, sizeof (ai_hints));
1784         ai_hints.ai_flags  = 0;
1785 #ifdef AI_PASSIVE
1786         ai_hints.ai_flags |= AI_PASSIVE;
1787 #endif
1788 #ifdef AI_ADDRCONFIG
1789         ai_hints.ai_flags |= AI_ADDRCONFIG;
1790 #endif
1791         ai_hints.ai_family   = AF_UNSPEC;
1792         ai_hints.ai_socktype = SOCK_DGRAM;
1793         ai_hints.ai_protocol = IPPROTO_UDP;
1794
1795         ai_return = getaddrinfo (node, service, &ai_hints, &ai_list);
1796         if (ai_return != 0)
1797         {
1798                 ERROR ("network plugin: getaddrinfo (%s, %s) failed: %s",
1799                                 (se->node == NULL) ? "(null)" : se->node,
1800                                 (se->service == NULL) ? "(null)" : se->service,
1801                                 gai_strerror (ai_return));
1802                 return (-1);
1803         }
1804
1805         for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
1806         {
1807                 int status;
1808
1809                 if (se->type == SOCKENT_TYPE_SERVER) /* {{{ */
1810                 {
1811                         int *tmp;
1812
1813                         tmp = realloc (se->data.server.fd,
1814                                         sizeof (*tmp) * (se->data.server.fd_num + 1));
1815                         if (tmp == NULL)
1816                         {
1817                                 ERROR ("network plugin: realloc failed.");
1818                                 continue;
1819                         }
1820                         se->data.server.fd = tmp;
1821                         tmp = se->data.server.fd + se->data.server.fd_num;
1822
1823                         *tmp = socket (ai_ptr->ai_family, ai_ptr->ai_socktype,
1824                                         ai_ptr->ai_protocol);
1825                         if (*tmp < 0)
1826                         {
1827                                 char errbuf[1024];
1828                                 ERROR ("network plugin: socket(2) failed: %s",
1829                                                 sstrerror (errno, errbuf,
1830                                                         sizeof (errbuf)));
1831                                 continue;
1832                         }
1833
1834                         status = network_bind_socket (*tmp, ai_ptr);
1835                         if (status != 0)
1836                         {
1837                                 close (*tmp);
1838                                 *tmp = -1;
1839                                 continue;
1840                         }
1841
1842                         se->data.server.fd_num++;
1843                         continue;
1844                 } /* }}} if (se->type == SOCKENT_TYPE_SERVER) */
1845                 else /* if (se->type == SOCKENT_TYPE_CLIENT) {{{ */
1846                 {
1847                         se->data.client.fd = socket (ai_ptr->ai_family,
1848                                         ai_ptr->ai_socktype,
1849                                         ai_ptr->ai_protocol);
1850                         if (se->data.client.fd < 0)
1851                         {
1852                                 char errbuf[1024];
1853                                 ERROR ("network plugin: socket(2) failed: %s",
1854                                                 sstrerror (errno, errbuf,
1855                                                         sizeof (errbuf)));
1856                                 continue;
1857                         }
1858
1859                         se->data.client.addr = malloc (sizeof (*se->data.client.addr));
1860                         if (se->data.client.addr == NULL)
1861                         {
1862                                 ERROR ("network plugin: malloc failed.");
1863                                 close (se->data.client.fd);
1864                                 se->data.client.fd = -1;
1865                                 continue;
1866                         }
1867
1868                         memset (se->data.client.addr, 0, sizeof (*se->data.client.addr));
1869                         assert (sizeof (*se->data.client.addr) >= ai_ptr->ai_addrlen);
1870                         memcpy (se->data.client.addr, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
1871                         se->data.client.addrlen = ai_ptr->ai_addrlen;
1872
1873                         network_set_ttl (se, ai_ptr);
1874
1875                         /* We don't open more than one write-socket per
1876                          * node/service pair.. */
1877                         break;
1878                 } /* }}} if (se->type == SOCKENT_TYPE_CLIENT) */
1879         } /* for (ai_list) */
1880
1881         freeaddrinfo (ai_list);
1882
1883         /* Check if all went well. */
1884         if (se->type == SOCKENT_TYPE_SERVER)
1885         {
1886                 if (se->data.server.fd_num <= 0)
1887                         return (-1);
1888         }
1889         else /* if (se->type == SOCKENT_TYPE_CLIENT) */
1890         {
1891                 if (se->data.client.fd < 0)
1892                         return (-1);
1893         }
1894
1895         return (0);
1896 } /* }}} int sockent_open */
1897
1898 /* Add a sockent to the global list of sockets */
1899 static int sockent_add (sockent_t *se) /* {{{ */
1900 {
1901         sockent_t *last_ptr;
1902
1903         if (se == NULL)
1904                 return (-1);
1905
1906         if (se->type == SOCKENT_TYPE_SERVER)
1907         {
1908                 struct pollfd *tmp;
1909                 size_t i;
1910
1911                 tmp = realloc (listen_sockets_pollfd,
1912                                 sizeof (*tmp) * (listen_sockets_num
1913                                         + se->data.server.fd_num));
1914                 if (tmp == NULL)
1915                 {
1916                         ERROR ("network plugin: realloc failed.");
1917                         return (-1);
1918                 }
1919                 listen_sockets_pollfd = tmp;
1920                 tmp = listen_sockets_pollfd + listen_sockets_num;
1921
1922                 for (i = 0; i < se->data.server.fd_num; i++)
1923                 {
1924                         memset (tmp + i, 0, sizeof (*tmp));
1925                         tmp[i].fd = se->data.server.fd[i];
1926                         tmp[i].events = POLLIN | POLLPRI;
1927                         tmp[i].revents = 0;
1928                 }
1929
1930                 listen_sockets_num += se->data.server.fd_num;
1931
1932                 if (listen_sockets == NULL)
1933                 {
1934                         listen_sockets = se;
1935                         return (0);
1936                 }
1937                 last_ptr = listen_sockets;
1938         }
1939         else /* if (se->type == SOCKENT_TYPE_CLIENT) */
1940         {
1941                 if (sending_sockets == NULL)
1942                 {
1943                         sending_sockets = se;
1944                         return (0);
1945                 }
1946                 last_ptr = sending_sockets;
1947         }
1948
1949         while (last_ptr->next != NULL)
1950                 last_ptr = last_ptr->next;
1951         last_ptr->next = se;
1952
1953         return (0);
1954 } /* }}} int sockent_add */
1955
1956 static void *dispatch_thread (void __attribute__((unused)) *arg) /* {{{ */
1957 {
1958   while (42)
1959   {
1960     receive_list_entry_t *ent;
1961     sockent_t *se;
1962
1963     /* Lock and wait for more data to come in */
1964     pthread_mutex_lock (&receive_list_lock);
1965     while ((listen_loop == 0)
1966         && (receive_list_head == NULL))
1967       pthread_cond_wait (&receive_list_cond, &receive_list_lock);
1968
1969     /* Remove the head entry and unlock */
1970     ent = receive_list_head;
1971     if (ent != NULL)
1972       receive_list_head = ent->next;
1973     pthread_mutex_unlock (&receive_list_lock);
1974
1975     /* Check whether we are supposed to exit. We do NOT check `listen_loop'
1976      * because we dispatch all missing packets before shutting down. */
1977     if (ent == NULL)
1978       break;
1979
1980     /* Look for the correct `sockent_t' */
1981     se = listen_sockets;
1982     while (se != NULL)
1983     {
1984       size_t i;
1985
1986       for (i = 0; i < se->data.server.fd_num; i++)
1987         if (se->data.server.fd[i] == ent->fd)
1988           break;
1989
1990       if (i < se->data.server.fd_num)
1991         break;
1992
1993       se = se->next;
1994     }
1995
1996     if (se == NULL)
1997     {
1998             ERROR ("network plugin: Got packet from FD %i, but can't "
1999                             "find an appropriate socket entry.",
2000                             ent->fd);
2001             sfree (ent);
2002             continue;
2003     }
2004
2005     parse_packet (se, ent->data, ent->data_len, /* flags = */ 0);
2006     sfree (ent);
2007   } /* while (42) */
2008
2009   return (NULL);
2010 } /* }}} void *dispatch_thread */
2011
2012 static int network_receive (void) /* {{{ */
2013 {
2014         char buffer[BUFF_SIZE];
2015         int  buffer_len;
2016
2017         int i;
2018         int status;
2019
2020         receive_list_entry_t *private_list_head;
2021         receive_list_entry_t *private_list_tail;
2022
2023         assert (listen_sockets_num > 0);
2024
2025         private_list_head = NULL;
2026         private_list_tail = NULL;
2027
2028         while (listen_loop == 0)
2029         {
2030                 status = poll (listen_sockets_pollfd, listen_sockets_num, -1);
2031
2032                 if (status <= 0)
2033                 {
2034                         char errbuf[1024];
2035                         if (errno == EINTR)
2036                                 continue;
2037                         ERROR ("poll failed: %s",
2038                                         sstrerror (errno, errbuf, sizeof (errbuf)));
2039                         return (-1);
2040                 }
2041
2042                 for (i = 0; (i < listen_sockets_num) && (status > 0); i++)
2043                 {
2044                         receive_list_entry_t *ent;
2045
2046                         if ((listen_sockets_pollfd[i].revents
2047                                                 & (POLLIN | POLLPRI)) == 0)
2048                                 continue;
2049                         status--;
2050
2051                         buffer_len = recv (listen_sockets_pollfd[i].fd,
2052                                         buffer, sizeof (buffer),
2053                                         0 /* no flags */);
2054                         if (buffer_len < 0)
2055                         {
2056                                 char errbuf[1024];
2057                                 ERROR ("recv failed: %s",
2058                                                 sstrerror (errno, errbuf,
2059                                                         sizeof (errbuf)));
2060                                 return (-1);
2061                         }
2062
2063                         /* TODO: Possible performance enhancement: Do not free
2064                          * these entries in the dispatch thread but put them in
2065                          * another list, so we don't have to allocate more and
2066                          * more of these structures. */
2067                         ent = malloc (sizeof (receive_list_entry_t));
2068                         if (ent == NULL)
2069                         {
2070                                 ERROR ("network plugin: malloc failed.");
2071                                 return (-1);
2072                         }
2073                         memset (ent, 0, sizeof (receive_list_entry_t));
2074                         ent->fd = listen_sockets_pollfd[i].fd;
2075                         ent->next = NULL;
2076
2077                         /* Hopefully this be optimized out by the compiler. It
2078                          * might help prevent stupid bugs in the future though.
2079                          */
2080                         assert (sizeof (ent->data) == sizeof (buffer));
2081
2082                         memcpy (ent->data, buffer, buffer_len);
2083                         ent->data_len = buffer_len;
2084
2085                         if (private_list_head == NULL)
2086                                 private_list_head = ent;
2087                         else
2088                                 private_list_tail->next = ent;
2089                         private_list_tail = ent;
2090
2091                         /* Do not block here. Blocking here has led to
2092                          * insufficient performance in the past. */
2093                         if (pthread_mutex_trylock (&receive_list_lock) == 0)
2094                         {
2095                                 if (receive_list_head == NULL)
2096                                         receive_list_head = private_list_head;
2097                                 else
2098                                         receive_list_tail->next = private_list_head;
2099                                 receive_list_tail = private_list_tail;
2100
2101                                 private_list_head = NULL;
2102                                 private_list_tail = NULL;
2103
2104                                 pthread_cond_signal (&receive_list_cond);
2105                                 pthread_mutex_unlock (&receive_list_lock);
2106                         }
2107                 } /* for (listen_sockets_pollfd) */
2108         } /* while (listen_loop == 0) */
2109
2110         /* Make sure everything is dispatched before exiting. */
2111         if (private_list_head != NULL)
2112         {
2113                 pthread_mutex_lock (&receive_list_lock);
2114
2115                 if (receive_list_head == NULL)
2116                         receive_list_head = private_list_head;
2117                 else
2118                         receive_list_tail->next = private_list_head;
2119                 receive_list_tail = private_list_tail;
2120
2121                 private_list_head = NULL;
2122                 private_list_tail = NULL;
2123
2124                 pthread_cond_signal (&receive_list_cond);
2125                 pthread_mutex_unlock (&receive_list_lock);
2126         }
2127
2128         return (0);
2129 } /* }}} int network_receive */
2130
2131 static void *receive_thread (void __attribute__((unused)) *arg)
2132 {
2133         return (network_receive () ? (void *) 1 : (void *) 0);
2134 } /* void *receive_thread */
2135
2136 static void network_init_buffer (void)
2137 {
2138         memset (send_buffer, 0, sizeof (send_buffer));
2139         send_buffer_ptr = send_buffer;
2140         send_buffer_fill = 0;
2141
2142         memset (&send_buffer_vl, 0, sizeof (send_buffer_vl));
2143 } /* int network_init_buffer */
2144
2145 static void networt_send_buffer_plain (const sockent_t *se, /* {{{ */
2146                 const char *buffer, size_t buffer_size)
2147 {
2148         int status;
2149
2150         while (42)
2151         {
2152                 status = sendto (se->data.client.fd, buffer, buffer_size,
2153                     /* flags = */ 0,
2154                     (struct sockaddr *) se->data.client.addr,
2155                     se->data.client.addrlen);
2156                 if (status < 0)
2157                 {
2158                         char errbuf[1024];
2159                         if (errno == EINTR)
2160                                 continue;
2161                         ERROR ("network plugin: sendto failed: %s",
2162                                         sstrerror (errno, errbuf,
2163                                                 sizeof (errbuf)));
2164                         break;
2165                 }
2166
2167                 break;
2168         } /* while (42) */
2169 } /* }}} void networt_send_buffer_plain */
2170
2171 #if HAVE_LIBGCRYPT
2172 #define BUFFER_ADD(p,s) do { \
2173   memcpy (buffer + buffer_offset, (p), (s)); \
2174   buffer_offset += (s); \
2175 } while (0)
2176
2177 static void networt_send_buffer_signed (const sockent_t *se, /* {{{ */
2178                 const char *in_buffer, size_t in_buffer_size)
2179 {
2180   part_signature_sha256_t ps;
2181   char buffer[BUFF_SIG_SIZE + in_buffer_size];
2182   size_t buffer_offset;
2183   size_t username_len;
2184
2185   gcry_md_hd_t hd;
2186   gcry_error_t err;
2187   unsigned char *hash;
2188
2189   hd = NULL;
2190   err = gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
2191   if (err != 0)
2192   {
2193     ERROR ("network plugin: Creating HMAC object failed: %s",
2194         gcry_strerror (err));
2195     return;
2196   }
2197
2198   err = gcry_md_setkey (hd, se->data.client.password,
2199       strlen (se->data.client.password));
2200   if (err != 0)
2201   {
2202     ERROR ("network plugin: gcry_md_setkey failed: %s",
2203         gcry_strerror (err));
2204     gcry_md_close (hd);
2205     return;
2206   }
2207
2208   username_len = strlen (se->data.client.username);
2209   if (username_len > (BUFF_SIG_SIZE - PART_SIGNATURE_SHA256_SIZE))
2210   {
2211     ERROR ("network plugin: Username too long: %s",
2212         se->data.client.username);
2213     return;
2214   }
2215
2216   memcpy (buffer + PART_SIGNATURE_SHA256_SIZE,
2217       se->data.client.username, username_len);
2218   memcpy (buffer + PART_SIGNATURE_SHA256_SIZE + username_len,
2219       in_buffer, in_buffer_size);
2220
2221   /* Initialize the `ps' structure. */
2222   memset (&ps, 0, sizeof (ps));
2223   ps.head.type = htons (TYPE_SIGN_SHA256);
2224   ps.head.length = htons (PART_SIGNATURE_SHA256_SIZE + username_len);
2225
2226   /* Calculate the hash value. */
2227   gcry_md_write (hd, buffer + PART_SIGNATURE_SHA256_SIZE,
2228       username_len + in_buffer_size);
2229   hash = gcry_md_read (hd, GCRY_MD_SHA256);
2230   if (hash == NULL)
2231   {
2232     ERROR ("network plugin: gcry_md_read failed.");
2233     gcry_md_close (hd);
2234     return;
2235   }
2236   memcpy (ps.hash, hash, sizeof (ps.hash));
2237
2238   /* Add the header */
2239   buffer_offset = 0;
2240
2241   BUFFER_ADD (&ps.head.type, sizeof (ps.head.type));
2242   BUFFER_ADD (&ps.head.length, sizeof (ps.head.length));
2243   BUFFER_ADD (ps.hash, sizeof (ps.hash));
2244
2245   assert (buffer_offset == PART_SIGNATURE_SHA256_SIZE);
2246
2247   gcry_md_close (hd);
2248   hd = NULL;
2249
2250   buffer_offset = PART_SIGNATURE_SHA256_SIZE + username_len + in_buffer_size;
2251   networt_send_buffer_plain (se, buffer, buffer_offset);
2252 } /* }}} void networt_send_buffer_signed */
2253
2254 static void networt_send_buffer_encrypted (sockent_t *se, /* {{{ */
2255                 const char *in_buffer, size_t in_buffer_size)
2256 {
2257   part_encryption_aes256_t pea;
2258   char buffer[BUFF_SIG_SIZE + in_buffer_size];
2259   size_t buffer_size;
2260   size_t buffer_offset;
2261   size_t header_size;
2262   size_t username_len;
2263   gcry_error_t err;
2264   gcry_cipher_hd_t cypher;
2265
2266   /* Initialize the header fields */
2267   memset (&pea, 0, sizeof (pea));
2268   pea.head.type = htons (TYPE_ENCR_AES256);
2269
2270   pea.username = se->data.client.username;
2271
2272   username_len = strlen (pea.username);
2273   if ((PART_ENCRYPTION_AES256_SIZE + username_len) > BUFF_SIG_SIZE)
2274   {
2275     ERROR ("network plugin: Username too long: %s", pea.username);
2276     return;
2277   }
2278
2279   buffer_size = PART_ENCRYPTION_AES256_SIZE + username_len + in_buffer_size;
2280   header_size = PART_ENCRYPTION_AES256_SIZE + username_len
2281     - sizeof (pea.hash);
2282
2283   assert (buffer_size <= sizeof (buffer));
2284   DEBUG ("network plugin: networt_send_buffer_encrypted: "
2285       "buffer_size = %zu;", buffer_size);
2286
2287   pea.head.length = htons ((uint16_t) (PART_ENCRYPTION_AES256_SIZE
2288         + username_len + in_buffer_size));
2289   pea.username_length = htons ((uint16_t) username_len);
2290
2291   /* Chose a random initialization vector. */
2292   gcry_randomize ((void *) &pea.iv, sizeof (pea.iv), GCRY_STRONG_RANDOM);
2293
2294   /* Create hash of the payload */
2295   gcry_md_hash_buffer (GCRY_MD_SHA1, pea.hash, in_buffer, in_buffer_size);
2296
2297   /* Initialize the buffer */
2298   buffer_offset = 0;
2299   memset (buffer, 0, sizeof (buffer));
2300
2301
2302   BUFFER_ADD (&pea.head.type, sizeof (pea.head.type));
2303   BUFFER_ADD (&pea.head.length, sizeof (pea.head.length));
2304   BUFFER_ADD (&pea.username_length, sizeof (pea.username_length));
2305   BUFFER_ADD (pea.username, username_len);
2306   BUFFER_ADD (pea.iv, sizeof (pea.iv));
2307   assert (buffer_offset == header_size);
2308   BUFFER_ADD (pea.hash, sizeof (pea.hash));
2309   BUFFER_ADD (in_buffer, in_buffer_size);
2310
2311   assert (buffer_offset == buffer_size);
2312
2313   cypher = network_get_aes256_cypher (se, pea.iv, sizeof (pea.iv),
2314       se->data.client.password);
2315   if (cypher == NULL)
2316     return;
2317
2318   /* Encrypt the buffer in-place */
2319   err = gcry_cipher_encrypt (cypher,
2320       buffer      + header_size,
2321       buffer_size - header_size,
2322       /* in = */ NULL, /* in len = */ 0);
2323   if (err != 0)
2324   {
2325     ERROR ("network plugin: gcry_cipher_encrypt returned: %s",
2326         gcry_strerror (err));
2327     return;
2328   }
2329
2330   /* Send it out without further modifications */
2331   networt_send_buffer_plain (se, buffer, buffer_size);
2332 } /* }}} void networt_send_buffer_encrypted */
2333 #undef BUFFER_ADD
2334 #endif /* HAVE_LIBGCRYPT */
2335
2336 static void network_send_buffer (char *buffer, size_t buffer_len) /* {{{ */
2337 {
2338   sockent_t *se;
2339
2340   DEBUG ("network plugin: network_send_buffer: buffer_len = %zu", buffer_len);
2341
2342   for (se = sending_sockets; se != NULL; se = se->next)
2343   {
2344 #if HAVE_LIBGCRYPT
2345     if (se->data.client.security_level == SECURITY_LEVEL_ENCRYPT)
2346       networt_send_buffer_encrypted (se, buffer, buffer_len);
2347     else if (se->data.client.security_level == SECURITY_LEVEL_SIGN)
2348       networt_send_buffer_signed (se, buffer, buffer_len);
2349     else /* if (se->data.client.security_level == SECURITY_LEVEL_NONE) */
2350 #endif /* HAVE_LIBGCRYPT */
2351       networt_send_buffer_plain (se, buffer, buffer_len);
2352   } /* for (sending_sockets) */
2353 } /* }}} void network_send_buffer */
2354
2355 static int add_to_buffer (char *buffer, int buffer_size, /* {{{ */
2356                 value_list_t *vl_def,
2357                 const data_set_t *ds, const value_list_t *vl)
2358 {
2359         char *buffer_orig = buffer;
2360
2361         if (strcmp (vl_def->host, vl->host) != 0)
2362         {
2363                 if (write_part_string (&buffer, &buffer_size, TYPE_HOST,
2364                                         vl->host, strlen (vl->host)) != 0)
2365                         return (-1);
2366                 sstrncpy (vl_def->host, vl->host, sizeof (vl_def->host));
2367         }
2368
2369         if (vl_def->time != vl->time)
2370         {
2371                 if (write_part_number (&buffer, &buffer_size, TYPE_TIME,
2372                                         (uint64_t) vl->time))
2373                         return (-1);
2374                 vl_def->time = vl->time;
2375         }
2376
2377         if (vl_def->interval != vl->interval)
2378         {
2379                 if (write_part_number (&buffer, &buffer_size, TYPE_INTERVAL,
2380                                         (uint64_t) vl->interval))
2381                         return (-1);
2382                 vl_def->interval = vl->interval;
2383         }
2384
2385         if (strcmp (vl_def->plugin, vl->plugin) != 0)
2386         {
2387                 if (write_part_string (&buffer, &buffer_size, TYPE_PLUGIN,
2388                                         vl->plugin, strlen (vl->plugin)) != 0)
2389                         return (-1);
2390                 sstrncpy (vl_def->plugin, vl->plugin, sizeof (vl_def->plugin));
2391         }
2392
2393         if (strcmp (vl_def->plugin_instance, vl->plugin_instance) != 0)
2394         {
2395                 if (write_part_string (&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
2396                                         vl->plugin_instance,
2397                                         strlen (vl->plugin_instance)) != 0)
2398                         return (-1);
2399                 sstrncpy (vl_def->plugin_instance, vl->plugin_instance, sizeof (vl_def->plugin_instance));
2400         }
2401
2402         if (strcmp (vl_def->type, vl->type) != 0)
2403         {
2404                 if (write_part_string (&buffer, &buffer_size, TYPE_TYPE,
2405                                         vl->type, strlen (vl->type)) != 0)
2406                         return (-1);
2407                 sstrncpy (vl_def->type, ds->type, sizeof (vl_def->type));
2408         }
2409
2410         if (strcmp (vl_def->type_instance, vl->type_instance) != 0)
2411         {
2412                 if (write_part_string (&buffer, &buffer_size, TYPE_TYPE_INSTANCE,
2413                                         vl->type_instance,
2414                                         strlen (vl->type_instance)) != 0)
2415                         return (-1);
2416                 sstrncpy (vl_def->type_instance, vl->type_instance, sizeof (vl_def->type_instance));
2417         }
2418         
2419         if (write_part_values (&buffer, &buffer_size, ds, vl) != 0)
2420                 return (-1);
2421
2422         return (buffer - buffer_orig);
2423 } /* }}} int add_to_buffer */
2424
2425 static void flush_buffer (void)
2426 {
2427         DEBUG ("network plugin: flush_buffer: send_buffer_fill = %i",
2428                         send_buffer_fill);
2429
2430         network_send_buffer (send_buffer, (size_t) send_buffer_fill);
2431         network_init_buffer ();
2432 }
2433
2434 static int network_write (const data_set_t *ds, const value_list_t *vl,
2435                 user_data_t __attribute__((unused)) *user_data)
2436 {
2437         int status;
2438
2439         /* If the value is already in the cache, we have received it via the
2440          * network. We write it again if forwarding is activated. It's then in
2441          * the cache and should we receive it again we will ignore it. */
2442         status = cache_check (vl);
2443         if ((network_config_forward == 0)
2444                         && (status != 0))
2445                 return (0);
2446
2447         pthread_mutex_lock (&send_buffer_lock);
2448
2449         status = add_to_buffer (send_buffer_ptr,
2450                         sizeof (send_buffer) - (send_buffer_fill + BUFF_SIG_SIZE),
2451                         &send_buffer_vl,
2452                         ds, vl);
2453         if (status >= 0)
2454         {
2455                 /* status == bytes added to the buffer */
2456                 send_buffer_fill += status;
2457                 send_buffer_ptr  += status;
2458         }
2459         else
2460         {
2461                 flush_buffer ();
2462
2463                 status = add_to_buffer (send_buffer_ptr,
2464                                 sizeof (send_buffer) - (send_buffer_fill + BUFF_SIG_SIZE),
2465                                 &send_buffer_vl,
2466                                 ds, vl);
2467
2468                 if (status >= 0)
2469                 {
2470                         send_buffer_fill += status;
2471                         send_buffer_ptr  += status;
2472                 }
2473         }
2474
2475         if (status < 0)
2476         {
2477                 ERROR ("network plugin: Unable to append to the "
2478                                 "buffer for some weird reason");
2479         }
2480         else if ((sizeof (send_buffer) - send_buffer_fill) < 15)
2481         {
2482                 flush_buffer ();
2483         }
2484
2485         pthread_mutex_unlock (&send_buffer_lock);
2486
2487         return ((status < 0) ? -1 : 0);
2488 } /* int network_write */
2489
2490 static int network_config_set_boolean (const oconfig_item_t *ci, /* {{{ */
2491     int *retval)
2492 {
2493   if ((ci->values_num != 1)
2494       || ((ci->values[0].type != OCONFIG_TYPE_BOOLEAN)
2495         && (ci->values[0].type != OCONFIG_TYPE_STRING)))
2496   {
2497     ERROR ("network plugin: The `%s' config option needs "
2498         "exactly one boolean argument.", ci->key);
2499     return (-1);
2500   }
2501
2502   if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN)
2503   {
2504     if (ci->values[0].value.boolean)
2505       *retval = 1;
2506     else
2507       *retval = 0;
2508   }
2509   else
2510   {
2511     char *str = ci->values[0].value.string;
2512
2513     if ((strcasecmp ("true", str) == 0)
2514         || (strcasecmp ("yes", str) == 0)
2515         || (strcasecmp ("on", str) == 0))
2516       *retval = 1;
2517     else if ((strcasecmp ("false", str) == 0)
2518         || (strcasecmp ("no", str) == 0)
2519         || (strcasecmp ("off", str) == 0))
2520       *retval = 0;
2521     else
2522     {
2523       ERROR ("network plugin: Cannot parse string value `%s' of the `%s' "
2524           "option as boolean value.",
2525           str, ci->key);
2526       return (-1);
2527     }
2528   }
2529
2530   return (0);
2531 } /* }}} int network_config_set_boolean */
2532
2533 static int network_config_set_ttl (const oconfig_item_t *ci) /* {{{ */
2534 {
2535   int tmp;
2536   if ((ci->values_num != 1)
2537       || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
2538   {
2539     WARNING ("network plugin: The `TimeToLive' config option needs exactly "
2540         "one numeric argument.");
2541     return (-1);
2542   }
2543
2544   tmp = (int) ci->values[0].value.number;
2545   if ((tmp > 0) && (tmp <= 255))
2546     network_config_ttl = tmp;
2547
2548   return (0);
2549 } /* }}} int network_config_set_ttl */
2550
2551 #if HAVE_LIBGCRYPT
2552 static int network_config_set_string (const oconfig_item_t *ci, /* {{{ */
2553     char **ret_string)
2554 {
2555   char *tmp;
2556   if ((ci->values_num != 1)
2557       || (ci->values[0].type != OCONFIG_TYPE_STRING))
2558   {
2559     WARNING ("network plugin: The `%s' config option needs exactly "
2560         "one string argument.", ci->key);
2561     return (-1);
2562   }
2563
2564   tmp = strdup (ci->values[0].value.string);
2565   if (tmp == NULL)
2566     return (-1);
2567
2568   sfree (*ret_string);
2569   *ret_string = tmp;
2570
2571   return (0);
2572 } /* }}} int network_config_set_string */
2573 #endif /* HAVE_LIBGCRYPT */
2574
2575 #if HAVE_LIBGCRYPT
2576 static int network_config_set_security_level (oconfig_item_t *ci, /* {{{ */
2577     int *retval)
2578 {
2579   char *str;
2580   if ((ci->values_num != 1)
2581       || (ci->values[0].type != OCONFIG_TYPE_STRING))
2582   {
2583     WARNING ("network plugin: The `SecurityLevel' config option needs exactly "
2584         "one string argument.");
2585     return (-1);
2586   }
2587
2588   str = ci->values[0].value.string;
2589   if (strcasecmp ("Encrypt", str) == 0)
2590     *retval = SECURITY_LEVEL_ENCRYPT;
2591   else if (strcasecmp ("Sign", str) == 0)
2592     *retval = SECURITY_LEVEL_SIGN;
2593   else if (strcasecmp ("None", str) == 0)
2594     *retval = SECURITY_LEVEL_NONE;
2595   else
2596   {
2597     WARNING ("network plugin: Unknown security level: %s.", str);
2598     return (-1);
2599   }
2600
2601   return (0);
2602 } /* }}} int network_config_set_security_level */
2603 #endif /* HAVE_LIBGCRYPT */
2604
2605 static int network_config_add_listen (const oconfig_item_t *ci) /* {{{ */
2606 {
2607   sockent_t *se;
2608   int status;
2609   int i;
2610
2611   if ((ci->values_num < 1) || (ci->values_num > 2)
2612       || (ci->values[0].type != OCONFIG_TYPE_STRING)
2613       || ((ci->values_num > 1) && (ci->values[1].type != OCONFIG_TYPE_STRING)))
2614   {
2615     ERROR ("network plugin: The `%s' config option needs "
2616         "one or two string arguments.", ci->key);
2617     return (-1);
2618   }
2619
2620   se = malloc (sizeof (*se));
2621   if (se == NULL)
2622   {
2623     ERROR ("network plugin: malloc failed.");
2624     return (-1);
2625   }
2626   sockent_init (se, SOCKENT_TYPE_SERVER);
2627
2628   se->node = strdup (ci->values[0].value.string);
2629   if (ci->values_num >= 2)
2630     se->service = strdup (ci->values[1].value.string);
2631
2632   for (i = 0; i < ci->children_num; i++)
2633   {
2634     oconfig_item_t *child = ci->children + i;
2635
2636 #if HAVE_LIBGCRYPT
2637     if (strcasecmp ("AuthFile", child->key) == 0)
2638       network_config_set_string (child, &se->data.server.auth_file);
2639     else if (strcasecmp ("SecurityLevel", child->key) == 0)
2640       network_config_set_security_level (child,
2641           &se->data.server.security_level);
2642     else
2643 #endif /* HAVE_LIBGCRYPT */
2644     {
2645       WARNING ("network plugin: Option `%s' is not allowed here.",
2646           child->key);
2647     }
2648   }
2649
2650 #if HAVE_LIBGCRYPT
2651   if ((se->data.server.security_level > SECURITY_LEVEL_NONE)
2652       && (se->data.server.auth_file == NULL))
2653   {
2654     ERROR ("network plugin: A security level higher than `none' was "
2655         "requested, but no AuthFile option was given. Cowardly refusing to "
2656         "open this socket!");
2657     sockent_destroy (se);
2658     return (-1);
2659   }
2660 #endif /* HAVE_LIBGCRYPT */
2661
2662   status = sockent_open (se);
2663   if (status != 0)
2664   {
2665     ERROR ("network plugin: network_config_add_listen: sockent_open failed.");
2666     sockent_destroy (se);
2667     return (-1);
2668   }
2669
2670   status = sockent_add (se);
2671   if (status != 0)
2672   {
2673     ERROR ("network plugin: network_config_add_listen: sockent_add failed.");
2674     sockent_destroy (se);
2675     return (-1);
2676   }
2677
2678   return (0);
2679 } /* }}} int network_config_add_listen */
2680
2681 static int network_config_add_server (const oconfig_item_t *ci) /* {{{ */
2682 {
2683   sockent_t *se;
2684   int status;
2685   int i;
2686
2687   if ((ci->values_num < 1) || (ci->values_num > 2)
2688       || (ci->values[0].type != OCONFIG_TYPE_STRING)
2689       || ((ci->values_num > 1) && (ci->values[1].type != OCONFIG_TYPE_STRING)))
2690   {
2691     ERROR ("network plugin: The `%s' config option needs "
2692         "one or two string arguments.", ci->key);
2693     return (-1);
2694   }
2695
2696   se = malloc (sizeof (*se));
2697   if (se == NULL)
2698   {
2699     ERROR ("network plugin: malloc failed.");
2700     return (-1);
2701   }
2702   sockent_init (se, SOCKENT_TYPE_CLIENT);
2703
2704   se->node = strdup (ci->values[0].value.string);
2705   if (ci->values_num >= 2)
2706     se->service = strdup (ci->values[1].value.string);
2707
2708   for (i = 0; i < ci->children_num; i++)
2709   {
2710     oconfig_item_t *child = ci->children + i;
2711
2712 #if HAVE_LIBGCRYPT
2713     if (strcasecmp ("Username", child->key) == 0)
2714       network_config_set_string (child, &se->data.client.username);
2715     else if (strcasecmp ("Password", child->key) == 0)
2716       network_config_set_string (child, &se->data.client.password);
2717     else if (strcasecmp ("SecurityLevel", child->key) == 0)
2718       network_config_set_security_level (child,
2719           &se->data.client.security_level);
2720     else
2721 #endif /* HAVE_LIBGCRYPT */
2722     {
2723       WARNING ("network plugin: Option `%s' is not allowed here.",
2724           child->key);
2725     }
2726   }
2727
2728 #if HAVE_LIBGCRYPT
2729   if ((se->data.client.security_level > SECURITY_LEVEL_NONE)
2730       && ((se->data.client.username == NULL)
2731         || (se->data.client.password == NULL)))
2732   {
2733     ERROR ("network plugin: A security level higher than `none' was "
2734         "requested, but no Username or Password option was given. "
2735         "Cowardly refusing to open this socket!");
2736     sockent_destroy (se);
2737     return (-1);
2738   }
2739 #endif /* HAVE_LIBGCRYPT */
2740
2741   status = sockent_open (se);
2742   if (status != 0)
2743   {
2744     ERROR ("network plugin: network_config_add_server: sockent_open failed.");
2745     sockent_destroy (se);
2746     return (-1);
2747   }
2748
2749   status = sockent_add (se);
2750   if (status != 0)
2751   {
2752     ERROR ("network plugin: network_config_add_server: sockent_add failed.");
2753     sockent_destroy (se);
2754     return (-1);
2755   }
2756
2757   return (0);
2758 } /* }}} int network_config_add_server */
2759
2760 static int network_config_set_cache_flush (const oconfig_item_t *ci) /* {{{ */
2761 {
2762   int tmp;
2763   if ((ci->values_num != 1)
2764       || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
2765   {
2766     WARNING ("network plugin: The `CacheFlush' config option needs exactly "
2767         "one numeric argument.");
2768     return (-1);
2769   }
2770
2771   tmp = (int) ci->values[0].value.number;
2772   if (tmp > 0)
2773     cache_flush_interval = tmp;
2774
2775   return (0);
2776 } /* }}} int network_config_set_cache_flush */
2777
2778 static int network_config (oconfig_item_t *ci) /* {{{ */
2779 {
2780   int i;
2781
2782   for (i = 0; i < ci->children_num; i++)
2783   {
2784     oconfig_item_t *child = ci->children + i;
2785
2786     if (strcasecmp ("Listen", child->key) == 0)
2787       network_config_add_listen (child);
2788     else if (strcasecmp ("Server", child->key) == 0)
2789       network_config_add_server (child);
2790     else if (strcasecmp ("TimeToLive", child->key) == 0)
2791       network_config_set_ttl (child);
2792     else if (strcasecmp ("Forward", child->key) == 0)
2793       network_config_set_boolean (child, &network_config_forward);
2794     else if (strcasecmp ("CacheFlush", child->key) == 0)
2795       network_config_set_cache_flush (child);
2796     else
2797     {
2798       WARNING ("network plugin: Option `%s' is not allowed here.",
2799           child->key);
2800     }
2801   }
2802
2803   return (0);
2804 } /* }}} int network_config */
2805
2806 static int network_notification (const notification_t *n,
2807                 user_data_t __attribute__((unused)) *user_data)
2808 {
2809   char  buffer[BUFF_SIZE];
2810   char *buffer_ptr = buffer;
2811   int   buffer_free = sizeof (buffer);
2812   int   status;
2813
2814   memset (buffer, '\0', sizeof (buffer));
2815
2816
2817   status = write_part_number (&buffer_ptr, &buffer_free, TYPE_TIME,
2818       (uint64_t) n->time);
2819   if (status != 0)
2820     return (-1);
2821
2822   status = write_part_number (&buffer_ptr, &buffer_free, TYPE_SEVERITY,
2823       (uint64_t) n->severity);
2824   if (status != 0)
2825     return (-1);
2826
2827   if (strlen (n->host) > 0)
2828   {
2829     status = write_part_string (&buffer_ptr, &buffer_free, TYPE_HOST,
2830         n->host, strlen (n->host));
2831     if (status != 0)
2832       return (-1);
2833   }
2834
2835   if (strlen (n->plugin) > 0)
2836   {
2837     status = write_part_string (&buffer_ptr, &buffer_free, TYPE_PLUGIN,
2838         n->plugin, strlen (n->plugin));
2839     if (status != 0)
2840       return (-1);
2841   }
2842
2843   if (strlen (n->plugin_instance) > 0)
2844   {
2845     status = write_part_string (&buffer_ptr, &buffer_free,
2846         TYPE_PLUGIN_INSTANCE,
2847         n->plugin_instance, strlen (n->plugin_instance));
2848     if (status != 0)
2849       return (-1);
2850   }
2851
2852   if (strlen (n->type) > 0)
2853   {
2854     status = write_part_string (&buffer_ptr, &buffer_free, TYPE_TYPE,
2855         n->type, strlen (n->type));
2856     if (status != 0)
2857       return (-1);
2858   }
2859
2860   if (strlen (n->type_instance) > 0)
2861   {
2862     status = write_part_string (&buffer_ptr, &buffer_free, TYPE_TYPE_INSTANCE,
2863         n->type_instance, strlen (n->type_instance));
2864     if (status != 0)
2865       return (-1);
2866   }
2867
2868   status = write_part_string (&buffer_ptr, &buffer_free, TYPE_MESSAGE,
2869       n->message, strlen (n->message));
2870   if (status != 0)
2871     return (-1);
2872
2873   network_send_buffer (buffer, sizeof (buffer) - buffer_free);
2874
2875   return (0);
2876 } /* int network_notification */
2877
2878 static int network_shutdown (void)
2879 {
2880         listen_loop++;
2881
2882         /* Kill the listening thread */
2883         if (receive_thread_running != 0)
2884         {
2885                 INFO ("network plugin: Stopping receive thread.");
2886                 pthread_kill (receive_thread_id, SIGTERM);
2887                 pthread_join (receive_thread_id, NULL /* no return value */);
2888                 memset (&receive_thread_id, 0, sizeof (receive_thread_id));
2889                 receive_thread_running = 0;
2890         }
2891
2892         /* Shutdown the dispatching thread */
2893         if (dispatch_thread_running != 0)
2894         {
2895                 INFO ("network plugin: Stopping dispatch thread.");
2896                 pthread_mutex_lock (&receive_list_lock);
2897                 pthread_cond_broadcast (&receive_list_cond);
2898                 pthread_mutex_unlock (&receive_list_lock);
2899                 pthread_join (dispatch_thread_id, /* ret = */ NULL);
2900                 dispatch_thread_running = 0;
2901         }
2902
2903         sockent_destroy (listen_sockets);
2904
2905         if (send_buffer_fill > 0)
2906                 flush_buffer ();
2907
2908         if (cache_tree != NULL)
2909         {
2910                 void *key;
2911                 void *value;
2912
2913                 while (c_avl_pick (cache_tree, &key, &value) == 0)
2914                 {
2915                         sfree (key);
2916                         sfree (value);
2917                 }
2918                 c_avl_destroy (cache_tree);
2919                 cache_tree = NULL;
2920         }
2921
2922         /* TODO: Close `sending_sockets' */
2923
2924         plugin_unregister_config ("network");
2925         plugin_unregister_init ("network");
2926         plugin_unregister_write ("network");
2927         plugin_unregister_shutdown ("network");
2928
2929         /* Let the init function do it's move again ;) */
2930         cache_flush_last = 0;
2931
2932         return (0);
2933 } /* int network_shutdown */
2934
2935 static int network_init (void)
2936 {
2937         /* Check if we were already initialized. If so, just return - there's
2938          * nothing more to do (for now, that is). */
2939         if (cache_flush_last != 0)
2940                 return (0);
2941
2942 #if HAVE_LIBGCRYPT
2943         gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
2944         gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
2945         gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
2946 #endif
2947
2948         plugin_register_shutdown ("network", network_shutdown);
2949
2950         network_init_buffer ();
2951
2952         cache_tree = c_avl_create ((int (*) (const void *, const void *)) strcmp);
2953         cache_flush_last = time (NULL);
2954
2955         /* setup socket(s) and so on */
2956         if (sending_sockets != NULL)
2957         {
2958                 plugin_register_write ("network", network_write,
2959                                 /* user_data = */ NULL);
2960                 plugin_register_notification ("network", network_notification,
2961                                 /* user_data = */ NULL);
2962         }
2963
2964         /* If no threads need to be started, return here. */
2965         if ((listen_sockets_num == 0)
2966                         || ((dispatch_thread_running != 0)
2967                                 && (receive_thread_running != 0)))
2968                 return (0);
2969
2970         if (dispatch_thread_running == 0)
2971         {
2972                 int status;
2973                 status = pthread_create (&dispatch_thread_id,
2974                                 NULL /* no attributes */,
2975                                 dispatch_thread,
2976                                 NULL /* no argument */);
2977                 if (status != 0)
2978                 {
2979                         char errbuf[1024];
2980                         ERROR ("network: pthread_create failed: %s",
2981                                         sstrerror (errno, errbuf,
2982                                                 sizeof (errbuf)));
2983                 }
2984                 else
2985                 {
2986                         dispatch_thread_running = 1;
2987                 }
2988         }
2989
2990         if (receive_thread_running == 0)
2991         {
2992                 int status;
2993                 status = pthread_create (&receive_thread_id,
2994                                 NULL /* no attributes */,
2995                                 receive_thread,
2996                                 NULL /* no argument */);
2997                 if (status != 0)
2998                 {
2999                         char errbuf[1024];
3000                         ERROR ("network: pthread_create failed: %s",
3001                                         sstrerror (errno, errbuf,
3002                                                 sizeof (errbuf)));
3003                 }
3004                 else
3005                 {
3006                         receive_thread_running = 1;
3007                 }
3008         }
3009
3010         return (0);
3011 } /* int network_init */
3012
3013 /* 
3014  * The flush option of the network plugin cannot flush individual identifiers.
3015  * All the values are added to a buffer and sent when the buffer is full, the
3016  * requested value may or may not be in there, it's not worth finding out. We
3017  * just send the buffer if `flush'  is called - if the requested value was in
3018  * there, good. If not, well, then there is nothing to flush.. -octo
3019  */
3020 static int network_flush (int timeout,
3021                 const char __attribute__((unused)) *identifier,
3022                 user_data_t __attribute__((unused)) *user_data)
3023 {
3024         pthread_mutex_lock (&send_buffer_lock);
3025
3026         if (((time (NULL) - cache_flush_last) >= timeout)
3027                         && (send_buffer_fill > 0))
3028         {
3029                 flush_buffer ();
3030         }
3031
3032         pthread_mutex_unlock (&send_buffer_lock);
3033
3034         return (0);
3035 } /* int network_flush */
3036
3037 void module_register (void)
3038 {
3039         plugin_register_complex_config ("network", network_config);
3040         plugin_register_init   ("network", network_init);
3041         plugin_register_flush   ("network", network_flush,
3042                         /* user_data = */ NULL);
3043 } /* void module_register */
3044
3045 /* vim: set fdm=marker : */