Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
      3  * Copyright (c) 1996,1999 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 ISC DISCLAIMS ALL WARRANTIES
     10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     11  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
     12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     15  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     16  */
     17 
     18 #ifdef HAVE_CONFIG_H
     19 #include "config.h"
     20 #endif
     21 
     22 #include <netdissect-stdinc.h>
     23 #include <stddef.h>
     24 #include <string.h>
     25 
     26 #include "strtoaddr.h"
     27 
     28 #ifndef NS_INADDRSZ
     29 #define NS_INADDRSZ	4	/* IPv4 T_A */
     30 #endif
     31 
     32 #ifndef NS_IN6ADDRSZ
     33 #define NS_IN6ADDRSZ	16	/* IPv6 T_AAAA */
     34 #endif
     35 
     36 #ifndef NS_INT16SZ
     37 #define NS_INT16SZ	2	/* #/bytes of data in a uint16_t */
     38 #endif
     39 
     40 /*%
     41  * WARNING: Don't even consider trying to compile this on a system where
     42  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
     43  */
     44 
     45 #ifndef NS_IN6ADDRSZ
     46 #define NS_IN6ADDRSZ   16   /* IPv6 T_AAAA */
     47 #endif
     48 
     49 /* int
     50  * strtoaddr(src, dst)
     51  *	convert presentation level IPv4 address to network order binary form.
     52  * return:
     53  *	1 if `src' is a valid input, else 0.
     54  * notice:
     55  *	does not touch `dst' unless it's returning 1.
     56  * author:
     57  *	Paul Vixie, 1996.
     58  */
     59 int
     60 strtoaddr(const char *src, void *dst)
     61 {
     62 	uint32_t val;
     63 	u_int digit;
     64 	ptrdiff_t n;
     65 	unsigned char c;
     66 	u_int parts[4];
     67 	u_int *pp = parts;
     68 
     69 	c = *src;
     70 	for (;;) {
     71 		/*
     72 		 * Collect number up to ``.''.
     73 		 * Values are specified as for C:
     74 		 * 0x=hex, 0=octal, isdigit=decimal.
     75 		 */
     76 		if (!isdigit(c))
     77 			return (0);
     78 		val = 0;
     79 		if (c == '0') {
     80 			c = *++src;
     81 			if (c == 'x' || c == 'X')
     82 				return (0);
     83 			else if (isdigit(c) && c != '9')
     84 				return (0);
     85 		}
     86 		for (;;) {
     87 			if (isdigit(c)) {
     88 				digit = c - '0';
     89 				if (digit >= 10)
     90 					break;
     91 				val = (val * 10) + digit;
     92 				c = *++src;
     93 			} else
     94 				break;
     95 		}
     96 		if (c == '.') {
     97 			/*
     98 			 * Internet format:
     99 			 *	a.b.c.d
    100 			 *	a.b.c	(with c treated as 16 bits)
    101 			 *	a.b	(with b treated as 24 bits)
    102 			 *	a	(with a treated as 32 bits)
    103 			 */
    104 			if (pp >= parts + 3)
    105 				return (0);
    106 			*pp++ = val;
    107 			c = *++src;
    108 		} else
    109 			break;
    110 	}
    111 	/*
    112 	 * Check for trailing characters.
    113 	 */
    114 	if (c != '\0' && !isspace(c))
    115 		return (0);
    116 	/*
    117 	 * Find the number of parts specified.
    118 	 * It must be 4; we only support dotted quads, we don't
    119 	 * support shorthand.
    120 	 */
    121 	n = pp - parts + 1;
    122 	if (n != 4)
    123 		return (0);
    124 	/*
    125 	 * parts[0-2] were set to the first 3 parts of the address;
    126 	 * val was set to the 4th part.
    127 	 *
    128 	 * Check if any part is bigger than 255.
    129 	 */
    130 	if ((parts[0] | parts[1] | parts[2] | val) > 0xff)
    131 		return (0);
    132 	/*
    133 	 * Add the other three parts to val.
    134 	 */
    135 	val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
    136 	if (dst) {
    137 		val = htonl(val);
    138 		memcpy(dst, &val, NS_INADDRSZ);
    139 	}
    140 	return (1);
    141 }
    142 
    143 /* int
    144  * strtoaddr6(src, dst)
    145  *	convert presentation level IPv6 address to network order binary form.
    146  * return:
    147  *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
    148  * notice:
    149  *	(1) does not touch `dst' unless it's returning 1.
    150  *	(2) :: in a full address is silently ignored.
    151  * credit:
    152  *	inspired by Mark Andrews.
    153  * author:
    154  *	Paul Vixie, 1996.
    155  */
    156 int
    157 strtoaddr6(const char *src, void *dst)
    158 {
    159 	static const char xdigits_l[] = "0123456789abcdef",
    160 			  xdigits_u[] = "0123456789ABCDEF";
    161 	u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
    162 	const char *xdigits, *curtok;
    163 	int ch, seen_xdigits;
    164 	u_int val;
    165 
    166 	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
    167 	endp = tp + NS_IN6ADDRSZ;
    168 	colonp = NULL;
    169 	/* Leading :: requires some special handling. */
    170 	if (*src == ':')
    171 		if (*++src != ':')
    172 			return (0);
    173 	curtok = src;
    174 	seen_xdigits = 0;
    175 	val = 0;
    176 	while ((ch = *src++) != '\0') {
    177 		const char *pch;
    178 
    179 		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
    180 			pch = strchr((xdigits = xdigits_u), ch);
    181 		if (pch != NULL) {
    182 			val <<= 4;
    183 			val |= (int)(pch - xdigits);
    184 			if (++seen_xdigits > 4)
    185 				return (0);
    186 			continue;
    187 		}
    188 		if (ch == ':') {
    189 			curtok = src;
    190 			if (!seen_xdigits) {
    191 				if (colonp)
    192 					return (0);
    193 				colonp = tp;
    194 				continue;
    195 			} else if (*src == '\0')
    196 				return (0);
    197 			if (tp + NS_INT16SZ > endp)
    198 				return (0);
    199 			*tp++ = (u_char) (val >> 8) & 0xff;
    200 			*tp++ = (u_char) val & 0xff;
    201 			seen_xdigits = 0;
    202 			val = 0;
    203 			continue;
    204 		}
    205 		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
    206 		    strtoaddr(curtok, tp) > 0) {
    207 			tp += NS_INADDRSZ;
    208 			seen_xdigits = 0;
    209 			break;	/*%< '\\0' was seen by strtoaddr(). */
    210 		}
    211 		return (0);
    212 	}
    213 	if (seen_xdigits) {
    214 		if (tp + NS_INT16SZ > endp)
    215 			return (0);
    216 		*tp++ = (u_char) (val >> 8) & 0xff;
    217 		*tp++ = (u_char) val & 0xff;
    218 	}
    219 	if (colonp != NULL) {
    220 		/*
    221 		 * Since some memmove()'s erroneously fail to handle
    222 		 * overlapping regions, we'll do the shift by hand.
    223 		 */
    224 		const ptrdiff_t n = tp - colonp;
    225 		int i;
    226 
    227 		if (tp == endp)
    228 			return (0);
    229 		for (i = 1; i <= n; i++) {
    230 			endp[- i] = colonp[n - i];
    231 			colonp[n - i] = 0;
    232 		}
    233 		tp = endp;
    234 	}
    235 	if (tp != endp)
    236 		return (0);
    237 	memcpy(dst, tmp, NS_IN6ADDRSZ);
    238 	return (1);
    239 }
    240