From bb524e99c9dd9555b0f77275bbb5574d47689fc8 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 25 May 2007 18:22:37 +0000 Subject: r12955@catbus: nickm | 2007-05-25 13:17:30 -0400 First bare stubs of ipv6 work: commit some (untested, hence doublessly broken) implementations of inet_ntop/pton for systems that lack them. svn:r10326 --- configure.in | 2 +- doc/TODO | 6 ++ src/common/compat.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/common/compat.h | 12 ++++ src/common/util.c | 2 +- src/common/util.h | 2 +- 6 files changed, 182 insertions(+), 3 deletions(-) diff --git a/configure.in b/configure.in index 1df038c96..bac5d91db 100644 --- a/configure.in +++ b/configure.in @@ -152,7 +152,7 @@ dnl ------------------------------------------------------------------- dnl Check for functions before libevent, since libevent-1.2 apparently dnl exports strlcpy without defining it in a header. -AC_CHECK_FUNCS(gettimeofday ftime socketpair uname inet_aton strptime getrlimit strlcat strlcpy strtoull ftello getaddrinfo localtime_r gmtime_r memmem strtok_r) +AC_CHECK_FUNCS(gettimeofday ftime socketpair uname inet_aton strptime getrlimit strlcat strlcpy strtoull ftello getaddrinfo localtime_r gmtime_r memmem strtok_r inet_pton inet_ntop) if test $enable_threads = "yes"; then AC_CHECK_HEADERS(pthread.h) diff --git a/doc/TODO b/doc/TODO index 943d9d9f8..b52d989a5 100644 --- a/doc/TODO +++ b/doc/TODO @@ -238,6 +238,12 @@ Things we'd like to do in 0.2.0.x: - Let controller set router flags for authority to transmit, and for client to use. - Support relaying streams to ipv6. + - Internal code support for ipv6: + o Clone ipv6 functions (inet_ntop, inet_pton) where they don't exist. + - Most address variables need to become sockaddrs. + - Teach resolving code how to handle ipv6. + - Teach exit policies about ipv6 (consider ipv4/ipv6 interaction!) + - ... - Let servers decide to support BEGIN_DIR but not DirPort. - Tor should bind its ports before dropping privs, so users don't have to do the ipchains dance. diff --git a/src/common/compat.c b/src/common/compat.c index a15d09367..b9888d9a5 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -807,6 +807,167 @@ tor_inet_aton(const char *c, struct in_addr* addr) #endif } +/** DOCDOC */ +const char * +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; + else + return dst; + } 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; + uint16_t words[8]; + for (i = 0; i < 8; ++i) { + words[i] = (((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[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 (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; + } + } + cp = buf; + for (i = 0; i < 8; ++i) { + if (words[i] == 0 && longestGapPos == i) { + *cp++ = ':'; + *cp++ = ':'; + while (i < 8 && words[i] == 0) + ++i; + --i; /* to compensate for loop increment. */ + } else { + tor_snprintf(cp, sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]); + cp += strlen(cp); + if (i != 7) + *cp++ = ':'; + } + } + if (strlen(buf) > len) + return NULL; + strlcpy(dst, buf, len); + return dst; + } else { + return NULL; + } +#endif +} + +/** DOCDOC */ +int +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. */ + if (dot == src) + return 0; + else if (!dot) + eow = src+strlen(src); + else { + uint32_t a; + for (eow = dot-1; eow >= src && TOR_ISDIGIT(*eow); --eow) + ; + ++eow; + + if (inet_aton(eow, &in) != 1) + return 0; + a = ntohl(in.s_addr); + words[6] = a >> 16; + words[7] = a & 0xFFFF; + setWords += 2; + } + + i = 0; + while (src < eow) { + if (i > 7) + return 0; + if (TOR_ISXDIGIT(*src)) { + char *next; + int 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 != ':') + return 0; + ++src; + } else if (*src == ':' && i > 0 && gapPos==-1) { + gapPos = i; + ++src; + } else if (*src == ':' && i == 0 && src[1] == ':') { + gapPos = i; + src += 2; + } else { + return 0; + } + } + + if (setWords > 8 || (setWords < 8 && gapPos == -1)) + return 0; + + if (gapPos >= 0) { + int gapLen = 8 - setWords; + memmove(&words[gapPos+gapLen], &words[gapPos], + sizeof(uint16_t)*(8-gapPos)); + } + 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; + } else { + return -1; + } +#endif +} + + /** Similar behavior to Unix gethostbyname: resolve name, and set * *addr to the proper IP address, in network byte order. Returns 0 * on success, -1 on failure; 1 on transient failure. diff --git a/src/common/compat.h b/src/common/compat.h index cd3643740..be8e19eee 100644 --- a/src/common/compat.h +++ b/src/common/compat.h @@ -32,6 +32,9 @@ #ifdef HAVE_STRING_H #include #endif +#ifdef HAVE_CTYPE_H +#include +#endif #include #ifndef NULL_REP_IS_ZERO_BYTES @@ -241,8 +244,17 @@ int get_n_open_sockets(void); typedef int socklen_t; #endif +#ifndef HAVE_STRUCT_IN6_ADDR +struct in6_addr +{ + uint8_t s6_addr[16]; +}; +#endif + struct in_addr; int tor_inet_aton(const char *cp, struct in_addr *addr) ATTR_NONNULL((1,2)); +const char *tor_inet_ntop(int af, const void *src, char *dst, size_t len); +int tor_inet_pton(int af, const char *src, void *dst); int tor_lookup_hostname(const char *name, uint32_t *addr) ATTR_NONNULL((1,2)); void set_socket_nonblocking(int socket); int tor_socketpair(int family, int type, int protocol, int fd[2]); diff --git a/src/common/util.c b/src/common/util.c index 7ca08363d..889ede100 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -1952,7 +1952,7 @@ parse_addr_and_port_range(const char *s, uint32_t *addr_out, * buf. */ int -tor_inet_ntoa(struct in_addr *in, char *buf, size_t buf_len) +tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len) { uint32_t a = ntohl(in->s_addr); return tor_snprintf(buf, buf_len, "%d.%d.%d.%d", diff --git a/src/common/util.h b/src/common/util.h index f04160935..ab8aea86e 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -250,7 +250,7 @@ int parse_addr_and_port_range(const char *s, uint32_t *addr_out, uint16_t *port_max_out); int addr_mask_get_bits(uint32_t mask); #define INET_NTOA_BUF_LEN 16 -int tor_inet_ntoa(struct in_addr *in, char *buf, size_t buf_len); +int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len); char *tor_dup_addr(uint32_t addr) ATTR_MALLOC; int get_interface_address(int severity, uint32_t *addr); -- cgit v1.2.3