blob: 81a041f24bf2c643b063240cf8bc9957d76dc648 [file] [log] [blame]
/*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996,1999 by Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <netdissect-stdinc.h>
#include <stddef.h>
#include <string.h>
#include "strtoaddr.h"
#ifndef NS_INADDRSZ
#define NS_INADDRSZ 4 /* IPv4 T_A */
#endif
#ifndef NS_IN6ADDRSZ
#define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */
#endif
#ifndef NS_INT16SZ
#define NS_INT16SZ 2 /* #/bytes of data in a uint16_t */
#endif
/*%
* WARNING: Don't even consider trying to compile this on a system where
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
*/
#ifndef NS_IN6ADDRSZ
#define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */
#endif
/* int
* strtoaddr(src, dst)
* convert presentation level IPv4 address to network order binary form.
* return:
* 1 if `src' is a valid input, else 0.
* notice:
* does not touch `dst' unless it's returning 1.
* author:
* Paul Vixie, 1996.
*/
int
strtoaddr(const char *src, void *dst)
{
uint32_t val;
u_int digit;
ptrdiff_t n;
unsigned char c;
u_int parts[4];
u_int *pp = parts;
c = *src;
for (;;) {
/*
* Collect number up to ``.''.
* Values are specified as for C:
* 0x=hex, 0=octal, isdigit=decimal.
*/
if (!isdigit(c))
return (0);
val = 0;
if (c == '0') {
c = *++src;
if (c == 'x' || c == 'X')
return (0);
else if (isdigit(c) && c != '9')
return (0);
}
for (;;) {
if (isdigit(c)) {
digit = c - '0';
if (digit >= 10)
break;
val = (val * 10) + digit;
c = *++src;
} else
break;
}
if (c == '.') {
/*
* Internet format:
* a.b.c.d
* a.b.c (with c treated as 16 bits)
* a.b (with b treated as 24 bits)
* a (with a treated as 32 bits)
*/
if (pp >= parts + 3)
return (0);
*pp++ = val;
c = *++src;
} else
break;
}
/*
* Check for trailing characters.
*/
if (c != '\0' && !isspace(c))
return (0);
/*
* Find the number of parts specified.
* It must be 4; we only support dotted quads, we don't
* support shorthand.
*/
n = pp - parts + 1;
if (n != 4)
return (0);
/*
* parts[0-2] were set to the first 3 parts of the address;
* val was set to the 4th part.
*
* Check if any part is bigger than 255.
*/
if ((parts[0] | parts[1] | parts[2] | val) > 0xff)
return (0);
/*
* Add the other three parts to val.
*/
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
if (dst) {
val = htonl(val);
memcpy(dst, &val, NS_INADDRSZ);
}
return (1);
}
/* int
* strtoaddr6(src, dst)
* convert presentation level IPv6 address to network order binary form.
* return:
* 1 if `src' is a valid [RFC1884 2.2] address, else 0.
* notice:
* (1) does not touch `dst' unless it's returning 1.
* (2) :: in a full address is silently ignored.
* credit:
* inspired by Mark Andrews.
* author:
* Paul Vixie, 1996.
*/
int
strtoaddr6(const char *src, void *dst)
{
static const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
const char *xdigits, *curtok;
int ch, seen_xdigits;
u_int val;
memset((tp = tmp), '\0', NS_IN6ADDRSZ);
endp = tp + NS_IN6ADDRSZ;
colonp = NULL;
/* Leading :: requires some special handling. */
if (*src == ':')
if (*++src != ':')
return (0);
curtok = src;
seen_xdigits = 0;
val = 0;
while ((ch = *src++) != '\0') {
const char *pch;
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
pch = strchr((xdigits = xdigits_u), ch);
if (pch != NULL) {
val <<= 4;
val |= (int)(pch - xdigits);
if (++seen_xdigits > 4)
return (0);
continue;
}
if (ch == ':') {
curtok = src;
if (!seen_xdigits) {
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;
seen_xdigits = 0;
val = 0;
continue;
}
if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
strtoaddr(curtok, tp) > 0) {
tp += NS_INADDRSZ;
seen_xdigits = 0;
break; /*%< '\\0' was seen by strtoaddr(). */
}
return (0);
}
if (seen_xdigits) {
if (tp + NS_INT16SZ > endp)
return (0);
*tp++ = (u_char) (val >> 8) & 0xff;
*tp++ = (u_char) val & 0xff;
}
if (colonp != NULL) {
/*
* Since some memmove()'s erroneously fail to handle
* overlapping regions, we'll do the shift by hand.
*/
const ptrdiff_t n = tp - colonp;
int 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);
}