inet_pton.c revision 1219:f89f56c2d9ac
1238722Skargl/*
2238722Skargl * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
3238722Skargl * Use is subject to license terms.
4238722Skargl */
5238722Skargl
6238722Skargl/*
7238722Skargl * Copyright (c) 1996 by Internet Software Consortium.
8238722Skargl *
9238722Skargl * Permission to use, copy, modify, and distribute this software for any
10238722Skargl * purpose with or without fee is hereby granted, provided that the above
11238722Skargl * copyright notice and this permission notice appear in all copies.
12238722Skargl *
13238722Skargl * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
14238722Skargl * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
15238722Skargl * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
16238722Skargl * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
17238722Skargl * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18238722Skargl * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19238722Skargl * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20238722Skargl * SOFTWARE.
21238722Skargl */
22238722Skargl
23238722Skargl#pragma ident	"%Z%%M%	%I%	%E% SMI"
24238722Skargl
25238722Skargl#include "mt.h"
26238722Skargl#include <stdlib.h>
27238722Skargl#include <ctype.h>
28238722Skargl#include <string.h>
29238722Skargl#include <strings.h>
30238722Skargl#include <netdb.h>
31238722Skargl#include <stdio.h>
32240864Skargl#include <arpa/inet.h>
33238722Skargl#include <netinet/in.h>
34238722Skargl#include <sys/socket.h>
35238722Skargl#include <errno.h>
36238722Skargl
37238722Skarglstatic int	inet_pton4(const char *src, uchar_t *dst);
38238722Skarglstatic int	inet_pton6(const char *src, uchar_t *dst);
39238784Skargl
40238722Skargl/*
41238722Skargl * int
42238722Skargl * inet_pton(af, src, dst)
43238722Skargl *	convert from presentation format (which usually means ASCII printable)
44238722Skargl *	to network format (which is usually some kind of binary format).
45238722Skargl * return:
46238722Skargl *	1 if the address was valid for the specified address family
47238722Skargl *	0 if the address wasn't valid (`dst' is untouched in this case)
48238783Skargl *	-1 if some other error occurred (`dst' is untouched in this case, too)
49238722Skargl * author:
50238722Skargl *	Paul Vixie, 1996.  Taken from on297-gate:dns stuff
51238722Skargl */
52240861Skarglint
53238722Skarglinet_pton(int af, const char *src, void *dst)
54238722Skargl{
55238722Skargl	switch (af) {
56238722Skargl	case AF_INET:
57238722Skargl		return (inet_pton4(src, dst));
58238722Skargl	case AF_INET6:
59238722Skargl		return (inet_pton6(src, dst));
60238722Skargl	default:
61238722Skargl		errno = EAFNOSUPPORT;
62238722Skargl		return (-1);
63241051Skargl	}
64238722Skargl	/* NOTREACHED */
65241051Skargl}
66238722Skargl
67241516Skargl/*
68238722Skargl * int
69238784Skargl * inet_pton4(src, dst)
70238784Skargl *	like inet_aton() but without all the hexadecimal and shorthand.
71238784Skargl * return:
72238722Skargl *	1 if `src' is a valid dotted quad, else 0.
73240864Skargl * notice:
74238722Skargl *	does not touch `dst' unless it's returning 1.
75238722Skargl *
76238722Skargl */
77238722Skargl#define	INADDRSZ	4
78238722Skargl#define	IN6ADDRSZ	16
79238784Skargl#define	INT16SZ		2
80238722Skargl
81238722Skarglstatic int
82238722Skarglinet_pton4(const char *src, uchar_t *dst)
83238722Skargl{
84238722Skargl	static const char digits[] = "0123456789";
85238722Skargl	int saw_digit, octets, ch;
86238722Skargl	uchar_t tmp[INADDRSZ], *tp;
87238722Skargl
88238784Skargl	saw_digit = 0;
89241516Skargl	octets = 0;
90241516Skargl	*(tp = tmp) = 0;
91240861Skargl	while ((ch = *src++) != '\0') {
92240861Skargl		const char *pch;
93241516Skargl
94241516Skargl		if ((pch = strchr(digits, ch)) != NULL) {
95238722Skargl			uint_t new = *tp * 10 + (pch - digits);
96238722Skargl
97238722Skargl			if (new > 255)
98238722Skargl				return (0);
99241516Skargl			*tp = new;
100241516Skargl			if (!saw_digit) {
101238722Skargl				if (++octets > 4)
102240861Skargl					return (0);
103240861Skargl				saw_digit = 1;
104240861Skargl			}
105240861Skargl		} else if (ch == '.' && saw_digit) {
106240861Skargl			if (octets == 4)
107240861Skargl				return (0);
108240861Skargl			*++tp = 0;
109240861Skargl			saw_digit = 0;
110240861Skargl		} else
111240861Skargl			return (0);
112240861Skargl	}
113240861Skargl	if (octets < 4)
114240861Skargl		return (0);
115240861Skargl
116240861Skargl	(void) memcpy(dst, tmp, INADDRSZ);
117240861Skargl	return (1);
118240861Skargl}
119240861Skargl
120240861Skargl
121240861Skargl/*
122240861Skargl * int
123240861Skargl * inet_pton6(src, dst)
124240861Skargl *	convert presentation level address to network order binary form.
125240861Skargl * return:
126240861Skargl *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
127240861Skargl * notice:
128240861Skargl *	(1) does not touch `dst' unless it's returning 1.
129240861Skargl *	(2) :: in a full address is silently ignored.
130240861Skargl * credit:
131240861Skargl *	inspired by Mark Andrews.
132240861Skargl *
133240861Skargl */
134240861Skargl
135240861Skargl
136240861Skarglstatic int
137240861Skarglinet_pton6(const char *src, uchar_t *dst)
138240861Skargl{
139240861Skargl	static const char xdigits_l[] = "0123456789abcdef",
140240861Skargl			xdigits_u[] = "0123456789ABCDEF";
141240861Skargl	uchar_t tmp[IN6ADDRSZ], *tp, *endp, *colonp;
142240861Skargl	const char *xdigits, *curtok;
143240861Skargl	int ch, saw_xdigit;
144240861Skargl	uint_t val;
145240861Skargl
146240861Skargl	(void) memset((tp = tmp), '\0', IN6ADDRSZ);
147240861Skargl	endp = tp + IN6ADDRSZ;
148240861Skargl	colonp = NULL;
149240861Skargl	/* Leading :: requires some special handling. */
150240861Skargl	if (*src == ':')
151240861Skargl		if (*++src != ':')
152240861Skargl			return (0);
153240861Skargl	curtok = src;
154240861Skargl	saw_xdigit = 0;
155240861Skargl	val = 0;
156240861Skargl	while ((ch = *src++) != '\0') {
157240861Skargl		const char *pch;
158240861Skargl
159240861Skargl		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
160240861Skargl			pch = strchr((xdigits = xdigits_u), ch);
161240861Skargl		if (pch != NULL) {
162240861Skargl			val <<= 4;
163240861Skargl			val |= (pch - xdigits);
164240861Skargl			if (val > 0xffff)
165240861Skargl				return (0);
166240861Skargl			saw_xdigit = 1;
167240861Skargl			continue;
168240861Skargl		}
169240861Skargl		if (ch == ':') {
170240861Skargl			curtok = src;
171240861Skargl			if (!saw_xdigit) {
172240861Skargl				if (colonp)
173240861Skargl					return (0);
174240861Skargl				colonp = tp;
175240861Skargl				continue;
176240861Skargl			} else if (*src == '\0') {
177240861Skargl				return (0);
178240861Skargl			}
179240861Skargl			if (tp + INT16SZ > endp)
180240861Skargl				return (0);
181240861Skargl			*tp++ = (uchar_t)(val >> 8) & 0xff;
182240861Skargl			*tp++ = (uchar_t)val & 0xff;
183240861Skargl			saw_xdigit = 0;
184240861Skargl			val = 0;
185240861Skargl			continue;
186240861Skargl		}
187240861Skargl		if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
188240861Skargl		    inet_pton4(curtok, tp) > 0) {
189240861Skargl			tp += INADDRSZ;
190240861Skargl			saw_xdigit = 0;
191240861Skargl			break;	/* '\0' was seen by inet_pton4(). */
192240861Skargl		}
193240861Skargl		return (0);
194240861Skargl	}
195240861Skargl	if (saw_xdigit) {
196240861Skargl		if (tp + INT16SZ > endp)
197240861Skargl			return (0);
198240861Skargl		*tp++ = (uchar_t)(val >> 8) & 0xff;
199240861Skargl		*tp++ = (uchar_t)val & 0xff;
200240861Skargl	}
201240861Skargl	if (colonp != NULL) {
202240861Skargl		/*
203240861Skargl		 * Since some memmove()'s erroneously fail to handle
204240861Skargl		 * overlapping regions, we'll do the shift by hand.
205240861Skargl		 */
206240861Skargl		const int n = tp - colonp;
207240861Skargl		int i;
208240861Skargl
209240861Skargl		if (tp == endp)
210240861Skargl			return (0);
211240861Skargl		for (i = 1; i <= n; i++) {
212240861Skargl			endp[- i] = colonp[n - i];
213240861Skargl			colonp[n - i] = 0;
214240861Skargl		}
215240861Skargl		tp = endp;
216240861Skargl	}
217240861Skargl	if (tp != endp)
218240861Skargl		return (0);
219240861Skargl	(void) memcpy(dst, tmp, IN6ADDRSZ);
220240861Skargl	return (1);
221240861Skargl}
222240861Skargl