1 #include "lookup.h"
2 #include "stdio_impl.h"
3 #include <arpa/inet.h>
4 #include <ctype.h>
5 #include <limits.h>
6 #include <net/if.h>
7 #include <netdb.h>
8 #include <netinet/in.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <sys/socket.h>
12
13 int __dns_parse(const unsigned char*, int, int (*)(void*, int, const void*, int, const void*),
14 void*);
15 int __dn_expand(const unsigned char*, const unsigned char*, const unsigned char*, char*, int);
16 int __res_mkquery(int, const char*, int, int, const unsigned char*, int, const unsigned char*,
17 unsigned char*, int);
18 int __res_send(const unsigned char*, int, unsigned char*, int);
19
20 #define PTR_MAX (64 + sizeof ".in-addr.arpa")
21 #define RR_PTR 12
22
itoa(char * p,unsigned x)23 static char* itoa(char* p, unsigned x) {
24 p += 3 * sizeof(int);
25 *--p = 0;
26 do {
27 *--p = '0' + x % 10;
28 x /= 10;
29 } while (x);
30 return p;
31 }
32
mkptr4(char * s,const unsigned char * ip)33 static void mkptr4(char* s, const unsigned char* ip) {
34 sprintf(s, "%d.%d.%d.%d.in-addr.arpa", ip[3], ip[2], ip[1], ip[0]);
35 }
36
mkptr6(char * s,const unsigned char * ip)37 static void mkptr6(char* s, const unsigned char* ip) {
38 static const char xdigits[] = "0123456789abcdef";
39 int i;
40 for (i = 15; i >= 0; i--) {
41 *s++ = xdigits[ip[i] & 15];
42 *s++ = '.';
43 *s++ = xdigits[ip[i] >> 4];
44 *s++ = '.';
45 }
46 strcpy(s, "ip6.arpa");
47 }
48
dns_parse_callback(void * c,int rr,const void * data,int len,const void * packet)49 static int dns_parse_callback(void* c, int rr, const void* data, int len, const void* packet) {
50 if (rr != RR_PTR)
51 return 0;
52 if (__dn_expand(packet, (const unsigned char*)packet + 512, data, c, 256) <= 0)
53 *(char*)c = 0;
54 return 0;
55 }
56
getnameinfo(const struct sockaddr * restrict sa,socklen_t sl,char * restrict node,socklen_t nodelen,char * restrict serv,socklen_t servlen,int flags)57 int getnameinfo(const struct sockaddr* restrict sa, socklen_t sl, char* restrict node,
58 socklen_t nodelen, char* restrict serv, socklen_t servlen, int flags) {
59 char ptr[PTR_MAX];
60 char buf[256], num[3 * sizeof(int) + 1];
61 int af = sa->sa_family;
62 unsigned char* a;
63 unsigned scopeid;
64
65 switch (af) {
66 case AF_INET:
67 a = (void*)&((struct sockaddr_in*)sa)->sin_addr;
68 if (sl < sizeof(struct sockaddr_in))
69 return EAI_FAMILY;
70 mkptr4(ptr, a);
71 scopeid = 0;
72 break;
73 case AF_INET6:
74 a = (void*)&((struct sockaddr_in6*)sa)->sin6_addr;
75 if (sl < sizeof(struct sockaddr_in6))
76 return EAI_FAMILY;
77 if (memcmp(a, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12))
78 mkptr6(ptr, a);
79 else
80 mkptr4(ptr, a + 12);
81 scopeid = ((struct sockaddr_in6*)sa)->sin6_scope_id;
82 break;
83 default:
84 return EAI_FAMILY;
85 }
86
87 if (node && nodelen) {
88 buf[0] = 0;
89 if (!*buf && !(flags & NI_NUMERICHOST)) {
90 unsigned char query[18 + PTR_MAX], reply[512];
91 int qlen = __res_mkquery(0, ptr, 1, RR_PTR, 0, 0, 0, query, sizeof query);
92 int rlen = __res_send(query, qlen, reply, sizeof reply);
93 buf[0] = 0;
94 if (rlen > 0)
95 __dns_parse(reply, rlen, dns_parse_callback, buf);
96 }
97 if (!*buf) {
98 if (flags & NI_NAMEREQD)
99 return EAI_NONAME;
100 inet_ntop(af, a, buf, sizeof buf);
101 if (scopeid) {
102 char *p = 0, tmp[IF_NAMESIZE + 1];
103 if (!(flags & NI_NUMERICSCOPE) &&
104 (IN6_IS_ADDR_LINKLOCAL(a) || IN6_IS_ADDR_MC_LINKLOCAL(a)))
105 p = if_indextoname(scopeid, tmp + 1);
106 if (!p)
107 p = itoa(num, scopeid);
108 *--p = '%';
109 strcat(buf, p);
110 }
111 }
112 if (strlen(buf) >= nodelen)
113 return EAI_OVERFLOW;
114 strcpy(node, buf);
115 }
116
117 if (serv && servlen) {
118 char* p = buf;
119 int port = ntohs(((struct sockaddr_in*)sa)->sin_port);
120 buf[0] = 0;
121 if (!*p)
122 p = itoa(num, port);
123 if (strlen(p) >= servlen)
124 return EAI_OVERFLOW;
125 strcpy(serv, p);
126 }
127
128 return 0;
129 }
130