#include <config.h>
#if !defined(HAVE_INET_PTON)
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <errno.h>
#include "sudo_compat.h"
#ifndef EAFNOSUPPORT
# define EAFNOSUPPORT EINVAL
#endif
#ifndef NS_INADDRSZ
# ifdef INADDRSZ
# define NS_INADDRSZ INADDRSZ
# else
# define NS_INADDRSZ 4
# endif
#endif
#ifndef NS_IN6ADDRSZ
# ifdef IN6ADDRSZ
# define NS_IN6ADDRSZ IN6ADDRSZ
# else
# define NS_IN6ADDRSZ 16
# endif
#endif
#ifndef NS_INT16SZ
# ifdef INT16SZ
# define NS_INT16SZ INT16SZ
# else
# define NS_INT16SZ 2
# endif
#endif
static int
inet_pton4(const char *src, u_char *dst)
{
const char digits[] = "0123456789";
int saw_digit, octets, ch;
u_char tmp[NS_INADDRSZ], *tp;
saw_digit = 0;
octets = 0;
*(tp = tmp) = '\0';
while ((ch = (unsigned char)*src++) != '\0') {
const char *pch;
if ((pch = strchr(digits, ch)) != NULL) {
u_int new = *tp * 10 + (pch - digits);
if (new > 255)
return (0);
if (!saw_digit) {
if (++octets > 4)
return (0);
saw_digit = 1;
}
*tp = new;
} else if (ch == '.' && saw_digit) {
if (octets == 4)
return (0);
*++tp = 0;
saw_digit = 0;
} else
return (0);
}
if (octets < 4)
return (0);
memcpy(dst, tmp, NS_INADDRSZ);
return (1);
}
#ifdef HAVE_STRUCT_IN6_ADDR
static int
inet_pton6(const char *src, u_char *dst)
{
const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
const char *xdigits, *curtok;
int ch, saw_xdigit, count_xdigit;
u_int val;
memset((tp = tmp), 0, NS_IN6ADDRSZ);
endp = tp + NS_IN6ADDRSZ;
colonp = NULL;
if (*src == ':')
if (*++src != ':')
return (0);
curtok = src;
saw_xdigit = count_xdigit = 0;
val = 0;
while ((ch = (unsigned char)*src++) != '\0') {
const char *pch;
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
pch = strchr((xdigits = xdigits_u), ch);
if (pch != NULL) {
if (count_xdigit >= 4)
return (0);
val <<= 4;
val |= (pch - xdigits);
if (val > 0xffff)
return (0);
saw_xdigit = 1;
count_xdigit++;
continue;
}
if (ch == ':') {
curtok = src;
if (!saw_xdigit) {
if (colonp)
return (0);
colonp = tp;
continue;
} else if (*src == '\0') {
return (0);
}
if (tp + NS_INT16SZ > endp)
return (0);
*tp++ = (u_char) (val >> 8) & 0xff;
*tp++ = (u_char) val & 0xff;
saw_xdigit = 0;
count_xdigit = 0;
val = 0;
continue;
}
if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
inet_pton4(curtok, tp) > 0) {
tp += NS_INADDRSZ;
saw_xdigit = 0;
count_xdigit = 0;
break;
}
return (0);
}
if (saw_xdigit) {
if (tp + NS_INT16SZ > endp)
return (0);
*tp++ = (u_char) (val >> 8) & 0xff;
*tp++ = (u_char) val & 0xff;
}
if (colonp != NULL) {
const long n = tp - colonp;
long i;
if (tp == endp)
return (0);
for (i = 1; i <= n; i++) {
endp[- i] = colonp[n - i];
colonp[n - i] = 0;
}
tp = endp;
}
if (tp != endp)
return (0);
memcpy(dst, tmp, NS_IN6ADDRSZ);
return (1);
}
#endif
int
sudo_inet_pton(int af, const char *src, void *dst)
{
switch (af) {
case AF_INET:
return (inet_pton4(src, dst));
#ifdef HAVE_STRUCT_IN6_ADDR
case AF_INET6:
return (inet_pton6(src, dst));
#endif
default:
errno = EAFNOSUPPORT;
return (-1);
}
}
#endif