Blame gl/inet_pton.c

Packit Service 4684c1
/* inet_pton.c -- convert IPv4 and IPv6 addresses from text to binary form
Packit Service 4684c1
Packit Service 4684c1
   Copyright (C) 2006, 2008-2020 Free Software Foundation, Inc.
Packit Service 4684c1
Packit Service 4684c1
   This program is free software: you can redistribute it and/or modify
Packit Service 4684c1
   it under the terms of the GNU Lesser General Public License as published by
Packit Service 4684c1
   the Free Software Foundation; either version 2.1 of the License, or
Packit Service 4684c1
   (at your option) any later version.
Packit Service 4684c1
Packit Service 4684c1
   This program is distributed in the hope that it will be useful,
Packit Service 4684c1
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 4684c1
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 4684c1
   GNU Lesser General Public License for more details.
Packit Service 4684c1
Packit Service 4684c1
   You should have received a copy of the GNU Lesser General Public License
Packit Service 4684c1
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit Service 4684c1
Packit Service 4684c1
/*
Packit Service 4684c1
 * Copyright (c) 1996,1999 by Internet Software Consortium.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Permission to use, copy, modify, and distribute this software for any
Packit Service 4684c1
 * purpose with or without fee is hereby granted, provided that the above
Packit Service 4684c1
 * copyright notice and this permission notice appear in all copies.
Packit Service 4684c1
 *
Packit Service 4684c1
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
Packit Service 4684c1
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
Packit Service 4684c1
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
Packit Service 4684c1
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
Packit Service 4684c1
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
Packit Service 4684c1
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
Packit Service 4684c1
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
Packit Service 4684c1
 * SOFTWARE.
Packit Service 4684c1
 */
Packit Service 4684c1
Packit Service 4684c1
#include <config.h>
Packit Service 4684c1
Packit Service 4684c1
/* Specification.  */
Packit Service 4684c1
#include <arpa/inet.h>
Packit Service 4684c1
Packit Service 4684c1
#if HAVE_DECL_INET_PTON
Packit Service 4684c1
Packit Service 4684c1
# undef inet_pton
Packit Service 4684c1
Packit Service 4684c1
int
Packit Service 4684c1
rpl_inet_pton (int af, const char *restrict src, void *restrict dst)
Packit Service 4684c1
{
Packit Service 4684c1
  return inet_pton (af, src, dst);
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
#else
Packit Service 4684c1
Packit Service 4684c1
# include <c-ctype.h>
Packit Service 4684c1
# include <string.h>
Packit Service 4684c1
# include <errno.h>
Packit Service 4684c1
Packit Service 4684c1
# define NS_INADDRSZ 4
Packit Service 4684c1
# define NS_IN6ADDRSZ 16
Packit Service 4684c1
# define NS_INT16SZ 2
Packit Service 4684c1
Packit Service 4684c1
/*
Packit Service 4684c1
 * WARNING: Don't even consider trying to compile this on a system where
Packit Service 4684c1
 * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
Packit Service 4684c1
 */
Packit Service 4684c1
Packit Service 4684c1
static int inet_pton4 (const char *src, unsigned char *dst);
Packit Service 4684c1
# if HAVE_IPV6
Packit Service 4684c1
static int inet_pton6 (const char *src, unsigned char *dst);
Packit Service 4684c1
# endif
Packit Service 4684c1
Packit Service 4684c1
/* int
Packit Service 4684c1
 * inet_pton(af, src, dst)
Packit Service 4684c1
 *      convert from presentation format (which usually means ASCII printable)
Packit Service 4684c1
 *      to network format (which is usually some kind of binary format).
Packit Service 4684c1
 * return:
Packit Service 4684c1
 *      1 if the address was valid for the specified address family
Packit Service 4684c1
 *      0 if the address wasn't valid ('dst' is untouched in this case)
Packit Service 4684c1
 *      -1 if some other error occurred ('dst' is untouched in this case, too)
Packit Service 4684c1
 * author:
Packit Service 4684c1
 *      Paul Vixie, 1996.
Packit Service 4684c1
 */
Packit Service 4684c1
int
Packit Service 4684c1
inet_pton (int af, const char *restrict src, void *restrict dst)
Packit Service 4684c1
{
Packit Service 4684c1
  switch (af)
Packit Service 4684c1
    {
Packit Service 4684c1
    case AF_INET:
Packit Service 4684c1
      return (inet_pton4 (src, dst));
Packit Service 4684c1
Packit Service 4684c1
# if HAVE_IPV6
Packit Service 4684c1
    case AF_INET6:
Packit Service 4684c1
      return (inet_pton6 (src, dst));
Packit Service 4684c1
# endif
Packit Service 4684c1
Packit Service 4684c1
    default:
Packit Service 4684c1
      errno = EAFNOSUPPORT;
Packit Service 4684c1
      return (-1);
Packit Service 4684c1
    }
Packit Service 4684c1
  /* NOTREACHED */
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* int
Packit Service 4684c1
 * inet_pton4(src, dst)
Packit Service 4684c1
 *      like inet_aton() but without all the hexadecimal, octal (with the
Packit Service 4684c1
 *      exception of 0) and shorthand.
Packit Service 4684c1
 * return:
Packit Service 4684c1
 *      1 if 'src' is a valid dotted quad, else 0.
Packit Service 4684c1
 * notice:
Packit Service 4684c1
 *      does not touch 'dst' unless it's returning 1.
Packit Service 4684c1
 * author:
Packit Service 4684c1
 *      Paul Vixie, 1996.
Packit Service 4684c1
 */
Packit Service 4684c1
static int
Packit Service 4684c1
inet_pton4 (const char *restrict src, unsigned char *restrict dst)
Packit Service 4684c1
{
Packit Service 4684c1
  int saw_digit, octets, ch;
Packit Service 4684c1
  unsigned char tmp[NS_INADDRSZ], *tp;
Packit Service 4684c1
Packit Service 4684c1
  saw_digit = 0;
Packit Service 4684c1
  octets = 0;
Packit Service 4684c1
  *(tp = tmp) = 0;
Packit Service 4684c1
  while ((ch = *src++) != '\0')
Packit Service 4684c1
    {
Packit Service 4684c1
Packit Service 4684c1
      if (ch >= '0' && ch <= '9')
Packit Service 4684c1
        {
Packit Service 4684c1
          unsigned new = *tp * 10 + (ch - '0');
Packit Service 4684c1
Packit Service 4684c1
          if (saw_digit && *tp == 0)
Packit Service 4684c1
            return (0);
Packit Service 4684c1
          if (new > 255)
Packit Service 4684c1
            return (0);
Packit Service 4684c1
          *tp = new;
Packit Service 4684c1
          if (!saw_digit)
Packit Service 4684c1
            {
Packit Service 4684c1
              if (++octets > 4)
Packit Service 4684c1
                return (0);
Packit Service 4684c1
              saw_digit = 1;
Packit Service 4684c1
            }
Packit Service 4684c1
        }
Packit Service 4684c1
      else if (ch == '.' && saw_digit)
Packit Service 4684c1
        {
Packit Service 4684c1
          if (octets == 4)
Packit Service 4684c1
            return (0);
Packit Service 4684c1
          *++tp = 0;
Packit Service 4684c1
          saw_digit = 0;
Packit Service 4684c1
        }
Packit Service 4684c1
      else
Packit Service 4684c1
        return (0);
Packit Service 4684c1
    }
Packit Service 4684c1
  if (octets < 4)
Packit Service 4684c1
    return (0);
Packit Service 4684c1
  memcpy (dst, tmp, NS_INADDRSZ);
Packit Service 4684c1
  return (1);
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
# if HAVE_IPV6
Packit Service 4684c1
Packit Service 4684c1
/* int
Packit Service 4684c1
 * inet_pton6(src, dst)
Packit Service 4684c1
 *      convert presentation level address to network order binary form.
Packit Service 4684c1
 * return:
Packit Service 4684c1
 *      1 if 'src' is a valid [RFC1884 2.2] address, else 0.
Packit Service 4684c1
 * notice:
Packit Service 4684c1
 *      (1) does not touch 'dst' unless it's returning 1.
Packit Service 4684c1
 *      (2) :: in a full address is silently ignored.
Packit Service 4684c1
 * credit:
Packit Service 4684c1
 *      inspired by Mark Andrews.
Packit Service 4684c1
 * author:
Packit Service 4684c1
 *      Paul Vixie, 1996.
Packit Service 4684c1
 */
Packit Service 4684c1
static int
Packit Service 4684c1
inet_pton6 (const char *restrict src, unsigned char *restrict dst)
Packit Service 4684c1
{
Packit Service 4684c1
  static const char xdigits[] = "0123456789abcdef";
Packit Service 4684c1
  unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
Packit Service 4684c1
  const char *curtok;
Packit Service 4684c1
  int ch, saw_xdigit;
Packit Service 4684c1
  unsigned val;
Packit Service 4684c1
Packit Service 4684c1
  tp = memset (tmp, '\0', NS_IN6ADDRSZ);
Packit Service 4684c1
  endp = tp + NS_IN6ADDRSZ;
Packit Service 4684c1
  colonp = NULL;
Packit Service 4684c1
  /* Leading :: requires some special handling. */
Packit Service 4684c1
  if (*src == ':')
Packit Service 4684c1
    if (*++src != ':')
Packit Service 4684c1
      return (0);
Packit Service 4684c1
  curtok = src;
Packit Service 4684c1
  saw_xdigit = 0;
Packit Service 4684c1
  val = 0;
Packit Service 4684c1
  while ((ch = c_tolower (*src++)) != '\0')
Packit Service 4684c1
    {
Packit Service 4684c1
      const char *pch;
Packit Service 4684c1
Packit Service 4684c1
      pch = strchr (xdigits, ch);
Packit Service 4684c1
      if (pch != NULL)
Packit Service 4684c1
        {
Packit Service 4684c1
          val <<= 4;
Packit Service 4684c1
          val |= (pch - xdigits);
Packit Service 4684c1
          if (val > 0xffff)
Packit Service 4684c1
            return (0);
Packit Service 4684c1
          saw_xdigit = 1;
Packit Service 4684c1
          continue;
Packit Service 4684c1
        }
Packit Service 4684c1
      if (ch == ':')
Packit Service 4684c1
        {
Packit Service 4684c1
          curtok = src;
Packit Service 4684c1
          if (!saw_xdigit)
Packit Service 4684c1
            {
Packit Service 4684c1
              if (colonp)
Packit Service 4684c1
                return (0);
Packit Service 4684c1
              colonp = tp;
Packit Service 4684c1
              continue;
Packit Service 4684c1
            }
Packit Service 4684c1
          else if (*src == '\0')
Packit Service 4684c1
            {
Packit Service 4684c1
              return (0);
Packit Service 4684c1
            }
Packit Service 4684c1
          if (tp + NS_INT16SZ > endp)
Packit Service 4684c1
            return (0);
Packit Service 4684c1
          *tp++ = (u_char) (val >> 8) & 0xff;
Packit Service 4684c1
          *tp++ = (u_char) val & 0xff;
Packit Service 4684c1
          saw_xdigit = 0;
Packit Service 4684c1
          val = 0;
Packit Service 4684c1
          continue;
Packit Service 4684c1
        }
Packit Service 4684c1
      if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
Packit Service 4684c1
          inet_pton4 (curtok, tp) > 0)
Packit Service 4684c1
        {
Packit Service 4684c1
          tp += NS_INADDRSZ;
Packit Service 4684c1
          saw_xdigit = 0;
Packit Service 4684c1
          break;                /* '\0' was seen by inet_pton4(). */
Packit Service 4684c1
        }
Packit Service 4684c1
      return (0);
Packit Service 4684c1
    }
Packit Service 4684c1
  if (saw_xdigit)
Packit Service 4684c1
    {
Packit Service 4684c1
      if (tp + NS_INT16SZ > endp)
Packit Service 4684c1
        return (0);
Packit Service 4684c1
      *tp++ = (u_char) (val >> 8) & 0xff;
Packit Service 4684c1
      *tp++ = (u_char) val & 0xff;
Packit Service 4684c1
    }
Packit Service 4684c1
  if (colonp != NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      /*
Packit Service 4684c1
       * Since some memmove()'s erroneously fail to handle
Packit Service 4684c1
       * overlapping regions, we'll do the shift by hand.
Packit Service 4684c1
       */
Packit Service 4684c1
      const int n = tp - colonp;
Packit Service 4684c1
      int i;
Packit Service 4684c1
Packit Service 4684c1
      if (tp == endp)
Packit Service 4684c1
        return (0);
Packit Service 4684c1
      for (i = 1; i <= n; i++)
Packit Service 4684c1
        {
Packit Service 4684c1
          endp[-i] = colonp[n - i];
Packit Service 4684c1
          colonp[n - i] = 0;
Packit Service 4684c1
        }
Packit Service 4684c1
      tp = endp;
Packit Service 4684c1
    }
Packit Service 4684c1
  if (tp != endp)
Packit Service 4684c1
    return (0);
Packit Service 4684c1
  memcpy (dst, tmp, NS_IN6ADDRSZ);
Packit Service 4684c1
  return (1);
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
# endif
Packit Service 4684c1
Packit Service 4684c1
#endif