/*
* 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;
}
syntax highlighted by Code2HTML, v. 0.9.1