1/* $NetBSD: inet_pton.c,v 1.9 2007/07/23 11:45:52 lukem Exp $ */ 2/* from NetBSD: inet_pton.c,v 1.3 2006/09/26 05:59:18 lukem Exp */ 3 4/* 5 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 6 * Copyright (c) 1996,1999 by Internet Software Consortium. 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 18 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21#include "tnftp.h" 22 23#if defined(HAVE_ARPA_NAMESER_H) 24# include <arpa/nameser.h> 25#endif 26#if !defined(NS_INADDRSZ) 27# define NS_INADDRSZ 4 28#endif 29#if !defined(NS_IN6ADDRSZ) 30# define NS_IN6ADDRSZ 16 31#endif 32#if !defined(NS_INT16SZ) 33# define NS_INT16SZ 2 34#endif 35 36/* 37 * WARNING: Don't even consider trying to compile this on a system where 38 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 39 */ 40 41static int inet_pton4(const char *src, unsigned char *dst, int pton); 42#ifdef INET6 43static int inet_pton6(const char *src, unsigned char *dst); 44#endif /* INET6 */ 45 46/* int 47 * inet_pton(af, src, dst) 48 * convert from presentation format (which usually means ASCII printable) 49 * to network format (which is usually some kind of binary format). 50 * return: 51 * 1 if the address was valid for the specified address family 52 * 0 if the address wasn't valid (`dst' is untouched in this case) 53 * -1 if some other error occurred (`dst' is untouched in this case, too) 54 * author: 55 * Paul Vixie, 1996. 56 */ 57int 58inet_pton(int af, const char *src, void *dst) 59{ 60 61 switch (af) { 62 case AF_INET: 63 return (inet_pton4(src, dst, 1)); 64#ifdef INET6 65 case AF_INET6: 66 return (inet_pton6(src, dst)); 67#endif /* INET6 */ 68 default: 69 errno = EAFNOSUPPORT; 70 return (-1); 71 } 72 /* NOTREACHED */ 73} 74 75/* int 76 * inet_pton4(src, dst, pton) 77 * when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand. 78 * when last arg is 1: inet_pton(). decimal dotted-quad only. 79 * return: 80 * 1 if `src' is a valid input, else 0. 81 * notice: 82 * does not touch `dst' unless it's returning 1. 83 * author: 84 * Paul Vixie, 1996. 85 */ 86static int 87inet_pton4(const char *src, unsigned char *dst, int pton) 88{ 89 uint32_t val; 90 unsigned int digit, base; 91 int n; 92 unsigned char c; 93 unsigned int parts[4]; 94 register unsigned int *pp = parts; 95 96 c = *src; 97 for (;;) { 98 /* 99 * Collect number up to ``.''. 100 * Values are specified as for C: 101 * 0x=hex, 0=octal, isdigit=decimal. 102 */ 103 if (!isdigit(c)) 104 return (0); 105 val = 0; base = 10; 106 if (c == '0') { 107 c = *++src; 108 if (c == 'x' || c == 'X') 109 base = 16, c = *++src; 110 else if (isdigit(c) && c != '9') 111 base = 8; 112 } 113 /* inet_pton() takes decimal only */ 114 if (pton && base != 10) 115 return (0); 116 for (;;) { 117 if (isdigit(c)) { 118 digit = c - '0'; 119 if (digit >= base) 120 break; 121 val = (val * base) + digit; 122 c = *++src; 123 } else if (base == 16 && isxdigit(c)) { 124 digit = c + 10 - (islower(c) ? 'a' : 'A'); 125 if (digit >= 16) 126 break; 127 val = (val << 4) | digit; 128 c = *++src; 129 } else 130 break; 131 } 132 if (c == '.') { 133 /* 134 * Internet format: 135 * a.b.c.d 136 * a.b.c (with c treated as 16 bits) 137 * a.b (with b treated as 24 bits) 138 * a (with a treated as 32 bits) 139 */ 140 if (pp >= parts + 3) 141 return (0); 142 *pp++ = val; 143 c = *++src; 144 } else 145 break; 146 } 147 /* 148 * Check for trailing characters. 149 */ 150 if (c != '\0' && !isspace(c)) 151 return (0); 152 /* 153 * Concoct the address according to 154 * the number of parts specified. 155 */ 156 n = pp - parts + 1; 157 /* inet_pton() takes dotted-quad only. it does not take shorthand. */ 158 if (pton && n != 4) 159 return (0); 160 switch (n) { 161 162 case 0: 163 return (0); /* initial nondigit */ 164 165 case 1: /* a -- 32 bits */ 166 break; 167 168 case 2: /* a.b -- 8.24 bits */ 169 if (parts[0] > 0xff || val > 0xffffff) 170 return (0); 171 val |= parts[0] << 24; 172 break; 173 174 case 3: /* a.b.c -- 8.8.16 bits */ 175 if ((parts[0] | parts[1]) > 0xff || val > 0xffff) 176 return (0); 177 val |= (parts[0] << 24) | (parts[1] << 16); 178 break; 179 180 case 4: /* a.b.c.d -- 8.8.8.8 bits */ 181 if ((parts[0] | parts[1] | parts[2] | val) > 0xff) 182 return (0); 183 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 184 break; 185 } 186 if (dst) { 187 val = htonl(val); 188 memcpy(dst, &val, NS_INADDRSZ); 189 } 190 return (1); 191} 192 193#ifdef INET6 194/* int 195 * inet_pton6(src, dst) 196 * convert presentation level address to network order binary form. 197 * return: 198 * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 199 * notice: 200 * (1) does not touch `dst' unless it's returning 1. 201 * (2) :: in a full address is silently ignored. 202 * credit: 203 * inspired by Mark Andrews. 204 * author: 205 * Paul Vixie, 1996. 206 */ 207static int 208inet_pton6(const char *src, unsigned char *dst) 209{ 210 static const char xdigits_l[] = "0123456789abcdef", 211 xdigits_u[] = "0123456789ABCDEF"; 212 unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; 213 const char *xdigits, *curtok; 214 int ch, saw_xdigit; 215 unsigned int val; 216 217 memset((tp = tmp), '\0', NS_IN6ADDRSZ); 218 endp = tp + NS_IN6ADDRSZ; 219 colonp = NULL; 220 /* Leading :: requires some special handling. */ 221 if (*src == ':') 222 if (*++src != ':') 223 return (0); 224 curtok = src; 225 saw_xdigit = 0; 226 val = 0; 227 while ((ch = *src++) != '\0') { 228 const char *pch; 229 230 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 231 pch = strchr((xdigits = xdigits_u), ch); 232 if (pch != NULL) { 233 val <<= 4; 234 val |= (pch - xdigits); 235 if (val > 0xffff) 236 return (0); 237 saw_xdigit = 1; 238 continue; 239 } 240 if (ch == ':') { 241 curtok = src; 242 if (!saw_xdigit) { 243 if (colonp) 244 return (0); 245 colonp = tp; 246 continue; 247 } else if (*src == '\0') 248 return (0); 249 if (tp + NS_INT16SZ > endp) 250 return (0); 251 *tp++ = (unsigned char) (val >> 8) & 0xff; 252 *tp++ = (unsigned char) val & 0xff; 253 saw_xdigit = 0; 254 val = 0; 255 continue; 256 } 257 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && 258 inet_pton4(curtok, tp, 1) > 0) { 259 tp += NS_INADDRSZ; 260 saw_xdigit = 0; 261 break; /* '\0' was seen by inet_pton4(). */ 262 } 263 return (0); 264 } 265 if (saw_xdigit) { 266 if (tp + NS_INT16SZ > endp) 267 return (0); 268 *tp++ = (unsigned char) (val >> 8) & 0xff; 269 *tp++ = (unsigned char) val & 0xff; 270 } 271 if (colonp != NULL) { 272 /* 273 * Since some memmove()'s erroneously fail to handle 274 * overlapping regions, we'll do the shift by hand. 275 */ 276 const int n = tp - colonp; 277 int i; 278 279 if (tp == endp) 280 return (0); 281 for (i = 1; i <= n; i++) { 282 endp[- i] = colonp[n - i]; 283 colonp[n - i] = 0; 284 } 285 tp = endp; 286 } 287 if (tp != endp) 288 return (0); 289 memcpy(dst, tmp, NS_IN6ADDRSZ); 290 return (1); 291} 292#endif /* INET6 */ 293