net-snmp 5.7
|
00001 /* Id: inet_pton.c,v 1.5 2001/04/13 15:24:35 lukem Exp */ 00002 /* $NetBSD: inet_pton.c,v 1.16 2000/02/07 18:51:02 itojun Exp $ */ 00003 00004 /* Copyright (c) 1996 by Internet Software Consortium. 00005 * 00006 * Permission to use, copy, modify, and distribute this software for any 00007 * purpose with or without fee is hereby granted, provided that the above 00008 * copyright notice and this permission notice appear in all copies. 00009 * 00010 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 00011 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 00012 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 00013 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 00014 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 00015 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 00016 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 00017 * SOFTWARE. 00018 */ 00019 00020 #include <net-snmp/net-snmp-config.h> 00021 00022 #include <ctype.h> 00023 00024 #if HAVE_ARPA_NAMESER_H 00025 #include <arpa/nameser.h> 00026 #endif 00027 00028 #include <errno.h> 00029 #include <stdio.h> 00030 #if HAVE_STRING_H 00031 #include <string.h> 00032 #else 00033 #include <strings.h> 00034 #endif 00035 00036 #include <net-snmp/types.h> 00037 #include "inet_pton.h" 00038 00039 #ifndef EAFNOSUPPORT 00040 #define EAFNOSUPPORT WSAEAFNOSUPPORT 00041 #endif 00042 00043 #ifndef IN6ADDRSZ 00044 #define IN6ADDRSZ 16 00045 #endif 00046 00047 #ifndef INT16SZ 00048 #define INT16SZ 2 00049 #endif 00050 00051 #ifndef INADDRSZ 00052 #define INADDRSZ 4 00053 #endif 00054 00055 /* 00056 * WARNING: Don't even consider trying to compile this on a system where 00057 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 00058 */ 00059 00060 static int inet_pton4(const char *src, u_char *dst, int pton); 00061 #ifdef NETSNMP_ENABLE_IPV6 00062 static int inet_pton6(const char *src, u_char *dst); 00063 #endif 00064 00065 /* int 00066 * inet_pton(af, src, dst) 00067 * convert from presentation format (which usually means ASCII printable) 00068 * to network format (which is usually some kind of binary format). 00069 * return: 00070 * 1 if the address was valid for the specified address family 00071 * 0 if the address wasn't valid (`dst' is untouched in this case) 00072 * -1 if some other error occurred (`dst' is untouched in this case, too) 00073 * author: 00074 * Paul Vixie, 1996. 00075 */ 00076 int 00077 inet_pton(int af, const char *src, void *dst) 00078 { 00079 00080 switch (af) { 00081 case AF_INET: 00082 return (inet_pton4(src, dst, 1)); 00083 #ifdef NETSNMP_ENABLE_IPV6 00084 case AF_INET6: 00085 return (inet_pton6(src, dst)); 00086 #endif 00087 default: 00088 errno = EAFNOSUPPORT; 00089 return (-1); 00090 } 00091 /* NOTREACHED */ 00092 } 00093 00094 /* int 00095 * inet_pton4(src, dst, pton) 00096 * when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand. 00097 * when last arg is 1: inet_pton(). decimal dotted-quad only. 00098 * return: 00099 * 1 if `src' is a valid input, else 0. 00100 * notice: 00101 * does not touch `dst' unless it's returning 1. 00102 * author: 00103 * Paul Vixie, 1996. 00104 */ 00105 static int 00106 inet_pton4(const char *src, u_char *dst, int pton) 00107 { 00108 u_int val; 00109 u_int digit; 00110 int base, n; 00111 unsigned char c; 00112 u_int parts[4]; 00113 register u_int *pp = parts; 00114 00115 c = *src; 00116 for (;;) { 00117 /* 00118 * Collect number up to ``.''. 00119 * Values are specified as for C: 00120 * 0x=hex, 0=octal, isdigit=decimal. 00121 */ 00122 if (!isdigit(c)) 00123 return (0); 00124 val = 0; base = 10; 00125 if (c == '0') { 00126 c = *++src; 00127 if (c == 'x' || c == 'X') 00128 base = 16, c = *++src; 00129 else if (isdigit(c) && c != '9') 00130 base = 8; 00131 } 00132 /* inet_pton() takes decimal only */ 00133 if (pton && base != 10) 00134 return (0); 00135 for (;;) { 00136 if (isdigit(c)) { 00137 digit = c - '0'; 00138 if ((int)digit >= base) 00139 break; 00140 val = (val * base) + digit; 00141 c = *++src; 00142 } else if (base == 16 && isxdigit(c)) { 00143 digit = c + 10 - (islower(c) ? 'a' : 'A'); 00144 if (digit >= 16) 00145 break; 00146 val = (val << 4) | digit; 00147 c = *++src; 00148 } else 00149 break; 00150 } 00151 if (c == '.') { 00152 /* 00153 * Internet format: 00154 * a.b.c.d 00155 * a.b.c (with c treated as 16 bits) 00156 * a.b (with b treated as 24 bits) 00157 * a (with a treated as 32 bits) 00158 */ 00159 if (pp >= parts + 3) 00160 return (0); 00161 *pp++ = val; 00162 c = *++src; 00163 } else 00164 break; 00165 } 00166 /* 00167 * Check for trailing characters. 00168 */ 00169 if (c != '\0' && !isspace(c)) 00170 return (0); 00171 /* 00172 * Concoct the address according to 00173 * the number of parts specified. 00174 */ 00175 n = pp - parts + 1; 00176 /* inet_pton() takes dotted-quad only. it does not take shorthand. */ 00177 if (pton && n != 4) 00178 return (0); 00179 switch (n) { 00180 00181 case 0: 00182 return (0); /* initial nondigit */ 00183 00184 case 1: /* a -- 32 bits */ 00185 break; 00186 00187 case 2: /* a.b -- 8.24 bits */ 00188 if (parts[0] > 0xff || val > 0xffffff) 00189 return (0); 00190 val |= parts[0] << 24; 00191 break; 00192 00193 case 3: /* a.b.c -- 8.8.16 bits */ 00194 if ((parts[0] | parts[1]) > 0xff || val > 0xffff) 00195 return (0); 00196 val |= (parts[0] << 24) | (parts[1] << 16); 00197 break; 00198 00199 case 4: /* a.b.c.d -- 8.8.8.8 bits */ 00200 if ((parts[0] | parts[1] | parts[2] | val) > 0xff) 00201 return (0); 00202 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 00203 break; 00204 } 00205 if (dst) { 00206 val = htonl(val); 00207 memcpy(dst, &val, INADDRSZ); 00208 } 00209 return (1); 00210 } 00211 00212 #ifdef NETSNMP_ENABLE_IPV6 00213 /* int 00214 * inet_pton6(src, dst) 00215 * convert presentation level address to network order binary form. 00216 * return: 00217 * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 00218 * notice: 00219 * (1) does not touch `dst' unless it's returning 1. 00220 * (2) :: in a full address is silently ignored. 00221 * credit: 00222 * inspired by Mark Andrews. 00223 * author: 00224 * Paul Vixie, 1996. 00225 */ 00226 static int 00227 inet_pton6(const char *src, u_char *dst) 00228 { 00229 static const char xdigits_l[] = "0123456789abcdef", 00230 xdigits_u[] = "0123456789ABCDEF"; 00231 u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp; 00232 const char *xdigits, *curtok; 00233 int ch, saw_xdigit; 00234 u_int val; 00235 00236 memset((tp = tmp), '\0', IN6ADDRSZ); 00237 endp = tp + IN6ADDRSZ; 00238 colonp = NULL; 00239 /* Leading :: requires some special handling. */ 00240 if (*src == ':') 00241 if (*++src != ':') 00242 return (0); 00243 curtok = src; 00244 saw_xdigit = 0; 00245 val = 0; 00246 while ((ch = *src++) != '\0') { 00247 const char *pch; 00248 00249 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 00250 pch = strchr((xdigits = xdigits_u), ch); 00251 if (pch != NULL) { 00252 val <<= 4; 00253 val |= (pch - xdigits); 00254 if (val > 0xffff) 00255 return (0); 00256 saw_xdigit = 1; 00257 continue; 00258 } 00259 if (ch == ':') { 00260 curtok = src; 00261 if (!saw_xdigit) { 00262 if (colonp) 00263 return (0); 00264 colonp = tp; 00265 continue; 00266 } else if (*src == '\0') 00267 return (0); 00268 if (tp + INT16SZ > endp) 00269 return (0); 00270 *tp++ = (u_char) (val >> 8) & 0xff; 00271 *tp++ = (u_char) val & 0xff; 00272 saw_xdigit = 0; 00273 val = 0; 00274 continue; 00275 } 00276 if (ch == '.' && ((tp + INADDRSZ) <= endp) && 00277 inet_pton4(curtok, tp, 1) > 0) { 00278 tp += INADDRSZ; 00279 saw_xdigit = 0; 00280 break; /* '\0' was seen by inet_pton4(). */ 00281 } 00282 return (0); 00283 } 00284 if (saw_xdigit) { 00285 if (tp + INT16SZ > endp) 00286 return (0); 00287 *tp++ = (u_char) (val >> 8) & 0xff; 00288 *tp++ = (u_char) val & 0xff; 00289 } 00290 if (colonp != NULL) { 00291 /* 00292 * Since some memmove()'s erroneously fail to handle 00293 * overlapping regions, we'll do the shift by hand. 00294 */ 00295 const int n = tp - colonp; 00296 int i; 00297 00298 if (tp == endp) 00299 return (0); 00300 for (i = 1; i <= n; i++) { 00301 endp[- i] = colonp[n - i]; 00302 colonp[n - i] = 0; 00303 } 00304 tp = endp; 00305 } 00306 if (tp != endp) 00307 return (0); 00308 memcpy(dst, tmp, IN6ADDRSZ); 00309 return (1); 00310 } 00311 #endif