From: elieyal Date: Mon, 18 Jun 2018 07:59:59 +0000 (+0300) Subject: Add Bind Address option X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=33542aa99bfd8181f6e2f66fff6c59b843d6cf4e;p=collectd.git Add Bind Address option This change allows to Bind Address to an IP address instead of the binding to the Interface Name in the server section. Example: SecurityLevel Encrypt Username "user" Password "secret" BindAddress "10.9.25.59" ResolveInterval 14400 Credit to: Ofir Hermesh --- diff --git a/src/network.c b/src/network.c index 84ba00b5..16ff12d1 100644 --- a/src/network.c +++ b/src/network.c @@ -134,6 +134,7 @@ typedef struct sockent { char *node; char *service; int interface; + struct sockaddr_storage *bind_address; union { struct sockent_client client; @@ -1683,6 +1684,39 @@ static int network_set_interface(const sockent_t *se, return 0; } /* }}} network_set_interface */ +static int network_bind_socket_to_addr(sockent_t *se, + const struct addrinfo *ai) { + + if (se->bind_address == NULL) + return 0; + + DEBUG("fd %i: bind socket to address", se->data.client.fd); + char pbuffer[64]; + + if (ai->ai_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)(se->bind_address); + inet_ntop(AF_INET, &(addr->sin_addr), pbuffer, 64); + INFO("binding client socket to ipv4 address: %s", pbuffer); + if (bind(se->data.client.fd, (struct sockaddr *)addr, sizeof(*addr)) == + -1) { + ERROR("network_bind_socket_to_addr: %s", STRERRNO); + return -1; + } + } else if (ai->ai_family == AF_INET6) { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)(se->bind_address); + inet_ntop(AF_INET, &(addr->sin6_addr), pbuffer, 64); + INFO("binding client socket to ipv6 address: %s", pbuffer); + if (bind(se->data.client.fd, (struct sockaddr *)addr, sizeof(*addr)) == + -1) { + ERROR("network_bind_socket_to_addr: %s", STRERRNO); + return -1; + } + } + + return 0; +} +/* int network_bind_socket_to_addr */ + static int network_bind_socket(int fd, const struct addrinfo *ai, const int interface_idx) { #if KERNEL_SOLARIS @@ -1820,6 +1854,7 @@ static sockent_t *sockent_create(int type) /* {{{ */ se->node = NULL; se->service = NULL; se->interface = 0; + se->bind_address = NULL; se->next = NULL; if (type == SOCKENT_TYPE_SERVER) { @@ -1989,6 +2024,7 @@ static int sockent_client_connect(sockent_t *se) /* {{{ */ network_set_ttl(se, ai_ptr); network_set_interface(se, ai_ptr); + network_bind_socket_to_addr(se, ai_ptr); /* We don't open more than one write-socket per * node/service pair.. */ @@ -2684,6 +2720,42 @@ static int network_config_set_interface(const oconfig_item_t *ci, /* {{{ */ return 0; } /* }}} int network_config_set_interface */ +static int +network_config_set_bind_address(const oconfig_item_t *ci, + struct sockaddr_storage **bind_address) { + char addr_text[256]; + + if (cf_util_get_string_buffer(ci, addr_text, sizeof(addr_text)) != 0) + return -1; + + int ret; + struct addrinfo hint, *res = NULL; + + memset(&hint, '\0', sizeof hint); + hint.ai_family = PF_UNSPEC; + hint.ai_flags = AI_NUMERICHOST; + + ret = getaddrinfo(addr_text, NULL, &hint, &res); + if (ret) { + ERROR("Invalid address"); + return 1; + } + + *bind_address = malloc(sizeof(**bind_address)); + (*bind_address)->ss_family = res->ai_family; + if (res->ai_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)(*bind_address); + inet_pton(AF_INET, addr_text, &(addr->sin_addr)); + } else if (res->ai_family == AF_INET6) { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)(*bind_address); + inet_pton(AF_INET6, addr_text, &(addr->sin6_addr)); + } else { + ERROR("%s is an unknown address format %d\n", addr_text, res->ai_family); + } + + return 0; +} /* int network_config_set_bind_address */ + static int network_config_set_buffer_size(const oconfig_item_t *ci) /* {{{ */ { int tmp = 0; @@ -2843,6 +2915,8 @@ static int network_config_add_server(const oconfig_item_t *ci) /* {{{ */ #endif /* HAVE_GCRYPT_H */ if (strcasecmp("Interface", child->key) == 0) network_config_set_interface(child, &se->interface); + else if (strcasecmp("BindAddress", child->key) == 0) + network_config_set_bind_address(child, &se->bind_address); else if (strcasecmp("ResolveInterval", child->key) == 0) cf_util_get_cdtime(child, &se->data.client.resolve_interval); else {