/* * This code is loosely based on src/lib/libc/net/inet_addr.c from FreeBSD 4.8 */ #include "sm/generic.h" SM_RCSID("@(#)$Id: sm_inet_arpa2ipv4.c,v 1.2 2005/01/18 00:06:21 ca Exp $") #include "sm/assert.h" #include "sm/error.h" #include "sm/ctype.h" #include "sm/net.h" sm_ret_T sm_inet_arpa2ipv4(const char *cp, ipv4_T *ipv4) { ulong parts[4], ul; ipv4_T val; char *c, *endptr; int n; bool gotend; c = (char *)cp; n = 0; gotend = false; ul = 0; while (!gotend) { errno = 0; ul = strtoul(c, &endptr, 0); if (errno == ERANGE) /* Fail completely if it overflowed. */ return sm_error_perm(SM_EM_IP, errno); /* ** If the whole string is invalid, endptr will equal c. this ** way we can make sure someone hasn't gone '.12' or something ** which would get past the next check. */ if (endptr == c) return sm_error_perm(SM_EM_IP, EINVAL); parts[n] = ul; c = endptr; /* Check the next character past the previous number's end */ switch (*c) { case '.': if (n >= 3) { if (strcasecmp(c, ".in-addr.arpa") != 0) return sm_error_perm(SM_EM_IP, EINVAL); else { gotend = true; break; } } n++; c++; break; default: return sm_error_perm(SM_EM_IP, EINVAL); } } if (n != 3) return sm_error_perm(SM_EM_IP, EINVAL); if (parts[3] > 0xff || parts[2] > 0xff || parts[1] > 0xff || parts[0] > 0xff) return sm_error_perm(SM_EM_IP, EINVAL); val = (parts[3] << 24) | (parts[2] << 16) | (parts[1] << 8) | parts[0]; if (ipv4 != NULL) *ipv4 = htonl(val); return SM_SUCCESS; }