1156952Sume/* 2156952Sume * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3156952Sume * Copyright (c) 1996,1999 by Internet Software Consortium. 4156952Sume * 5156952Sume * Permission to use, copy, modify, and distribute this software for any 6156952Sume * purpose with or without fee is hereby granted, provided that the above 7156952Sume * copyright notice and this permission notice appear in all copies. 8156952Sume * 9156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10156952Sume * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11156952Sume * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12156952Sume * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13156952Sume * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14156952Sume * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15156952Sume * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16156952Sume */ 17156952Sume 18156952Sume#if defined(LIBC_SCCS) && !defined(lint) 19269867Sumestatic const char rcsid[] = "$Id: inet_pton.c,v 1.5 2005/07/28 06:51:47 marka Exp $"; 20156952Sume#endif /* LIBC_SCCS and not lint */ 21156956Sume#include <sys/cdefs.h> 22156956Sume__FBSDID("$FreeBSD: releng/11.0/lib/libc/inet/inet_pton.c 298226 2016-04-18 21:05:15Z avos $"); 23156952Sume 24156952Sume#include "port_before.h" 25156952Sume#include <sys/param.h> 26156952Sume#include <sys/socket.h> 27156952Sume#include <netinet/in.h> 28156952Sume#include <arpa/inet.h> 29156952Sume#include <arpa/nameser.h> 30156952Sume#include <string.h> 31156952Sume#include <errno.h> 32156952Sume#include "port_after.h" 33156952Sume 34170244Sume/*% 35156952Sume * WARNING: Don't even consider trying to compile this on a system where 36156952Sume * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 37156952Sume */ 38156952Sume 39156956Sumestatic int inet_pton4(const char *src, u_char *dst); 40156956Sumestatic int inet_pton6(const char *src, u_char *dst); 41156952Sume 42156952Sume/* int 43156952Sume * inet_pton(af, src, dst) 44156952Sume * convert from presentation format (which usually means ASCII printable) 45156952Sume * to network format (which is usually some kind of binary format). 46156952Sume * return: 47156952Sume * 1 if the address was valid for the specified address family 48156952Sume * 0 if the address wasn't valid (`dst' is untouched in this case) 49156952Sume * -1 if some other error occurred (`dst' is untouched in this case, too) 50156952Sume * author: 51156952Sume * Paul Vixie, 1996. 52156952Sume */ 53156952Sumeint 54156956Sumeinet_pton(int af, const char * __restrict src, void * __restrict dst) 55156952Sume{ 56156952Sume switch (af) { 57156952Sume case AF_INET: 58156952Sume return (inet_pton4(src, dst)); 59156952Sume case AF_INET6: 60156952Sume return (inet_pton6(src, dst)); 61156952Sume default: 62156952Sume errno = EAFNOSUPPORT; 63156952Sume return (-1); 64156952Sume } 65156952Sume /* NOTREACHED */ 66156952Sume} 67156952Sume 68156952Sume/* int 69156952Sume * inet_pton4(src, dst) 70156952Sume * like inet_aton() but without all the hexadecimal and shorthand. 71156952Sume * return: 72156952Sume * 1 if `src' is a valid dotted quad, else 0. 73156952Sume * notice: 74156952Sume * does not touch `dst' unless it's returning 1. 75156952Sume * author: 76156952Sume * Paul Vixie, 1996. 77156952Sume */ 78156952Sumestatic int 79156956Sumeinet_pton4(const char *src, u_char *dst) 80156952Sume{ 81156952Sume static const char digits[] = "0123456789"; 82156952Sume int saw_digit, octets, ch; 83156952Sume u_char tmp[NS_INADDRSZ], *tp; 84156952Sume 85156952Sume saw_digit = 0; 86156952Sume octets = 0; 87156952Sume *(tp = tmp) = 0; 88156952Sume while ((ch = *src++) != '\0') { 89156952Sume const char *pch; 90156952Sume 91156952Sume if ((pch = strchr(digits, ch)) != NULL) { 92156952Sume u_int new = *tp * 10 + (pch - digits); 93156952Sume 94156952Sume if (saw_digit && *tp == 0) 95156952Sume return (0); 96156952Sume if (new > 255) 97156952Sume return (0); 98156952Sume *tp = new; 99156952Sume if (!saw_digit) { 100156952Sume if (++octets > 4) 101156952Sume return (0); 102156952Sume saw_digit = 1; 103156952Sume } 104156952Sume } else if (ch == '.' && saw_digit) { 105156952Sume if (octets == 4) 106156952Sume return (0); 107156952Sume *++tp = 0; 108156952Sume saw_digit = 0; 109156952Sume } else 110156952Sume return (0); 111156952Sume } 112156952Sume if (octets < 4) 113156952Sume return (0); 114156952Sume memcpy(dst, tmp, NS_INADDRSZ); 115156952Sume return (1); 116156952Sume} 117156952Sume 118156952Sume/* int 119156952Sume * inet_pton6(src, dst) 120156952Sume * convert presentation level address to network order binary form. 121156952Sume * return: 122156952Sume * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 123156952Sume * notice: 124156952Sume * (1) does not touch `dst' unless it's returning 1. 125156952Sume * (2) :: in a full address is silently ignored. 126156952Sume * credit: 127156952Sume * inspired by Mark Andrews. 128156952Sume * author: 129156952Sume * Paul Vixie, 1996. 130156952Sume */ 131156952Sumestatic int 132156956Sumeinet_pton6(const char *src, u_char *dst) 133156952Sume{ 134156952Sume static const char xdigits_l[] = "0123456789abcdef", 135156952Sume xdigits_u[] = "0123456789ABCDEF"; 136156952Sume u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; 137156952Sume const char *xdigits, *curtok; 138156952Sume int ch, seen_xdigits; 139156952Sume u_int val; 140156952Sume 141156952Sume memset((tp = tmp), '\0', NS_IN6ADDRSZ); 142156952Sume endp = tp + NS_IN6ADDRSZ; 143156952Sume colonp = NULL; 144156952Sume /* Leading :: requires some special handling. */ 145156952Sume if (*src == ':') 146156952Sume if (*++src != ':') 147156952Sume return (0); 148156952Sume curtok = src; 149156952Sume seen_xdigits = 0; 150156952Sume val = 0; 151156952Sume while ((ch = *src++) != '\0') { 152156952Sume const char *pch; 153156952Sume 154156952Sume if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 155156952Sume pch = strchr((xdigits = xdigits_u), ch); 156156952Sume if (pch != NULL) { 157156952Sume val <<= 4; 158156952Sume val |= (pch - xdigits); 159156952Sume if (++seen_xdigits > 4) 160156952Sume return (0); 161156952Sume continue; 162156952Sume } 163156952Sume if (ch == ':') { 164156952Sume curtok = src; 165156952Sume if (!seen_xdigits) { 166156952Sume if (colonp) 167156952Sume return (0); 168156952Sume colonp = tp; 169156952Sume continue; 170156952Sume } else if (*src == '\0') { 171156952Sume return (0); 172156952Sume } 173156952Sume if (tp + NS_INT16SZ > endp) 174156952Sume return (0); 175156952Sume *tp++ = (u_char) (val >> 8) & 0xff; 176156952Sume *tp++ = (u_char) val & 0xff; 177156952Sume seen_xdigits = 0; 178156952Sume val = 0; 179156952Sume continue; 180156952Sume } 181156952Sume if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && 182156952Sume inet_pton4(curtok, tp) > 0) { 183156952Sume tp += NS_INADDRSZ; 184156952Sume seen_xdigits = 0; 185170244Sume break; /*%< '\\0' was seen by inet_pton4(). */ 186156952Sume } 187156952Sume return (0); 188156952Sume } 189156952Sume if (seen_xdigits) { 190156952Sume if (tp + NS_INT16SZ > endp) 191156952Sume return (0); 192156952Sume *tp++ = (u_char) (val >> 8) & 0xff; 193156952Sume *tp++ = (u_char) val & 0xff; 194156952Sume } 195156952Sume if (colonp != NULL) { 196156952Sume /* 197156952Sume * Since some memmove()'s erroneously fail to handle 198156952Sume * overlapping regions, we'll do the shift by hand. 199156952Sume */ 200156952Sume const int n = tp - colonp; 201156952Sume int i; 202156952Sume 203156952Sume if (tp == endp) 204156952Sume return (0); 205156952Sume for (i = 1; i <= n; i++) { 206156952Sume endp[- i] = colonp[n - i]; 207156952Sume colonp[n - i] = 0; 208156952Sume } 209156952Sume tp = endp; 210156952Sume } 211156952Sume if (tp != endp) 212156952Sume return (0); 213156952Sume memcpy(dst, tmp, NS_IN6ADDRSZ); 214156952Sume return (1); 215156952Sume} 216156956Sume 217156956Sume/* 218156956Sume * Weak aliases for applications that use certain private entry points, 219156956Sume * and fail to include <arpa/inet.h>. 220156956Sume */ 221156956Sume#undef inet_pton 222156956Sume__weak_reference(__inet_pton, inet_pton); 223170244Sume 224170244Sume/*! \file */ 225