From b69e09ecd2ab5803178ce84efb020181bb81bd21 Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Wed, 25 Sep 2013 11:53:11 +0200 Subject: [PATCH] libcollectdclient: Implement the lcc_server_set_interface() function. Copied from the network plugin. License changed to MIT with permission from Max Henkel, thank you very much! --- src/libcollectdclient/collectd/network.h | 1 + src/libcollectdclient/network.c | 85 +++++++++++++++++++++++- 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/src/libcollectdclient/collectd/network.h b/src/libcollectdclient/collectd/network.h index 39626667..049f7f02 100644 --- a/src/libcollectdclient/collectd/network.h +++ b/src/libcollectdclient/collectd/network.h @@ -65,6 +65,7 @@ int lcc_server_destroy (lcc_network_t *net, lcc_server_t *srv); /* Configure servers */ int lcc_server_set_ttl (lcc_server_t *srv, uint8_t ttl); +int lcc_server_set_interface (lcc_server_t *srv, char const *interface); int lcc_server_set_security_level (lcc_server_t *srv, lcc_security_level_t level, const char *username, const char *password); diff --git a/src/libcollectdclient/network.c b/src/libcollectdclient/network.c index 6b6450c9..ddb3b5b9 100644 --- a/src/libcollectdclient/network.c +++ b/src/libcollectdclient/network.c @@ -1,6 +1,7 @@ /** * collectd - src/libcollectdclient/network.c - * Copyright (C) 2005-2012 Florian octo Forster + * Copyright (C) 2005-2013 Florian Forster + * Copyright (C) 2010 Max Henkel * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -21,7 +22,8 @@ * DEALINGS IN THE SOFTWARE. * * Authors: - * Florian octo Forster + * Florian Forster + * Max Henkel **/ #include "collectd.h" @@ -41,6 +43,10 @@ # include #endif +#if HAVE_NET_IF_H +# include +#endif + #include "collectd/network.h" #include "collectd/network_buffer.h" @@ -379,6 +385,81 @@ int lcc_server_set_ttl (lcc_server_t *srv, uint8_t ttl) /* {{{ */ return (0); } /* }}} int lcc_server_set_ttl */ +int lcc_server_set_interface (lcc_server_t *srv, char const *interface) /* {{{ */ +{ + int if_index; + int status; + + if ((srv == NULL) || (interface == NULL)) + return (EINVAL); + + if_index = if_nametoindex (interface); + if (if_index == 0) + return (ENOENT); + + /* IPv4 multicast */ + if (srv->sa->sa_family == AF_INET) + { + struct sockaddr_in *addr = (struct sockaddr_in *) srv->sa; + + 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; + + 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 = if_index; +#else + 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 + + status = setsockopt (srv->fd, IPPROTO_IP, IP_MULTICAST_IF, + &mreq, sizeof (mreq)); + if (status != 0) + return (status); + + return (0); + } + } + + /* IPv6 multicast */ + if (srv->sa->sa_family == AF_INET6) + { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *) srv->sa; + + if (IN6_IS_ADDR_MULTICAST (&addr->sin6_addr)) + { + status = setsockopt (srv->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, + &if_index, sizeof (if_index)); + if (status != 0) + return (status); + + return (0); + } + } + + /* else: Not a multicast interface. */ +#if defined(SO_BINDTODEVICE) + status = setsockopt (srv->fd, SOL_SOCKET, SO_BINDTODEVICE, + interface, strlen (interface) + 1); + if (status != 0) + return (-1); +#endif + + return (0); +} /* }}} int lcc_server_set_interface */ + int lcc_server_set_security_level (lcc_server_t *srv, /* {{{ */ lcc_security_level_t level, const char *username, const char *password) -- 2.30.2