From 01dc3f4fea73e4df31cc3e3bb1cd5580fc0d7938 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Wed, 4 Jun 2014 16:53:39 -0400 Subject: [PATCH] add support for reverse name lookups from hosts file to getnameinfo this also affects the legacy gethostbyaddr family, which uses getnameinfo as its backend. some other minor changes associated with the refactoring of source files are also made; in particular, the resolv.conf parser now uses the same code that's used elsewhere to handle ip literals, so as a side effect it can now accept a scope id for nameserver addressed with link-local scope. --- src/network/getnameinfo.c | 58 +++++++++++++++++++++++++++++++--- src/network/lookup.h | 1 + src/network/lookup_ipliteral.c | 51 ++++++++++++++++++++++++++++++ src/network/lookup_name.c | 41 ++---------------------- src/network/res_msend.c | 21 ++++++++---- 5 files changed, 122 insertions(+), 50 deletions(-) create mode 100644 src/network/lookup_ipliteral.c diff --git a/src/network/getnameinfo.c b/src/network/getnameinfo.c index 6962ed1a..708ec5e0 100644 --- a/src/network/getnameinfo.c +++ b/src/network/getnameinfo.c @@ -6,6 +6,9 @@ #include #include #include +#include +#include "lookup.h" +#include "stdio_impl.h" int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *), void *); int __dn_expand(const unsigned char *, const unsigned char *, const unsigned char *, char *, int); @@ -42,6 +45,47 @@ static void mkptr6(char *s, const unsigned char *ip) strcpy(s, "ip6.arpa"); } +static char *reverse_hosts(char *buf, const unsigned char *a, unsigned scopeid, int family) +{ + char line[512], *p, *z; + unsigned char _buf[1032], atmp[16]; + struct address iplit; + FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf); + if (!f) return 0; + if (family == AF_INET) { + memcpy(atmp+12, a, 4); + memcpy(atmp, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + a = atmp; + } + while (fgets(line, sizeof line, f)) { + if ((p=strchr(line, '#'))) *p++='\n', *p=0; + + for (p=line; *p && !isspace(*p); p++); + *p++ = 0; + if (__lookup_ipliteral(&iplit, line, AF_UNSPEC)<=0) + continue; + + if (iplit.family == AF_INET) { + memcpy(iplit.addr+12, iplit.addr, 4); + memcpy(iplit.addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + iplit.scopeid = 0; + } + + if (memcmp(a, iplit.addr, 16) || iplit.scopeid != scopeid) + continue; + + for (; *p && isspace(*p); p++); + for (z=p; *z && !isspace(*z); z++); + *z = 0; + if (z-p < 256) { + memcpy(buf, p, z-p+1); + break; + } + } + __fclose_ca(f); + return 0; +} + static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet) { char tmp[256]; @@ -62,13 +106,14 @@ int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl, char buf[256], num[3*sizeof(int)+1]; int af = sa->sa_family; unsigned char *a; - unsigned x; + unsigned scopeid; switch (af) { case AF_INET: a = (void *)&((struct sockaddr_in *)sa)->sin_addr; if (sl != sizeof(struct sockaddr_in)) return EAI_FAMILY; mkptr4(ptr, a); + scopeid = 0; break; case AF_INET6: a = (void *)&((struct sockaddr_in6 *)sa)->sin6_addr; @@ -77,6 +122,7 @@ int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl, mkptr6(ptr, a); else mkptr4(ptr, a+12); + scopeid = ((struct sockaddr_in6 *)sa)->sin6_scope_id; break; default: return EAI_FAMILY; @@ -85,6 +131,9 @@ int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl, if (node && nodelen) { buf[0] = 0; if (!(flags & NI_NUMERICHOST)) { + reverse_hosts(buf, a, scopeid, af); + } + if (!*buf && !(flags & NI_NUMERICHOST)) { unsigned char query[18+PTR_MAX], reply[512]; int qlen = __res_mkquery(0, ptr, 1, RR_PTR, 0, 0, 0, query, sizeof query); @@ -96,15 +145,14 @@ int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl, if (!*buf) { if (flags & NI_NAMEREQD) return EAI_NONAME; inet_ntop(af, a, buf, sizeof buf); - if (af == AF_INET6 && - (x = ((struct sockaddr_in6 *)sa)->sin6_scope_id)) { + if (scopeid) { char *p = 0, tmp[IF_NAMESIZE+1]; if (!(flags & NI_NUMERICSCOPE) && (IN6_IS_ADDR_LINKLOCAL(a) || IN6_IS_ADDR_MC_LINKLOCAL(a))) - p = if_indextoname(x, tmp+1); + p = if_indextoname(scopeid, tmp+1); if (!p) - p = itoa(num, x); + p = itoa(num, scopeid); *--p = '%'; strcat(buf, p); } diff --git a/src/network/lookup.h b/src/network/lookup.h index 82c969ec..19c9e488 100644 --- a/src/network/lookup.h +++ b/src/network/lookup.h @@ -22,5 +22,6 @@ struct service { int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int proto, int flags); int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, int flags); +int __lookup_ipliteral(struct address buf[static 1], const char *name, int family); #endif diff --git a/src/network/lookup_ipliteral.c b/src/network/lookup_ipliteral.c new file mode 100644 index 00000000..8dacffc1 --- /dev/null +++ b/src/network/lookup_ipliteral.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "lookup.h" + +int __inet_aton(const char *, struct in_addr *); + +int __lookup_ipliteral(struct address buf[static 1], const char *name, int family) +{ + struct in_addr a4; + struct in6_addr a6; + if (family != AF_INET6 && __inet_aton(name, &a4)>0) { + memcpy(&buf[0].addr, &a4, sizeof a4); + buf[0].family = AF_INET; + buf[0].scopeid = 0; + return 1; + } + if (family != AF_INET) { + char tmp[64]; + char *p = strchr(name, '%'), *z; + unsigned long long scopeid; + if (p && p-name < 64) { + memcpy(tmp, name, p-name); + tmp[p-name] = 0; + name = tmp; + } + if (inet_pton(AF_INET6, name, &a6)<=0) return 0; + memcpy(&buf[0].addr, &a6, sizeof a6); + buf[0].family = AF_INET6; + if (p) { + if (isdigit(*++p)) scopeid = strtoull(p, &z, 10); + else z = p-1; + if (*z) { + if (!IN6_IS_ADDR_LINKLOCAL(&a6) && + !IN6_IS_ADDR_MC_LINKLOCAL(&a6)) + return EAI_NONAME; + scopeid = if_nametoindex(p); + if (!scopeid) return EAI_NONAME; + } + if (scopeid > UINT_MAX) return EAI_NONAME; + buf[0].scopeid = scopeid; + } + return 1; + } + return 0; +} diff --git a/src/network/lookup_name.c b/src/network/lookup_name.c index 492e932c..f324e547 100644 --- a/src/network/lookup_name.c +++ b/src/network/lookup_name.c @@ -37,45 +37,9 @@ static int name_from_null(struct address buf[static 2], const char *name, int fa return cnt; } -int __inet_aton(const char *, struct in_addr *); - static int name_from_numeric(struct address buf[static 1], const char *name, int family) { - struct in_addr a4; - struct in6_addr a6; - if (family != AF_INET6 && __inet_aton(name, &a4)>0) { - memcpy(&buf[0].addr, &a4, sizeof a4); - buf[0].family = AF_INET; - return 1; - } - if (family != AF_INET) { - char tmp[64]; - char *p = strchr(name, '%'), *z; - unsigned long long scopeid; - if (p && p-name < 64) { - memcpy(tmp, name, p-name); - tmp[p-name] = 0; - name = tmp; - } - if (inet_pton(AF_INET6, name, &a6)<=0) return 0; - memcpy(&buf[0].addr, &a6, sizeof a6); - buf[0].family = AF_INET6; - if (p) { - if (isdigit(*++p)) scopeid = strtoull(p, &z, 10); - else z = p-1; - if (*z) { - if (!IN6_IS_ADDR_LINKLOCAL(&a6) && - !IN6_IS_ADDR_MC_LINKLOCAL(&a6)) - return EAI_NONAME; - scopeid = if_nametoindex(p); - if (!scopeid) return EAI_NONAME; - } - if (scopeid > UINT_MAX) return EAI_NONAME; - buf[0].scopeid = scopeid; - } - return 1; - } - return 0; + return __lookup_ipliteral(buf, name, family); } static int name_from_hosts(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family) @@ -133,11 +97,13 @@ static int dns_parse_callback(void *c, int rr, const void *data, int len, const case RR_A: if (len != 4) return -1; ctx->addrs[ctx->cnt].family = AF_INET; + ctx->addrs[ctx->cnt].scopeid = 0; memcpy(ctx->addrs[ctx->cnt++].addr, data, 4); break; case RR_AAAA: if (len != 16) return -1; ctx->addrs[ctx->cnt].family = AF_INET6; + ctx->addrs[ctx->cnt].scopeid = 0; memcpy(ctx->addrs[ctx->cnt++].addr, data, 16); break; case RR_CNAME: @@ -227,7 +193,6 @@ int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], c if (buf[i].family != AF_INET) continue; memcpy(buf[i].addr+12, buf[i].addr, 4); memcpy(buf[i].addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); - buf[i].scopeid = 0; buf[i].family = AF_INET6; } } diff --git a/src/network/res_msend.c b/src/network/res_msend.c index a5b7793a..5192b4d8 100644 --- a/src/network/res_msend.c +++ b/src/network/res_msend.c @@ -12,6 +12,7 @@ #include #include "stdio_impl.h" #include "syscall.h" +#include "lookup.h" static void cleanup(void *p) { @@ -47,6 +48,7 @@ int __res_msend(int nqueries, const unsigned char *const *queries, int cs; struct pollfd pfd; unsigned long t0, t1, t2; + struct address iplit; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); @@ -76,13 +78,18 @@ int __res_msend(int nqueries, const unsigned char *const *queries, for (z=s; *z && !isspace(*z); z++); *z=0; - if (inet_pton(AF_INET, s, &ns[nns].sin.sin_addr)>0) { - ns[nns].sin.sin_port = htons(53); - ns[nns++].sin.sin_family = AF_INET; - } else if (inet_pton(AF_INET6, s, &ns[nns].sin6.sin6_addr)>0) { - sl = sizeof sa.sin6; - ns[nns].sin6.sin6_port = htons(53); - ns[nns++].sin6.sin6_family = family = AF_INET6; + if (__lookup_ipliteral(&iplit, s, AF_UNSPEC)>0) { + if (iplit.family == AF_INET) { + memcpy(&ns[nns].sin.sin_addr, iplit.addr, 4); + ns[nns].sin.sin_port = htons(53); + ns[nns++].sin.sin_family = AF_INET; + } else { + sl = sizeof sa.sin6; + memcpy(&ns[nns].sin6.sin6_addr, iplit.addr, 16); + ns[nns].sin6.sin6_port = htons(53); + ns[nns].sin6.sin6_scope_id = iplit.scopeid; + ns[nns++].sin6.sin6_family = family = AF_INET6; + } } } if (f) __fclose_ca(f); -- 2.25.1