Blame gl/inet_pton.c

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