1/* vi: set sw=4 ts=4: */ 2/* 3 * stolen from net-tools-1.59 and stripped down for busybox by 4 * Erik Andersen <andersen@codepoet.org> 5 * 6 * Heavily modified by Manuel Novoa III Mar 12, 2001 7 * 8 * Licensed under GPLv2, see file LICENSE in this tarball for details. 9 */ 10 11#include "libbb.h" 12#include "inet_common.h" 13 14int FAST_FUNC INET_resolve(const char *name, struct sockaddr_in *s_in, int hostfirst) 15{ 16 struct hostent *hp; 17#if ENABLE_FEATURE_ETC_NETWORKS 18 struct netent *np; 19#endif 20 21 /* Grmpf. -FvK */ 22 s_in->sin_family = AF_INET; 23 s_in->sin_port = 0; 24 25 /* Default is special, meaning 0.0.0.0. */ 26 if (!strcmp(name, bb_str_default)) { 27 s_in->sin_addr.s_addr = INADDR_ANY; 28 return 1; 29 } 30 /* Look to see if it's a dotted quad. */ 31 if (inet_aton(name, &s_in->sin_addr)) { 32 return 0; 33 } 34 /* If we expect this to be a hostname, try hostname database first */ 35#ifdef DEBUG 36 if (hostfirst) { 37 bb_error_msg("gethostbyname(%s)", name); 38 } 39#endif 40 if (hostfirst) { 41 hp = gethostbyname(name); 42 if (hp != NULL) { 43 memcpy(&s_in->sin_addr, hp->h_addr_list[0], 44 sizeof(struct in_addr)); 45 return 0; 46 } 47 } 48#if ENABLE_FEATURE_ETC_NETWORKS 49 /* Try the NETWORKS database to see if this is a known network. */ 50#ifdef DEBUG 51 bb_error_msg("getnetbyname(%s)", name); 52#endif 53 np = getnetbyname(name); 54 if (np != NULL) { 55 s_in->sin_addr.s_addr = htonl(np->n_net); 56 return 1; 57 } 58#endif 59 if (hostfirst) { 60 /* Don't try again */ 61 return -1; 62 } 63#ifdef DEBUG 64 res_init(); 65 _res.options |= RES_DEBUG; 66 bb_error_msg("gethostbyname(%s)", name); 67#endif 68 hp = gethostbyname(name); 69 if (hp == NULL) { 70 return -1; 71 } 72 memcpy(&s_in->sin_addr, hp->h_addr_list[0], sizeof(struct in_addr)); 73 return 0; 74} 75 76 77/* numeric: & 0x8000: default instead of *, 78 * & 0x4000: host instead of net, 79 * & 0x0fff: don't resolve 80 */ 81char* FAST_FUNC INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t netmask) 82{ 83 /* addr-to-name cache */ 84 struct addr { 85 struct addr *next; 86 struct sockaddr_in addr; 87 int host; 88 char name[1]; 89 }; 90 static struct addr *cache = NULL; 91 92 struct addr *pn; 93 char *name; 94 uint32_t ad, host_ad; 95 int host = 0; 96 97 if (s_in->sin_family != AF_INET) { 98#ifdef DEBUG 99 bb_error_msg("rresolve: unsupported address family %d!", 100 s_in->sin_family); 101#endif 102 errno = EAFNOSUPPORT; 103 return NULL; 104 } 105 ad = s_in->sin_addr.s_addr; 106#ifdef DEBUG 107 bb_error_msg("rresolve: %08x, mask %08x, num %08x", (unsigned)ad, netmask, numeric); 108#endif 109 if (ad == INADDR_ANY) { 110 if ((numeric & 0x0FFF) == 0) { 111 if (numeric & 0x8000) 112 return xstrdup(bb_str_default); 113 return xstrdup("*"); 114 } 115 } 116 if (numeric & 0x0FFF) 117 return xstrdup(inet_ntoa(s_in->sin_addr)); 118 119 if ((ad & (~netmask)) != 0 || (numeric & 0x4000)) 120 host = 1; 121 pn = cache; 122 while (pn) { 123 if (pn->addr.sin_addr.s_addr == ad && pn->host == host) { 124#ifdef DEBUG 125 bb_error_msg("rresolve: found %s %08x in cache", 126 (host ? "host" : "net"), (unsigned)ad); 127#endif 128 return xstrdup(pn->name); 129 } 130 pn = pn->next; 131 } 132 133 host_ad = ntohl(ad); 134 name = NULL; 135 if (host) { 136 struct hostent *ent; 137#ifdef DEBUG 138 bb_error_msg("gethostbyaddr (%08x)", (unsigned)ad); 139#endif 140 ent = gethostbyaddr((char *) &ad, 4, AF_INET); 141 if (ent) 142 name = xstrdup(ent->h_name); 143 } else if (ENABLE_FEATURE_ETC_NETWORKS) { 144 struct netent *np; 145#ifdef DEBUG 146 bb_error_msg("getnetbyaddr (%08x)", (unsigned)host_ad); 147#endif 148 np = getnetbyaddr(host_ad, AF_INET); 149 if (np) 150 name = xstrdup(np->n_name); 151 } 152 if (!name) 153 name = xstrdup(inet_ntoa(s_in->sin_addr)); 154 pn = xmalloc(sizeof(*pn) + strlen(name)); /* no '+ 1', it's already accounted for */ 155 pn->next = cache; 156 pn->addr = *s_in; 157 pn->host = host; 158 strcpy(pn->name, name); 159 cache = pn; 160 return name; 161} 162 163#if ENABLE_FEATURE_IPV6 164 165int FAST_FUNC INET6_resolve(const char *name, struct sockaddr_in6 *sin6) 166{ 167 struct addrinfo req, *ai = NULL; 168 int s; 169 170 memset(&req, 0, sizeof(req)); 171 req.ai_family = AF_INET6; 172 s = getaddrinfo(name, NULL, &req, &ai); 173 if (s != 0) { 174 bb_error_msg("getaddrinfo: %s: %d", name, s); 175 return -1; 176 } 177 memcpy(sin6, ai->ai_addr, sizeof(*sin6)); 178 freeaddrinfo(ai); 179 return 0; 180} 181 182#ifndef IN6_IS_ADDR_UNSPECIFIED 183# define IN6_IS_ADDR_UNSPECIFIED(a) \ 184 (((uint32_t *) (a))[0] == 0 && ((uint32_t *) (a))[1] == 0 && \ 185 ((uint32_t *) (a))[2] == 0 && ((uint32_t *) (a))[3] == 0) 186#endif 187 188 189char* FAST_FUNC INET6_rresolve(struct sockaddr_in6 *sin6, int numeric) 190{ 191 char name[128]; 192 int s; 193 194 if (sin6->sin6_family != AF_INET6) { 195#ifdef DEBUG 196 bb_error_msg("rresolve: unsupported address family %d!", 197 sin6->sin6_family); 198#endif 199 errno = EAFNOSUPPORT; 200 return NULL; 201 } 202 if (numeric & 0x7FFF) { 203 inet_ntop(AF_INET6, &sin6->sin6_addr, name, sizeof(name)); 204 return xstrdup(name); 205 } 206 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 207 if (numeric & 0x8000) 208 return xstrdup(bb_str_default); 209 return xstrdup("*"); 210 } 211 212 s = getnameinfo((struct sockaddr *) sin6, sizeof(*sin6), 213 name, sizeof(name), 214 /*serv,servlen:*/ NULL, 0, 215 0); 216 if (s != 0) { 217 bb_error_msg("getnameinfo failed"); 218 return NULL; 219 } 220 return xstrdup(name); 221} 222 223#endif /* CONFIG_FEATURE_IPV6 */ 224