summaryrefslogtreecommitdiff
path: root/ares_process.c
diff options
context:
space:
mode:
authorBen Greear <greearb@candelatech.com>2010-07-18 23:58:39 +0200
committerDaniel Stenberg <daniel@haxx.se>2010-07-18 23:58:39 +0200
commite3b04e5a4796215d2483aba3cb75c72ba337ac14 (patch)
tree3671ebcef566e0e32f00a50b0557b88bd8b67475 /ares_process.c
parent45a09b7efba9665bdc08e227f4baf51fab3862ae (diff)
downloadc-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.c40
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;