123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- /* Copyright (C) 1996-2019 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Extended from original form by Ulrich Drepper <drepper@cygnus.com>, 1996.
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
- /* Parts of this file are plain copies of the file `getnetnamadr.c' from
- the bind package and it has the following copyright. */
- /* Copyright (c) 1993 Carlos Leandro and Rui Salgueiro
- * Dep. Matematica Universidade de Coimbra, Portugal, Europe
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
- /*
- * Copyright (c) 1983, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
- #include <ctype.h>
- #include <errno.h>
- #include <netdb.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdint.h>
- #include <stddef.h>
- #include "nsswitch.h"
- #include <arpa/inet.h>
- #include <arpa/nameser.h>
- #include <resolv/resolv-internal.h>
- #include <resolv/resolv_context.h>
- /* Maximum number of aliases we allow. */
- #define MAX_NR_ALIASES 48
- #if PACKETSZ > 65536
- # define MAXPACKET PACKETSZ
- #else
- # define MAXPACKET 65536
- #endif
- typedef enum
- {
- BYADDR,
- BYNAME
- } lookup_method;
- /* We need this time later. */
- typedef union querybuf
- {
- HEADER hdr;
- u_char buf[MAXPACKET];
- } querybuf;
- /* Prototypes for local functions. */
- static enum nss_status getanswer_r (const querybuf *answer, int anslen,
- struct netent *result, char *buffer,
- size_t buflen, int *errnop, int *h_errnop,
- lookup_method net_i);
- enum nss_status
- _nss_dns_getnetbyname_r (const char *name, struct netent *result,
- char *buffer, size_t buflen, int *errnop,
- int *herrnop)
- {
- /* Return entry for network with NAME. */
- union
- {
- querybuf *buf;
- u_char *ptr;
- } net_buffer;
- querybuf *orig_net_buffer;
- int anslen;
- enum nss_status status;
- struct resolv_context *ctx = __resolv_context_get ();
- if (ctx == NULL)
- {
- *errnop = errno;
- *herrnop = NETDB_INTERNAL;
- return NSS_STATUS_UNAVAIL;
- }
- net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
- anslen = __res_context_search
- (ctx, name, C_IN, T_PTR, net_buffer.buf->buf,
- 1024, &net_buffer.ptr, NULL, NULL, NULL, NULL);
- if (anslen < 0)
- {
- /* Nothing found. */
- *errnop = errno;
- if (net_buffer.buf != orig_net_buffer)
- free (net_buffer.buf);
- __resolv_context_put (ctx);
- return (errno == ECONNREFUSED
- || errno == EPFNOSUPPORT
- || errno == EAFNOSUPPORT)
- ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
- }
- status = getanswer_r (net_buffer.buf, anslen, result, buffer, buflen,
- errnop, herrnop, BYNAME);
- if (net_buffer.buf != orig_net_buffer)
- free (net_buffer.buf);
- __resolv_context_put (ctx);
- return status;
- }
- enum nss_status
- _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result,
- char *buffer, size_t buflen, int *errnop,
- int *herrnop)
- {
- /* Return entry for network with NAME. */
- enum nss_status status;
- union
- {
- querybuf *buf;
- u_char *ptr;
- } net_buffer;
- querybuf *orig_net_buffer;
- unsigned int net_bytes[4];
- char qbuf[MAXDNAME];
- int cnt, anslen;
- uint32_t net2;
- int olderr = errno;
- /* No net address lookup for IPv6 yet. */
- if (type != AF_INET)
- return NSS_STATUS_UNAVAIL;
- struct resolv_context *ctx = __resolv_context_get ();
- if (ctx == NULL)
- {
- *errnop = errno;
- *herrnop = NETDB_INTERNAL;
- return NSS_STATUS_UNAVAIL;
- }
- net2 = (uint32_t) net;
- for (cnt = 4; net2 != 0; net2 >>= 8)
- net_bytes[--cnt] = net2 & 0xff;
- switch (cnt)
- {
- case 3:
- /* Class A network. */
- sprintf (qbuf, "0.0.0.%u.in-addr.arpa", net_bytes[3]);
- break;
- case 2:
- /* Class B network. */
- sprintf (qbuf, "0.0.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2]);
- break;
- case 1:
- /* Class C network. */
- sprintf (qbuf, "0.%u.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2],
- net_bytes[1]);
- break;
- case 0:
- /* Class D - E network. */
- sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2],
- net_bytes[1], net_bytes[0]);
- break;
- }
- net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
- anslen = __res_context_query (ctx, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
- 1024, &net_buffer.ptr, NULL, NULL, NULL, NULL);
- if (anslen < 0)
- {
- /* Nothing found. */
- int err = errno;
- __set_errno (olderr);
- if (net_buffer.buf != orig_net_buffer)
- free (net_buffer.buf);
- __resolv_context_put (ctx);
- return (err == ECONNREFUSED
- || err == EPFNOSUPPORT
- || err == EAFNOSUPPORT)
- ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
- }
- status = getanswer_r (net_buffer.buf, anslen, result, buffer, buflen,
- errnop, herrnop, BYADDR);
- if (net_buffer.buf != orig_net_buffer)
- free (net_buffer.buf);
- if (status == NSS_STATUS_SUCCESS)
- {
- /* Strip trailing zeros. */
- unsigned int u_net = net; /* Maybe net should be unsigned? */
- while ((u_net & 0xff) == 0 && u_net != 0)
- u_net >>= 8;
- result->n_net = u_net;
- }
- __resolv_context_put (ctx);
- return status;
- }
- static enum nss_status
- getanswer_r (const querybuf *answer, int anslen, struct netent *result,
- char *buffer, size_t buflen, int *errnop, int *h_errnop,
- lookup_method net_i)
- {
- /*
- * Find first satisfactory answer
- *
- * answer --> +------------+ ( MESSAGE )
- * | Header |
- * +------------+
- * | Question | the question for the name server
- * +------------+
- * | Answer | RRs answering the question
- * +------------+
- * | Authority | RRs pointing toward an authority
- * | Additional | RRs holding additional information
- * +------------+
- */
- struct net_data
- {
- char *aliases[MAX_NR_ALIASES];
- char linebuffer[0];
- } *net_data;
- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct net_data);
- buffer += pad;
- if (__glibc_unlikely (buflen < sizeof (*net_data) + pad))
- {
- /* The buffer is too small. */
- too_small:
- *errnop = ERANGE;
- *h_errnop = NETDB_INTERNAL;
- return NSS_STATUS_TRYAGAIN;
- }
- buflen -= pad;
- net_data = (struct net_data *) buffer;
- int linebuflen = buflen - offsetof (struct net_data, linebuffer);
- if (buflen - offsetof (struct net_data, linebuffer) != linebuflen)
- linebuflen = INT_MAX;
- const unsigned char *end_of_message = &answer->buf[anslen];
- const HEADER *header_pointer = &answer->hdr;
- /* #/records in the answer section. */
- int answer_count = ntohs (header_pointer->ancount);
- /* #/entries in the question section. */
- int question_count = ntohs (header_pointer->qdcount);
- char *bp = net_data->linebuffer;
- const unsigned char *cp = &answer->buf[HFIXEDSZ];
- char **alias_pointer;
- int have_answer;
- u_char packtmp[NS_MAXCDNAME];
- if (question_count == 0)
- {
- /* FIXME: the Sun version uses for host name lookup an additional
- parameter for pointing to h_errno. this is missing here.
- OSF/1 has a per-thread h_errno variable. */
- if (header_pointer->aa != 0)
- {
- __set_h_errno (HOST_NOT_FOUND);
- return NSS_STATUS_NOTFOUND;
- }
- else
- {
- __set_h_errno (TRY_AGAIN);
- return NSS_STATUS_TRYAGAIN;
- }
- }
- /* Skip the question part. */
- while (question_count-- > 0)
- {
- int n = __dn_skipname (cp, end_of_message);
- if (n < 0 || end_of_message - (cp + n) < QFIXEDSZ)
- {
- __set_h_errno (NO_RECOVERY);
- return NSS_STATUS_UNAVAIL;
- }
- cp += n + QFIXEDSZ;
- }
- alias_pointer = result->n_aliases = &net_data->aliases[0];
- *alias_pointer = NULL;
- have_answer = 0;
- while (--answer_count >= 0 && cp < end_of_message)
- {
- int n = __ns_name_unpack (answer->buf, end_of_message, cp,
- packtmp, sizeof packtmp);
- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
- {
- if (errno == EMSGSIZE)
- goto too_small;
- n = -1;
- }
- if (n > 0 && bp[0] == '.')
- bp[0] = '\0';
- if (n < 0 || res_dnok (bp) == 0)
- break;
- cp += n;
- if (end_of_message - cp < 10)
- {
- __set_h_errno (NO_RECOVERY);
- return NSS_STATUS_UNAVAIL;
- }
- int type, class;
- GETSHORT (type, cp);
- GETSHORT (class, cp);
- cp += INT32SZ; /* TTL */
- uint16_t rdatalen;
- GETSHORT (rdatalen, cp);
- if (end_of_message - cp < rdatalen)
- {
- __set_h_errno (NO_RECOVERY);
- return NSS_STATUS_UNAVAIL;
- }
- if (class == C_IN && type == T_PTR)
- {
- n = __ns_name_unpack (answer->buf, end_of_message, cp,
- packtmp, sizeof packtmp);
- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
- {
- if (errno == EMSGSIZE)
- goto too_small;
- n = -1;
- }
- if (n < 0 || !res_hnok (bp))
- {
- /* XXX What does this mean? The original form from bind
- returns NULL. Incrementing cp has no effect in any case.
- What should I return here. ??? */
- cp += n;
- return NSS_STATUS_UNAVAIL;
- }
- cp += rdatalen;
- if (alias_pointer + 2 < &net_data->aliases[MAX_NR_ALIASES])
- {
- *alias_pointer++ = bp;
- n = strlen (bp) + 1;
- bp += n;
- linebuflen -= n;
- result->n_addrtype = class == C_IN ? AF_INET : AF_UNSPEC;
- ++have_answer;
- }
- }
- else
- /* Skip over unknown record data. */
- cp += rdatalen;
- }
- if (have_answer)
- {
- *alias_pointer = NULL;
- switch (net_i)
- {
- case BYADDR:
- result->n_name = *result->n_aliases++;
- result->n_net = 0L;
- return NSS_STATUS_SUCCESS;
- case BYNAME:
- {
- char **ap;
- for (ap = result->n_aliases; *ap != NULL; ++ap)
- {
- /* Check each alias name for being of the forms:
- 4.3.2.1.in-addr.arpa = net 1.2.3.4
- 3.2.1.in-addr.arpa = net 0.1.2.3
- 2.1.in-addr.arpa = net 0.0.1.2
- 1.in-addr.arpa = net 0.0.0.1
- */
- uint32_t val = 0; /* Accumulator for n_net value. */
- unsigned int shift = 0; /* Which part we are parsing now. */
- const char *p = *ap; /* Consuming the string. */
- do
- {
- /* Match the leading 0 or 0[xX] base indicator. */
- unsigned int base = 10;
- if (*p == '0' && p[1] != '.')
- {
- base = 8;
- ++p;
- if (*p == 'x' || *p == 'X')
- {
- base = 16;
- ++p;
- if (*p == '.')
- break; /* No digit here. Give up on alias. */
- }
- if (*p == '\0')
- break;
- }
- uint32_t part = 0; /* Accumulates this part's number. */
- do
- {
- if (isdigit (*p) && (*p - '0' < base))
- part = (part * base) + (*p - '0');
- else if (base == 16 && isxdigit (*p))
- part = (part << 4) + 10 + (tolower (*p) - 'a');
- ++p;
- } while (*p != '\0' && *p != '.');
- if (*p != '.')
- break; /* Bad form. Give up on this name. */
- /* Install this as the next more significant byte. */
- val |= part << shift;
- shift += 8;
- ++p;
- /* If we are out of digits now, there are two cases:
- 1. We are done with digits and now see "in-addr.arpa".
- 2. This is not the droid we are looking for. */
- if (!isdigit (*p) && !strcasecmp (p, "in-addr.arpa"))
- {
- result->n_net = val;
- return NSS_STATUS_SUCCESS;
- }
- /* Keep going when we have seen fewer than 4 parts. */
- } while (shift < 32);
- }
- }
- break;
- }
- }
- __set_h_errno (TRY_AGAIN);
- return NSS_STATUS_TRYAGAIN;
- }
|