diff options
Diffstat (limited to 'src/sock.c')
-rw-r--r-- | src/sock.c | 66 |
1 files changed, 58 insertions, 8 deletions
@@ -34,6 +34,7 @@ #include "text.h" #include "conf.h" #include "loop.h" +#include "sblist.h" /* * Return a human readable error for getaddrinfo() and getnameinfo(). @@ -68,7 +69,7 @@ bind_socket (int sockfd, const char *addr, int family) n = getaddrinfo (addr, NULL, &hints, &res); if (n != 0) { log_message (LOG_INFO, - "bind_socket: getaddrinfo failed for %s: ", addr, get_gai_error (n)); + "bind_socket: getaddrinfo failed for %s: %s", addr, get_gai_error (n)); return -1; } @@ -87,12 +88,32 @@ bind_socket (int sockfd, const char *addr, int family) return sockfd; } +/** + * Try binding the given socket to supplied addresses, stopping when one succeeds. + */ +static int +bind_socket_list (int sockfd, sblist *addresses, int family) +{ + size_t nb_addresses = sblist_getsize(addresses); + size_t i; + + for (i = 0; i < nb_addresses; i++) { + const char *address = *(const char **)sblist_get(addresses, i); + if (bind_socket(sockfd, address, family) >= 0) { + log_message(LOG_INFO, "Bound to %s", address); + return 0; + } + } + + return -1; +} + /* * Open a connection to a remote host. It's been re-written to use * the getaddrinfo() library function, which allows for a protocol * independent implementation (mostly for IPv4 and IPv6 addresses.) */ -int opensock (const char *host, int port, const char *bind_to) +int opensock (const char *host, int port, const char *bind_to, const char *bind_to_alt) { int sockfd, n; struct addrinfo hints, *res, *ressave; @@ -103,6 +124,10 @@ int opensock (const char *host, int port, const char *bind_to) log_message(LOG_INFO, "opensock: opening connection to %s:%d", host, port); + if (bind_to) { + log_message(LOG_INFO, + "opensock: bind to %s or %s", bind_to, bind_to_alt); + } memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_UNSPEC; @@ -130,13 +155,16 @@ int opensock (const char *host, int port, const char *bind_to) /* Bind to the specified address */ if (bind_to) { if (bind_socket (sockfd, bind_to, - res->ai_family) < 0) { + res->ai_family) < 0 && + (!bind_to_alt || + bind_socket (sockfd, bind_to_alt, + res->ai_family) < 0)) { close (sockfd); continue; /* can't bind, so try again */ } - } else if (config->bind_address) { - if (bind_socket (sockfd, config->bind_address, - res->ai_family) < 0) { + } else if (config->bind_addrs) { + if (bind_socket_list (sockfd, config->bind_addrs, + res->ai_family) < 0) { close (sockfd); continue; /* can't bind, so try again */ } @@ -277,7 +305,7 @@ static int listen_on_one_socket(struct addrinfo *ad) * Upon success, the listen-fds are added to the listen_fds list * and 0 is returned. Upon error, -1 is returned. */ -int listen_sock (const char *addr, uint16_t port, vector_t listen_fds) +int listen_sock (const char *addr, uint16_t port, sblist* listen_fds) { struct addrinfo hints, *result, *rp; char portstr[6]; @@ -315,7 +343,7 @@ int listen_sock (const char *addr, uint16_t port, vector_t listen_fds) continue; } - vector_append (listen_fds, &listenfd, sizeof(int)); + sblist_add (listen_fds, &listenfd); /* success */ ret = 0; @@ -361,6 +389,28 @@ int getsock_ip (int fd, char *ipaddr) return 0; } +int getmapped_ipv4 (const char *ipv6mapped_conf, const char *ipaddr, char *ipaddr_mapped) +{ + struct in6_addr addr6; + struct in_addr addr; + + memset(&addr6, 0, sizeof(addr6)); + if ( inet_pton(AF_INET6, ipaddr, &addr6) < 0 ) + return -1; + + memcpy(&addr, addr6.s6_addr + 12, sizeof(addr)); + return inet_ntop(AF_INET, &addr, ipaddr_mapped, IP_LENGTH) == NULL ? -1 : 0; +} + +int getmapped_ipv6 (const char *ipv4mapped_conf, const char *ipaddr, char *ipaddr_mapped) +{ + memset(ipaddr_mapped, 0, IP_LENGTH); + strncpy(ipaddr_mapped, ipv4mapped_conf, IP_LENGTH-1); + strncat(ipaddr_mapped, ipaddr, IP_LENGTH-1-strlen(ipaddr_mapped)); + return 0; +} + + /* * Return the peer's socket information. */ |