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