Merge "Add marking of DNS sockets for mark based routing"

This commit is contained in:
Geremy Condra 2013-07-11 22:10:30 +00:00 committed by Android (Google) Code Review
commit bb17967761
7 changed files with 72 additions and 35 deletions

View File

@ -207,13 +207,13 @@ void endprotoent(void);
void endservent(void); void endservent(void);
void freehostent(struct hostent *); void freehostent(struct hostent *);
struct hostent *gethostbyaddr(const void *, socklen_t, int); struct hostent *gethostbyaddr(const void *, socklen_t, int);
struct hostent *android_gethostbyaddrforiface(const void *, socklen_t, int, const char*); struct hostent *android_gethostbyaddrforiface(const void *, socklen_t, int, const char*, int);
int gethostbyaddr_r(const void *, int, int, struct hostent *, char *, size_t, struct hostent **, int *); int gethostbyaddr_r(const void *, int, int, struct hostent *, char *, size_t, struct hostent **, int *);
struct hostent *gethostbyname(const char *); struct hostent *gethostbyname(const char *);
int gethostbyname_r(const char *, struct hostent *, char *, size_t, struct hostent **, int *); int gethostbyname_r(const char *, struct hostent *, char *, size_t, struct hostent **, int *);
struct hostent *gethostbyname2(const char *, int); struct hostent *gethostbyname2(const char *, int);
int gethostbyname2_r(const char *, int, struct hostent *, char *, size_t, struct hostent **, int *); int gethostbyname2_r(const char *, int, struct hostent *, char *, size_t, struct hostent **, int *);
struct hostent *android_gethostbynameforiface(const char *, int, const char *); struct hostent *android_gethostbynameforiface(const char *, int, const char *, int);
struct hostent *gethostent(void); struct hostent *gethostent(void);
int gethostent_r(struct hostent *, char *, size_t, struct hostent **, int *); int gethostent_r(struct hostent *, char *, size_t, struct hostent **, int *);
struct hostent *getipnodebyaddr(const void *, size_t, int, int *); struct hostent *getipnodebyaddr(const void *, size_t, int, int *);
@ -241,9 +241,9 @@ void sethostent(int);
void setnetent(int); void setnetent(int);
void setprotoent(int); void setprotoent(int);
int getaddrinfo(const char *, const char *, const struct addrinfo *, struct addrinfo **); int getaddrinfo(const char *, const char *, const struct addrinfo *, struct addrinfo **);
int android_getaddrinfoforiface(const char *, const char *, const struct addrinfo *, const char *, struct addrinfo **); int android_getaddrinfoforiface(const char *, const char *, const struct addrinfo *, const char *, int, struct addrinfo **);
int getnameinfo(const struct sockaddr *, socklen_t, char *, size_t, char *, size_t, int); int getnameinfo(const struct sockaddr *, socklen_t, char *, size_t, char *, size_t, int);
int android_getnameinfoforiface(const struct sockaddr *, socklen_t, char *, size_t, char *, size_t, int, const char *); int android_getnameinfoforiface(const struct sockaddr *, socklen_t, char *, size_t, char *, size_t, int, const char *, int);
void freeaddrinfo(struct addrinfo *); void freeaddrinfo(struct addrinfo *);
const char *gai_strerror(int); const char *gai_strerror(int);
void setnetgrent(const char *); void setnetgrent(const char *);

View File

@ -126,7 +126,7 @@ static struct hostent *_gethtbyname2(const char *, int);
static int _dns_gethtbyaddr(void *, void *, va_list); static int _dns_gethtbyaddr(void *, void *, va_list);
static int _dns_gethtbyname(void *, void *, va_list); static int _dns_gethtbyname(void *, void *, va_list);
static struct hostent *gethostbyname_internal(const char *, int, res_state, const char *); static struct hostent *gethostbyname_internal(const char *, int, res_state, const char *, int);
static const ns_src default_dns_files[] = { static const ns_src default_dns_files[] = {
{ NSSRC_FILES, NS_SUCCESS }, { NSSRC_FILES, NS_SUCCESS },
@ -497,13 +497,13 @@ gethostbyname(const char *name)
/* try IPv6 first - if that fails do IPv4 */ /* try IPv6 first - if that fails do IPv4 */
if (res->options & RES_USE_INET6) { if (res->options & RES_USE_INET6) {
hp = gethostbyname_internal(name, AF_INET6, res, NULL); hp = gethostbyname_internal(name, AF_INET6, res, NULL, 0);
if (hp) { if (hp) {
__res_put_state(res); __res_put_state(res);
return hp; return hp;
} }
} }
hp = gethostbyname_internal(name, AF_INET, res, NULL); hp = gethostbyname_internal(name, AF_INET, res, NULL, 0);
__res_put_state(res); __res_put_state(res);
return hp; return hp;
} }
@ -511,18 +511,18 @@ gethostbyname(const char *name)
struct hostent * struct hostent *
gethostbyname2(const char *name, int af) gethostbyname2(const char *name, int af)
{ {
return android_gethostbynameforiface(name, af, NULL); return android_gethostbynameforiface(name, af, NULL, 0);
} }
struct hostent * struct hostent *
android_gethostbynameforiface(const char *name, int af, const char *iface) android_gethostbynameforiface(const char *name, int af, const char *iface, int mark)
{ {
struct hostent *hp; struct hostent *hp;
res_state res = __res_get_state(); res_state res = __res_get_state();
if (res == NULL) if (res == NULL)
return NULL; return NULL;
hp = gethostbyname_internal(name, af, res, iface); hp = gethostbyname_internal(name, af, res, iface, mark);
__res_put_state(res); __res_put_state(res);
return hp; return hp;
} }
@ -741,7 +741,7 @@ gethostbyname_internal_real(const char *name, int af, res_state res)
// very similar in proxy-ness to android_getaddrinfo_proxy // very similar in proxy-ness to android_getaddrinfo_proxy
static struct hostent * static struct hostent *
gethostbyname_internal(const char *name, int af, res_state res, const char *iface) gethostbyname_internal(const char *name, int af, res_state res, const char *iface, int mark)
{ {
const char *cache_mode = getenv("ANDROID_DNS_MODE"); const char *cache_mode = getenv("ANDROID_DNS_MODE");
FILE* proxy = NULL; FILE* proxy = NULL;
@ -749,6 +749,7 @@ gethostbyname_internal(const char *name, int af, res_state res, const char *ifac
if (cache_mode != NULL && strcmp(cache_mode, "local") == 0) { if (cache_mode != NULL && strcmp(cache_mode, "local") == 0) {
res_setiface(res, iface); res_setiface(res, iface);
res_setmark(res, mark);
return gethostbyname_internal_real(name, af, res); return gethostbyname_internal_real(name, af, res);
} }
@ -780,7 +781,7 @@ exit:
struct hostent * struct hostent *
android_gethostbyaddrforiface_proxy(const void *addr, android_gethostbyaddrforiface_proxy(const void *addr,
socklen_t len, int af, const char* iface) socklen_t len, int af, const char* iface, int mark)
{ {
struct hostent *result = NULL; struct hostent *result = NULL;
FILE* proxy = android_open_proxy(); FILE* proxy = android_open_proxy();
@ -810,7 +811,7 @@ exit:
struct hostent * struct hostent *
android_gethostbyaddrforiface_real(const void *addr, android_gethostbyaddrforiface_real(const void *addr,
socklen_t len, int af, const char* iface) socklen_t len, int af, const char* iface, int mark)
{ {
const u_char *uaddr = (const u_char *)addr; const u_char *uaddr = (const u_char *)addr;
socklen_t size; socklen_t size;
@ -858,28 +859,28 @@ android_gethostbyaddrforiface_real(const void *addr,
hp = NULL; hp = NULL;
h_errno = NETDB_INTERNAL; h_errno = NETDB_INTERNAL;
if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr", if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
default_dns_files, uaddr, len, af, iface) != NS_SUCCESS) default_dns_files, uaddr, len, af, iface, mark) != NS_SUCCESS)
return NULL; return NULL;
h_errno = NETDB_SUCCESS; h_errno = NETDB_SUCCESS;
return hp; return hp;
} }
struct hostent * struct hostent *
android_gethostbyaddrforiface(const void *addr, socklen_t len, int af, const char* iface) android_gethostbyaddrforiface(const void *addr, socklen_t len, int af, const char* iface, int mark)
{ {
const char *cache_mode = getenv("ANDROID_DNS_MODE"); const char *cache_mode = getenv("ANDROID_DNS_MODE");
if (cache_mode == NULL || strcmp(cache_mode, "local") != 0) { if (cache_mode == NULL || strcmp(cache_mode, "local") != 0) {
return android_gethostbyaddrforiface_proxy(addr, len, af, iface); return android_gethostbyaddrforiface_proxy(addr, len, af, iface, mark);
} else { } else {
return android_gethostbyaddrforiface_real(addr,len, af,iface); return android_gethostbyaddrforiface_real(addr,len, af, iface, mark);
} }
} }
struct hostent * struct hostent *
gethostbyaddr(const void *addr, socklen_t len, int af) gethostbyaddr(const void *addr, socklen_t len, int af)
{ {
return android_gethostbyaddrforiface(addr, len, af, NULL); return android_gethostbyaddrforiface(addr, len, af, NULL, 0);
} }
@ -1315,6 +1316,7 @@ _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap)
int len, af, advance; int len, af, advance;
res_state res; res_state res;
const char* iface; const char* iface;
int mark;
res_static rs = __res_get_static(); res_static rs = __res_get_static();
assert(rv != NULL); assert(rv != NULL);
@ -1323,6 +1325,7 @@ _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap)
len = va_arg(ap, int); len = va_arg(ap, int);
af = va_arg(ap, int); af = va_arg(ap, int);
iface = va_arg(ap, char *); iface = va_arg(ap, char *);
mark = va_arg(ap, int);
switch (af) { switch (af) {
case AF_INET: case AF_INET:
@ -1365,6 +1368,7 @@ _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap)
return NS_NOTFOUND; return NS_NOTFOUND;
} }
res_setiface(res, iface); res_setiface(res, iface);
res_setmark(res, mark);
n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf)); n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf));
if (n < 0) { if (n < 0) {
free(buf); free(buf);

View File

@ -214,7 +214,7 @@ struct res_target {
static int str2number(const char *); static int str2number(const char *);
static int explore_fqdn(const struct addrinfo *, const char *, static int explore_fqdn(const struct addrinfo *, const char *,
const char *, struct addrinfo **, const char *iface); const char *, struct addrinfo **, const char *iface, int mark);
static int explore_null(const struct addrinfo *, static int explore_null(const struct addrinfo *,
const char *, struct addrinfo **); const char *, struct addrinfo **);
static int explore_numeric(const struct addrinfo *, const char *, static int explore_numeric(const struct addrinfo *, const char *,
@ -577,12 +577,12 @@ int
getaddrinfo(const char *hostname, const char *servname, getaddrinfo(const char *hostname, const char *servname,
const struct addrinfo *hints, struct addrinfo **res) const struct addrinfo *hints, struct addrinfo **res)
{ {
return android_getaddrinfoforiface(hostname, servname, hints, NULL, res); return android_getaddrinfoforiface(hostname, servname, hints, NULL, 0, res);
} }
int int
android_getaddrinfoforiface(const char *hostname, const char *servname, android_getaddrinfoforiface(const char *hostname, const char *servname,
const struct addrinfo *hints, const char *iface, struct addrinfo **res) const struct addrinfo *hints, const char *iface, int mark, struct addrinfo **res)
{ {
struct addrinfo sentinel; struct addrinfo sentinel;
struct addrinfo *cur; struct addrinfo *cur;
@ -761,7 +761,7 @@ android_getaddrinfoforiface(const char *hostname, const char *servname,
pai->ai_protocol = ex->e_protocol; pai->ai_protocol = ex->e_protocol;
error = explore_fqdn(pai, hostname, servname, error = explore_fqdn(pai, hostname, servname,
&cur->ai_next, iface); &cur->ai_next, iface, mark);
while (cur && cur->ai_next) while (cur && cur->ai_next)
cur = cur->ai_next; cur = cur->ai_next;
@ -794,7 +794,7 @@ android_getaddrinfoforiface(const char *hostname, const char *servname,
*/ */
static int static int
explore_fqdn(const struct addrinfo *pai, const char *hostname, explore_fqdn(const struct addrinfo *pai, const char *hostname,
const char *servname, struct addrinfo **res, const char *iface) const char *servname, struct addrinfo **res, const char *iface, int mark)
{ {
struct addrinfo *result; struct addrinfo *result;
struct addrinfo *cur; struct addrinfo *cur;
@ -820,7 +820,7 @@ explore_fqdn(const struct addrinfo *pai, const char *hostname,
return 0; return 0;
switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
default_dns_files, hostname, pai, iface)) { default_dns_files, hostname, pai, iface, mark)) {
case NS_TRYAGAIN: case NS_TRYAGAIN:
error = EAI_AGAIN; error = EAI_AGAIN;
goto free; goto free;
@ -1889,10 +1889,12 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
struct res_target q, q2; struct res_target q, q2;
res_state res; res_state res;
const char* iface; const char* iface;
int mark;
name = va_arg(ap, char *); name = va_arg(ap, char *);
pai = va_arg(ap, const struct addrinfo *); pai = va_arg(ap, const struct addrinfo *);
iface = va_arg(ap, char *); iface = va_arg(ap, char *);
mark = va_arg(ap, int);
//fprintf(stderr, "_dns_getaddrinfo() name = '%s'\n", name); //fprintf(stderr, "_dns_getaddrinfo() name = '%s'\n", name);
memset(&q, 0, sizeof(q)); memset(&q, 0, sizeof(q));
@ -1980,6 +1982,7 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
* and have a cache hit that would be wasted, so we do the rest there on miss * and have a cache hit that would be wasted, so we do the rest there on miss
*/ */
res_setiface(res, iface); res_setiface(res, iface);
res_setmark(res, mark);
if (res_searchN(name, &q, res) < 0) { if (res_searchN(name, &q, res) < 0) {
__res_put_state(res); __res_put_state(res);
free(buf); free(buf);

View File

@ -93,7 +93,7 @@ struct sockinet {
}; };
static int getnameinfo_inet(const struct sockaddr *, socklen_t, char *, static int getnameinfo_inet(const struct sockaddr *, socklen_t, char *,
socklen_t, char *, socklen_t, int, const char*); socklen_t, char *, socklen_t, int, const char*, int);
#ifdef INET6 #ifdef INET6
static int ip6_parsenumeric(const struct sockaddr *, const char *, char *, static int ip6_parsenumeric(const struct sockaddr *, const char *, char *,
socklen_t, int); socklen_t, int);
@ -108,16 +108,16 @@ static int getnameinfo_local(const struct sockaddr *, socklen_t, char *,
*/ */
int getnameinfo(const struct sockaddr* sa, socklen_t salen, char* host, size_t hostlen, char* serv, size_t servlen, int flags) int getnameinfo(const struct sockaddr* sa, socklen_t salen, char* host, size_t hostlen, char* serv, size_t servlen, int flags)
{ {
return android_getnameinfoforiface(sa, salen, host, hostlen, serv, servlen, flags, NULL); return android_getnameinfoforiface(sa, salen, host, hostlen, serv, servlen, flags, NULL, 0);
} }
int android_getnameinfoforiface(const struct sockaddr* sa, socklen_t salen, char* host, size_t hostlen, char* serv, size_t servlen, int flags, const char* iface) int android_getnameinfoforiface(const struct sockaddr* sa, socklen_t salen, char* host, size_t hostlen, char* serv, size_t servlen, int flags, const char* iface, int mark)
{ {
switch (sa->sa_family) { switch (sa->sa_family) {
case AF_INET: case AF_INET:
case AF_INET6: case AF_INET6:
return getnameinfo_inet(sa, salen, host, hostlen, return getnameinfo_inet(sa, salen, host, hostlen,
serv, servlen, flags, iface); serv, servlen, flags, iface, mark);
case AF_LOCAL: case AF_LOCAL:
return getnameinfo_local(sa, salen, host, hostlen, return getnameinfo_local(sa, salen, host, hostlen,
serv, servlen, flags); serv, servlen, flags);
@ -158,10 +158,10 @@ getnameinfo_local(const struct sockaddr *sa, socklen_t salen,
* the address. On failure -1 is returned in which case * the address. On failure -1 is returned in which case
* normal execution flow shall continue. */ * normal execution flow shall continue. */
static int static int
android_gethostbyaddr_proxy(char* nameBuf, size_t nameBufLen, const void *addr, socklen_t addrLen, int addrFamily, const char* iface) android_gethostbyaddr_proxy(char* nameBuf, size_t nameBufLen, const void *addr, socklen_t addrLen, int addrFamily, const char* iface, int mark)
{ {
struct hostent *hostResult = struct hostent *hostResult =
android_gethostbyaddrforiface_proxy(addr, addrLen, addrFamily, iface); android_gethostbyaddrforiface_proxy(addr, addrLen, addrFamily, iface, mark);
if (hostResult == NULL) return 0; if (hostResult == NULL) return 0;
@ -179,7 +179,7 @@ static int
getnameinfo_inet(const struct sockaddr* sa, socklen_t salen, getnameinfo_inet(const struct sockaddr* sa, socklen_t salen,
char *host, socklen_t hostlen, char *host, socklen_t hostlen,
char *serv, socklen_t servlen, char *serv, socklen_t servlen,
int flags, const char* iface) int flags, const char* iface, int mark)
{ {
const struct afd *afd; const struct afd *afd;
struct servent *sp; struct servent *sp;
@ -321,14 +321,15 @@ getnameinfo_inet(const struct sockaddr* sa, socklen_t salen,
char android_proxy_buf[MAXDNAME]; char android_proxy_buf[MAXDNAME];
int hostnamelen = android_gethostbyaddr_proxy(android_proxy_buf, int hostnamelen = android_gethostbyaddr_proxy(android_proxy_buf,
MAXDNAME, addr, afd->a_addrlen, afd->a_af, iface); MAXDNAME, addr, afd->a_addrlen, afd->a_af, iface, mark);
if (hostnamelen > 0) { if (hostnamelen > 0) {
hp = &android_proxy_hostent; hp = &android_proxy_hostent;
hp->h_name = android_proxy_buf; hp->h_name = android_proxy_buf;
} else if (!hostnamelen) { } else if (!hostnamelen) {
hp = NULL; hp = NULL;
} else { } else {
hp = android_gethostbyaddrforiface(addr, afd->a_addrlen, afd->a_af, iface); hp = android_gethostbyaddrforiface(addr, afd->a_addrlen, afd->a_af,
iface, mark);
} }
if (hp) { if (hp) {

View File

@ -806,4 +806,11 @@ void res_setiface(res_state statp, const char* iface)
} }
} }
} }
void res_setmark(res_state statp, int mark)
{
if (statp != NULL) {
statp->_mark = mark;
}
}
#endif /* ANDROID_CHANGES */ #endif /* ANDROID_CHANGES */

View File

@ -762,10 +762,13 @@ send_vc(res_state statp,
if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) { if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
struct sockaddr_storage peer; struct sockaddr_storage peer;
socklen_t size = sizeof peer; socklen_t size = sizeof peer;
int old_mark;
int mark_size = sizeof(old_mark);
if (getpeername(statp->_vcsock, if (getpeername(statp->_vcsock,
(struct sockaddr *)(void *)&peer, &size) < 0 || (struct sockaddr *)(void *)&peer, &size) < 0 ||
!sock_eq((struct sockaddr *)(void *)&peer, nsap)) { !sock_eq((struct sockaddr *)(void *)&peer, nsap) ||
getsockopt(statp->_vcsock, SOL_SOCKET, SO_MARK, &old_mark, &mark_size) < 0 ||
old_mark != statp->_mark) {
res_nclose(statp); res_nclose(statp);
statp->_flags &= ~RES_F_VC; statp->_flags &= ~RES_F_VC;
} }
@ -795,6 +798,14 @@ send_vc(res_state statp,
return (-1); return (-1);
} }
} }
if (statp->_mark != 0) {
if (setsockopt(statp->_vcsock, SOL_SOCKET,
SO_MARK, &statp->_mark, sizeof(statp->_mark)) < 0) {
*terrno = errno;
Perror(statp, stderr, "setsockopt", errno);
return -1;
}
}
errno = 0; errno = 0;
if (random_bind(statp->_vcsock,nsap->sa_family) < 0) { if (random_bind(statp->_vcsock,nsap->sa_family) < 0) {
*terrno = errno; *terrno = errno;
@ -1070,6 +1081,14 @@ send_dg(res_state statp,
return (-1); return (-1);
} }
} }
if (statp->_mark != 0) {
if (setsockopt(EXT(statp).nssocks[ns], SOL_SOCKET,
SO_MARK, &(statp->_mark), sizeof(statp->_mark)) < 0) {
res_nclose(statp);
return -1;
}
}
#ifndef CANNOT_CONNECT_DGRAM #ifndef CANNOT_CONNECT_DGRAM
/* /*
* On a 4.3BSD+ machine (client and server, * On a 4.3BSD+ machine (client and server,
@ -1097,6 +1116,7 @@ send_dg(res_state statp,
#endif /* !CANNOT_CONNECT_DGRAM */ #endif /* !CANNOT_CONNECT_DGRAM */
Dprint(statp->options & RES_DEBUG, Dprint(statp->options & RES_DEBUG,
(stdout, ";; new DG socket\n")) (stdout, ";; new DG socket\n"))
} }
s = EXT(statp).nssocks[ns]; s = EXT(statp).nssocks[ns];
#ifndef CANNOT_CONNECT_DGRAM #ifndef CANNOT_CONNECT_DGRAM

View File

@ -175,6 +175,7 @@ struct __res_state {
res_send_qhook qhook; /* query hook */ res_send_qhook qhook; /* query hook */
res_send_rhook rhook; /* response hook */ res_send_rhook rhook; /* response hook */
int res_h_errno; /* last one set for this context */ int res_h_errno; /* last one set for this context */
int _mark; /* If non-0 SET_MARK to _mark on all request sockets */
int _vcsock; /* PRIVATE: for res_send VC i/o */ int _vcsock; /* PRIVATE: for res_send VC i/o */
u_int _flags; /* PRIVATE: see below */ u_int _flags; /* PRIVATE: see below */
u_int _pad; /* make _u 64 bit aligned */ u_int _pad; /* make _u 64 bit aligned */
@ -490,6 +491,7 @@ int res_getservers(res_state,
union res_sockaddr_union *, int); union res_sockaddr_union *, int);
void res_setiface(); void res_setiface();
void res_setmark();
u_int res_randomid(void); u_int res_randomid(void);
__END_DECLS __END_DECLS