summaryrefslogtreecommitdiffhomepage
path: root/src/sock.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sock.c')
-rw-r--r--src/sock.c66
1 files changed, 58 insertions, 8 deletions
diff --git a/src/sock.c b/src/sock.c
index 73ddebd..7aa43e2 100644
--- a/src/sock.c
+++ b/src/sock.c
@@ -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.
*/