(root)/
glibc-2.38/
resolv/
nss_dns/
dns-network.c
       1  /* Copyright (C) 1996-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  /* Parts of this file are plain copies of the file `getnetnamadr.c' from
      19     the bind package and it has the following copyright.  */
      20  
      21  /* Copyright (c) 1993 Carlos Leandro and Rui Salgueiro
      22   *      Dep. Matematica Universidade de Coimbra, Portugal, Europe
      23   *
      24   * Permission to use, copy, modify, and distribute this software for any
      25   * purpose with or without fee is hereby granted, provided that the above
      26   * copyright notice and this permission notice appear in all copies.
      27   */
      28  /*
      29   * Copyright (c) 1983, 1993
      30   *      The Regents of the University of California.  All rights reserved.
      31   *
      32   * Redistribution and use in source and binary forms, with or without
      33   * modification, are permitted provided that the following conditions
      34   * are met:
      35   * 1. Redistributions of source code must retain the above copyright
      36   *    notice, this list of conditions and the following disclaimer.
      37   * 2. Redistributions in binary form must reproduce the above copyright
      38   *    notice, this list of conditions and the following disclaimer in the
      39   *    documentation and/or other materials provided with the distribution.
      40   * 4. Neither the name of the University nor the names of its contributors
      41   *    may be used to endorse or promote products derived from this software
      42   *    without specific prior written permission.
      43   *
      44   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      45   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      46   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      47   * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      48   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      49   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      50   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      51   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      52   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      53   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      54   * SUCH DAMAGE.
      55   */
      56  
      57  #include <ctype.h>
      58  #include <errno.h>
      59  #include <netdb.h>
      60  #include <stdio.h>
      61  #include <stdlib.h>
      62  #include <string.h>
      63  #include <stdint.h>
      64  #include <stddef.h>
      65  
      66  #include "nsswitch.h"
      67  #include <arpa/inet.h>
      68  #include <arpa/nameser.h>
      69  #include <nss_dns.h>
      70  #include <resolv/resolv-internal.h>
      71  #include <resolv/resolv_context.h>
      72  
      73  /* Maximum number of aliases we allow.  */
      74  #define MAX_NR_ALIASES	48
      75  
      76  
      77  #if PACKETSZ > 65536
      78  # define MAXPACKET	PACKETSZ
      79  #else
      80  # define MAXPACKET	65536
      81  #endif
      82  
      83  
      84  typedef enum
      85  {
      86    BYADDR,
      87    BYNAME
      88  } lookup_method;
      89  
      90  
      91  /* We need this time later.  */
      92  typedef union querybuf
      93  {
      94    HEADER hdr;
      95    u_char buf[MAXPACKET];
      96  } querybuf;
      97  
      98  /* Prototypes for local functions.  */
      99  static enum nss_status getanswer_r (const querybuf *answer, int anslen,
     100  				    struct netent *result, char *buffer,
     101  				    size_t buflen, int *errnop, int *h_errnop,
     102  				    lookup_method net_i);
     103  
     104  
     105  enum nss_status
     106  _nss_dns_getnetbyname_r (const char *name, struct netent *result,
     107  			 char *buffer, size_t buflen, int *errnop,
     108  			 int *herrnop)
     109  {
     110    /* Return entry for network with NAME.  */
     111    union
     112    {
     113      querybuf *buf;
     114      u_char *ptr;
     115    } net_buffer;
     116    querybuf *orig_net_buffer;
     117    int anslen;
     118    enum nss_status status;
     119  
     120    struct resolv_context *ctx = __resolv_context_get ();
     121    if (ctx == NULL)
     122      {
     123        *errnop = errno;
     124        *herrnop = NETDB_INTERNAL;
     125        return NSS_STATUS_UNAVAIL;
     126      }
     127  
     128    net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
     129  
     130    anslen = __res_context_search
     131      (ctx, name, C_IN, T_PTR, net_buffer.buf->buf,
     132       1024, &net_buffer.ptr, NULL, NULL, NULL, NULL);
     133    if (anslen < 0)
     134      {
     135        /* Nothing found.  */
     136        *errnop = errno;
     137        if (net_buffer.buf != orig_net_buffer)
     138  	free (net_buffer.buf);
     139        __resolv_context_put (ctx);
     140        return (errno == ECONNREFUSED
     141  	      || errno == EPFNOSUPPORT
     142  	      || errno == EAFNOSUPPORT)
     143  	? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
     144      }
     145  
     146    status = getanswer_r (net_buffer.buf, anslen, result, buffer, buflen,
     147  			errnop, herrnop, BYNAME);
     148    if (net_buffer.buf != orig_net_buffer)
     149      free (net_buffer.buf);
     150    __resolv_context_put (ctx);
     151    return status;
     152  }
     153  libc_hidden_def (_nss_dns_getnetbyname_r)
     154  
     155  enum nss_status
     156  _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result,
     157  			 char *buffer, size_t buflen, int *errnop,
     158  			 int *herrnop)
     159  {
     160    /* Return entry for network with NAME.  */
     161    enum nss_status status;
     162    union
     163    {
     164      querybuf *buf;
     165      u_char *ptr;
     166    } net_buffer;
     167    querybuf *orig_net_buffer;
     168    unsigned int net_bytes[4];
     169    char qbuf[MAXDNAME];
     170    int cnt, anslen;
     171    uint32_t net2;
     172    int olderr = errno;
     173  
     174    /* No net address lookup for IPv6 yet.  */
     175    if (type != AF_INET)
     176      return NSS_STATUS_UNAVAIL;
     177  
     178    struct resolv_context *ctx = __resolv_context_get ();
     179    if (ctx == NULL)
     180      {
     181        *errnop = errno;
     182        *herrnop = NETDB_INTERNAL;
     183        return NSS_STATUS_UNAVAIL;
     184      }
     185  
     186    net2 = (uint32_t) net;
     187    for (cnt = 4; net2 != 0; net2 >>= 8)
     188      net_bytes[--cnt] = net2 & 0xff;
     189  
     190    switch (cnt)
     191      {
     192      case 3:
     193        /* Class A network.  */
     194        sprintf (qbuf, "0.0.0.%u.in-addr.arpa", net_bytes[3]);
     195        break;
     196      case 2:
     197        /* Class B network.  */
     198        sprintf (qbuf, "0.0.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2]);
     199        break;
     200      case 1:
     201        /* Class C network.  */
     202        sprintf (qbuf, "0.%u.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2],
     203  	       net_bytes[1]);
     204        break;
     205      case 0:
     206        /* Class D - E network.  */
     207        sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2],
     208  	       net_bytes[1], net_bytes[0]);
     209        break;
     210      }
     211  
     212    net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
     213  
     214    anslen = __res_context_query (ctx, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
     215  				1024, &net_buffer.ptr, NULL, NULL, NULL, NULL);
     216    if (anslen < 0)
     217      {
     218        /* Nothing found.  */
     219        int err = errno;
     220        __set_errno (olderr);
     221        if (net_buffer.buf != orig_net_buffer)
     222  	free (net_buffer.buf);
     223        __resolv_context_put (ctx);
     224        return (err == ECONNREFUSED
     225  	      || err == EPFNOSUPPORT
     226  	      || err == EAFNOSUPPORT)
     227  	? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
     228      }
     229  
     230    status = getanswer_r (net_buffer.buf, anslen, result, buffer, buflen,
     231  			errnop, herrnop, BYADDR);
     232    if (net_buffer.buf != orig_net_buffer)
     233      free (net_buffer.buf);
     234    if (status == NSS_STATUS_SUCCESS)
     235      {
     236        /* Strip trailing zeros.  */
     237        unsigned int u_net = net;	/* Maybe net should be unsigned?  */
     238  
     239        while ((u_net & 0xff) == 0 && u_net != 0)
     240  	u_net >>= 8;
     241        result->n_net = u_net;
     242      }
     243  
     244    __resolv_context_put (ctx);
     245    return status;
     246  }
     247  libc_hidden_def (_nss_dns_getnetbyaddr_r)
     248  
     249  static enum nss_status
     250  getanswer_r (const querybuf *answer, int anslen, struct netent *result,
     251  	     char *buffer, size_t buflen, int *errnop, int *h_errnop,
     252  	     lookup_method net_i)
     253  {
     254    /*
     255     * Find first satisfactory answer
     256     *
     257     *      answer --> +------------+  ( MESSAGE )
     258     *                 |   Header   |
     259     *                 +------------+
     260     *                 |  Question  | the question for the name server
     261     *                 +------------+
     262     *                 |   Answer   | RRs answering the question
     263     *                 +------------+
     264     *                 | Authority  | RRs pointing toward an authority
     265     *                 | Additional | RRs holding additional information
     266     *                 +------------+
     267     */
     268    struct net_data
     269    {
     270      char *aliases[MAX_NR_ALIASES];
     271      char linebuffer[0];
     272    } *net_data;
     273  
     274    uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct net_data);
     275    buffer += pad;
     276  
     277    if (__glibc_unlikely (buflen < sizeof (*net_data) + pad))
     278      {
     279        /* The buffer is too small.  */
     280      too_small:
     281        *errnop = ERANGE;
     282        *h_errnop = NETDB_INTERNAL;
     283        return NSS_STATUS_TRYAGAIN;
     284      }
     285    buflen -= pad;
     286  
     287    net_data = (struct net_data *) buffer;
     288    int linebuflen = buflen - offsetof (struct net_data, linebuffer);
     289    if (buflen - offsetof (struct net_data, linebuffer) != linebuflen)
     290      linebuflen = INT_MAX;
     291    const unsigned char *end_of_message = &answer->buf[anslen];
     292    const HEADER *header_pointer = &answer->hdr;
     293    /* #/records in the answer section.  */
     294    int answer_count =  ntohs (header_pointer->ancount);
     295    /* #/entries in the question section.  */
     296    int question_count = ntohs (header_pointer->qdcount);
     297    char *bp = net_data->linebuffer;
     298    const unsigned char *cp = &answer->buf[HFIXEDSZ];
     299    char **alias_pointer;
     300    int have_answer;
     301    u_char packtmp[NS_MAXCDNAME];
     302  
     303    if (question_count == 0)
     304      {
     305        /* FIXME: the Sun version uses for host name lookup an additional
     306  	 parameter for pointing to h_errno.  this is missing here.
     307  	 OSF/1 has a per-thread h_errno variable.  */
     308        if (header_pointer->aa != 0)
     309  	{
     310  	  __set_h_errno (HOST_NOT_FOUND);
     311  	  return NSS_STATUS_NOTFOUND;
     312  	}
     313        else
     314  	{
     315  	  __set_h_errno (TRY_AGAIN);
     316  	  return NSS_STATUS_TRYAGAIN;
     317  	}
     318      }
     319  
     320    /* Skip the question part.  */
     321    while (question_count-- > 0)
     322      {
     323        int n = __libc_dn_skipname (cp, end_of_message);
     324        if (n < 0 || end_of_message - (cp + n) < QFIXEDSZ)
     325         {
     326           __set_h_errno (NO_RECOVERY);
     327           return NSS_STATUS_UNAVAIL;
     328         }
     329        cp += n + QFIXEDSZ;
     330      }
     331  
     332    alias_pointer = result->n_aliases = &net_data->aliases[0];
     333    *alias_pointer = NULL;
     334    have_answer = 0;
     335  
     336    while (--answer_count >= 0 && cp < end_of_message)
     337      {
     338        int n = __ns_name_unpack (answer->buf, end_of_message, cp,
     339  				packtmp, sizeof packtmp);
     340        if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
     341  	{
     342  	  if (errno == EMSGSIZE)
     343  	    goto too_small;
     344  
     345  	  n = -1;
     346  	}
     347  
     348        if (n < 0 || __libc_res_dnok (bp) == 0)
     349  	break;
     350        cp += n;
     351  
     352        if (end_of_message - cp < 10)
     353  	{
     354  	  __set_h_errno (NO_RECOVERY);
     355  	  return NSS_STATUS_UNAVAIL;
     356  	}
     357  
     358        int type, class;
     359        GETSHORT (type, cp);
     360        GETSHORT (class, cp);
     361        cp += INT32SZ;		/* TTL */
     362        uint16_t rdatalen;
     363        GETSHORT (rdatalen, cp);
     364        if (end_of_message - cp < rdatalen)
     365  	{
     366  	  __set_h_errno (NO_RECOVERY);
     367  	  return NSS_STATUS_UNAVAIL;
     368  	}
     369  
     370        if (class == C_IN && type == T_PTR)
     371  	{
     372  	  n = __ns_name_unpack (answer->buf, end_of_message, cp,
     373  				packtmp, sizeof packtmp);
     374  	  if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
     375  	    {
     376  	      if (errno == EMSGSIZE)
     377  		goto too_small;
     378  
     379  	      n = -1;
     380  	    }
     381  
     382  	  if (n < 0 || !__libc_res_hnok (bp))
     383  	    {
     384  	      /* XXX What does this mean?  The original form from bind
     385  		 returns NULL. Incrementing cp has no effect in any case.
     386  		 What should I return here. ??? */
     387  	      cp += n;
     388  	      return NSS_STATUS_UNAVAIL;
     389  	    }
     390  	  cp += rdatalen;
     391           if (alias_pointer + 2 < &net_data->aliases[MAX_NR_ALIASES])
     392             {
     393               *alias_pointer++ = bp;
     394               n = strlen (bp) + 1;
     395               bp += n;
     396               linebuflen -= n;
     397               result->n_addrtype = class == C_IN ? AF_INET : AF_UNSPEC;
     398               ++have_answer;
     399             }
     400  	}
     401        else
     402  	/* Skip over unknown record data.  */
     403  	cp += rdatalen;
     404      }
     405  
     406    if (have_answer)
     407      {
     408        *alias_pointer = NULL;
     409        switch (net_i)
     410  	{
     411  	case BYADDR:
     412  	  result->n_name = *result->n_aliases++;
     413  	  result->n_net = 0L;
     414  	  return NSS_STATUS_SUCCESS;
     415  
     416  	case BYNAME:
     417  	  {
     418  	    char **ap;
     419  	    for (ap = result->n_aliases; *ap != NULL; ++ap)
     420  	      {
     421  		/* Check each alias name for being of the forms:
     422  		   4.3.2.1.in-addr.arpa		= net 1.2.3.4
     423  		   3.2.1.in-addr.arpa		= net 0.1.2.3
     424  		   2.1.in-addr.arpa		= net 0.0.1.2
     425  		   1.in-addr.arpa		= net 0.0.0.1
     426  		*/
     427  		uint32_t val = 0;	/* Accumulator for n_net value.  */
     428  		unsigned int shift = 0; /* Which part we are parsing now.  */
     429  		const char *p = *ap; /* Consuming the string.  */
     430  		do
     431  		  {
     432  		    /* Match the leading 0 or 0[xX] base indicator.  */
     433  		    unsigned int base = 10;
     434  		    if (*p == '0' && p[1] != '.')
     435  		      {
     436  			base = 8;
     437  			++p;
     438  			if (*p == 'x' || *p == 'X')
     439  			  {
     440  			    base = 16;
     441  			    ++p;
     442  			    if (*p == '.')
     443  			      break; /* No digit here.  Give up on alias.  */
     444  			  }
     445  			if (*p == '\0')
     446  			  break;
     447  		      }
     448  
     449  		    uint32_t part = 0; /* Accumulates this part's number.  */
     450  		    do
     451  		      {
     452  			if (isdigit (*p) && (*p - '0' < base))
     453  			  part = (part * base) + (*p - '0');
     454  			else if (base == 16 && isxdigit (*p))
     455  			  part = (part << 4) + 10 + (tolower (*p) - 'a');
     456  			++p;
     457  		      } while (*p != '\0' && *p != '.');
     458  
     459  		    if (*p != '.')
     460  		      break;	/* Bad form.  Give up on this name.  */
     461  
     462  		    /* Install this as the next more significant byte.  */
     463  		    val |= part << shift;
     464  		    shift += 8;
     465  		    ++p;
     466  
     467  		    /* If we are out of digits now, there are two cases:
     468  		       1. We are done with digits and now see "in-addr.arpa".
     469  		       2. This is not the droid we are looking for.  */
     470  		    if (!isdigit (*p) && !__strcasecmp (p, "in-addr.arpa"))
     471  		      {
     472  			result->n_net = val;
     473  			return NSS_STATUS_SUCCESS;
     474  		      }
     475  
     476  		    /* Keep going when we have seen fewer than 4 parts.  */
     477  		  } while (shift < 32);
     478  	      }
     479  	  }
     480  	  break;
     481  	}
     482      }
     483  
     484    __set_h_errno (TRY_AGAIN);
     485    return NSS_STATUS_TRYAGAIN;
     486  }