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 * 9 */ 10 11#include "libbb.h" 12#include "inet_common.h" 13 14int 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#endif 67 68#ifdef DEBUG 69 bb_error_msg("gethostbyname(%s)", name); 70#endif 71 hp = gethostbyname(name); 72 if (hp == NULL) { 73 return -1; 74 } 75 memcpy(&s_in->sin_addr, hp->h_addr_list[0], sizeof(struct in_addr)); 76 return 0; 77} 78 79 80/* numeric: & 0x8000: default instead of *, 81 * & 0x4000: host instead of net, 82 * & 0x0fff: don't resolve 83 */ 84char *INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t netmask) 85{ 86 /* addr-to-name cache */ 87 struct addr { 88 struct addr *next; 89 struct sockaddr_in addr; 90 int host; 91 char name[1]; 92 }; 93 static struct addr *cache = NULL; 94 95 struct addr *pn; 96 char *name; 97 uint32_t ad, host_ad; 98 int host = 0; 99 100 /* Grmpf. -FvK */ 101 if (s_in->sin_family != AF_INET) { 102#ifdef DEBUG 103 bb_error_msg("rresolve: unsupported address family %d!", 104 s_in->sin_family); 105#endif 106 errno = EAFNOSUPPORT; 107 return NULL; 108 } 109 ad = s_in->sin_addr.s_addr; 110#ifdef DEBUG 111 bb_error_msg("rresolve: %08x, mask %08x, num %08x", (unsigned)ad, netmask, numeric); 112#endif 113 if (ad == INADDR_ANY) { 114 if ((numeric & 0x0FFF) == 0) { 115 if (numeric & 0x8000) 116 return xstrdup(bb_str_default); 117 return xstrdup("*"); 118 } 119 } 120 if (numeric & 0x0FFF) 121 return xstrdup(inet_ntoa(s_in->sin_addr)); 122 123 if ((ad & (~netmask)) != 0 || (numeric & 0x4000)) 124 host = 1; 125 pn = cache; 126 while (pn) { 127 if (pn->addr.sin_addr.s_addr == ad && pn->host == host) { 128#ifdef DEBUG 129 bb_error_msg("rresolve: found %s %08x in cache", 130 (host ? "host" : "net"), (unsigned)ad); 131#endif 132 return xstrdup(pn->name); 133 } 134 pn = pn->next; 135 } 136 137 host_ad = ntohl(ad); 138 name = NULL; 139 if (host) { 140 struct hostent *ent; 141#ifdef DEBUG 142 bb_error_msg("gethostbyaddr (%08x)", (unsigned)ad); 143#endif 144 ent = gethostbyaddr((char *) &ad, 4, AF_INET); 145 if (ent) 146 name = xstrdup(ent->h_name); 147 } else if (ENABLE_FEATURE_ETC_NETWORKS) { 148 struct netent *np; 149#ifdef DEBUG 150 bb_error_msg("getnetbyaddr (%08x)", (unsigned)host_ad); 151#endif 152 np = getnetbyaddr(host_ad, AF_INET); 153 if (np) 154 name = xstrdup(np->n_name); 155 } 156 if (!name) 157 name = xstrdup(inet_ntoa(s_in->sin_addr)); 158 pn = xmalloc(sizeof(*pn) + strlen(name)); /* no '+ 1', it's already accounted for */ 159 pn->next = cache; 160 pn->addr = *s_in; 161 pn->host = host; 162 strcpy(pn->name, name); 163 cache = pn; 164 return name; 165} 166 167#if ENABLE_FEATURE_IPV6 168 169int INET6_resolve(const char *name, struct sockaddr_in6 *sin6) 170{ 171 struct addrinfo req, *ai; 172 int s; 173 174 memset(&req, '\0', sizeof req); 175 req.ai_family = AF_INET6; 176 s = getaddrinfo(name, NULL, &req, &ai); 177 if (s) { 178 bb_error_msg("getaddrinfo: %s: %d", name, s); 179 return -1; 180 } 181 memcpy(sin6, ai->ai_addr, sizeof(struct sockaddr_in6)); 182 freeaddrinfo(ai); 183 return 0; 184} 185 186#ifndef IN6_IS_ADDR_UNSPECIFIED 187# define IN6_IS_ADDR_UNSPECIFIED(a) \ 188 (((uint32_t *) (a))[0] == 0 && ((uint32_t *) (a))[1] == 0 && \ 189 ((uint32_t *) (a))[2] == 0 && ((uint32_t *) (a))[3] == 0) 190#endif 191 192 193char *INET6_rresolve(struct sockaddr_in6 *sin6, int numeric) 194{ 195 char name[128]; 196 int s; 197 198 /* Grmpf. -FvK */ 199 if (sin6->sin6_family != AF_INET6) { 200#ifdef DEBUG 201 bb_error_msg("rresolve: unsupport address family %d!", 202 sin6->sin6_family); 203#endif 204 errno = EAFNOSUPPORT; 205 return NULL; 206 } 207 if (numeric & 0x7FFF) { 208 inet_ntop(AF_INET6, &sin6->sin6_addr, name, sizeof(name)); 209 return xstrdup(name); 210 } 211 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 212 if (numeric & 0x8000) 213 return xstrdup(bb_str_default); 214 return xstrdup("*"); 215 } 216 217 s = getnameinfo((struct sockaddr *) sin6, sizeof(struct sockaddr_in6), 218 name, sizeof(name), NULL, 0, 0); 219 if (s) { 220 bb_error_msg("getnameinfo failed"); 221 return NULL; 222 } 223 return xstrdup(name); 224} 225 226#endif /* CONFIG_FEATURE_IPV6 */ 227