#endif
#include <errno.h>
#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
#ifndef _EVENT_HAVE_GETTIMEOFDAY
#include <sys/timeb.h>
#include "event2/util.h"
#include "log.h"
+#include "strlcpy-internal.h"
+
int
evutil_socketpair(int family, int type, int protocol, evutil_socket_t fd[2])
{
return r;
#endif
}
+
+#define USE_INTERNAL_NTOP
+#define USE_INTERNAL_PTON
+
+const char *
+evutil_inet_ntop(int af, const void *src, char *dst, size_t len)
+{
+#if defined(_EVENT_HAVE_INET_NTOP) && !defined(USE_INTERNAL_NTOP)
+ return inet_ntop(af, src, dst, len);
+#else
+ if (af == AF_INET) {
+ const struct in_addr *in = src;
+ const ev_uint32_t a = ntohl(in->s_addr);
+ int r;
+ r = evutil_snprintf(dst, len, "%d.%d.%d.%d",
+ (int)(ev_uint8_t)((a>>24)&0xff),
+ (int)(ev_uint8_t)((a>>16)&0xff),
+ (int)(ev_uint8_t)((a>>8 )&0xff),
+ (int)(ev_uint8_t)((a )&0xff));
+ if (r<0||r>=len)
+ return NULL;
+ else
+ return dst;
+#ifdef AF_INET6
+ } else if (af == AF_INET6) {
+ const struct in6_addr *addr = src;
+ char buf[64], *cp;
+ int longestGapLen = 0, longestGapPos = -1, i,
+ curGapPos = -1, curGapLen = 0;
+ ev_uint16_t words[8];
+ for (i = 0; i < 8; ++i) {
+ words[i] =
+ (((ev_uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1];
+ }
+ if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
+ words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) ||
+ (words[5] == 0xffff))) {
+ /* This is an IPv4 address. */
+ if (words[5] == 0) {
+ evutil_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d",
+ addr->s6_addr[12], addr->s6_addr[13],
+ addr->s6_addr[14], addr->s6_addr[15]);
+ } else {
+ evutil_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5],
+ addr->s6_addr[12], addr->s6_addr[13],
+ addr->s6_addr[14], addr->s6_addr[15]);
+ }
+ if (strlen(buf) > len)
+ return NULL;
+ strlcpy(dst, buf, len);
+ return dst;
+ }
+ i = 0;
+ while (i < 8) {
+ if (words[i] == 0) {
+ curGapPos = i++;
+ curGapLen = 1;
+ while (i<8 && words[i] == 0) {
+ ++i; ++curGapLen;
+ }
+ if (curGapLen > longestGapLen) {
+ longestGapPos = curGapPos;
+ longestGapLen = curGapLen;
+ }
+ } else {
+ ++i;
+ }
+ }
+ if (longestGapLen<=1)
+ longestGapPos = -1;
+
+ cp = buf;
+ for (i = 0; i < 8; ++i) {
+ if (words[i] == 0 && longestGapPos == i) {
+ if (i == 0)
+ *cp++ = ':';
+ *cp++ = ':';
+ while (i < 8 && words[i] == 0)
+ ++i;
+ --i; /* to compensate for loop increment. */
+ } else {
+ evutil_snprintf(cp,
+ sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]);
+ cp += strlen(cp);
+ if (i != 7)
+ *cp++ = ':';
+ }
+ }
+ *cp = '\0';
+ if (strlen(buf) > len)
+ return NULL;
+ strlcpy(dst, buf, len);
+ return dst;
+#endif
+ } else {
+ return NULL;
+ }
+#endif
+}
+
+#define ISDIGIT(c) isdigit((int)(unsigned char)(c))
+#define ISXDIGIT(c) isxdigit((int)(unsigned char)(c))
+
+int
+evutil_inet_pton(int af, const char *src, void *dst)
+{
+#if defined(_EVENT_HAVE_INET_PTON) && !defined(USE_INTERNAL_PTON)
+ return inet_pton(af, src, dst);
+#else
+ if (af == AF_INET) {
+#ifdef _EVENT_HAVE_INET_ATON
+ return inet_aton(src, dst);
+#else
+ ev_uint32_t r;
+ struct in_addr *out = dst;
+ if (strcmp(c, "255.255.255.255") == 0) {
+ out->s_addr = 0xffffffffu;
+ } else {
+ r = inet_addr(c);
+ if (r == INADDR_NONE)
+ return 0;
+ addr->s_addr = r;
+ }
+ return 1;
+#endif
+#ifdef AF_INET6
+ } else if (af == AF_INET6) {
+ struct in6_addr *out = dst;
+ uint16_t words[8];
+ int gapPos = -1, i, setWords=0;
+ const char *dot = strchr(src, '.');
+ const char *eow; /* end of words. */
+ if (dot == src)
+ return 0;
+ else if (!dot)
+ eow = src+strlen(src);
+ else {
+ int byte1,byte2,byte3,byte4;
+ char more;
+ for (eow = dot-1; eow >= src && ISDIGIT(*eow); --eow)
+ ;
+ ++eow;
+
+ /* We use "scanf" because some platform inet_aton()s are too lax
+ * about IPv4 addresses of the form "1.2.3" */
+ if (sscanf(eow, "%d.%d.%d.%d%c",
+ &byte1,&byte2,&byte3,&byte4,&more) != 4)
+ return 0;
+
+ if (byte1 > 255 || byte1 < 0 ||
+ byte2 > 255 || byte2 < 0 ||
+ byte3 > 255 || byte3 < 0 ||
+ byte4 > 255 || byte4 < 0)
+ return 0;
+
+ words[6] = (byte1<<8) | byte2;
+ words[7] = (byte3<<8) | byte4;
+ setWords += 2;
+ }
+
+ i = 0;
+ while (src < eow) {
+ if (i > 7)
+ return 0;
+ if (ISXDIGIT(*src)) {
+ char *next;
+ long r = strtol(src, &next, 16);
+ if (next > 4+src)
+ return 0;
+ if (next == src)
+ return 0;
+ if (r<0 || r>65536)
+ return 0;
+
+ words[i++] = (uint16_t)r;
+ setWords++;
+ src = next;
+ if (*src != ':' && src != eow)
+ return 0;
+ ++src;
+ } else if (*src == ':' && i > 0 && gapPos==-1) {
+ gapPos = i;
+ ++src;
+ } else if (*src == ':' && i == 0 && src[1] == ':' && gapPos==-1) {
+ gapPos = i;
+ src += 2;
+ } else {
+ return 0;
+ }
+ }
+
+ if (setWords > 8 ||
+ (setWords == 8 && gapPos != -1) ||
+ (setWords < 8 && gapPos == -1))
+ return 0;
+
+ if (gapPos >= 0) {
+ int nToMove = setWords - (dot ? 2 : 0) - gapPos;
+ int gapLen = 8 - setWords;
+ // assert(nToMove >= 0);
+ if (nToMove < 0)
+ return -1; /* should be impossible */
+ memmove(&words[gapPos+gapLen], &words[gapPos],
+ sizeof(uint16_t)*nToMove);
+ memset(&words[gapPos], 0, sizeof(uint16_t)*gapLen);
+ }
+ for (i = 0; i < 8; ++i) {
+ out->s6_addr[2*i ] = words[i] >> 8;
+ out->s6_addr[2*i+1] = words[i] & 0xff;
+ }
+
+ return 1;
+#endif
+ } else {
+ return -1;
+ }
+#endif
+}
--- /dev/null
+/*
+ * Copyright (c) 2009 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifndef WIN32
+#include <sys/socket.h>
+#include <sys/signal.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "event2/util.h"
+
+void util_suite(void);
+
+enum entry_status { NORMAL, CANONICAL, BAD };
+
+/* This is a big table of results we expect from generating and parsing */
+static struct ipv4_entry {
+ const char *addr;
+ ev_uint32_t res;
+ enum entry_status status;
+} ipv4_entries[] = {
+ { "1.2.3.4", 0x01020304u, CANONICAL },
+ { "255.255.255.255", 0xffffffffu, CANONICAL },
+ { "256.0.0.0", 0, BAD },
+ { "ABC", 0, BAD },
+ { "1.2.3.4.5", 0, BAD },
+ { "176.192.208.244", 0xb0c0d0f4, CANONICAL },
+ { NULL, 0, BAD },
+};
+
+static struct ipv6_entry {
+ const char *addr;
+ ev_uint32_t res[4];
+ enum entry_status status;
+} ipv6_entries[] = {
+ { "::", { 0, 0, 0, 0, }, CANONICAL },
+ { "0:0:0:0:0:0:0:0", { 0, 0, 0, 0, }, NORMAL },
+ { "::1", { 0, 0, 0, 1, }, CANONICAL },
+ { "ffff:1::", { 0xffff0001u, 0, 0, 0, }, CANONICAL },
+ { "ffff:0000::", { 0xffff0000u, 0, 0, 0, }, NORMAL },
+ { "ffff::1234", { 0xffff0000u, 0, 0, 0x1234, }, CANONICAL },
+ { "0102::1.2.3.4", {0x01020000u, 0, 0, 0x01020304u }, NORMAL },
+ { "::9:c0a8:1:1", { 0, 0, 0x0009c0a8u, 0x00010001u }, CANONICAL },
+ { "::ffff:1.2.3.4", { 0, 0, 0x000ffffu, 0x01020304u }, CANONICAL },
+ { "FFFF::", { 0xffff0000u, 0, 0, 0 }, NORMAL },
+ { "foobar.", { 0, 0, 0, 0 }, BAD },
+ { "foobar", { 0, 0, 0, 0 }, BAD },
+ { "fo:obar", { 0, 0, 0, 0 }, BAD },
+ { "ffff", { 0, 0, 0, 0 }, BAD },
+ { "fffff::", { 0, 0, 0, 0 }, BAD },
+ { "fffff::", { 0, 0, 0, 0 }, BAD },
+ { "1:2:33333:4::", { 0, 0, 0, 0 }, BAD },
+ { "1:2:3:4:5:6:7:8:9", { 0, 0, 0, 0 }, BAD },
+ { "1::2::3", { 0, 0, 0, 0 }, BAD },
+ { ":::1", { 0, 0, 0, 0 }, BAD },
+ { NULL, { 0, 0, 0, 0, }, BAD },
+};
+
+static void
+regress_ipv4_parse(void)
+{
+ int i;
+ int ok = 1;
+ printf("Testing IPv4 parsing...");
+
+ for (i = 0; ipv4_entries[i].addr; ++i) {
+ char written[128];
+ struct ipv4_entry *ent = &ipv4_entries[i];
+ struct in_addr in;
+ int r;
+ r = evutil_inet_pton(AF_INET, ent->addr, &in);
+ if (r == 0) {
+ if (ent->status != BAD) {
+ printf("%s did not parse, but it's a good address!\n",
+ ent->addr);
+ ok = 0;
+ }
+ continue;
+ }
+ if (ent->status == BAD) {
+ printf("%s parsed, but we expected an error\n", ent->addr);
+ ok = 0;
+ continue;
+ }
+ if (ntohl(in.s_addr) != ent->res) {
+ printf("%s parsed to %lx, but we expected %lx\n", ent->addr,
+ (unsigned long)ntohl(in.s_addr),
+ (unsigned long)ent->res);
+ ok = 0;
+ continue;
+ }
+ if (ent->status == CANONICAL) {
+ const char *w = evutil_inet_ntop(AF_INET, &in, written,
+ sizeof(written));
+ if (!w) {
+ printf("Tried to write out %s; got NULL.\n", ent->addr);
+ ok = 0;
+ continue;
+ }
+ if (strcmp(written, ent->addr)) {
+ printf("Tried to write out %s; got %s\n", ent->addr, written);
+ ok = 0;
+ continue;
+ }
+ }
+
+ }
+ if (!ok) {
+ printf("FAILED\n");
+ exit(1);
+ }
+ printf("OK\n");
+}
+
+static void
+regress_ipv6_parse(void)
+{
+#ifdef AF_INET6
+ int i, j;
+ int ok = 1;
+ printf("Testing IPv6 parsing...");
+
+ for (i = 0; ipv6_entries[i].addr; ++i) {
+ char written[128];
+ struct ipv6_entry *ent = &ipv6_entries[i];
+ struct in6_addr in6;
+ int r;
+ r = evutil_inet_pton(AF_INET6, ent->addr, &in6);
+ if (r == 0) {
+ if (ent->status != BAD) {
+ printf("%s did not parse, but it's a good address!\n",
+ ent->addr);
+ ok = 0;
+ }
+ continue;
+ }
+ if (ent->status == BAD) {
+ printf("%s parsed, but we expected an error\n", ent->addr);
+ ok = 0;
+ continue;
+ }
+ for (j = 0; j < 4; ++j) {
+ /* Can't use s6_addr32 here; some don't have it. */
+ ev_uint32_t u =
+ (in6.s6_addr[j*4 ] << 24) |
+ (in6.s6_addr[j*4+1] << 16) |
+ (in6.s6_addr[j*4+2] << 8) |
+ (in6.s6_addr[j*4+3]);
+ if (u != ent->res[j]) {
+ printf("%s did not parse as expected.\n", ent->addr);
+ ok = 0;
+ continue;
+ }
+ }
+ if (ent->status == CANONICAL) {
+ const char *w = evutil_inet_ntop(AF_INET6, &in6, written,
+ sizeof(written));
+ if (!w) {
+ printf("Tried to write out %s; got NULL.\n", ent->addr);
+ ok = 0;
+ continue;
+ }
+ if (strcmp(written, ent->addr)) {
+ printf("Tried to write out %s; got %s\n", ent->addr, written);
+ ok = 0;
+ continue;
+ }
+ }
+
+ }
+ if (!ok) {
+ printf("FAILED\n");
+ exit(1);
+ }
+ printf("OK\n");
+#else
+ print("Skipping IPv6 address parsing.\n");
+#endif
+}
+
+
+void
+util_suite(void)
+{
+ regress_ipv4_parse();
+ regress_ipv6_parse();
+}