net-snmp
5.4.1
|
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 #ifndef HAVE_INET_PTON 00023 00024 #if HAVE_ARPA_NAMESER_H 00025 #include <arpa/nameser.h> 00026 #endif 00027 00028 /* 00029 * Net-SNMP Win32 additions 00030 */ 00031 #if defined(HAVE_WINSOCK_H) || defined(cygwin) 00032 #include <winsock2.h> 00033 #include <ws2tcpip.h> 00034 #include <errno.h> 00035 #include <stdio.h> 00036 #endif 00037 00038 #ifndef EAFNOSUPPORT 00039 #define EAFNOSUPPORT WSAEAFNOSUPPORT 00040 #endif 00041 00042 #ifndef IN6ADDRSZ 00043 #define IN6ADDRSZ 16 00044 #endif 00045 00046 #ifndef INT16SZ 00047 #define INT16SZ 2 00048 #endif 00049 /* 00050 * End of Net-SNMP Win32 additions 00051 */ 00052 00053 #ifndef INADDRSZ 00054 #define INADDRSZ 4 00055 #endif 00056 00057 /* 00058 * WARNING: Don't even consider trying to compile this on a system where 00059 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 00060 */ 00061 00062 static int inet_pton4(const char *src, u_char *dst, int pton); 00063 #ifdef NETSNMP_ENABLE_IPV6 00064 static int inet_pton6(const char *src, u_char *dst); 00065 #endif 00066 00067 /* int 00068 * inet_pton(af, src, dst) 00069 * convert from presentation format (which usually means ASCII printable) 00070 * to network format (which is usually some kind of binary format). 00071 * return: 00072 * 1 if the address was valid for the specified address family 00073 * 0 if the address wasn't valid (`dst' is untouched in this case) 00074 * -1 if some other error occurred (`dst' is untouched in this case, too) 00075 * author: 00076 * Paul Vixie, 1996. 00077 */ 00078 int 00079 inet_pton(af, src, dst) 00080 int af; 00081 const char *src; 00082 void *dst; 00083 { 00084 00085 switch (af) { 00086 case AF_INET: 00087 return (inet_pton4(src, dst, 1)); 00088 #ifdef NETSNMP_ENABLE_IPV6 00089 case AF_INET6: 00090 return (inet_pton6(src, dst)); 00091 #endif 00092 default: 00093 errno = EAFNOSUPPORT; 00094 return (-1); 00095 } 00096 /* NOTREACHED */ 00097 } 00098 00099 /* int 00100 * inet_pton4(src, dst, pton) 00101 * when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand. 00102 * when last arg is 1: inet_pton(). decimal dotted-quad only. 00103 * return: 00104 * 1 if `src' is a valid input, else 0. 00105 * notice: 00106 * does not touch `dst' unless it's returning 1. 00107 * author: 00108 * Paul Vixie, 1996. 00109 */ 00110 static int 00111 inet_pton4(src, dst, pton) 00112 const char *src; 00113 u_char *dst; 00114 int pton; 00115 { 00116 u_int val; 00117 u_int digit; 00118 int base, n; 00119 unsigned char c; 00120 u_int parts[4]; 00121 register u_int *pp = parts; 00122 00123 c = *src; 00124 for (;;) { 00125 /* 00126 * Collect number up to ``.''. 00127 * Values are specified as for C: 00128 * 0x=hex, 0=octal, isdigit=decimal. 00129 */ 00130 if (!isdigit(c)) 00131 return (0); 00132 val = 0; base = 10; 00133 if (c == '0') { 00134 c = *++src; 00135 if (c == 'x' || c == 'X') 00136 base = 16, c = *++src; 00137 else if (isdigit(c) && c != '9') 00138 base = 8; 00139 } 00140 /* inet_pton() takes decimal only */ 00141 if (pton && base != 10) 00142 return (0); 00143 for (;;) { 00144 if (isdigit(c)) { 00145 digit = c - '0'; 00146 if ((int)digit >= base) 00147 break; 00148 val = (val * base) + digit; 00149 c = *++src; 00150 } else if (base == 16 && isxdigit(c)) { 00151 digit = c + 10 - (islower(c) ? 'a' : 'A'); 00152 if (digit >= 16) 00153 break; 00154 val = (val << 4) | digit; 00155 c = *++src; 00156 } else 00157 break; 00158 } 00159 if (c == '.') { 00160 /* 00161 * Internet format: 00162 * a.b.c.d 00163 * a.b.c (with c treated as 16 bits) 00164 * a.b (with b treated as 24 bits) 00165 * a (with a treated as 32 bits) 00166 */ 00167 if (pp >= parts + 3) 00168 return (0); 00169 *pp++ = val; 00170 c = *++src; 00171 } else 00172 break; 00173 } 00174 /* 00175 * Check for trailing characters. 00176 */ 00177 if (c != '\0' && !isspace(c)) 00178 return (0); 00179 /* 00180 * Concoct the address according to 00181 * the number of parts specified. 00182 */ 00183 n = pp - parts + 1; 00184 /* inet_pton() takes dotted-quad only. it does not take shorthand. */ 00185 if (pton && n != 4) 00186 return (0); 00187 switch (n) { 00188 00189 case 0: 00190 return (0); /* initial nondigit */ 00191 00192 case 1: /* a -- 32 bits */ 00193 break; 00194 00195 case 2: /* a.b -- 8.24 bits */ 00196 if (parts[0] > 0xff || val > 0xffffff) 00197 return (0); 00198 val |= parts[0] << 24; 00199 break; 00200 00201 case 3: /* a.b.c -- 8.8.16 bits */ 00202 if ((parts[0] | parts[1]) > 0xff || val > 0xffff) 00203 return (0); 00204 val |= (parts[0] << 24) | (parts[1] << 16); 00205 break; 00206 00207 case 4: /* a.b.c.d -- 8.8.8.8 bits */ 00208 if ((parts[0] | parts[1] | parts[2] | val) > 0xff) 00209 return (0); 00210 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 00211 break; 00212 } 00213 if (dst) { 00214 val = htonl(val); 00215 memcpy(dst, &val, INADDRSZ); 00216 } 00217 return (1); 00218 } 00219 00220 #ifdef NETSNMP_ENABLE_IPV6 00221 /* int 00222 * inet_pton6(src, dst) 00223 * convert presentation level address to network order binary form. 00224 * return: 00225 * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 00226 * notice: 00227 * (1) does not touch `dst' unless it's returning 1. 00228 * (2) :: in a full address is silently ignored. 00229 * credit: 00230 * inspired by Mark Andrews. 00231 * author: 00232 * Paul Vixie, 1996. 00233 */ 00234 static int 00235 inet_pton6(src, dst) 00236 const char *src; 00237 u_char *dst; 00238 { 00239 static const char xdigits_l[] = "0123456789abcdef", 00240 xdigits_u[] = "0123456789ABCDEF"; 00241 u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp; 00242 const char *xdigits, *curtok; 00243 int ch, saw_xdigit; 00244 u_int val; 00245 00246 memset((tp = tmp), '\0', IN6ADDRSZ); 00247 endp = tp + IN6ADDRSZ; 00248 colonp = NULL; 00249 /* Leading :: requires some special handling. */ 00250 if (*src == ':') 00251 if (*++src != ':') 00252 return (0); 00253 curtok = src; 00254 saw_xdigit = 0; 00255 val = 0; 00256 while ((ch = *src++) != '\0') { 00257 const char *pch; 00258 00259 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 00260 pch = strchr((xdigits = xdigits_u), ch); 00261 if (pch != NULL) { 00262 val <<= 4; 00263 val |= (pch - xdigits); 00264 if (val > 0xffff) 00265 return (0); 00266 saw_xdigit = 1; 00267 continue; 00268 } 00269 if (ch == ':') { 00270 curtok = src; 00271 if (!saw_xdigit) { 00272 if (colonp) 00273 return (0); 00274 colonp = tp; 00275 continue; 00276 } else if (*src == '\0') 00277 return (0); 00278 if (tp + INT16SZ > endp) 00279 return (0); 00280 *tp++ = (u_char) (val >> 8) & 0xff; 00281 *tp++ = (u_char) val & 0xff; 00282 saw_xdigit = 0; 00283 val = 0; 00284 continue; 00285 } 00286 if (ch == '.' && ((tp + INADDRSZ) <= endp) && 00287 inet_pton4(curtok, tp, 1) > 0) { 00288 tp += INADDRSZ; 00289 saw_xdigit = 0; 00290 break; /* '\0' was seen by inet_pton4(). */ 00291 } 00292 return (0); 00293 } 00294 if (saw_xdigit) { 00295 if (tp + INT16SZ > endp) 00296 return (0); 00297 *tp++ = (u_char) (val >> 8) & 0xff; 00298 *tp++ = (u_char) val & 0xff; 00299 } 00300 if (colonp != NULL) { 00301 /* 00302 * Since some memmove()'s erroneously fail to handle 00303 * overlapping regions, we'll do the shift by hand. 00304 */ 00305 const int n = tp - colonp; 00306 int i; 00307 00308 if (tp == endp) 00309 return (0); 00310 for (i = 1; i <= n; i++) { 00311 endp[- i] = colonp[n - i]; 00312 colonp[n - i] = 0; 00313 } 00314 tp = endp; 00315 } 00316 if (tp != endp) 00317 return (0); 00318 memcpy(dst, tmp, IN6ADDRSZ); 00319 return (1); 00320 } 00321 #endif 00322 00323 #endif /* HAVE_INET_PTON */