Blame snmplib/inet_pton.c

Packit fcad23
/*	Id: inet_pton.c,v 1.5 2001/04/13 15:24:35 lukem Exp 	*/
Packit fcad23
/*	$NetBSD: inet_pton.c,v 1.16 2000/02/07 18:51:02 itojun Exp $	*/
Packit fcad23
Packit fcad23
/* Copyright (c) 1996 by Internet Software Consortium.
Packit fcad23
 *
Packit fcad23
 * Permission to use, copy, modify, and distribute this software for any
Packit fcad23
 * purpose with or without fee is hereby granted, provided that the above
Packit fcad23
 * copyright notice and this permission notice appear in all copies.
Packit fcad23
 *
Packit fcad23
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
Packit fcad23
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
Packit fcad23
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
Packit fcad23
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
Packit fcad23
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
Packit fcad23
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
Packit fcad23
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
Packit fcad23
 * SOFTWARE.
Packit fcad23
 */
Packit fcad23
Packit fcad23
#include <net-snmp/net-snmp-config.h>
Packit fcad23
Packit fcad23
#include <ctype.h>
Packit fcad23
Packit fcad23
#if HAVE_ARPA_NAMESER_H
Packit fcad23
#include <arpa/nameser.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#include <errno.h>
Packit fcad23
#include <stdio.h>
Packit fcad23
#if HAVE_STRING_H
Packit fcad23
#include <string.h>
Packit fcad23
#else
Packit fcad23
#include <strings.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#include <net-snmp/types.h>
Packit fcad23
#include "inet_pton.h"
Packit fcad23
Packit fcad23
#ifndef EAFNOSUPPORT
Packit fcad23
#define EAFNOSUPPORT            WSAEAFNOSUPPORT
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#ifndef IN6ADDRSZ
Packit fcad23
#define	IN6ADDRSZ	16
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#ifndef INT16SZ
Packit fcad23
#define	INT16SZ		2
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#ifndef INADDRSZ
Packit fcad23
#define	INADDRSZ	4
Packit fcad23
#endif
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * WARNING: Don't even consider trying to compile this on a system where
Packit fcad23
 * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
Packit fcad23
 */
Packit fcad23
Packit fcad23
static int	inet_pton4(const char *src, u_char *dst, int pton);
Packit fcad23
#ifdef NETSNMP_ENABLE_IPV6
Packit fcad23
static int	inet_pton6(const char *src, u_char *dst);
Packit fcad23
#endif
Packit fcad23
Packit fcad23
/* int
Packit fcad23
 * inet_pton(af, src, dst)
Packit fcad23
 *	convert from presentation format (which usually means ASCII printable)
Packit fcad23
 *	to network format (which is usually some kind of binary format).
Packit fcad23
 * return:
Packit fcad23
 *	1 if the address was valid for the specified address family
Packit fcad23
 *	0 if the address wasn't valid (`dst' is untouched in this case)
Packit fcad23
 *	-1 if some other error occurred (`dst' is untouched in this case, too)
Packit fcad23
 * author:
Packit fcad23
 *	Paul Vixie, 1996.
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
netsnmp_inet_pton(int af, const char *src, void *dst)
Packit fcad23
{
Packit fcad23
Packit fcad23
	switch (af) {
Packit fcad23
	case AF_INET:
Packit fcad23
		return (inet_pton4(src, dst, 1));
Packit fcad23
#ifdef NETSNMP_ENABLE_IPV6
Packit fcad23
	case AF_INET6:
Packit fcad23
		return (inet_pton6(src, dst));
Packit fcad23
#endif
Packit fcad23
	default:
Packit fcad23
		errno = EAFNOSUPPORT;
Packit fcad23
		return (-1);
Packit fcad23
	}
Packit fcad23
	/* NOTREACHED */
Packit fcad23
}
Packit fcad23
Packit fcad23
/* int
Packit fcad23
 * inet_pton4(src, dst, pton)
Packit fcad23
 *	when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand.
Packit fcad23
 *	when last arg is 1: inet_pton(). decimal dotted-quad only.
Packit fcad23
 * return:
Packit fcad23
 *	1 if `src' is a valid input, else 0.
Packit fcad23
 * notice:
Packit fcad23
 *	does not touch `dst' unless it's returning 1.
Packit fcad23
 * author:
Packit fcad23
 *	Paul Vixie, 1996.
Packit fcad23
 */
Packit fcad23
static int
Packit fcad23
inet_pton4(const char *src, u_char *dst, int pton)
Packit fcad23
{
Packit fcad23
	u_int val;
Packit fcad23
	u_int digit;
Packit fcad23
	int base, n;
Packit fcad23
	unsigned char c;
Packit fcad23
	u_int parts[4];
Packit fcad23
	register u_int *pp = parts;
Packit fcad23
Packit fcad23
	c = *src;
Packit fcad23
	for (;;) {
Packit fcad23
		/*
Packit fcad23
		 * Collect number up to ``.''.
Packit fcad23
		 * Values are specified as for C:
Packit fcad23
		 * 0x=hex, 0=octal, isdigit=decimal.
Packit fcad23
		 */
Packit fcad23
		if (!isdigit(c))
Packit fcad23
			return (0);
Packit fcad23
		val = 0; base = 10;
Packit fcad23
		if (c == '0') {
Packit fcad23
			c = *++src;
Packit fcad23
			if (c == 'x' || c == 'X')
Packit fcad23
				base = 16, c = *++src;
Packit fcad23
			else if (isdigit(c) && c != '9')
Packit fcad23
				base = 8;
Packit fcad23
		}
Packit fcad23
		/* inet_pton() takes decimal only */
Packit fcad23
		if (pton && base != 10)
Packit fcad23
			return (0);
Packit fcad23
		for (;;) {
Packit fcad23
			if (isdigit(c)) {
Packit fcad23
				digit = c - '0';
Packit fcad23
				if ((int)digit >= base)
Packit fcad23
					break;
Packit fcad23
				val = (val * base) + digit;
Packit fcad23
				c = *++src;
Packit fcad23
			} else if (base == 16 && isxdigit(c)) {
Packit fcad23
				digit = c + 10 - (islower(c) ? 'a' : 'A');
Packit fcad23
				if (digit >= 16)
Packit fcad23
					break;
Packit fcad23
				val = (val << 4) | digit;
Packit fcad23
				c = *++src;
Packit fcad23
			} else
Packit fcad23
				break;
Packit fcad23
		}
Packit fcad23
		if (c == '.') {
Packit fcad23
			/*
Packit fcad23
			 * Internet format:
Packit fcad23
			 *	a.b.c.d
Packit fcad23
			 *	a.b.c	(with c treated as 16 bits)
Packit fcad23
			 *	a.b	(with b treated as 24 bits)
Packit fcad23
			 *	a	(with a treated as 32 bits)
Packit fcad23
			 */
Packit fcad23
			if (pp >= parts + 3)
Packit fcad23
				return (0);
Packit fcad23
			*pp++ = val;
Packit fcad23
			c = *++src;
Packit fcad23
		} else
Packit fcad23
			break;
Packit fcad23
	}
Packit fcad23
	/*
Packit fcad23
	 * Check for trailing characters.
Packit fcad23
	 */
Packit fcad23
	if (c != '\0' && !isspace(c))
Packit fcad23
		return (0);
Packit fcad23
	/*
Packit fcad23
	 * Concoct the address according to
Packit fcad23
	 * the number of parts specified.
Packit fcad23
	 */
Packit fcad23
	n = pp - parts + 1;
Packit fcad23
	/* inet_pton() takes dotted-quad only.  it does not take shorthand. */
Packit fcad23
	if (pton && n != 4)
Packit fcad23
		return (0);
Packit fcad23
	switch (n) {
Packit fcad23
Packit fcad23
	case 0:
Packit fcad23
		return (0);		/* initial nondigit */
Packit fcad23
Packit fcad23
	case 1:				/* a -- 32 bits */
Packit fcad23
		break;
Packit fcad23
Packit fcad23
	case 2:				/* a.b -- 8.24 bits */
Packit fcad23
		if (parts[0] > 0xff || val > 0xffffff)
Packit fcad23
			return (0);
Packit fcad23
		val |= parts[0] << 24;
Packit fcad23
		break;
Packit fcad23
Packit fcad23
	case 3:				/* a.b.c -- 8.8.16 bits */
Packit fcad23
		if ((parts[0] | parts[1]) > 0xff || val > 0xffff)
Packit fcad23
			return (0);
Packit fcad23
		val |= (parts[0] << 24) | (parts[1] << 16);
Packit fcad23
		break;
Packit fcad23
Packit fcad23
	case 4:				/* a.b.c.d -- 8.8.8.8 bits */
Packit fcad23
		if ((parts[0] | parts[1] | parts[2] | val) > 0xff)
Packit fcad23
			return (0);
Packit fcad23
		val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
Packit fcad23
		break;
Packit fcad23
	}
Packit fcad23
	if (dst) {
Packit fcad23
		val = htonl(val);
Packit fcad23
		memcpy(dst, &val, INADDRSZ);
Packit fcad23
	}
Packit fcad23
	return (1);
Packit fcad23
}
Packit fcad23
Packit fcad23
#ifdef NETSNMP_ENABLE_IPV6
Packit fcad23
/* int
Packit fcad23
 * inet_pton6(src, dst)
Packit fcad23
 *	convert presentation level address to network order binary form.
Packit fcad23
 * return:
Packit fcad23
 *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
Packit fcad23
 * notice:
Packit fcad23
 *	(1) does not touch `dst' unless it's returning 1.
Packit fcad23
 *	(2) :: in a full address is silently ignored.
Packit fcad23
 * credit:
Packit fcad23
 *	inspired by Mark Andrews.
Packit fcad23
 * author:
Packit fcad23
 *	Paul Vixie, 1996.
Packit fcad23
 */
Packit fcad23
static int
Packit fcad23
inet_pton6(const char *src, u_char *dst)
Packit fcad23
{
Packit fcad23
	static const char xdigits_l[] = "0123456789abcdef",
Packit fcad23
			  xdigits_u[] = "0123456789ABCDEF";
Packit fcad23
	u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
Packit fcad23
	const char *xdigits, *curtok;
Packit fcad23
	int ch, saw_xdigit;
Packit fcad23
	u_int val;
Packit fcad23
Packit fcad23
	memset((tp = tmp), '\0', IN6ADDRSZ);
Packit fcad23
	endp = tp + IN6ADDRSZ;
Packit fcad23
	colonp = NULL;
Packit fcad23
	/* Leading :: requires some special handling. */
Packit fcad23
	if (*src == ':')
Packit fcad23
		if (*++src != ':')
Packit fcad23
			return (0);
Packit fcad23
	curtok = src;
Packit fcad23
	saw_xdigit = 0;
Packit fcad23
	val = 0;
Packit fcad23
	while ((ch = *src++) != '\0') {
Packit fcad23
		const char *pch;
Packit fcad23
Packit fcad23
		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
Packit fcad23
			pch = strchr((xdigits = xdigits_u), ch);
Packit fcad23
		if (pch != NULL) {
Packit fcad23
			val <<= 4;
Packit fcad23
			val |= (pch - xdigits);
Packit fcad23
			if (val > 0xffff)
Packit fcad23
				return (0);
Packit fcad23
			saw_xdigit = 1;
Packit fcad23
			continue;
Packit fcad23
		}
Packit fcad23
		if (ch == ':') {
Packit fcad23
			curtok = src;
Packit fcad23
			if (!saw_xdigit) {
Packit fcad23
				if (colonp)
Packit fcad23
					return (0);
Packit fcad23
				colonp = tp;
Packit fcad23
				continue;
Packit fcad23
			} else if (*src == '\0')
Packit fcad23
				return (0);
Packit fcad23
			if (tp + INT16SZ > endp)
Packit fcad23
				return (0);
Packit fcad23
			*tp++ = (u_char) (val >> 8) & 0xff;
Packit fcad23
			*tp++ = (u_char) val & 0xff;
Packit fcad23
			saw_xdigit = 0;
Packit fcad23
			val = 0;
Packit fcad23
			continue;
Packit fcad23
		}
Packit fcad23
		if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
Packit fcad23
		    inet_pton4(curtok, tp, 1) > 0) {
Packit fcad23
			tp += INADDRSZ;
Packit fcad23
			saw_xdigit = 0;
Packit fcad23
			break;	/* '\0' was seen by inet_pton4(). */
Packit fcad23
		}
Packit fcad23
		return (0);
Packit fcad23
	}
Packit fcad23
	if (saw_xdigit) {
Packit fcad23
		if (tp + INT16SZ > endp)
Packit fcad23
			return (0);
Packit fcad23
		*tp++ = (u_char) (val >> 8) & 0xff;
Packit fcad23
		*tp++ = (u_char) val & 0xff;
Packit fcad23
	}
Packit fcad23
	if (colonp != NULL) {
Packit fcad23
		/*
Packit fcad23
		 * Since some memmove()'s erroneously fail to handle
Packit fcad23
		 * overlapping regions, we'll do the shift by hand.
Packit fcad23
		 */
Packit fcad23
		const int n = tp - colonp;
Packit fcad23
		int i;
Packit fcad23
Packit fcad23
		if (tp == endp)
Packit fcad23
			return (0);
Packit fcad23
		for (i = 1; i <= n; i++) {
Packit fcad23
			endp[- i] = colonp[n - i];
Packit fcad23
			colonp[n - i] = 0;
Packit fcad23
		}
Packit fcad23
		tp = endp;
Packit fcad23
	}
Packit fcad23
	if (tp != endp)
Packit fcad23
		return (0);
Packit fcad23
	memcpy(dst, tmp, IN6ADDRSZ);
Packit fcad23
	return (1);
Packit fcad23
}
Packit fcad23
#endif