diff options
author | Ben Greear <greearb@candelatech.com> | 2010-07-18 23:58:39 +0200 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2010-07-18 23:58:39 +0200 |
commit | e3b04e5a4796215d2483aba3cb75c72ba337ac14 (patch) | |
tree | 3671ebcef566e0e32f00a50b0557b88bd8b67475 /ares_process.c | |
parent | 45a09b7efba9665bdc08e227f4baf51fab3862ae (diff) | |
download | c-ares-e3b04e5a4796215d2483aba3cb75c72ba337ac14.tar.gz c-ares-e3b04e5a4796215d2483aba3cb75c72ba337ac14.tar.bz2 c-ares-e3b04e5a4796215d2483aba3cb75c72ba337ac14.zip |
local-bind: Support binding to local interface/IPs
Add 3 new functions to set the local binding for the out-going
socket connection, and add ares_set_servers_csv() to set a
list of servers at once as a comma-separated string.
Signed-off-by: Ben Greear <greearb@candelatech.com>
Diffstat (limited to 'ares_process.c')
-rw-r--r-- | ares_process.c | 40 |
1 files changed, 35 insertions, 5 deletions
diff --git a/ares_process.c b/ares_process.c index 3ef1ddb..14dce71 100644 --- a/ares_process.c +++ b/ares_process.c @@ -91,7 +91,6 @@ static void skip_server(ares_channel channel, struct query *query, int whichserver); static void next_server(ares_channel channel, struct query *query, struct timeval *now); -static int configure_socket(ares_socket_t s, ares_channel channel); static int open_tcp_socket(ares_channel channel, struct server_state *server); static int open_udp_socket(ares_channel channel, struct server_state *server); static int same_questions(const unsigned char *qbuf, int qlen, @@ -869,7 +868,7 @@ static int setsocknonblock(ares_socket_t sockfd, /* operate on this */ #endif } -static int configure_socket(ares_socket_t s, ares_channel channel) +static int configure_socket(ares_socket_t s, int family, ares_channel channel) { setsocknonblock(s, TRUE); @@ -892,8 +891,39 @@ static int configure_socket(ares_socket_t s, ares_channel channel) sizeof(channel->socket_receive_buffer_size)) == -1) return -1; +#ifdef SO_BINDTODEVICE + if (channel->local_dev_name[0]) { + if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, + channel->local_dev_name, sizeof(channel->local_dev_name))) { + /* Only root can do this, and usually not fatal if it doesn't work, so */ + /* just continue on. */ + } + } +#endif + + if (family == AF_INET) { + if (channel->local_ip4) { + struct sockaddr_in sa; + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = htonl(channel->local_ip4); + if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0) + return -1; + } + } + else if (family == AF_INET6) { + if (memcmp(channel->local_ip6, &in6addr_any, sizeof(channel->local_ip6)) != 0) { + struct sockaddr_in6 sa; + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + memcpy(&sa.sin6_addr, channel->local_ip6, sizeof(channel->local_ip6)); + if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0) + return -1; + } + } + return 0; - } +} static int open_tcp_socket(ares_channel channel, struct server_state *server) { @@ -936,7 +966,7 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server) return -1; /* Configure it. */ - if (configure_socket(s, channel) < 0) + if (configure_socket(s, server->addr.family, channel) < 0) { sclose(s); return -1; @@ -1028,7 +1058,7 @@ static int open_udp_socket(ares_channel channel, struct server_state *server) return -1; /* Set the socket non-blocking. */ - if (configure_socket(s, channel) < 0) + if (configure_socket(s, server->addr.family, channel) < 0) { sclose(s); return -1; |