diff --git a/src/common/compat.c b/src/common/compat.c index ed06701ab7..64e9dae5e2 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -821,7 +821,6 @@ tor_inet_ntop(int af, const void *src, char *dst, size_t len) #ifdef HAVE_INET_NTOP return inet_ntop(af,src,dst,(socklen_t)len); #else - /* XXXX needs testing. !!!! */ if (af == AF_INET) { if (tor_inet_ntoa(src, dst, len) < 0) return NULL; @@ -839,9 +838,15 @@ tor_inet_ntop(int af, const void *src, char *dst, size_t len) if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && words[4] == 0 && (words[5] == 0 || words[5] == 0xffff) && words[6]) { /* This is an IPv4 address. */ - tor_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 (words[5] == 0) { + tor_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 { + tor_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); @@ -863,10 +868,14 @@ tor_inet_ntop(int af, const void *src, char *dst, size_t len) ++i; } } + if (longestGapLen<=1) + longestGapPos = -1; + cp = buf; for (i = 0; i < 8; ++i) { if (words[i] == 0 && longestGapPos == i) { - *cp++ = ':'; + if (i == 0) + *cp++ = ':'; *cp++ = ':'; while (i < 8 && words[i] == 0) ++i; @@ -878,6 +887,7 @@ tor_inet_ntop(int af, const void *src, char *dst, size_t len) *cp++ = ':'; } } + *cp = '\0'; if (strlen(buf) > len) return NULL; strlcpy(dst, buf, len); @@ -903,13 +913,11 @@ tor_inet_pton(int af, const char *src, void *dst) #ifdef HAVE_INET_PTON return inet_pton(af, src, dst); #else - /* XXXX needs testing. !!!! */ if (af == AF_INET) { return tor_inet_aton(src, dst); } else if (af == AF_INET6) { struct in6_addr *out = dst; uint16_t words[8]; - struct in_addr in; int gapPos = -1, i, setWords=0; const char *dot = strchr(src, '.'); const char *eow; /* end of words. */ @@ -918,16 +926,25 @@ tor_inet_pton(int af, const char *src, void *dst) else if (!dot) eow = src+strlen(src); else { - uint32_t a; + int byte1,byte2,byte3,byte4; + char more; for (eow = dot-1; eow >= src && TOR_ISDIGIT(*eow); --eow) ; ++eow; - if (tor_inet_aton(eow, &in) != 1) + /* 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; - a = ntohl(in.s_addr); - words[6] = a >> 16; - words[7] = a & 0xFFFF; + + 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; } @@ -948,7 +965,7 @@ tor_inet_pton(int af, const char *src, void *dst) words[i++] = (uint16_t)r; setWords++; src = next; - if (*src != ':') + if (*src != ':' && src != eow) return 0; ++src; } else if (*src == ':' && i > 0 && gapPos==-1) { @@ -966,9 +983,12 @@ tor_inet_pton(int af, const char *src, void *dst) return 0; if (gapPos >= 0) { + int nToMove = setWords - (dot ? 2 : 0) - gapPos; int gapLen = 8 - setWords; + tor_assert(nToMove >= 0); memmove(&words[gapPos+gapLen], &words[gapPos], - sizeof(uint16_t)*(8-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; diff --git a/src/or/test.c b/src/or/test.c index 4307b1007e..19db66e8a7 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -310,6 +310,7 @@ test_buffers(void) test_memeq(str, (char*)_buf_peek_raw_buffer(buf), 10); /* XXX Check rest. */ test_eq(eof, 0); + i = read_to_buf(s, 1024, buf, &eof); test_eq(i, 0); test_eq(buf_capacity(buf), MAX_BUF_SIZE); @@ -968,6 +969,127 @@ test_util(void) test_eq(round_to_power_of_2(0), 2); } +static void +_test_eq_ip6(struct in6_addr *a, struct in6_addr *b, const char *e1, + const char *e2, int line) +{ + int i; + int ok = 1; + for (i = 0; i < 16; ++i) { + if (a->s6_addr[i] != b->s6_addr[i]) { + ok = 0; + break; + } + } + if (ok) { + printf("."); fflush(stdout); + } else { + char buf1[128], *cp1; + char buf2[128], *cp2; + have_failed = 1; + cp1 = buf1; cp2 = buf2; + for (i=0; i<16; ++i) { + tor_snprintf(cp1, sizeof(buf1)-(cp1-buf1), "%02x", a->s6_addr[i]); + tor_snprintf(cp2, sizeof(buf2)-(cp2-buf2), "%02x", b->s6_addr[i]); + cp1 += 2; cp2 += 2; + if ((i%2)==1 && i != 15) { + *cp1++ = ':'; + *cp2++ = ':'; + } + } + *cp1 = *cp2 = '\0'; + printf("Line %d: assertion failed: (%s == %s)\n" + " %s != %s\n", line, e1, e2, buf1, buf2); + fflush(stdout); + } +} +#define test_eq_ip6(a,b) _test_eq_ip6((a),(b),#a,#b,__LINE__) + +#define test_pton6_same(a,b) do { \ + r = tor_inet_pton(AF_INET6, a, &a1); \ + test_assert(r==1); \ + r = tor_inet_pton(AF_INET6, b, &a2); \ + test_assert(r==1); \ + test_eq_ip6(&a1,&a2); \ + } while(0) + +#define test_pton6_bad(a) \ + test_eq(0, tor_inet_pton(AF_INET6, a, &a1)) + +#define test_ntop6_reduces(a,b) do { \ + r = tor_inet_pton(AF_INET6, a, &a1); \ + test_assert(r==1); \ + test_streq(tor_inet_ntop(AF_INET6, &a1, buf, sizeof(buf)), b); \ + r = tor_inet_pton(AF_INET6, b, &a2); \ + test_assert(r==1); \ + test_eq_ip6(&a1, &a2); \ + } while (0) + +static void +test_ip6_helpers(void) +{ + char buf[64]; + struct in6_addr a1, a2; + int r, i; + // struct in_addr b1, b2; + /* Test tor_inet_ntop and tor_inet_pton: IPv6 */ + + /* === Test pton: valid af_inet6 */ + /* Simple, valid parsing. */ + r = tor_inet_pton(AF_INET6, + "0102:0304:0506:0708:090A:0B0C:0D0E:0F10", &a1); + test_assert(r==1); + for (i=0;i<16;++i) { test_eq(i+1, (int)a1.s6_addr[i]); } + /* ipv4 ending. */ + test_pton6_same("0102:0304:0506:0708:090A:0B0C:0D0E:0F10", + "0102:0304:0506:0708:090A:0B0C:13.14.15.16"); + /* shortened words. */ + test_pton6_same("0001:0099:BEEF:0000:0123:FFFF:0001:0001", + "1:99:BEEF:0:0123:FFFF:1:1"); + /* zeros at the beginning */ + test_pton6_same("0000:0000:0000:0000:0009:C0A8:0001:0001", + "::9:c0a8:1:1"); + test_pton6_same("0000:0000:0000:0000:0009:C0A8:0001:0001", + "::9:c0a8:0.1.0.1"); + /* zeros in the middle. */ + test_pton6_same("fe80:0000:0000:0000:0202:1111:0001:0001", + "fe80::202:1111:1:1"); + /* zeros at the end. */ + test_pton6_same("1000:0001:0000:0007:0000:0000:0000:0000", + "1000:1:0:7::"); + + /* === Test ntop: af_inet6 */ + test_ntop6_reduces("0:0:0:0:0:0:0:0", "::"); + + test_ntop6_reduces("0001:0099:BEEF:0000:0123:FFFF:0001:0001", + "1:99:beef:0:123:ffff:1:1"); + + test_ntop6_reduces("0:0:0:0:0:0:c0a8:0101", "::192.168.1.1"); + test_ntop6_reduces("0:0:0:0:0:ffff:c0a8:0101", "::ffff:192.168.1.1"); + test_ntop6_reduces("0000:0000:0000:0000:0009:C0A8:0001:0001", + "::9:c0a8:1:1"); + test_ntop6_reduces("fe80:0000:0000:0000:0202:1111:0001:0001", + "fe80::202:1111:1:1"); + test_ntop6_reduces("1000:0001:0000:0007:0000:0000:0000:0000", + "1000:1:0:7::"); + + /* === Test pton: invalid in6. */ + test_pton6_bad("foobar."); + test_pton6_bad("55555::"); + test_pton6_bad("9:-60::"); + test_pton6_bad("1:2:33333:4:0002:3::"); + // test_pton6_bad("1:2:3333:4:00002:3::"); //XXXX not bad. + test_pton6_bad("1:2:3333:4:fish:3::"); + test_pton6_bad("1:2:3:4:5:6:7:8:9"); + test_pton6_bad("1:2:3:4:5:6:7"); + test_pton6_bad("1:2:3:4:5:6:1.2.3.4.5"); + test_pton6_bad("1:2:3:4:5:6:1.2.3"); + test_pton6_bad("::1.2.3"); + test_pton6_bad("::1.2.3.4.5"); + test_pton6_bad("99"); + test_pton6_bad(""); +} + static void test_smartlist(void) { @@ -2277,6 +2399,7 @@ main(int c, char**v) test_crypto_dh(); test_crypto_s2k(); puts("\n========================= Util ============================"); + test_ip6_helpers(); test_gzip(); test_util(); test_smartlist();