X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fnetwork.c;h=74325a29483af445415cf89256f7be664721c559;hb=23a8901d57aa1e3ee48dc8f281ad5cc249d46446;hp=b6e21b999952424780abc4aeb883a739af14fdda;hpb=0d5e07999e8769be8f6808c6e7d910277384bb39;p=collectd.git diff --git a/src/network.c b/src/network.c index b6e21b99..74325a29 100644 --- a/src/network.c +++ b/src/network.c @@ -121,6 +121,7 @@ typedef struct sockent char *node; char *service; + int interface; union { @@ -257,7 +258,6 @@ typedef struct receive_list_entry_s receive_list_entry_t; * Private variables */ static int network_config_ttl = 0; -static int network_config_interface_idx = 0; static size_t network_config_packet_size = 1024; static int network_config_forward = 0; static int network_config_stats = 0; @@ -1144,7 +1144,10 @@ static int parse_part_encr_aes256 (sockent_t *se, /* {{{ */ cypher = network_get_aes256_cypher (se, pea.iv, sizeof (pea.iv), pea.username); if (cypher == NULL) + { + sfree (pea.username); return (-1); + } payload_len = part_size - (PART_ENCRYPTION_AES256_SIZE + username_len); assert (payload_len > 0); @@ -1156,6 +1159,7 @@ static int parse_part_encr_aes256 (sockent_t *se, /* {{{ */ /* in = */ NULL, /* in len = */ 0); if (err != 0) { + sfree (pea.username); ERROR ("network plugin: gcry_cipher_decrypt returned: %s", gcry_strerror (err)); return (-1); @@ -1174,6 +1178,7 @@ static int parse_part_encr_aes256 (sockent_t *se, /* {{{ */ buffer + buffer_offset, payload_len); if (memcmp (hash, pea.hash, sizeof (hash)) != 0) { + sfree (pea.username); ERROR ("network plugin: Decryption failed: Checksum mismatch."); return (-1); } @@ -1185,6 +1190,8 @@ static int parse_part_encr_aes256 (sockent_t *se, /* {{{ */ *ret_buffer = buffer + part_size; *ret_buffer_len = buffer_len - part_size; + sfree (pea.username); + return (0); } /* }}} int parse_part_encr_aes256 */ /* #endif HAVE_LIBGCRYPT */ @@ -1553,7 +1560,7 @@ static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai) if (setsockopt (se->data.client.fd, IPPROTO_IP, optname, &network_config_ttl, - sizeof (network_config_ttl)) == -1) + sizeof (network_config_ttl)) != 0) { char errbuf[1024]; ERROR ("setsockopt: %s", @@ -1574,7 +1581,7 @@ static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai) if (setsockopt (se->data.client.fd, IPPROTO_IPV6, optname, &network_config_ttl, - sizeof (network_config_ttl)) == -1) + sizeof (network_config_ttl)) != 0) { char errbuf[1024]; ERROR ("setsockopt: %s", @@ -1590,62 +1597,107 @@ static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai) static int network_set_interface (const sockent_t *se, const struct addrinfo *ai) /* {{{ */ { DEBUG ("network plugin: network_set_interface: interface index = %i;", - network_config_interface_idx); + se->interface); assert (se->type == SOCKENT_TYPE_CLIENT); if (ai->ai_family == AF_INET) { struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr; -#if KERNEL_LINUX - struct ip_mreqn mreq; -#else - struct ip_mreq mreq; -#endif - if (! IN_MULTICAST (ntohl (addr->sin_addr.s_addr))) - return (0); + if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr))) + { +#if HAVE_STRUCT_IP_MREQN_IMR_IFINDEX + /* If possible, use the "ip_mreqn" structure which has + * an "interface index" member. Using the interface + * index is preferred here, because of its similarity + * to the way IPv6 handles this. Unfortunately, it + * appears not to be portable. */ + struct ip_mreqn mreq; - mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr; -#if KERNEL_LINUX - mreq.imr_address.s_addr = ntohl (INADDR_ANY); - mreq.imr_ifindex = network_config_interface_idx; + memset (&mreq, 0, sizeof (mreq)); + mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr; + mreq.imr_address.s_addr = ntohl (INADDR_ANY); + mreq.imr_ifindex = se->interface; #else - mreq.imr_interface.s_addr = ntohl (INADDR_ANY); + struct ip_mreq mreq; + + memset (&mreq, 0, sizeof (mreq)); + mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr; + mreq.imr_interface.s_addr = ntohl (INADDR_ANY); #endif - if (setsockopt (se->data.client.fd, IPPROTO_IP, IP_MULTICAST_IF, - &mreq, sizeof (mreq)) == -1) - { - char errbuf[1024]; - ERROR ("setsockopt: %s", - sstrerror (errno, errbuf, sizeof (errbuf))); - return (-1); + if (setsockopt (se->data.client.fd, IPPROTO_IP, IP_MULTICAST_IF, + &mreq, sizeof (mreq)) != 0) + { + char errbuf[1024]; + ERROR ("setsockopt: %s", + sstrerror (errno, errbuf, sizeof (errbuf))); + return (-1); + } + + return (0); } } else if (ai->ai_family == AF_INET6) { struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai->ai_addr; - if (! IN6_IS_ADDR_MULTICAST (&addr->sin6_addr)) + if (IN6_IS_ADDR_MULTICAST (&addr->sin6_addr)) + { + if (setsockopt (se->data.client.fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, + &se->interface, + sizeof (se->interface)) != 0) + { + char errbuf[1024]; + ERROR ("setsockopt: %s", + sstrerror (errno, errbuf, + sizeof (errbuf))); + return (-1); + } + return (0); + } + } - if (setsockopt (se->data.client.fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, - &network_config_interface_idx, - sizeof (network_config_interface_idx)) == -1) + /* else: Not a multicast interface. */ +#if defined(HAVE_IF_INDEXTONAME) && HAVE_IF_INDEXTONAME && defined(SO_BINDTODEVICE) + if (se->interface != 0) + { + char interface_name[IFNAMSIZ]; + + if (if_indextoname (se->interface, interface_name) == NULL) + return (-1); + + DEBUG ("network plugin: Binding socket to interface %s", interface_name); + + if (setsockopt (se->data.client.fd, SOL_SOCKET, SO_BINDTODEVICE, + interface_name, + sizeof(interface_name)) == -1 ) { char errbuf[1024]; ERROR ("setsockopt: %s", - sstrerror (errno, errbuf, - sizeof (errbuf))); + sstrerror (errno, errbuf, sizeof (errbuf))); return (-1); } } +/* #endif HAVE_IF_INDEXTONAME && SO_BINDTODEVICE */ + +#else + WARNING ("network plugin: Cannot set the interface on a unicast " + "socket because " +# if !defined(SO_BINDTODEVICE) + "the the \"SO_BINDTODEVICE\" socket option " +# else + "the \"if_indextoname\" function " +# endif + "is not available on your system."); +#endif return (0); } /* }}} network_set_interface */ -static int network_bind_socket (int fd, const struct addrinfo *ai) +static int network_bind_socket (int fd, const struct addrinfo *ai, const int interface_idx) { int loop = 0; int yes = 1; @@ -1674,7 +1726,7 @@ static int network_bind_socket (int fd, const struct addrinfo *ai) struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr; if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr))) { -#if KERNEL_LINUX +#if HAVE_STRUCT_IP_MREQN_IMR_IFINDEX struct ip_mreqn mreq; #else struct ip_mreq mreq; @@ -1683,9 +1735,12 @@ static int network_bind_socket (int fd, const struct addrinfo *ai) DEBUG ("fd = %i; IPv4 multicast address found", fd); mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr; -#if KERNEL_LINUX +#if HAVE_STRUCT_IP_MREQN_IMR_IFINDEX + /* Set the interface using the interface index if + * possible (available). Unfortunately, the struct + * ip_mreqn is not portable. */ mreq.imr_address.s_addr = ntohl (INADDR_ANY); - mreq.imr_ifindex = network_config_interface_idx; + mreq.imr_ifindex = interface_idx; #else mreq.imr_interface.s_addr = ntohl (INADDR_ANY); #endif @@ -1709,6 +1764,8 @@ static int network_bind_socket (int fd, const struct addrinfo *ai) sizeof (errbuf))); return (-1); } + + return (0); } } else if (ai->ai_family == AF_INET6) @@ -1734,7 +1791,7 @@ static int network_bind_socket (int fd, const struct addrinfo *ai) * single interface; programs running on * multihomed hosts may need to join the same * group on more than one interface.*/ - mreq.ipv6mr_interface = network_config_interface_idx; + mreq.ipv6mr_interface = interface_idx; if (setsockopt (fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, sizeof (loop)) == -1) @@ -1755,8 +1812,35 @@ static int network_bind_socket (int fd, const struct addrinfo *ai) sizeof (errbuf))); return (-1); } + + return (0); + } + } + +#if defined(HAVE_IF_INDEXTONAME) && HAVE_IF_INDEXTONAME && defined(SO_BINDTODEVICE) + /* if a specific interface was set, bind the socket to it. But to avoid + * possible problems with multicast routing, only do that for non-multicast + * addresses */ + if (interface_idx != 0) + { + char interface_name[IFNAMSIZ]; + + if (if_indextoname (interface_idx, interface_name) == NULL) + return (-1); + + DEBUG ("fd = %i; Binding socket to interface %s", fd, interface_name); + + if (setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, + interface_name, + sizeof(interface_name)) == -1 ) + { + char errbuf[1024]; + ERROR ("setsockopt: %s", + sstrerror (errno, errbuf, sizeof (errbuf))); + return (-1); } } +#endif /* HAVE_IF_INDEXTONAME && SO_BINDTODEVICE */ return (0); } /* int network_bind_socket */ @@ -1773,6 +1857,7 @@ static int sockent_init (sockent_t *se, int type) /* {{{ */ se->type = SOCKENT_TYPE_CLIENT; se->node = NULL; se->service = NULL; + se->interface = 0; se->next = NULL; if (type == SOCKENT_TYPE_SERVER) @@ -1921,7 +2006,7 @@ static int sockent_open (sockent_t *se) /* {{{ */ continue; } - status = network_bind_socket (*tmp, ai_ptr); + status = network_bind_socket (*tmp, ai_ptr, se->interface); if (status != 0) { close (*tmp); @@ -2673,7 +2758,8 @@ static int network_config_set_ttl (const oconfig_item_t *ci) /* {{{ */ return (0); } /* }}} int network_config_set_ttl */ -static int network_config_set_interface (const oconfig_item_t *ci) /* {{{ */ +static int network_config_set_interface (const oconfig_item_t *ci, /* {{{ */ + int *interface) { if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) @@ -2683,7 +2769,10 @@ static int network_config_set_interface (const oconfig_item_t *ci) /* {{{ */ return (-1); } - network_config_interface_idx = if_nametoindex (ci->values[0].value.string); + if (interface == NULL) + return (-1); + + *interface = if_nametoindex (ci->values[0].value.string); return (0); } /* }}} int network_config_set_interface */ @@ -2799,6 +2888,10 @@ static int network_config_add_listen (const oconfig_item_t *ci) /* {{{ */ &se->data.server.security_level); else #endif /* HAVE_LIBGCRYPT */ + if (strcasecmp ("Interface", child->key) == 0) + network_config_set_interface (child, + &se->interface); + else { WARNING ("network plugin: Option `%s' is not allowed here.", child->key); @@ -2877,6 +2970,10 @@ static int network_config_add_server (const oconfig_item_t *ci) /* {{{ */ &se->data.client.security_level); else #endif /* HAVE_LIBGCRYPT */ + if (strcasecmp ("Interface", child->key) == 0) + network_config_set_interface (child, + &se->interface); + else { WARNING ("network plugin: Option `%s' is not allowed here.", child->key); @@ -2929,8 +3026,6 @@ static int network_config (oconfig_item_t *ci) /* {{{ */ network_config_add_server (child); else if (strcasecmp ("TimeToLive", child->key) == 0) network_config_set_ttl (child); - else if (strcasecmp ("Interface", child->key) == 0) - network_config_set_interface (child); else if (strcasecmp ("MaxPacketSize", child->key) == 0) network_config_set_buffer_size (child); else if (strcasecmp ("Forward", child->key) == 0)