Home | History | Annotate | Download | only in net
      1 /*	$OpenBSD: inet_pton.c,v 1.10 2015/09/13 21:36:08 guenther Exp $	*/
      2 
      3 /* Copyright (c) 1996 by Internet Software Consortium.
      4  *
      5  * Permission to use, copy, modify, and distribute this software for any
      6  * purpose with or without fee is hereby granted, provided that the above
      7  * copyright notice and this permission notice appear in all copies.
      8  *
      9  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
     10  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
     11  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
     12  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
     13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
     14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
     15  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     16  * SOFTWARE.
     17  */
     18 
     19 #include <sys/types.h>
     20 #include <sys/socket.h>
     21 #include <netinet/in.h>
     22 #include <arpa/inet.h>
     23 #include <arpa/nameser.h>
     24 #include <string.h>
     25 #include <errno.h>
     26 
     27 /*
     28  * WARNING: Don't even consider trying to compile this on a system where
     29  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
     30  */
     31 
     32 static int	inet_pton4(const char *src, u_char *dst);
     33 static int	inet_pton6(const char *src, u_char *dst);
     34 
     35 /* int
     36  * inet_pton(af, src, dst)
     37  *	convert from presentation format (which usually means ASCII printable)
     38  *	to network format (which is usually some kind of binary format).
     39  * return:
     40  *	1 if the address was valid for the specified address family
     41  *	0 if the address wasn't valid (`dst' is untouched in this case)
     42  *	-1 if some other error occurred (`dst' is untouched in this case, too)
     43  * author:
     44  *	Paul Vixie, 1996.
     45  */
     46 int
     47 inet_pton(int af, const char *src, void *dst)
     48 {
     49 	switch (af) {
     50 	case AF_INET:
     51 		return (inet_pton4(src, dst));
     52 	case AF_INET6:
     53 		return (inet_pton6(src, dst));
     54 	default:
     55 		errno = EAFNOSUPPORT;
     56 		return (-1);
     57 	}
     58 	/* NOTREACHED */
     59 }
     60 DEF_WEAK(inet_pton);
     61 
     62 /* int
     63  * inet_pton4(src, dst)
     64  *	like inet_aton() but without all the hexadecimal and shorthand.
     65  * return:
     66  *	1 if `src' is a valid dotted quad, else 0.
     67  * notice:
     68  *	does not touch `dst' unless it's returning 1.
     69  * author:
     70  *	Paul Vixie, 1996.
     71  */
     72 static int
     73 inet_pton4(const char *src, u_char *dst)
     74 {
     75 	static const char digits[] = "0123456789";
     76 	int saw_digit, octets, ch;
     77 	u_char tmp[INADDRSZ], *tp;
     78 
     79 	saw_digit = 0;
     80 	octets = 0;
     81 	*(tp = tmp) = 0;
     82 	while ((ch = *src++) != '\0') {
     83 		const char *pch;
     84 
     85 		if ((pch = strchr(digits, ch)) != NULL) {
     86 			u_int new = *tp * 10 + (pch - digits);
     87 
     88 			if (new > 255)
     89 				return (0);
     90 			if (! saw_digit) {
     91 				if (++octets > 4)
     92 					return (0);
     93 				saw_digit = 1;
     94 			}
     95 			*tp = new;
     96 		} else if (ch == '.' && saw_digit) {
     97 			if (octets == 4)
     98 				return (0);
     99 			*++tp = 0;
    100 			saw_digit = 0;
    101 		} else
    102 			return (0);
    103 	}
    104 	if (octets < 4)
    105 		return (0);
    106 
    107 	memcpy(dst, tmp, INADDRSZ);
    108 	return (1);
    109 }
    110 
    111 /* int
    112  * inet_pton6(src, dst)
    113  *	convert presentation level address to network order binary form.
    114  * return:
    115  *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
    116  * notice:
    117  *	does not touch `dst' unless it's returning 1.
    118  * credit:
    119  *	inspired by Mark Andrews.
    120  * author:
    121  *	Paul Vixie, 1996.
    122  */
    123 static int
    124 inet_pton6(const char *src, u_char *dst)
    125 {
    126 	static const char xdigits_l[] = "0123456789abcdef",
    127 			  xdigits_u[] = "0123456789ABCDEF";
    128 	u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
    129 	const char *xdigits, *curtok;
    130 	int ch, saw_xdigit, count_xdigit;
    131 	u_int val;
    132 
    133 	memset((tp = tmp), '\0', IN6ADDRSZ);
    134 	endp = tp + IN6ADDRSZ;
    135 	colonp = NULL;
    136 	/* Leading :: requires some special handling. */
    137 	if (*src == ':')
    138 		if (*++src != ':')
    139 			return (0);
    140 	curtok = src;
    141 	saw_xdigit = count_xdigit = 0;
    142 	val = 0;
    143 	while ((ch = *src++) != '\0') {
    144 		const char *pch;
    145 
    146 		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
    147 			pch = strchr((xdigits = xdigits_u), ch);
    148 		if (pch != NULL) {
    149 			if (count_xdigit >= 4)
    150 				return (0);
    151 			val <<= 4;
    152 			val |= (pch - xdigits);
    153 			if (val > 0xffff)
    154 				return (0);
    155 			saw_xdigit = 1;
    156 			count_xdigit++;
    157 			continue;
    158 		}
    159 		if (ch == ':') {
    160 			curtok = src;
    161 			if (!saw_xdigit) {
    162 				if (colonp)
    163 					return (0);
    164 				colonp = tp;
    165 				continue;
    166 			} else if (*src == '\0') {
    167 				return (0);
    168 			}
    169 			if (tp + INT16SZ > endp)
    170 				return (0);
    171 			*tp++ = (u_char) (val >> 8) & 0xff;
    172 			*tp++ = (u_char) val & 0xff;
    173 			saw_xdigit = 0;
    174 			count_xdigit = 0;
    175 			val = 0;
    176 			continue;
    177 		}
    178 		if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
    179 		    inet_pton4(curtok, tp) > 0) {
    180 			tp += INADDRSZ;
    181 			saw_xdigit = 0;
    182 			count_xdigit = 0;
    183 			break;	/* '\0' was seen by inet_pton4(). */
    184 		}
    185 		return (0);
    186 	}
    187 	if (saw_xdigit) {
    188 		if (tp + INT16SZ > endp)
    189 			return (0);
    190 		*tp++ = (u_char) (val >> 8) & 0xff;
    191 		*tp++ = (u_char) val & 0xff;
    192 	}
    193 	if (colonp != NULL) {
    194 		/*
    195 		 * Since some memmove()'s erroneously fail to handle
    196 		 * overlapping regions, we'll do the shift by hand.
    197 		 */
    198 		const int n = tp - colonp;
    199 		int i;
    200 
    201 		if (tp == endp)
    202 			return (0);
    203 		for (i = 1; i <= n; i++) {
    204 			endp[- i] = colonp[n - i];
    205 			colonp[n - i] = 0;
    206 		}
    207 		tp = endp;
    208 	}
    209 	if (tp != endp)
    210 		return (0);
    211 	memcpy(dst, tmp, IN6ADDRSZ);
    212 	return (1);
    213 }
    214