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