1/* 2 * Copyright (C) 2004, 2005, 2007, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1996-2001 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or 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 WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/*! \file lwinetpton.c 19 */ 20 21#if defined(LIBC_SCCS) && !defined(lint) 22static char rcsid[] = "$Id$"; 23#endif /* LIBC_SCCS and not lint */ 24 25#include <config.h> 26 27#include <errno.h> 28#include <string.h> 29 30#include <lwres/net.h> 31 32#define NS_INT16SZ 2 33#define NS_INADDRSZ 4 34#define NS_IN6ADDRSZ 16 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); 42static int inet_pton6(const char *src, unsigned char *dst); 43 44/*! 45 * int 46 * lwres_net_pton(af, src, dst) 47 * convert from presentation format (which usually means ASCII printable) 48 * to network format (which is usually some kind of binary format). 49 * return: 50 * 1 if the address was valid for the specified address family 51 * 0 if the address wasn't valid (`dst' is untouched in this case) 52 * -1 if some other error occurred (`dst' is untouched in this case, too) 53 * author: 54 * Paul Vixie, 1996. 55 */ 56int 57lwres_net_pton(int af, const char *src, void *dst) { 58 switch (af) { 59 case AF_INET: 60 return (inet_pton4(src, dst)); 61 case AF_INET6: 62 return (inet_pton6(src, dst)); 63 default: 64 errno = EAFNOSUPPORT; 65 return (-1); 66 } 67 /* NOTREACHED */ 68} 69 70/*! int 71 * inet_pton4(src, dst) 72 * like inet_aton() but without all the hexadecimal and shorthand. 73 * return: 74 * 1 if `src' is a valid dotted quad, else 0. 75 * notice: 76 * does not touch `dst' unless it's returning 1. 77 * author: 78 * Paul Vixie, 1996. 79 */ 80static int 81inet_pton4(const char *src, unsigned char *dst) { 82 static const char digits[] = "0123456789"; 83 int saw_digit, octets, ch; 84 unsigned char tmp[NS_INADDRSZ], *tp; 85 86 saw_digit = 0; 87 octets = 0; 88 *(tp = tmp) = 0; 89 while ((ch = *src++) != '\0') { 90 const char *pch; 91 92 if ((pch = strchr(digits, ch)) != NULL) { 93 unsigned int new = *tp * 10 + (pch - digits); 94 95 if (new > 255) 96 return (0); 97 *tp = new; 98 if (! saw_digit) { 99 if (++octets > 4) 100 return (0); 101 saw_digit = 1; 102 } 103 } else if (ch == '.' && saw_digit) { 104 if (octets == 4) 105 return (0); 106 /* 107 * "clang --analyse" generates warnings using: 108 * *++tp = 0; 109 */ 110 tp++; 111 *tp = 0; 112 saw_digit = 0; 113 } else 114 return (0); 115 } 116 if (octets < 4) 117 return (0); 118 memcpy(dst, tmp, NS_INADDRSZ); 119 return (1); 120} 121 122/*! int 123 * inet_pton6(src, dst) 124 * convert presentation level address to network order binary form. 125 * return: 126 * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 127 * notice: 128 * (1) does not touch `dst' unless it's returning 1. 129 * (2) :: in a full address is silently ignored. 130 * credit: 131 * inspired by Mark Andrews. 132 * author: 133 * Paul Vixie, 1996. 134 */ 135static int 136inet_pton6(const char *src, unsigned char *dst) { 137 static const char xdigits_l[] = "0123456789abcdef", 138 xdigits_u[] = "0123456789ABCDEF"; 139 unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; 140 const char *xdigits, *curtok; 141 int ch, seen_xdigits; 142 unsigned int val; 143 144 memset((tp = tmp), '\0', NS_IN6ADDRSZ); 145 endp = tp + NS_IN6ADDRSZ; 146 colonp = NULL; 147 /* Leading :: requires some special handling. */ 148 if (*src == ':') 149 if (*++src != ':') 150 return (0); 151 curtok = src; 152 seen_xdigits = 0; 153 val = 0; 154 while ((ch = *src++) != '\0') { 155 const char *pch; 156 157 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 158 pch = strchr((xdigits = xdigits_u), ch); 159 if (pch != NULL) { 160 val <<= 4; 161 val |= (pch - xdigits); 162 if (++seen_xdigits > 4) 163 return (0); 164 continue; 165 } 166 if (ch == ':') { 167 curtok = src; 168 if (!seen_xdigits) { 169 if (colonp) 170 return (0); 171 colonp = tp; 172 continue; 173 } 174 if (tp + NS_INT16SZ > endp) 175 return (0); 176 *tp++ = (unsigned char) (val >> 8) & 0xff; 177 *tp++ = (unsigned char) val & 0xff; 178 seen_xdigits = 0; 179 val = 0; 180 continue; 181 } 182 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && 183 inet_pton4(curtok, tp) > 0) { 184 tp += NS_INADDRSZ; 185 seen_xdigits = 0; 186 break; /* '\0' was seen by inet_pton4(). */ 187 } 188 return (0); 189 } 190 if (seen_xdigits) { 191 if (tp + NS_INT16SZ > endp) 192 return (0); 193 *tp++ = (unsigned char) (val >> 8) & 0xff; 194 *tp++ = (unsigned char) val & 0xff; 195 } 196 if (colonp != NULL) { 197 /* 198 * Since some memmove()'s erroneously fail to handle 199 * overlapping regions, we'll do the shift by hand. 200 */ 201 const int n = tp - colonp; 202 int i; 203 204 for (i = 1; i <= n; i++) { 205 endp[- i] = colonp[n - i]; 206 colonp[n - i] = 0; 207 } 208 tp = endp; 209 } 210 if (tp != endp) 211 return (0); 212 memcpy(dst, tmp, NS_IN6ADDRSZ); 213 return (1); 214} 215