1#include <netdb.h> 2#include <limits.h> 3#include <string.h> 4#include <stdio.h> 5#include <sys/socket.h> 6#include <netinet/in.h> 7#include <arpa/inet.h> 8#include <net/if.h> 9#include <ctype.h> 10#include "lookup.h" 11#include "stdio_impl.h" 12 13int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *), void *); 14int __dn_expand(const unsigned char *, const unsigned char *, const unsigned char *, char *, int); 15int __res_mkquery(int, const char *, int, int, const unsigned char *, int, const unsigned char*, unsigned char *, int); 16int __res_send(const unsigned char *, int, unsigned char *, int); 17 18#define PTR_MAX (64 + sizeof ".in-addr.arpa") 19#define RR_PTR 12 20 21static char *itoa(char *p, unsigned x) { 22 p += 3*sizeof(int); 23 *--p = 0; 24 do { 25 *--p = '0' + x % 10; 26 x /= 10; 27 } while (x); 28 return p; 29} 30 31static void mkptr4(char *s, const unsigned char *ip) 32{ 33 sprintf(s, "%d.%d.%d.%d.in-addr.arpa", 34 ip[3], ip[2], ip[1], ip[0]); 35} 36 37static void mkptr6(char *s, const unsigned char *ip) 38{ 39 static const char xdigits[] = "0123456789abcdef"; 40 int i; 41 for (i=15; i>=0; i--) { 42 *s++ = xdigits[ip[i]&15]; *s++ = '.'; 43 *s++ = xdigits[ip[i]>>4]; *s++ = '.'; 44 } 45 strcpy(s, "ip6.arpa"); 46} 47 48static void reverse_hosts(char *buf, const unsigned char *a, unsigned scopeid, int family) 49{ 50 char line[512], *p, *z; 51 unsigned char _buf[1032], atmp[16]; 52 struct address iplit; 53 FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf); 54 if (!f) return; 55 if (family == AF_INET) { 56 memcpy(atmp+12, a, 4); 57 memcpy(atmp, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); 58 a = atmp; 59 } 60 while (fgets(line, sizeof line, f)) { 61 if ((p=strchr(line, '#'))) *p++='\n', *p=0; 62 63 for (p=line; *p && !isspace(*p); p++); 64 *p++ = 0; 65 if (__lookup_ipliteral(&iplit, line, AF_UNSPEC)<=0) 66 continue; 67 68 if (iplit.family == AF_INET) { 69 memcpy(iplit.addr+12, iplit.addr, 4); 70 memcpy(iplit.addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); 71 iplit.scopeid = 0; 72 } 73 74 if (memcmp(a, iplit.addr, 16) || iplit.scopeid != scopeid) 75 continue; 76 77 for (; *p && isspace(*p); p++); 78 for (z=p; *z && !isspace(*z); z++); 79 *z = 0; 80 if (z-p < 256) { 81 memcpy(buf, p, z-p+1); 82 break; 83 } 84 } 85 __fclose_ca(f); 86} 87 88static void reverse_services(char *buf, int port, int dgram) 89{ 90 unsigned long svport; 91 char line[128], *p, *z; 92 unsigned char _buf[1032]; 93 FILE _f, *f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf); 94 if (!f) return; 95 while (fgets(line, sizeof line, f)) { 96 if ((p=strchr(line, '#'))) *p++='\n', *p=0; 97 98 for (p=line; *p && !isspace(*p); p++); 99 if (!*p) continue; 100 *p++ = 0; 101 svport = strtoul(p, &z, 10); 102 103 if (svport != port || z==p) continue; 104 if (dgram && strncmp(z, "/udp", 4)) continue; 105 if (!dgram && strncmp(z, "/tcp", 4)) continue; 106 if (p-line > 32) continue; 107 108 memcpy(buf, line, p-line); 109 break; 110 } 111 __fclose_ca(f); 112} 113 114static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet) 115{ 116 if (rr != RR_PTR) return 0; 117 if (__dn_expand(packet, (const unsigned char *)packet + 512, 118 data, c, 256) <= 0) 119 *(char *)c = 0; 120 return 0; 121 122} 123 124int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl, 125 char *restrict node, socklen_t nodelen, 126 char *restrict serv, socklen_t servlen, 127 int flags) 128{ 129 char ptr[PTR_MAX]; 130 char buf[256], num[3*sizeof(int)+1]; 131 int af = sa->sa_family; 132 unsigned char *a; 133 unsigned scopeid; 134 135 switch (af) { 136 case AF_INET: 137 a = (void *)&((struct sockaddr_in *)sa)->sin_addr; 138 if (sl < sizeof(struct sockaddr_in)) return EAI_FAMILY; 139 mkptr4(ptr, a); 140 scopeid = 0; 141 break; 142 case AF_INET6: 143 a = (void *)&((struct sockaddr_in6 *)sa)->sin6_addr; 144 if (sl < sizeof(struct sockaddr_in6)) return EAI_FAMILY; 145 if (memcmp(a, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12)) 146 mkptr6(ptr, a); 147 else 148 mkptr4(ptr, a+12); 149 scopeid = ((struct sockaddr_in6 *)sa)->sin6_scope_id; 150 break; 151 default: 152 return EAI_FAMILY; 153 } 154 155 if (node && nodelen) { 156 buf[0] = 0; 157 if (!(flags & NI_NUMERICHOST)) { 158 reverse_hosts(buf, a, scopeid, af); 159 } 160 if (!*buf && !(flags & NI_NUMERICHOST)) { 161 unsigned char query[18+PTR_MAX], reply[512]; 162 int qlen = __res_mkquery(0, ptr, 1, RR_PTR, 163 0, 0, 0, query, sizeof query); 164 int rlen = __res_send(query, qlen, reply, sizeof reply); 165 buf[0] = 0; 166 if (rlen > 0) 167 __dns_parse(reply, rlen, dns_parse_callback, buf); 168 } 169 if (!*buf) { 170 if (flags & NI_NAMEREQD) return EAI_NONAME; 171 inet_ntop(af, a, buf, sizeof buf); 172 if (scopeid) { 173 char *p = 0, tmp[IF_NAMESIZE+1]; 174 if (!(flags & NI_NUMERICSCOPE) && 175 (IN6_IS_ADDR_LINKLOCAL(a) || 176 IN6_IS_ADDR_MC_LINKLOCAL(a))) 177 p = if_indextoname(scopeid, tmp+1); 178 if (!p) 179 p = itoa(num, scopeid); 180 *--p = '%'; 181 strcat(buf, p); 182 } 183 } 184 if (strlen(buf) >= nodelen) return EAI_OVERFLOW; 185 strcpy(node, buf); 186 } 187 188 if (serv && servlen) { 189 char *p = buf; 190 int port = ntohs(((struct sockaddr_in *)sa)->sin_port); 191 buf[0] = 0; 192 if (!(flags & NI_NUMERICSERV)) 193 reverse_services(buf, port, flags & NI_DGRAM); 194 if (!*p) 195 p = itoa(num, port); 196 if (strlen(p) >= servlen) 197 return EAI_OVERFLOW; 198 strcpy(serv, p); 199 } 200 201 return 0; 202} 203