Blame lib/inet_pton.c

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