PageRenderTime 35ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/src/network.c

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