about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/network/getnameinfo.c58
-rw-r--r--src/network/lookup.h1
-rw-r--r--src/network/lookup_ipliteral.c51
-rw-r--r--src/network/lookup_name.c41
-rw-r--r--src/network/res_msend.c21
5 files changed, 122 insertions, 50 deletions
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 <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);
 			}
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 <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;
+}
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 <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);