Don't use a bind address for nameservers on loopback

If the user sets a bind address to use for nameservers, and a
nameserver happens to be on 127.0.0.1, the nameserver will generally
fail.  This patch alters this behavior so that the bind address is
only applied when the nameserver is on a non-loopback address.
This commit is contained in:
Nick Mathewson 2010-01-20 12:56:54 -05:00
parent 0683950384
commit 8d4aaf9086
4 changed files with 74 additions and 3 deletions

View File

@ -2448,7 +2448,8 @@ _evdns_nameserver_add_impl(struct evdns_base *base, const struct sockaddr *addre
if (ns->socket < 0) { err = 1; goto out1; } if (ns->socket < 0) { err = 1; goto out1; }
evutil_make_socket_nonblocking(ns->socket); evutil_make_socket_nonblocking(ns->socket);
if (base->global_outgoing_addrlen) { if (base->global_outgoing_addrlen &&
!evutil_sockaddr_is_loopback(address)) {
if (bind(ns->socket, if (bind(ns->socket,
(struct sockaddr*)&base->global_outgoing_address, (struct sockaddr*)&base->global_outgoing_address,
base->global_outgoing_addrlen) < 0) { base->global_outgoing_addrlen) < 0) {

View File

@ -1849,3 +1849,25 @@ _evutil_weakrand(void)
#endif #endif
} }
int
evutil_sockaddr_is_loopback(const struct sockaddr *addr)
{
static const char LOOPBACK_S6[16] =
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1";
if (addr->sa_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in *)addr;
return (ntohl(sin->sin_addr.s_addr) & 0xff000000) == 0x7f000000;
} else if (addr->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
/*
int i;
for (i=0;i<14;++i)
if (sin6->sin6_addr.s6_addr[i] != 0)
return 1;
return sin6->sin6_addr.s6_addr[15] == 1;
*/
return !memcmp(sin6->sin6_addr.s6_addr, LOOPBACK_S6, 16);
}
return 0;
}

View File

@ -275,6 +275,50 @@ regress_sockaddr_port_parse(void *ptr)
} }
} }
static struct sa_pred_ent {
const char *parse;
int is_loopback;
} sa_pred_entries[] = {
{ "127.0.0.1", 1 },
{ "127.0.3.2", 1 },
{ "128.1.2.3", 0 },
{ "18.0.0.1", 0 },
{ "129.168.1.1", 0 },
{ "::1", 1 },
{ "::0", 0 },
{ "f::1", 0 },
{ "::501", 0 },
{ NULL, 0 },
};
static void
test_evutil_sockaddr_predicates(void *ptr)
{
struct sockaddr_storage ss;
int r, i;
for (i=0; sa_pred_entries[i].parse; ++i) {
struct sa_pred_ent *ent = &sa_pred_entries[i];
int len = sizeof(ss);
r = evutil_parse_sockaddr_port(ent->parse, (struct sockaddr*)&ss, &len);
if (r<0) {
TT_FAIL(("Couldn't parse %s!", ent->parse));
continue;
}
/* sockaddr_is_loopback */
if (ent->is_loopback != evutil_sockaddr_is_loopback((struct sockaddr*)&ss)) {
TT_FAIL(("evutil_sockaddr_loopback(%s) not as expected",
ent->parse));
}
}
}
static void static void
test_evutil_strtoll(void *ptr) test_evutil_strtoll(void *ptr)
{ {
@ -758,6 +802,7 @@ struct testcase_t util_testcases[] = {
{ "ipv4_parse", regress_ipv4_parse, 0, NULL, NULL }, { "ipv4_parse", regress_ipv4_parse, 0, NULL, NULL },
{ "ipv6_parse", regress_ipv6_parse, 0, NULL, NULL }, { "ipv6_parse", regress_ipv6_parse, 0, NULL, NULL },
{ "sockaddr_port_parse", regress_sockaddr_port_parse, 0, NULL, NULL }, { "sockaddr_port_parse", regress_sockaddr_port_parse, 0, NULL, NULL },
{ "sockaddr_predicates", test_evutil_sockaddr_predicates, 0,NULL,NULL },
{ "evutil_snprintf", test_evutil_snprintf, 0, NULL, NULL }, { "evutil_snprintf", test_evutil_snprintf, 0, NULL, NULL },
{ "evutil_strtoll", test_evutil_strtoll, 0, NULL, NULL }, { "evutil_strtoll", test_evutil_strtoll, 0, NULL, NULL },
{ "evutil_casecmp", test_evutil_casecmp, 0, NULL, NULL }, { "evutil_casecmp", test_evutil_casecmp, 0, NULL, NULL },

View File

@ -232,12 +232,15 @@ void evutil_adjust_hints_for_addrconfig(struct evutil_addrinfo *hints);
int evutil_getaddrinfo_common(const char *nodename, const char *servname, int evutil_getaddrinfo_common(const char *nodename, const char *servname,
struct evutil_addrinfo *hints, struct evutil_addrinfo **res, int *portnum); struct evutil_addrinfo *hints, struct evutil_addrinfo **res, int *portnum);
int int evutil_getaddrinfo_async(struct evdns_base *dns_base,
evutil_getaddrinfo_async(struct evdns_base *dns_base,
const char *nodename, const char *servname, const char *nodename, const char *servname,
const struct evutil_addrinfo *hints_in, const struct evutil_addrinfo *hints_in,
void (*cb)(int, struct evutil_addrinfo *, void *), void *arg); void (*cb)(int, struct evutil_addrinfo *, void *), void *arg);
/** Return true iff sa is a looback address. (That is, it is 127.0.0.1/8, or
* ::1). */
int evutil_sockaddr_is_loopback(const struct sockaddr *sa);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif