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