inet_pton.c revision 302408
198943Sluigi/*	$KAME: inet_pton.c,v 1.5 2001/08/20 02:32:40 itojun Exp $	*/
2117328Sluigi
398943Sluigi/* Copyright (c) 1996 by Internet Software Consortium.
498943Sluigi *
598943Sluigi * Permission to use, copy, modify, and distribute this software for any
698943Sluigi * purpose with or without fee is hereby granted, provided that the above
798943Sluigi * copyright notice and this permission notice appear in all copies.
898943Sluigi *
998943Sluigi * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
1098943Sluigi * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
1198943Sluigi * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
1298943Sluigi * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
1398943Sluigi * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
1498943Sluigi * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
1598943Sluigi * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1698943Sluigi * SOFTWARE.
1798943Sluigi */
1898943Sluigi
1998943Sluigi#include <ldns/config.h>
2098943Sluigi
2198943Sluigi#include <string.h>
2298943Sluigi#include <stdio.h>
2398943Sluigi#include <errno.h>
2498943Sluigi
2598943Sluigi/*
2698943Sluigi * WARNING: Don't even consider trying to compile this on a system where
2798943Sluigi * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
2898943Sluigi */
2998943Sluigi
30136071Sgreenstatic int	inet_pton4 (const char *src, uint8_t *dst);
3198943Sluigistatic int	inet_pton6 (const char *src, uint8_t *dst);
3298943Sluigi
3398943Sluigi/*
3498943Sluigi *
3598943Sluigi * The definitions we might miss.
3698943Sluigi *
3798943Sluigi */
3898943Sluigi#ifndef NS_INT16SZ
3998943Sluigi#define	NS_INT16SZ	2
4098943Sluigi#endif
4198943Sluigi
4298943Sluigi#ifndef NS_IN6ADDRSZ
4398943Sluigi#define NS_IN6ADDRSZ 16
44117469Sluigi#endif
4598943Sluigi
4698943Sluigi#ifndef NS_INADDRSZ
47136071Sgreen#define NS_INADDRSZ 4
48136071Sgreen#endif
4998943Sluigi
5098943Sluigi/* int
51136071Sgreen * inet_pton(af, src, dst)
52145246Sbrooks *	convert from presentation format (which usually means ASCII printable)
5398943Sluigi *	to network format (which is usually some kind of binary format).
5498943Sluigi * return:
5598943Sluigi *	1 if the address was valid for the specified address family
5698943Sluigi *	0 if the address wasn't valid (`dst' is untouched in this case)
57145246Sbrooks *	-1 if some other error occurred (`dst' is untouched in this case, too)
5898943Sluigi * author:
5998943Sluigi *	Paul Vixie, 1996.
6098943Sluigi */
6198943Sluigiint
6298943Sluigiinet_pton(af, src, dst)
63117328Sluigi	int af;
6498943Sluigi	const char *src;
6598943Sluigi	void *dst;
6698943Sluigi{
6798943Sluigi	switch (af) {
6898943Sluigi	case AF_INET:
6998943Sluigi		return (inet_pton4(src, dst));
7098943Sluigi	case AF_INET6:
71102098Sluigi		return (inet_pton6(src, dst));
72123804Smaxim	default:
73101628Sluigi#ifdef EAFNOSUPPORT
74117328Sluigi		errno = EAFNOSUPPORT;
75123495Sluigi#else
7698943Sluigi		errno = ENOSYS;
7798943Sluigi#endif
7898943Sluigi		return (-1);
79130013Scsjp	}
80130013Scsjp	/* NOTREACHED */
81130013Scsjp}
82130013Scsjp
83130013Scsjp/* int
8498943Sluigi * inet_pton4(src, dst)
85158879Soleg *	like inet_aton() but without all the hexadecimal and shorthand.
86158879Soleg * return:
87158879Soleg *	1 if `src' is a valid dotted quad, else 0.
88158879Soleg * notice:
89158879Soleg *	does not touch `dst' unless it's returning 1.
90158879Soleg * author:
91158879Soleg *	Paul Vixie, 1996.
92158879Soleg */
93158879Solegstatic int
9498943Sluigiinet_pton4(src, dst)
95117328Sluigi	const char *src;
96117328Sluigi	uint8_t *dst;
97117328Sluigi{
98117328Sluigi	static const char digits[] = "0123456789";
99117328Sluigi	int saw_digit, octets, ch;
10098943Sluigi	uint8_t tmp[NS_INADDRSZ], *tp;
10198943Sluigi
10298943Sluigi	saw_digit = 0;
103117469Sluigi	octets = 0;
10498943Sluigi	*(tp = tmp) = 0;
10598943Sluigi	while ((ch = *src++) != '\0') {
10698943Sluigi		const char *pch;
10798943Sluigi
10898943Sluigi		if ((pch = strchr(digits, ch)) != NULL) {
10998943Sluigi			uint32_t new = *tp * 10 + (pch - digits);
11098943Sluigi
11198943Sluigi			if (new > 255)
11298943Sluigi				return (0);
11398943Sluigi			*tp = new;
11498943Sluigi			if (! saw_digit) {
11598943Sluigi				if (++octets > 4)
11698943Sluigi					return (0);
11798943Sluigi				saw_digit = 1;
11898943Sluigi			}
11998943Sluigi		} else if (ch == '.' && saw_digit) {
12098943Sluigi			if (octets == 4)
12198943Sluigi				return (0);
12298943Sluigi			*++tp = 0;
12398943Sluigi			saw_digit = 0;
12498943Sluigi		} else
12598943Sluigi			return (0);
12698943Sluigi	}
12798943Sluigi	if (octets < 4)
12898943Sluigi		return (0);
12998943Sluigi
13098943Sluigi	memcpy(dst, tmp, NS_INADDRSZ);
13198943Sluigi	return (1);
13298943Sluigi}
13398943Sluigi
13498943Sluigi/* int
13598943Sluigi * inet_pton6(src, dst)
13698943Sluigi *	convert presentation level address to network order binary form.
13798943Sluigi * return:
13898943Sluigi *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
13998943Sluigi * notice:
14098943Sluigi *	(1) does not touch `dst' unless it's returning 1.
14198943Sluigi *	(2) :: in a full address is silently ignored.
14298943Sluigi * credit:
14398943Sluigi *	inspired by Mark Andrews.
14498943Sluigi * author:
14598943Sluigi *	Paul Vixie, 1996.
14698943Sluigi */
14798943Sluigistatic int
14898943Sluigiinet_pton6(src, dst)
14998943Sluigi	const char *src;
15098943Sluigi	uint8_t *dst;
15198943Sluigi{
15298943Sluigi	static const char xdigits_l[] = "0123456789abcdef",
15398943Sluigi			  xdigits_u[] = "0123456789ABCDEF";
15498943Sluigi	uint8_t tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
15598943Sluigi	const char *xdigits, *curtok;
15698943Sluigi	int ch, saw_xdigit;
15798943Sluigi	uint32_t val;
15898943Sluigi
15998943Sluigi	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
16098943Sluigi	endp = tp + NS_IN6ADDRSZ;
16198943Sluigi	colonp = NULL;
16298943Sluigi	/* Leading :: requires some special handling. */
16398943Sluigi	if (*src == ':')
16498943Sluigi		if (*++src != ':')
16598943Sluigi			return (0);
16698943Sluigi	curtok = src;
16798943Sluigi	saw_xdigit = 0;
16898943Sluigi	val = 0;
16998943Sluigi	while ((ch = *src++) != '\0') {
17098943Sluigi		const char *pch;
17198943Sluigi
17298943Sluigi		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
17398943Sluigi			pch = strchr((xdigits = xdigits_u), ch);
17498943Sluigi		if (pch != NULL) {
17598943Sluigi			val <<= 4;
17698943Sluigi			val |= (pch - xdigits);
17798943Sluigi			if (val > 0xffff)
17898943Sluigi				return (0);
17998943Sluigi			saw_xdigit = 1;
18098943Sluigi			continue;
18198943Sluigi		}
18298943Sluigi		if (ch == ':') {
18398943Sluigi			curtok = src;
18498943Sluigi			if (!saw_xdigit) {
18598943Sluigi				if (colonp)
18698943Sluigi					return (0);
18798943Sluigi				colonp = tp;
18898943Sluigi				continue;
18998943Sluigi			}
19098943Sluigi			if (tp + NS_INT16SZ > endp)
19198943Sluigi				return (0);
19298943Sluigi			*tp++ = (uint8_t) (val >> 8) & 0xff;
19398943Sluigi			*tp++ = (uint8_t) val & 0xff;
19498943Sluigi			saw_xdigit = 0;
19598943Sluigi			val = 0;
19698943Sluigi			continue;
19798943Sluigi		}
19898943Sluigi		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
19998943Sluigi		    inet_pton4(curtok, tp) > 0) {
20098943Sluigi			tp += NS_INADDRSZ;
20198943Sluigi			saw_xdigit = 0;
20298943Sluigi			break;	/* '\0' was seen by inet_pton4(). */
203101641Sluigi		}
204101641Sluigi		return (0);
20598943Sluigi	}
20698943Sluigi	if (saw_xdigit) {
20798943Sluigi		if (tp + NS_INT16SZ > endp)
20898943Sluigi			return (0);
20998943Sluigi		*tp++ = (uint8_t) (val >> 8) & 0xff;
21098943Sluigi		*tp++ = (uint8_t) val & 0xff;
21198943Sluigi	}
212141351Sglebius	if (colonp != NULL) {
213141351Sglebius		/*
21498943Sluigi		 * Since some memmove()'s erroneously fail to handle
21598943Sluigi		 * overlapping regions, we'll do the shift by hand.
21698943Sluigi		 */
21798943Sluigi		const int n = tp - colonp;
21898943Sluigi		int i;
21998943Sluigi
22098943Sluigi		for (i = 1; i <= n; i++) {
22198943Sluigi			endp[- i] = colonp[n - i];
222136071Sgreen			colonp[n - i] = 0;
223136071Sgreen		}
224158879Soleg		tp = endp;
225158879Soleg	}
226136071Sgreen	if (tp != endp)
227158879Soleg		return (0);
22898943Sluigi	memcpy(dst, tmp, NS_IN6ADDRSZ);
22998943Sluigi	return (1);
230133600Scsjp}
23198943Sluigi