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