Blame src/gl/inet_pton.c

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