|
@@ -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 <b>name</b>, and set
|
|
|
* *addr to the proper IP address, in network byte order. Returns 0
|
|
|
* on success, -1 on failure; 1 on transient failure.
|