提交 01dc3f4f 编写于 作者: R Rich Felker

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.
上级 934aa135
......@@ -6,6 +6,9 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <ctype.h>
#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);
}
......
......@@ -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
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <limits.h>
#include <stdlib.h>
#include <ctype.h>
#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;
}
......@@ -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;
}
}
......
......@@ -12,6 +12,7 @@
#include <pthread.h>
#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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册