/* $OpenBSD: inet_pton.c,v 1.8 2010/05/06 15:47:14 claudio Exp $ */12/*3* SPDX-License-Identifier: ISC4*5* Copyright (c) 1996 by Internet Software Consortium.6*7* Permission to use, copy, modify, and distribute this software for any8* purpose with or without fee is hereby granted, provided that the above9* copyright notice and this permission notice appear in all copies.10*11* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS12* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES13* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE14* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL15* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR16* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS17* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS18* SOFTWARE.19*/2021#include <config.h>2223#if !defined(HAVE_INET_PTON)2425#include <sys/types.h>26#include <sys/socket.h>27#include <netinet/in.h>28#include <arpa/inet.h>29#include <arpa/nameser.h>30#include <string.h>31#include <errno.h>3233#include <sudo_compat.h>3435#ifndef EAFNOSUPPORT36# define EAFNOSUPPORT EINVAL37#endif3839#ifndef NS_INADDRSZ40# ifdef INADDRSZ41# define NS_INADDRSZ INADDRSZ42# else43# define NS_INADDRSZ 444# endif45#endif46#ifndef NS_IN6ADDRSZ47# ifdef IN6ADDRSZ48# define NS_IN6ADDRSZ IN6ADDRSZ49# else50# define NS_IN6ADDRSZ 1651# endif52#endif53#ifndef NS_INT16SZ54# ifdef INT16SZ55# define NS_INT16SZ INT16SZ56# else57# define NS_INT16SZ 258# endif59#endif6061/*62* WARNING: Don't even consider trying to compile this on a system where63* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.64*/6566/* int67* inet_pton4(src, dst)68* like inet_aton() but without all the hexadecimal and shorthand.69* return:70* 1 if `src' is a valid dotted quad, else 0.71* notice:72* does not touch `dst' unless it's returning 1.73* author:74* Paul Vixie, 1996.75*/76static int77inet_pton4(const char *src, u_char *dst)78{79const char digits[] = "0123456789";80int saw_digit, octets, ch;81u_char tmp[NS_INADDRSZ], *tp;8283saw_digit = 0;84octets = 0;85/* cppcheck-suppress uninitvar */86*(tp = tmp) = '\0';87while ((ch = (unsigned char)*src++) != '\0') {88const char *pch;8990if ((pch = strchr(digits, ch)) != NULL) {91unsigned int new = *tp * 10 + (pch - digits);9293if (new > 255)94return (0);95if (!saw_digit) {96if (++octets > 4)97return (0);98saw_digit = 1;99}100*tp = new;101} else if (ch == '.' && saw_digit) {102if (octets == 4)103return (0);104*++tp = 0;105saw_digit = 0;106} else107return (0);108}109if (octets < 4)110return (0);111112memcpy(dst, tmp, NS_INADDRSZ);113return (1);114}115116#ifdef HAVE_STRUCT_IN6_ADDR117/* int118* inet_pton6(src, dst)119* convert presentation level address to network order binary form.120* return:121* 1 if `src' is a valid [RFC1884 2.2] address, else 0.122* notice:123* does not touch `dst' unless it's returning 1.124* credit:125* inspired by Mark Andrews.126* author:127* Paul Vixie, 1996.128*/129static int130inet_pton6(const char *src, u_char *dst)131{132const char xdigits_l[] = "0123456789abcdef",133xdigits_u[] = "0123456789ABCDEF";134u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;135const char *xdigits, *curtok;136int ch, saw_xdigit, count_xdigit;137unsigned int val;138139/* cppcheck-suppress uninitvar */140memset((tp = tmp), 0, NS_IN6ADDRSZ);141endp = tp + NS_IN6ADDRSZ;142colonp = NULL;143/* Leading :: requires some special handling. */144if (*src == ':')145if (*++src != ':')146return (0);147curtok = src;148saw_xdigit = count_xdigit = 0;149val = 0;150while ((ch = (unsigned char)*src++) != '\0') {151const char *pch;152153if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)154pch = strchr((xdigits = xdigits_u), ch);155if (pch != NULL) {156if (count_xdigit >= 4)157return (0);158val <<= 4;159val |= (pch - xdigits);160if (val > 0xffff)161return (0);162saw_xdigit = 1;163count_xdigit++;164continue;165}166if (ch == ':') {167curtok = src;168if (!saw_xdigit) {169if (colonp)170return (0);171colonp = tp;172continue;173} else if (*src == '\0') {174return (0);175}176if (tp + NS_INT16SZ > endp)177return (0);178*tp++ = (u_char) (val >> 8) & 0xff;179*tp++ = (u_char) val & 0xff;180saw_xdigit = 0;181count_xdigit = 0;182val = 0;183continue;184}185if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&186inet_pton4(curtok, tp) > 0) {187tp += NS_INADDRSZ;188saw_xdigit = 0;189count_xdigit = 0;190break; /* '\0' was seen by inet_pton4(). */191}192return (0);193}194if (saw_xdigit) {195if (tp + NS_INT16SZ > endp)196return (0);197*tp++ = (u_char) (val >> 8) & 0xff;198*tp++ = (u_char) val & 0xff;199}200if (colonp != NULL) {201/*202* Since some memmove()'s erroneously fail to handle203* overlapping regions, we'll do the shift by hand.204*/205const long n = tp - colonp;206long i;207208if (tp == endp)209return (0);210for (i = 1; i <= n; i++) {211endp[- i] = colonp[n - i];212colonp[n - i] = 0;213}214tp = endp;215}216if (tp != endp)217return (0);218memcpy(dst, tmp, NS_IN6ADDRSZ);219return (1);220}221#endif /* HAVE_STRUCT_IN6_ADDR */222223/* int224* inet_pton(af, src, dst)225* convert from presentation format (which usually means ASCII printable)226* to network format (which is usually some kind of binary format).227* return:228* 1 if the address was valid for the specified address family229* 0 if the address wasn't valid (`dst' is untouched in this case)230* -1 if some other error occurred (`dst' is untouched in this case, too)231* author:232* Paul Vixie, 1996.233*/234int235sudo_inet_pton(int af, const char * restrict src, void * restrict dst)236{237switch (af) {238case AF_INET:239return (inet_pton4(src, dst));240#ifdef HAVE_STRUCT_IN6_ADDR241case AF_INET6:242return (inet_pton6(src, dst));243#endif /* HAVE_STRUCT_IN6_ADDR */244default:245errno = EAFNOSUPPORT;246return (-1);247}248/* NOTREACHED */249}250251#endif /* HAVE_INET_PTON */252253254