busybox/libbb/inet_common.c
<<
>>
Prefs
   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 source tree.
   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, "default") == 0) {
  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("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;
 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) {
 174                bb_error_msg("getaddrinfo: %s: %d", name, s);
 175                return -1;
 176        }
 177        memcpy(sin6, ai->ai_addr, sizeof(struct sockaddr_in6));
 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("default");
 209                return xstrdup("*");
 210        }
 211
 212        s = getnameinfo((struct sockaddr *) sin6, sizeof(struct sockaddr_in6),
 213                                name, sizeof(name), NULL, 0, 0);
 214        if (s) {
 215                bb_error_msg("getnameinfo failed");
 216                return NULL;
 217        }
 218        return xstrdup(name);
 219}
 220
 221#endif  /* CONFIG_FEATURE_IPV6 */
 222