diff options
Diffstat (limited to 'libbb/inet_common.c')
-rw-r--r-- | libbb/inet_common.c | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/libbb/inet_common.c b/libbb/inet_common.c new file mode 100644 index 0000000..0261d43 --- /dev/null +++ b/libbb/inet_common.c @@ -0,0 +1,174 @@ +/* + * stolen from net-tools-1.59 and stripped down for busybox by + * Erik Andersen <andersee@debian.org> + * + * Heavily modified by Manuel Novoa III Mar 12, 2001 + * + * Version: $Id: inet_common.c,v 1.1 2001/11/10 12:18:42 andersen Exp $ + * + */ + +#include "inet_common.h" +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "libbb.h" + +const char bb_INET_default[]="default"; + +int INET_resolve(const char *name, struct sockaddr_in *s_in, int hostfirst) +{ + struct hostent *hp; + struct netent *np; + + /* Grmpf. -FvK */ + s_in->sin_family = AF_INET; + s_in->sin_port = 0; + + /* Default is special, meaning 0.0.0.0. */ + if (!strcmp(name, bb_INET_default)) { + s_in->sin_addr.s_addr = INADDR_ANY; + return (1); + } + /* Look to see if it's a dotted quad. */ + if (inet_aton(name, &s_in->sin_addr)) { + return 0; + } + /* If we expect this to be a hostname, try hostname database first */ +#ifdef DEBUG + if (hostfirst) fprintf (stderr, "gethostbyname (%s)\n", name); +#endif + if (hostfirst && + (hp = gethostbyname(name)) != (struct hostent *) NULL) { + memcpy((char *) &s_in->sin_addr, (char *) hp->h_addr_list[0], + sizeof(struct in_addr)); + return 0; + } + /* Try the NETWORKS database to see if this is a known network. */ +#ifdef DEBUG + fprintf (stderr, "getnetbyname (%s)\n", name); +#endif + if ((np = getnetbyname(name)) != (struct netent *) NULL) { + s_in->sin_addr.s_addr = htonl(np->n_net); + return 1; + } + if (hostfirst) { + /* Don't try again */ + errno = h_errno; + return -1; + } +#ifdef DEBUG + res_init(); + _res.options |= RES_DEBUG; +#endif + +#ifdef DEBUG + fprintf (stderr, "gethostbyname (%s)\n", name); +#endif + if ((hp = gethostbyname(name)) == (struct hostent *) NULL) { + errno = h_errno; + return -1; + } + memcpy((char *) &s_in->sin_addr, (char *) hp->h_addr_list[0], + sizeof(struct in_addr)); + + return 0; +} + +/* cache */ +struct addr { + struct sockaddr_in addr; + char *name; + int host; + struct addr *next; +}; + +static struct addr *INET_nn = NULL; /* addr-to-name cache */ + +/* numeric: & 0x8000: default instead of *, + * & 0x4000: host instead of net, + * & 0x0fff: don't resolve + */ +int INET_rresolve(char *name, size_t len, struct sockaddr_in *s_in, + int numeric, unsigned int netmask) +{ + struct hostent *ent; + struct netent *np; + struct addr *pn; + unsigned long ad, host_ad; + int host = 0; + + /* Grmpf. -FvK */ + if (s_in->sin_family != AF_INET) { +#ifdef DEBUG + fprintf(stderr, _("rresolve: unsupport address family %d !\n"), s_in->sin_family); +#endif + errno = EAFNOSUPPORT; + return (-1); + } + ad = (unsigned long) s_in->sin_addr.s_addr; +#ifdef DEBUG + fprintf (stderr, "rresolve: %08lx, mask %08x, num %08x \n", ad, netmask, numeric); +#endif + if (ad == INADDR_ANY) { + if ((numeric & 0x0FFF) == 0) { + if (numeric & 0x8000) + safe_strncpy(name, bb_INET_default, len); + else + safe_strncpy(name, "*", len); + return (0); + } + } + if (numeric & 0x0FFF) { + safe_strncpy(name, inet_ntoa(s_in->sin_addr), len); + return (0); + } + + if ((ad & (~netmask)) != 0 || (numeric & 0x4000)) + host = 1; +#if 0 + INET_nn = NULL; +#endif + pn = INET_nn; + while (pn != NULL) { + if (pn->addr.sin_addr.s_addr == ad && pn->host == host) { + safe_strncpy(name, pn->name, len); +#ifdef DEBUG + fprintf (stderr, "rresolve: found %s %08lx in cache\n", (host? "host": "net"), ad); +#endif + return (0); + } + pn = pn->next; + } + + host_ad = ntohl(ad); + np = NULL; + ent = NULL; + if (host) { +#ifdef DEBUG + fprintf (stderr, "gethostbyaddr (%08lx)\n", ad); +#endif + ent = gethostbyaddr((char *) &ad, 4, AF_INET); + if (ent != NULL) + safe_strncpy(name, ent->h_name, len); + } else { +#ifdef DEBUG + fprintf (stderr, "getnetbyaddr (%08lx)\n", host_ad); +#endif + np = getnetbyaddr(host_ad, AF_INET); + if (np != NULL) + safe_strncpy(name, np->n_name, len); + } + if ((ent == NULL) && (np == NULL)) + safe_strncpy(name, inet_ntoa(s_in->sin_addr), len); + pn = (struct addr *) xmalloc(sizeof(struct addr)); + pn->addr = *s_in; + pn->next = INET_nn; + pn->host = host; + pn->name = xstrdup(name); + INET_nn = pn; + + return (0); +} |