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