Blame gnulib-tests/inet_pton.c

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