Blame gnulib-tests/inet_pton.c

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