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