Dear list, I wrote an extensive patch to make tor support * hidden services on ipv6-addresses * binding for socks on an ipv6-address * convert a lot of the internal data-structures for the comming full ipv6-support. I wrote it to tor-volunteers@xxxxxxxxxxxxxx on friday but got no answer thus I am posting them here. The code may not use the prefered naming-conventions or the tor_address_t -data-structure (because that one uses socket_addr and we only need the actual address-part) but I guess a refactoring for it to meet the coding-guidelines is far less work then writing it and getting it to work in the first place. Marcus Wolschon
Index: or/circuitlist.c =================================================================== --- or/circuitlist.c (Revision 12621) +++ or/circuitlist.c (Arbeitskopie) @@ -216,6 +216,11 @@ global_circuitlist = circ; } } +/** compare the 2 given ipv6-addresses + * + * * returns 0 if they are equal. + * */ +int compare_in6_addr(struct in6_addr a, struct in6_addr b); /** Append to <b>out</b> all circuits in state OR_WAIT waiting for * the given connection. */ @@ -235,7 +240,9 @@ tor_assert(circ->state == CIRCUIT_STATE_OR_WAIT); if (tor_digest_is_zero(circ->n_conn_id_digest)) { /* Look at addr/port. This is an unkeyed connection. */ - if (circ->n_addr != or_conn->_base.addr || + if (circ->n_family != or_conn->_base.socket_family || + (circ->n_family == AF_INET && circ->n_addr4 != or_conn->_base.addr4) || + (circ->n_family == AF_INET6 && compare_in6_addr(circ->n_addr6, or_conn->_base.addr6) != 0) || circ->n_port != or_conn->_base.port) continue; } else { @@ -558,8 +565,10 @@ } } } - if (!circ->n_conn && circ->n_addr && circ->n_port && - circ->n_addr == conn->addr && + if (!circ->n_conn && (circ->n_family != AF_INET || circ->n_addr4) && circ->n_port && + circ->n_family == conn->socket_family && + (circ->n_family != AF_INET || circ->n_addr4 == conn->addr4)&& + (circ->n_family != AF_INET6 || compare_in6_addr(circ->n_addr6, conn->addr6) == 0)&& circ->n_port == conn->port && conn->type == CONN_TYPE_OR && !memcmp(TO_OR_CONN(conn)->identity_digest, circ->n_conn_id_digest, Index: or/connection_or.c =================================================================== --- or/connection_or.c (Revision 12621) +++ or/connection_or.c (Arbeitskopie) @@ -336,14 +336,20 @@ if (get_options()->HttpsProxy) { char buf[1024]; - char addrbuf[INET_NTOA_BUF_LEN]; - struct in_addr in; + char addrbuf[64]; char *base64_authenticator=NULL; const char *authenticator = get_options()->HttpsProxyAuthenticator; + + if (conn->socket_family == AF_INET6) { + struct in6_addr addr; + addr = conn->addr6; + tor_inet_ntop(AF_INET6, &addr, addrbuf, sizeof(addrbuf)); + } else { + struct in_addr in; + in.s_addr = htonl(conn->addr4); + tor_inet_ntoa(&in, addrbuf, sizeof(addrbuf)); + } - in.s_addr = htonl(conn->addr); - tor_inet_ntoa(&in, addrbuf, sizeof(addrbuf)); - if (authenticator) { base64_authenticator = alloc_http_authenticator(authenticator); if (!base64_authenticator) @@ -375,6 +381,58 @@ * have an addr/port/id_digest, then fill in as much as we can. Start * by checking to see if this describes a router we know. */ static void +connection_or_init_conn_from_address6(or_connection_t *conn, + struct in6_addr addr6, uint16_t port, + const char *id_digest, + int started_here) +{ + or_options_t *options = get_options(); + routerinfo_t *r = router_get_by_digest(id_digest); + conn->bandwidthrate = (int)options->BandwidthRate; + conn->read_bucket = conn->bandwidthburst = (int)options->BandwidthBurst; + connection_or_set_identity_digest(conn, id_digest); + conn->_base.socket_family = AF_INET6; + conn->_base.addr6 = addr6; + conn->_base.port = port; + conn->real_socket_family = AF_INET6; + conn->real_addr6 = addr6; + if (r) { + if (conn->_base.addr4 == r->addr) + conn->is_canonical = 1; + if (!started_here) { + /* Override the addr/port, so our log messages will make sense. + * This is dangerous, since if we ever try looking up a conn by + * its actual addr/port, we won't remember. Careful! */ + /* XXXX020 this is stupid, and it's the reason we need real_addr to + * track is_canonical properly. */ + conn->_base.socket_family = AF_INET; + conn->_base.addr4 = r->addr; + conn->_base.port = r->or_port; + } + conn->nickname = tor_strdup(r->nickname); + tor_free(conn->_base.address); + conn->_base.address = tor_strdup(r->address); + } else { + const char *n; + /* If we're an authoritative directory server, we may know a + * nickname for this router. */ + n = dirserv_get_nickname_by_digest(id_digest); + if (n) { + conn->nickname = tor_strdup(n); + } else { + conn->nickname = tor_malloc(HEX_DIGEST_LEN+2); + conn->nickname[0] = '$'; + base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1, + conn->identity_digest, DIGEST_LEN); + } + tor_free(conn->_base.address); + conn->_base.address = tor_dup_addr6(addr6); + } +} +/** If we don't necessarily know the router we're connecting to, but we + * have an addr/port/id_digest, then fill in as much as we can. Start + * by checking to see if this describes a router we know. */ +static void connection_or_init_conn_from_address(or_connection_t *conn, uint32_t addr, uint16_t port, const char *id_digest, @@ -385,11 +443,13 @@ conn->bandwidthrate = (int)options->BandwidthRate; conn->read_bucket = conn->bandwidthburst = (int)options->BandwidthBurst; connection_or_set_identity_digest(conn, id_digest); - conn->_base.addr = addr; + conn->_base.socket_family = AF_INET; + conn->_base.addr4 = addr; conn->_base.port = port; - conn->real_addr = addr; + conn->real_socket_family = AF_INET; + conn->real_addr4 = addr; if (r) { - if (conn->_base.addr == r->addr) + if (conn->_base.addr4 == r->addr) conn->is_canonical = 1; if (!started_here) { /* Override the addr/port, so our log messages will make sense. @@ -397,7 +457,8 @@ * its actual addr/port, we won't remember. Careful! */ /* XXXX020 this is stupid, and it's the reason we need real_addr to * track is_canonical properly. */ - conn->_base.addr = r->addr; + conn->_base.socket_family = AF_INET; + conn->_base.addr4 = r->addr; conn->_base.port = r->or_port; } conn->nickname = tor_strdup(r->nickname); @@ -775,8 +836,13 @@ conn->handshake_state->started_here, id_digest) < 0) return -1; - connection_or_init_conn_from_address(conn, conn->_base.addr, - conn->_base.port, id_digest, 0); + if (conn->_base.socket_family == AF_INET6) { + connection_or_init_conn_from_address6(conn, conn->_base.addr6, + conn->_base.port, id_digest, 0); + } else { + connection_or_init_conn_from_address(conn, conn->_base.addr4, + conn->_base.port, id_digest, 0); + } if (connection_or_act_on_netinfo(conn)<0) return -1; return connection_or_set_state_open(conn); @@ -809,8 +875,13 @@ digest_rcvd) < 0) return -1; if (!started_here) { - connection_or_init_conn_from_address(conn,conn->_base.addr, - conn->_base.port, digest_rcvd, 0); + if (!conn->_base.socket_family == AF_INET6) { + connection_or_init_conn_from_address6(conn,conn->_base.addr6, + conn->_base.port, digest_rcvd, 0); + } else { + connection_or_init_conn_from_address(conn,conn->_base.addr4, + conn->_base.port, digest_rcvd, 0); + } } return connection_or_set_state_open(conn); } else { @@ -1040,7 +1111,11 @@ set_uint32(cell.payload, htonl(now)); cell.payload[4] = RESOLVED_TYPE_IPV4; cell.payload[5] = 4; - set_uint32(cell.payload+6, htonl(conn->_base.addr)); + if (conn->_base.socket_family == AF_INET6) { + log_warn(LD_BUG, "we do not support ipv6 in connection_or_send_netinfo() "); + return -1; + } + set_uint32(cell.payload+6, htonl(conn->_base.addr4)); /* My address. */ if ((me = router_get_my_routerinfo())) { Index: or/rendservice.c =================================================================== --- or/rendservice.c (Revision 12621) +++ or/rendservice.c (Arbeitskopie) @@ -20,7 +20,9 @@ typedef struct rend_service_port_config_t { uint16_t virtual_port; uint16_t real_port; - uint32_t real_addr; + u_int16_t real_family; // AF_INET or AF_INET6 + uint32_t real_addr4; // ipv4-address of hidden service depending on real_family + struct in6_addr real_addr6; // ipv6-address of hidden service depending on real_family } rend_service_port_config_t; /** Try to maintain this many intro points per service if possible. */ @@ -129,7 +131,6 @@ { int i; rend_service_port_config_t *p; - struct in_addr addr; if (!service->intro_prefer_nodes) service->intro_prefer_nodes = tor_strdup(""); @@ -166,15 +167,25 @@ } else { smartlist_set_capacity(service->ports, -1); smartlist_add(rend_service_list, service); - log_debug(LD_REND,"Configuring service with directory \"%s\"", + log_debug(LD_REND,"Configuring hidden service with directory \"%s\"", service->directory); for (i = 0; i < smartlist_len(service->ports); ++i) { - char addrbuf[INET_NTOA_BUF_LEN]; p = smartlist_get(service->ports, i); - addr.s_addr = htonl(p->real_addr); - tor_inet_ntoa(&addr, addrbuf, sizeof(addrbuf)); - log_debug(LD_REND,"Service maps port %d to %s:%d", - p->virtual_port, addrbuf, p->real_port); + if (p->real_family == AF_INET6) { + char addrbuf[42]; + struct in6_addr addr; + addr = p->real_addr6; + tor_inet_ntop(AF_INET6, &addr, addrbuf, sizeof(addrbuf)); + log_debug(LD_REND,"Hidden service maps ipv6 port %d to [%s]:%d", + p->virtual_port, addrbuf, p->real_port); + } else { + char addrbuf[INET_NTOA_BUF_LEN]; + struct in_addr addr; + addr.s_addr = htonl(p->real_addr4); + tor_inet_ntoa(&addr, addrbuf, sizeof(addrbuf)); + log_debug(LD_REND,"Hidden service maps ipv4 port %d to %s:%d", + p->virtual_port, addrbuf, p->real_port); + } } } } @@ -193,7 +204,6 @@ int virtport; int realport; uint16_t p; - uint32_t addr; const char *addrport; rend_service_port_config_t *result = NULL; @@ -212,32 +222,60 @@ goto err; } + result = tor_malloc(sizeof(rend_service_port_config_t)); + result->virtual_port = virtport; + if (smartlist_len(sl) == 1) { /* No addr:port part; use default. */ - realport = virtport; - addr = 0x7F000001u; /* 127.0.0.1 */ + result->real_family = AF_INET; + result->real_port = virtport; + result->real_addr4 = 0x7F000001u; /* 127.0.0.1 */ + log_warn(LD_CONFIG,"no address nor port in hidden service port " + "configuration->localhost."); } else { addrport = smartlist_get(sl,1); if (strchr(addrport, ':') || strchr(addrport, '.')) { - if (parse_addr_port(LOG_WARN, addrport, NULL, &addr, &p)<0) { - log_warn(LD_CONFIG,"Unparseable address in hidden service port " + uint32_t addr4; + if (parse_addr_port(LOG_WARN, addrport, NULL, &addr4, &p)<0) { + struct in6_addr addr6; + if (parse_addr6_port(LOG_WARN, addrport, NULL, &addr6, &p)<0) { + log_warn(LD_CONFIG,"Unparseable address in hidden service port " "configuration."); - goto err; + goto err; + } else { + // ipv6-address could be parsed + result->real_family = AF_INET6; + result->real_addr6 = addr6; + + char addrbuf[42]; + struct in6_addr addr; + addr = result->real_addr6; + tor_inet_ntop(AF_INET6, &addr, addrbuf, sizeof(addrbuf)); + log_warn(LD_CONFIG,"parse_port_config() parseable ipv6-address %s in hidden service port " + "configuration.", addrbuf); + } + } else { + // ipv4-address could be parsed + result->real_family = AF_INET; + result->real_addr4 = addr4; + log_warn(LD_CONFIG,"parse_port_config() parseable ipv4-address in hidden service port " + "configuration."); } realport = p?p:virtport; + result->real_port = realport; } else { /* No addr:port, no addr -- must be port. */ realport = atoi(addrport); if (realport < 1 || realport > 65535) goto err; - addr = 0x7F000001u; /* Default to 127.0.0.1 */ + result->real_family = AF_INET; + result->real_port = realport; + result->real_addr4 = 0x7F000001u; /* 127.0.0.1 */ + log_warn(LD_CONFIG,"no address in hidden service port " + "configuration->localhost."); } } - result = tor_malloc(sizeof(rend_service_port_config_t)); - result->virtual_port = virtport; - result->real_port = realport; - result->real_addr = addr; err: SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); smartlist_free(sl); @@ -286,6 +324,7 @@ if (!strcasecmp(line->key, "HiddenServicePort")) { portcfg = parse_port_config(line->value); if (!portcfg) { + log_warn(LD_CONFIG, "unparsable HiddenServicePort %s", line->value); rend_service_free(service); return -1; } @@ -387,7 +426,7 @@ const char *name = smartlist_get(service->intro_nodes, i); router = router_get_by_nickname(name, 1); if (!router) { - log_info(LD_REND,"Router '%s' not found for intro point %d. Skipping.", + log_info(LD_REND,"Router '%s' not found for hidden service intro point %d. Skipping.", safe_str(name), i); continue; } @@ -428,7 +467,7 @@ if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) || strlcat(fname,PATH_SEPARATOR"private_key",sizeof(fname)) >= sizeof(fname)) { - log_warn(LD_CONFIG, "Directory name too long to store key file: \"%s\".", + log_warn(LD_CONFIG, "Directory name too long to store key file: \"%s\" for hidden service.", s->directory); return -1; } @@ -438,17 +477,17 @@ /* Create service file */ if (rend_get_service_id(s->private_key, s->service_id)<0) { - log_warn(LD_BUG, "Internal error: couldn't encode service ID."); + log_warn(LD_BUG, "Internal error: couldn't encode hidden service ID."); return -1; } if (crypto_pk_get_digest(s->private_key, s->pk_digest)<0) { - log_warn(LD_BUG, "Couldn't compute hash of public key."); + log_warn(LD_BUG, "Couldn't compute hash of public key for hidden service."); return -1; } if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) || strlcat(fname,PATH_SEPARATOR"hostname",sizeof(fname)) >= sizeof(fname)) { - log_warn(LD_CONFIG, "Directory name too long to store hostname file:" + log_warn(LD_CONFIG, "Directory name too long to store hostname file for hidden service:" " \"%s\".", s->directory); return -1; } @@ -467,9 +506,11 @@ rend_service_get_by_pk_digest_and_version(const char* digest, uint8_t version) { + log_warn(LD_BUG, "Looking up hidden service for digest %s with version %i.", digest, version); SMARTLIST_FOREACH(rend_service_list, rend_service_t*, s, if (!memcmp(s->pk_digest,digest,DIGEST_LEN) && s->descriptor_version == version) return s); + log_warn(LD_BUG, "Couldn't find hidden service for digest %s with version %i.", digest, version); return NULL; } @@ -521,12 +562,12 @@ base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, circuit->rend_pk_digest, REND_SERVICE_ID_LEN); - log_info(LD_REND, "Received INTRODUCE2 cell for service %s on circ %d.", + log_info(LD_REND, "Received INTRODUCE2 cell for hidden service %s on circ %d.", escaped(serviceid), circuit->_base.n_circ_id); if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_INTRO) { log_warn(LD_PROTOCOL, - "Got an INTRODUCE2 over a non-introduction circuit %d.", + "Got an INTRODUCE2 over a non-introduction to hidden service circuit %d.", circuit->_base.n_circ_id); return -1; } @@ -534,7 +575,7 @@ /* min key length plus digest length plus nickname length */ if (request_len < DIGEST_LEN+REND_COOKIE_LEN+(MAX_NICKNAME_LEN+1)+ DH_KEY_LEN+42) { - log_warn(LD_PROTOCOL, "Got a truncated INTRODUCE2 cell on circ %d.", + log_warn(LD_PROTOCOL, "Got a truncated INTRODUCE2 cell on hidden service circ %d.", circuit->_base.n_circ_id); return -1; } @@ -543,7 +584,7 @@ service = rend_service_get_by_pk_digest_and_version( circuit->rend_pk_digest, circuit->rend_desc_version); if (!service) { - log_warn(LD_REND, "Got an INTRODUCE2 cell for an unrecognized service %s.", + log_warn(LD_REND, "Got an INTRODUCE2 cell for an unrecognized hidden service %s.", escaped(serviceid)); return -1; } @@ -560,7 +601,7 @@ if (memcmp(intro_key_digest, request, DIGEST_LEN)) { base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, request, REND_SERVICE_ID_LEN); - log_warn(LD_REND, "Got an INTRODUCE2 cell for the wrong service (%s).", + log_warn(LD_REND, "Got an INTRODUCE2 cell for the wrong hidden service (%s).", escaped(serviceid)); return -1; } @@ -568,7 +609,7 @@ keylen = crypto_pk_keysize(intro_key); if (request_len < keylen+DIGEST_LEN) { log_warn(LD_PROTOCOL, - "PK-encrypted portion of INTRODUCE2 cell was truncated."); + "PK-encrypted portion of INTRODUCE2 hidden service cell was truncated."); return -1; } /* Next N bytes is encrypted with service key */ @@ -577,7 +618,7 @@ intro_key,buf,request+DIGEST_LEN,request_len-DIGEST_LEN, PK_PKCS1_OAEP_PADDING,1); if (r<0) { - log_warn(LD_PROTOCOL, "Couldn't decrypt INTRODUCE2 cell."); + log_warn(LD_PROTOCOL, "Couldn't decrypt INTRODUCE2 hidden service cell."); return -1; } len = r; @@ -585,7 +626,8 @@ /* Version 2 INTRODUCE2 cell. */ int klen; extend_info = tor_malloc_zero(sizeof(extend_info_t)); - extend_info->addr = ntohl(get_uint32(buf+1)); + extend_info->family = AF_INET; + extend_info->addr4 = ntohl(get_uint32(buf+1)); extend_info->port = ntohs(get_uint16(buf+5)); memcpy(extend_info->identity_digest, buf+7, DIGEST_LEN); extend_info->nickname[0] = '$'; @@ -594,7 +636,7 @@ klen = ntohs(get_uint16(buf+7+DIGEST_LEN)); if ((int)len != 7+DIGEST_LEN+2+klen+20+128) { - log_warn(LD_PROTOCOL, "Bad length %u for version 2 INTRODUCE2 cell.", + log_warn(LD_PROTOCOL, "Bad length %u for version 2 INTRODUCE2 hidden service cell.", (int)len); reason = END_CIRC_REASON_TORPROTOCOL; goto err; @@ -602,7 +644,7 @@ extend_info->onion_key = crypto_pk_asn1_decode(buf+7+DIGEST_LEN+2, klen); if (!extend_info->onion_key) { log_warn(LD_PROTOCOL, - "Error decoding onion key in version 2 INTRODUCE2 cell."); + "Error decoding onion key in version 2 INTRODUCE2 hidden service cell."); reason = END_CIRC_REASON_TORPROTOCOL; goto err; } @@ -625,12 +667,12 @@ ptr=memchr(rp_nickname,0,nickname_field_len); if (!ptr || ptr == rp_nickname) { log_warn(LD_PROTOCOL, - "Couldn't find a nul-padded nickname in INTRODUCE2 cell."); + "Couldn't find a nul-padded nickname in INTRODUCE2 hidden service cell."); return -1; } if ((version == 0 && !is_legal_nickname(rp_nickname)) || (version == 1 && !is_legal_nickname_or_hexdigest(rp_nickname))) { - log_warn(LD_PROTOCOL, "Bad nickname in INTRODUCE2 cell."); + log_warn(LD_PROTOCOL, "Bad nickname in INTRODUCE2 hidden service cell."); return -1; } /* Okay, now we know that a nickname is at the start of the buffer. */ @@ -640,7 +682,7 @@ * any */ router = router_get_by_nickname(rp_nickname, 0); if (!router) { - log_info(LD_REND, "Couldn't find router %s named in introduce2 cell.", + log_info(LD_REND, "Couldn't find router %s named in introduce2 hidden service cell.", escaped_safe_str(rp_nickname)); /* XXXX Add a no-such-router reason? */ reason = END_CIRC_REASON_TORPROTOCOL; @@ -651,7 +693,7 @@ } if (len != REND_COOKIE_LEN+DH_KEY_LEN) { - log_warn(LD_PROTOCOL, "Bad length %u for INTRODUCE2 cell.", (int)len); + log_warn(LD_PROTOCOL, "Bad length %u for INTRODUCE2 hidden service cell.", (int)len); reason = END_CIRC_REASON_TORPROTOCOL; return -1; } @@ -663,13 +705,13 @@ dh = crypto_dh_new(); if (!dh || crypto_dh_generate_public(dh)<0) { log_warn(LD_BUG,"Internal error: couldn't build DH state " - "or generate public key."); + "or generate public key for hidden service."); reason = END_CIRC_REASON_INTERNAL; goto err; } if (crypto_dh_compute_secret(dh, ptr+REND_COOKIE_LEN, DH_KEY_LEN, keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) { - log_warn(LD_BUG, "Internal error: couldn't complete DH handshake"); + log_warn(LD_BUG, "Internal error: couldn't complete DH handshake for hidden service"); reason = END_CIRC_REASON_INTERNAL; goto err; } @@ -691,14 +733,14 @@ } if (!launched) { /* give up */ log_warn(LD_REND, "Giving up launching first hop of circuit to rendezvous " - "point %s for service %s.", + "point %s for hidden service %s.", escaped_safe_str(extend_info->nickname), serviceid); reason = END_CIRC_REASON_CONNECTFAILED; goto err; } log_info(LD_REND, "Accepted intro; launching circuit to %s " - "(cookie %s) for service %s.", + "(cookie %s) for hidden service %s.", escaped_safe_str(extend_info->nickname), hexcookie, serviceid); tor_assert(launched->build_state); /* Fill in the circuit's state. */ @@ -744,7 +786,7 @@ oldcirc->build_state->failure_count > MAX_REND_FAILURES || oldcirc->build_state->expiry_time < time(NULL)) { log_info(LD_REND, - "Attempt to build circuit to %s for rendezvous has failed " + "Attempt to build circuit to hidden service %s for rendezvous has failed " "too many times or expired; giving up.", oldcirc->build_state ? oldcirc->build_state->chosen_exit->nickname : "*unknown*"); @@ -755,18 +797,18 @@ tor_assert(oldstate); if (oldstate->pending_final_cpath == NULL) { - log_info(LD_REND,"Skipping relaunch of circ that failed on its first hop. " + log_info(LD_REND,"Skipping relaunch of circ that failed on its first hop for hidden service. " "Initiator will retry."); return; } - log_info(LD_REND,"Reattempting rendezvous circuit to '%s'", + log_info(LD_REND,"Reattempting rendezvous hidden service circuit to '%s'", oldstate->chosen_exit->nickname); newcirc = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND, 0, oldstate->chosen_exit, 0, 1, 1); if (!newcirc) { - log_warn(LD_REND,"Couldn't relaunch rendezvous circuit to '%s'.", + log_warn(LD_REND,"Couldn't relaunch rendezvous hidden service circuit to '%s'.", oldstate->chosen_exit->nickname); return; } @@ -796,7 +838,7 @@ origin_circuit_t *launched; log_info(LD_REND, - "Launching circuit to introduction point %s for service %s", + "Launching circuit to introduction point %s for hidden service %s", escaped_safe_str(nickname), service->service_id); rep_hist_note_used_internal(time(NULL), 1, 0); @@ -806,7 +848,7 @@ nickname, 1, 0, 1); if (!launched) { log_info(LD_REND, - "Can't launch circuit to establish introduction at %s.", + "Can't launch circuit to establish introduction for hidden service at %s.", escaped_safe_str(nickname)); return -1; } @@ -849,14 +891,14 @@ service = rend_service_get_by_pk_digest_and_version( circuit->rend_pk_digest, circuit->rend_desc_version); if (!service) { - log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %d.", + log_warn(LD_REND, "Unrecognized hidden service ID %s on introduction circuit %d.", serviceid, circuit->_base.n_circ_id); reason = END_CIRC_REASON_NOSUCHSERVICE; goto err; } log_info(LD_REND, - "Established circuit %d as introduction point for service %s", + "Established circuit %d as introduction point for hidden service %s", circuit->_base.n_circ_id, serviceid); /* If the introduction point will not be used in an unversioned @@ -879,7 +921,7 @@ note_crypto_pk_op(REND_SERVER); r = crypto_pk_private_sign_digest(intro_key, buf+len, buf, len); if (r<0) { - log_warn(LD_BUG, "Internal error: couldn't sign introduction request."); + log_warn(LD_BUG, "Internal error: couldn't sign introduction hidden service request."); reason = END_CIRC_REASON_INTERNAL; goto err; } @@ -889,7 +931,7 @@ RELAY_COMMAND_ESTABLISH_INTRO, buf, len, circuit->cpath->prev)<0) { log_info(LD_GENERAL, - "Couldn't send introduction request for service %s on circuit %d", + "Couldn't send introduction request for hidden service %s on circuit %d", serviceid, circuit->_base.n_circ_id); reason = END_CIRC_REASON_INTERNAL; goto err; @@ -914,13 +956,13 @@ if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) { log_warn(LD_PROTOCOL, - "received INTRO_ESTABLISHED cell on non-intro circuit."); + "received INTRO_ESTABLISHED cell on non-intro hidden service circuit."); goto err; } service = rend_service_get_by_pk_digest_and_version( circuit->rend_pk_digest, circuit->rend_desc_version); if (!service) { - log_warn(LD_REND, "Unknown service on introduction circuit %d.", + log_warn(LD_REND, "Unknown hidden service on introduction circuit %d.", circuit->_base.n_circ_id); goto err; } @@ -930,7 +972,7 @@ base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32 + 1, circuit->rend_pk_digest, REND_SERVICE_ID_LEN); log_info(LD_REND, - "Received INTRO_ESTABLISHED cell on circuit %d for service %s", + "Received INTRO_ESTABLISHED cell on circuit %d for hidden service %s", circuit->_base.n_circ_id, serviceid); return 0; @@ -964,13 +1006,13 @@ log_info(LD_REND, "Done building circuit %d to rendezvous with " - "cookie %s for service %s", + "cookie %s for hidden service %s", circuit->_base.n_circ_id, hexcookie, serviceid); service = rend_service_get_by_pk_digest_and_version( circuit->rend_pk_digest, circuit->rend_desc_version); if (!service) { - log_warn(LD_GENERAL, "Internal error: unrecognized service ID on " + log_warn(LD_GENERAL, "Internal error: unrecognized hidden service ID on " "introduction circuit."); reason = END_CIRC_REASON_INTERNAL; goto err; @@ -980,7 +1022,7 @@ memcpy(buf, circuit->rend_cookie, REND_COOKIE_LEN); if (crypto_dh_get_public(hop->dh_handshake_state, buf+REND_COOKIE_LEN, DH_KEY_LEN)<0) { - log_warn(LD_GENERAL,"Couldn't get DH public key."); + log_warn(LD_GENERAL,"Couldn't get DH public key for hidden service."); reason = END_CIRC_REASON_INTERNAL; goto err; } @@ -992,7 +1034,7 @@ RELAY_COMMAND_RENDEZVOUS1, buf, REND_COOKIE_LEN+DH_KEY_LEN+DIGEST_LEN, circuit->cpath->prev)<0) { - log_warn(LD_GENERAL, "Couldn't send RENDEZVOUS1 cell."); + log_warn(LD_GENERAL, "Couldn't send RENDEZVOUS1 cell for hidden service."); reason = END_CIRC_REASON_INTERNAL; goto err; } @@ -1078,7 +1120,7 @@ if (rend_encode_service_descriptor(service->desc, service->private_key, &desc, &desc_len)<0) { - log_warn(LD_BUG, "Internal error: couldn't encode service descriptor; " + log_warn(LD_BUG, "Internal error: couldn't encode hidden service descriptor; " "not uploading."); return; } @@ -1107,7 +1149,7 @@ seconds_valid = rend_encode_v2_descriptors(desc_strs, desc_ids, service->desc, now, NULL, 0); if (seconds_valid < 0) { - log_warn(LD_BUG, "Internal error: couldn't encode service descriptor; " + log_warn(LD_BUG, "Internal error: couldn't encode hidden service descriptor; " "not uploading."); return; } @@ -1138,8 +1180,8 @@ service->desc, now, NULL, 1); if (seconds_valid < 0) { - log_warn(LD_BUG, "Internal error: couldn't encode service " - "descriptor; not uploading."); + log_warn(LD_BUG, "Internal error: couldn't encode hidden service " + "descriptor for service %s; not uploading.", serviceid); return; } directory_post_to_hs_dir(desc_ids, desc_strs, serviceid, @@ -1153,7 +1195,7 @@ smartlist_free(desc_ids); } uploaded = 1; - log_info(LD_REND, "Successfully uploaded v2 rend descriptors!"); + log_info(LD_REND, "Successfully uploaded v2 rend hidden service descriptors for service %s!", serviceid); } } @@ -1242,7 +1284,7 @@ 0, 0); if (!router) { log_warn(LD_REND, - "Could only establish %d introduction points for %s.", + "Could only establish %d introduction points for hidden service %s.", smartlist_len(service->intro_nodes), service->service_id); break; } @@ -1255,7 +1297,7 @@ smartlist_add(intro_routers, router); smartlist_add(exclude_routers, router); smartlist_add(service->intro_nodes, hex_digest); - log_info(LD_REND, "Picked router %s as an intro point for %s.", + log_info(LD_REND, "Picked router %s as an intro point for hidden service %s.", router->nickname, service->service_id); } @@ -1271,7 +1313,7 @@ intro = smartlist_get(service->intro_nodes, j); r = rend_service_launch_establish_intro(service, intro); if (r<0) { - log_warn(LD_REND, "Error launching circuit to node %s for service %s.", + log_warn(LD_REND, "Error launching circuit to node %s for hidden service %s.", intro, service->service_id); } } @@ -1330,7 +1372,7 @@ for (i=0; i < smartlist_len(rend_service_list); ++i) { service = smartlist_get(rend_service_list, i); - log(severity, LD_GENERAL, "Service configured in \"%s\":", + log(severity, LD_GENERAL, "Hidden service configured in \"%s\":", service->directory); for (j=0; j < smartlist_len(service->intro_nodes); ++j) { nickname = smartlist_get(service->intro_nodes, j); @@ -1373,7 +1415,7 @@ rend_service_port_config_t *chosen_port; tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_S_REND_JOINED); - log_debug(LD_REND,"beginning to hunt for addr/port"); + log_debug(LD_REND,"beginning to hunt for addr/port for hidden ipv4 or ipv6 -service"); base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, circ->rend_pk_digest, REND_SERVICE_ID_LEN); service = rend_service_get_by_pk_digest_and_version(circ->rend_pk_digest, @@ -1394,11 +1436,25 @@ chosen_port = smartlist_choose(matching_ports); smartlist_free(matching_ports); if (chosen_port) { - conn->_base.addr = chosen_port->real_addr; + if (chosen_port->real_family == AF_INET6) { + conn->_base.addr6 = chosen_port->real_addr6; + + char addrbuf[42]; + struct in6_addr addr; + addr = conn->_base.addr6; + tor_inet_ntop(AF_INET6, &addr, addrbuf, sizeof(addrbuf)); + log_info(LD_REND, "rend_service_set_connection_addr_port() found virtual ipv6-port mapping exist for port %d on service %s on local ipv6 %s", + conn->_base.port, serviceid, addrbuf); + } else { + conn->_base.addr4 = chosen_port->real_addr4; + log_info(LD_REND, "rend_service_set_connection_addr_port() found virtual ipv4-port mapping exist for port %d on (ipv4) service %s", + conn->_base.port, serviceid); + } + conn->_base.socket_family = chosen_port->real_family; conn->_base.port = chosen_port->real_port; return 0; } - log_info(LD_REND, "No virtual port mapping exists for port %d on service %s", + log_info(LD_REND, "No virtual port mapping exists for port %d on hidden ipv4 or ipv6 - service %s", conn->_base.port,serviceid); return -1; } Index: or/routerlist.c =================================================================== --- or/routerlist.c (Revision 12621) +++ or/routerlist.c (Arbeitskopie) @@ -4496,7 +4496,7 @@ /* XXX020 make this louder once we have some v2hidservs */ log_info(LD_REND, "We don't have enough hidden service directories to " - "perform v2 rendezvous operations!"); + "perform v2 rendezvous operations! id=%s", id); return -1; } Index: or/connection_edge.c =================================================================== --- or/connection_edge.c (Revision 12621) +++ or/connection_edge.c (Arbeitskopie) @@ -204,7 +204,12 @@ payload[0] = reason; if (reason == END_STREAM_REASON_EXITPOLICY && !connection_edge_is_rendezvous_stream(conn)) { - set_uint32(payload+1, htonl(conn->_base.addr)); + if (conn->_base.socket_family == AF_INET6) { + log_warn(LD_BUG, + "ipv6 not supported in connection_edge_end for non-rendezvous-streams"); + return 0; + } + set_uint32(payload+1, htonl(conn->_base.addr4)); set_uint32(payload+5, htonl(dns_clip_ttl(conn->address_ttl))); payload_len += 8; } @@ -280,19 +285,28 @@ int connection_edge_finished_connecting(edge_connection_t *edge_conn) { - char valbuf[INET_NTOA_BUF_LEN]; connection_t *conn; - struct in_addr in; tor_assert(edge_conn); tor_assert(edge_conn->_base.type == CONN_TYPE_EXIT); conn = TO_CONN(edge_conn); tor_assert(conn->state == EXIT_CONN_STATE_CONNECTING); - in.s_addr = htonl(conn->addr); - tor_inet_ntoa(&in,valbuf,sizeof(valbuf)); - log_info(LD_EXIT,"Exit connection to %s:%u (%s) established.", - escaped_safe_str(conn->address),conn->port,safe_str(valbuf)); + if (conn->socket_family == AF_INET6) { + char addrbuf[42]; + struct in6_addr addr; + addr = conn->addr6; + tor_inet_ntop(AF_INET6, &addr, addrbuf, sizeof(addrbuf)); + log_info(LD_EXIT,"Exit connection to %s:%u (%s) established.", + escaped_safe_str(conn->address),conn->port,safe_str(addrbuf)); + } else { + char valbuf[INET_NTOA_BUF_LEN]; + struct in_addr in; + in.s_addr = htonl(conn->addr4); + tor_inet_ntoa(&in,valbuf,sizeof(valbuf)); + log_info(LD_EXIT,"Exit connection to %s:%u (%s) established.", + escaped_safe_str(conn->address),conn->port,safe_str(valbuf)); + } conn->state = EXIT_CONN_STATE_OPEN; connection_watch_events(conn, EV_READ); /* stop writing, continue reading */ @@ -305,8 +319,17 @@ RELAY_COMMAND_CONNECTED, NULL, 0) < 0) return 0; /* circuit is closed, don't continue */ } else { + if (conn->socket_family == AF_INET6) { + char addrbuf[42]; + struct in6_addr addr; + addr = conn->addr6; + tor_inet_ntop(AF_INET6, &addr, addrbuf, sizeof(addrbuf)); + log_info(LD_EXIT,"ipv6 not supported for exit connection to %s:%u (%s) that is not a rendezvous_stream.", + escaped_safe_str(conn->address),conn->port,safe_str(addrbuf)); + return -1; + } char connected_payload[8]; - set_uint32(connected_payload, htonl(conn->addr)); + set_uint32(connected_payload, htonl(conn->addr4)); set_uint32(connected_payload+4, htonl(dns_clip_ttl(edge_conn->address_ttl))); if (connection_edge_send_command(edge_conn, @@ -359,7 +382,7 @@ continue; conn = TO_EDGE_CONN(c); /* if it's an internal linked connection, don't yell its status. */ - severity = (!conn->_base.addr && !conn->_base.port) + severity = ((conn->_base.socket_family == AF_INET && !conn->_base.addr4) && !conn->_base.port) ? LOG_INFO : LOG_NOTICE; seconds_idle = now - conn->_base.timestamp_lastread; @@ -1991,7 +2014,7 @@ } conn->_base.address = tor_strdup("(Tor_internal)"); - conn->_base.addr = 0; + conn->_base.addr4 = 0; conn->_base.port = 0; if (connection_add(TO_CONN(conn)) < 0) { /* no space, forget it */ @@ -2371,8 +2394,11 @@ if (rh.command == RELAY_COMMAND_BEGIN_DIR) { tor_assert(or_circ); - if (or_circ->p_conn && or_circ->p_conn->_base.addr) - n_stream->_base.addr = or_circ->p_conn->_base.addr; + if (or_circ->p_conn && (or_circ->p_conn->_base.socket_family != AF_INET || or_circ->p_conn->_base.addr4)) { + n_stream->_base.socket_family = or_circ->p_conn->_base.socket_family; + n_stream->_base.addr4 = or_circ->p_conn->_base.addr4; + n_stream->_base.addr6 = or_circ->p_conn->_base.addr6; + } return connection_exit_connect_dir(n_stream); } @@ -2444,6 +2470,12 @@ return 0; } +/** compare the 2 given ipv6-addresses + * * + * * returns 0 if they are equal. + * */ +int compare_in6_addr(struct in6_addr a, struct in6_addr b); + /** Connect to conn's specified addr and port. If it worked, conn * has now been added to the connection_array. * @@ -2454,7 +2486,9 @@ void connection_exit_connect(edge_connection_t *edge_conn) { - uint32_t addr; + uint32_t addr4; + struct in6_addr addr6; + int addr_family = AF_INET; uint16_t port; connection_t *conn = TO_CONN(edge_conn); @@ -2468,19 +2502,33 @@ return; } - addr = conn->addr; port = conn->port; + if (conn->socket_family == AF_INET6) { + addr6 = conn->addr6; + addr_family = AF_INET6; + } else { + addr4 = conn->addr4; + } if (redirect_exit_list) { SMARTLIST_FOREACH(redirect_exit_list, exit_redirect_t *, r, - { - if (!addr_mask_cmp_bits(addr, r->addr, r->maskbits) && + {/* + if (!addr_mask_cmp_bits(addr, r->addr, r->maskbits) && + (r->port_min <= port) && (port <= r->port_max)) { + */ + if ( + (conn->socket_family == AF_INET/*r->family*/ && + ((conn->socket_family == AF_INET && !addr_mask_cmp_bits(addr4, r->addr, r->maskbits)) /*&& + (conn->socket_family == AF_INET6 && !compare_in6_addr(addr6, r->addr6))*/) + ) && (r->port_min <= port) && (port <= r->port_max)) { - struct in_addr in; + if (r->is_redirect) { char tmpbuf[INET_NTOA_BUF_LEN]; - addr = r->addr_dest; + addr_family = AF_INET; + addr4 = r->addr_dest; port = r->port_dest; - in.s_addr = htonl(addr); + struct in_addr in; + in.s_addr = htonl(addr4); tor_inet_ntoa(&in, tmpbuf, sizeof(tmpbuf)); log_debug(LD_EXIT, "Redirecting connection from %s:%d to %s:%d", escaped_safe_str(conn->address), conn->port, @@ -2492,7 +2540,13 @@ } log_debug(LD_EXIT,"about to try connecting"); - switch (connection_connect(conn, conn->address, addr, port)) { + int s = -1; + if (addr_family == AF_INET) { + s = connection_connect(conn, conn->address, addr4, port); + } else { + s = connection_connect6(conn, conn->address, addr6, port); + } + switch (s) { case -1: connection_edge_end_errno(edge_conn); circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn); @@ -2525,8 +2579,11 @@ NULL, 0); } else { /* normal stream */ /* This must be the original address, not the redirected address. */ + if (conn->socket_family == AF_INET6) { + log_warn(LD_BUG,"we do not support ipv6 in connection_exit_connect!"); + } char connected_payload[8]; - set_uint32(connected_payload, htonl(conn->addr)); + set_uint32(connected_payload, htonl(conn->addr4)); set_uint32(connected_payload+4, htonl(dns_clip_ttl(edge_conn->address_ttl))); connection_edge_send_command(edge_conn, @@ -2554,7 +2611,8 @@ dirconn = TO_DIR_CONN(connection_new(CONN_TYPE_DIR, AF_INET)); - dirconn->_base.addr = 0x7f000001; + dirconn->_base.socket_family = AF_INET; + dirconn->_base.addr4 = 0x7f000001; dirconn->_base.port = 0; dirconn->_base.address = tor_strdup("Tor network"); dirconn->_base.type = CONN_TYPE_DIR; Index: or/dns.c =================================================================== --- or/dns.c (Revision 12621) +++ or/dns.c (Arbeitskopie) @@ -413,7 +413,7 @@ { case RESOLVED_TYPE_IPV4: buf[1] = 4; - set_uint32(buf+2, htonl(conn->_base.addr)); + set_uint32(buf+2, htonl(conn->_base.addr4)); set_uint32(buf+6, htonl(ttl)); buflen = 10; break; @@ -627,7 +627,8 @@ /* first check if exitconn->_base.address is an IP. If so, we already * know the answer. */ if (tor_inet_aton(exitconn->_base.address, &in) != 0) { - exitconn->_base.addr = ntohl(in.s_addr); + exitconn->_base.socket_family = AF_INET; + exitconn->_base.addr4 = ntohl(in.s_addr); exitconn->address_ttl = DEFAULT_DNS_TTL; return 1; } @@ -694,7 +695,8 @@ tor_assert(is_resolve); *hostname_out = tor_strdup(resolve->result.hostname); } else { - exitconn->_base.addr = resolve->result.addr; + exitconn->_base.socket_family = AF_INET; + exitconn->_base.addr4 = resolve->result.addr; } return 1; case CACHE_STATE_CACHED_FAILED: @@ -1000,7 +1002,8 @@ pendconn = pend->conn; /* don't pass complex things to the connection_mark_for_close macro */ assert_connection_ok(TO_CONN(pendconn),time(NULL)); - pendconn->_base.addr = addr; + pendconn->_base.socket_family = AF_INET; + pendconn->_base.addr4 = addr; pendconn->address_ttl = ttl; if (outcome != DNS_RESOLVE_SUCCEEDED) { Index: or/or.h =================================================================== --- or/or.h (Revision 12621) +++ or/or.h (Arbeitskopie) @@ -851,8 +851,9 @@ int socket_family; /**< Address family of this connection's socket. Usually * AF_INET, but it can also be AF_UNIX, or in the future * AF_INET6 */ - uint32_t addr; /**< IP of the other side of the connection; used to identify + uint32_t addr4; /**< IP of the other side of the connection; used to identify * routers, along with port. */ + struct in6_addr addr6; uint16_t port; /**< If non-zero, port on the other end * of the connection. */ uint16_t marked_for_close; /**< Should we close this conn on the next @@ -913,7 +914,9 @@ * recent, we can rate limit it further. */ time_t client_used; - uint32_t real_addr; /**DOCDOC */ + int real_socket_family; /**< AF_INET or AF_INET6 */ + uint32_t real_addr4; /**< DOCDOC*/ + struct in6_addr real_addr6; circ_id_type_t circ_id_type:2; /**< When we send CREATE cells along this * connection, which half of the space should @@ -1576,8 +1579,10 @@ char nickname[MAX_HEX_NICKNAME_LEN+1]; /**< This router's nickname for * display. */ char identity_digest[DIGEST_LEN]; /**< Hash of this router's identity key. */ - uint16_t port; /**< OR port. */ - uint32_t addr; /**< IP address in host order. */ + uint16_t port; /**< OR port. */ + uint32_t addr4; /**< IPv4 address in host order. */ + struct in6_addr addr6; /**< IPv6 address. */ + u_int16_t family; /**< AF_INET6 or AF_INET */ crypto_pk_env_t *onion_key; /**< Current onionskin key. */ } extend_info_t; @@ -1737,7 +1742,11 @@ /** The port for the OR that is next in this circuit. */ uint16_t n_port; /** The IPv4 address of the OR that is next in this circuit. */ - uint32_t n_addr; + uint32_t n_addr4; + /** The IPv6 address of the OR that is next in this circuit. */ + struct in6_addr n_addr6; + /** AF_INET6 or AF_INET */ + u_int16_t n_family; /** True iff we are waiting for n_conn_cells to become less full before * allowing p_streams to add any more cells. (Origin circuit only.) */ @@ -2623,6 +2632,8 @@ int connection_connect(connection_t *conn, const char *address, uint32_t addr, uint16_t port); +int connection_connect6(connection_t *conn, const char *address, struct in6_addr addr, + uint16_t port); int retry_all_listeners(smartlist_t *replaced_conns, smartlist_t *new_conns); Index: or/connection.c =================================================================== --- or/connection.c (Revision 12621) +++ or/connection.c (Arbeitskopie) @@ -645,6 +645,44 @@ }); } +/** Create an AF_INET6 listenaddr struct. + * <b>listenaddress</b> provides the host and optionally the port information + * for the new structure. If no port is provided in <b>listenaddress</b> then + * <b>listenport</b> is used. + * + * If not NULL <b>readable_addrress</b> will contain a copy of the host part of + * <b>listenaddress</b>. + * + * The listenaddr struct has to be freed by the caller. + */ +static struct sockaddr_in6 * +create_inet6_sockaddr(const char *listenaddress, uint16_t listenport, + char **readable_address) { + struct sockaddr_in6 *listenaddr = NULL; + struct in6_addr addr6; + uint16_t usePort = 0; + + if (parse_addr6_port(LOG_WARN, + listenaddress, readable_address, &addr6, &usePort)<0) { + log_warn(LD_CONFIG, + "Error parsing/resolving ipv6 ListenAddress %s", listenaddress); + goto err; + } + if (usePort==0) + usePort = listenport; + + listenaddr = tor_malloc_zero(sizeof(struct sockaddr_in6)); + listenaddr->sin6_addr = addr6; + listenaddr->sin6_family = AF_INET; + listenaddr->sin6_port = htons((uint16_t) usePort); + + return listenaddr; + + err: + tor_free(listenaddr); + return NULL; +} + /** Create an AF_INET listenaddr struct. * <b>listenaddress</b> provides the host and optionally the port information * for the new structure. If no port is provided in <b>listenaddress</b> then @@ -747,7 +785,7 @@ return NULL; } - if (listensockaddr->sa_family == AF_INET) { + if (listensockaddr->sa_family == AF_INET6) { int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER); #ifndef MS_WINDOWS int one=1; @@ -756,6 +794,55 @@ start_reading = 1; usePort = ntohs( (uint16_t) + ((struct sockaddr_in6 *)listensockaddr)->sin6_port); + + log_notice(LD_NET, "Opening %s on ipv6 %s:%d", + conn_type_to_string(type), address, usePort); + + s = tor_open_socket(PF_INET6, + is_tcp ? SOCK_STREAM : SOCK_DGRAM, + is_tcp ? IPPROTO_TCP: IPPROTO_UDP); + if (s < 0) { + log_warn(LD_NET,"ipv6 socket creation failed."); + goto err; + } + +#ifndef MS_WINDOWS + /* REUSEADDR on normal places means you can rebind to the port + * right after somebody else has let it go. But REUSEADDR on win32 + * means you can bind to the port _even when somebody else + * already has it bound_. So, don't do that on Win32. */ + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*) &one, sizeof(one)); +#endif + + if (bind(s, listensockaddr, sizeof(struct sockaddr_in6)) < 0) { + const char *helpfulhint = ""; + int e = tor_socket_errno(s); + if (ERRNO_IS_EADDRINUSE(e)) + helpfulhint = ". Is Tor already running?"; + log_warn(LD_NET, "Could not bind to ipv6 %s:%u: %s%s", address, usePort, + tor_socket_strerror(e), helpfulhint); + tor_close_socket(s); + goto err; + } + + if (is_tcp) { + if (listen(s,SOMAXCONN) < 0) { + log_warn(LD_NET, "Could not listen on ipv6 %s:%u: %s", address, usePort, + tor_socket_strerror(tor_socket_errno(s))); + tor_close_socket(s); + goto err; + } + } + } else if (listensockaddr->sa_family == AF_INET) { + int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER); +#ifndef MS_WINDOWS + int one=1; +#endif + if (is_tcp) + start_reading = 1; + + usePort = ntohs( (uint16_t) ((struct sockaddr_in *)listensockaddr)->sin_port); log_notice(LD_NET, "Opening %s on %s:%d", @@ -877,23 +964,41 @@ check_sockaddr_in(struct sockaddr *sa, int len, int level) { int ok = 1; - struct sockaddr_in *sin=(struct sockaddr_in*)sa; - if (len != sizeof(struct sockaddr_in)) { - log_fn(level, LD_NET, "Length of address not as expected: %d vs %d", - len,(int)sizeof(struct sockaddr_in)); - ok = 0; - } - if (sa->sa_family != AF_INET) { + if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin=(struct sockaddr_in6*)sa; + + if (len != sizeof(struct sockaddr_in6)) { + log_fn(level, LD_NET, "Length of ipv6 address not as expected: %d vs %d", + len,(int)sizeof(struct sockaddr_in)); + ok = 0; + } + + if (sin->sin6_port == 0) { + log_fn(level, LD_NET, + "Address for new connection has port equal to zero."); + ok = 0; + } + } else if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin=(struct sockaddr_in*)sa; + + if (len != sizeof(struct sockaddr_in)) { + log_fn(level, LD_NET, "Length of ipv4 address not as expected: %d vs %d", + len,(int)sizeof(struct sockaddr_in)); + ok = 0; + } + + if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0) { + log_fn(level, LD_NET, + "Address for new connection has address/port equal to zero."); + ok = 0; + } + } else { log_fn(level, LD_NET, "Family of address not as expected: %d vs %d", sa->sa_family, AF_INET); ok = 0; } - if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0) { - log_fn(level, LD_NET, - "Address for new connection has address/port equal to zero."); - ok = 0; - } + return ok ? 0 : -1; } @@ -906,7 +1011,8 @@ int news; /* the new socket */ connection_t *newconn; /* information about the remote peer when connecting to other routers */ - struct sockaddr_in remote; + struct sockaddr_in remote4; + struct sockaddr_in6 remote6; char addrbuf[256]; /* length of the remote address. Must be whatever accept() needs. */ socklen_t remotelen = sizeof(addrbuf); @@ -916,7 +1022,7 @@ tor_assert((size_t)remotelen >= sizeof(struct sockaddr_in)); memset(addrbuf, 0, sizeof(addrbuf)); - news = accept(conn->s,(struct sockaddr *)&addrbuf,&remotelen); + news = accept(conn->s ,(struct sockaddr *)&addrbuf, &remotelen); if (news < 0) { /* accept() error */ int e = tor_socket_errno(conn->s); if (ERRNO_IS_ACCEPT_EAGAIN(e)) { @@ -953,7 +1059,7 @@ return 0; } - if (conn->socket_family == AF_INET) { + if (conn->socket_family == AF_INET || conn->socket_family == AF_INET6) { if (check_sockaddr_in((struct sockaddr*)addrbuf, remotelen, LOG_INFO)<0) { log_info(LD_NET, "accept() returned a strange address; trying getsockname()."); @@ -972,13 +1078,18 @@ } } } - memcpy(&remote, addrbuf, sizeof(struct sockaddr_in)); + if (conn->socket_family == AF_INET6) { + memcpy(&remote6, addrbuf, sizeof(struct sockaddr_in6)); + } else { + memcpy(&remote4, addrbuf, sizeof(struct sockaddr_in)); + } /* process entrance policies here, before we even create the connection */ if (new_type == CONN_TYPE_AP) { /* check sockspolicy to see if we should accept it */ - if (socks_policy_permits_address(ntohl(remote.sin_addr.s_addr)) == 0) { - tor_inet_ntoa(&remote.sin_addr, tmpbuf, sizeof(tmpbuf)); + //TODO: support ipv6 + if (conn->socket_family == AF_INET && socks_policy_permits_address(ntohl(remote4.sin_addr.s_addr)) == 0) { + tor_inet_ntoa(&remote4.sin_addr, tmpbuf, sizeof(tmpbuf)); log_notice(LD_APP, "Denying socks connection from untrusted address %s.", tmpbuf); @@ -988,8 +1099,9 @@ } if (new_type == CONN_TYPE_DIR) { /* check dirpolicy to see if we should accept it */ - if (dir_policy_permits_address(ntohl(remote.sin_addr.s_addr)) == 0) { - tor_inet_ntoa(&remote.sin_addr, tmpbuf, sizeof(tmpbuf)); + //TODO: support ipv6 + if (conn->socket_family == AF_INET && dir_policy_permits_address(ntohl(remote4.sin_addr.s_addr)) == 0) { + tor_inet_ntoa(&remote4.sin_addr, tmpbuf, sizeof(tmpbuf)); log_notice(LD_DIRSERV,"Denying dir connection from address %s.", tmpbuf); tor_close_socket(news); @@ -1001,9 +1113,16 @@ newconn->s = news; /* remember the remote address */ - newconn->addr = ntohl(remote.sin_addr.s_addr); - newconn->port = ntohs(remote.sin_port); - newconn->address = tor_dup_addr(newconn->addr); + if (conn->socket_family == AF_INET6) { + newconn->addr6 = remote6.sin6_addr; + newconn->port = ntohs(remote6.sin6_port); + newconn->address = tor_dup_addr6(newconn->addr6); + } else { + newconn->addr4 = remote4.sin_addr.s_addr; + newconn->port = ntohs(remote4.sin_port); + newconn->address = tor_dup_addr(newconn->addr4); + } + newconn->socket_family = conn->socket_family; } else if (conn->socket_family == AF_UNIX) { /* For now only control ports can be unix domain sockets @@ -1014,12 +1133,12 @@ newconn->s = news; /* remember the remote address -- do we have anything sane to put here? */ - newconn->addr = 0; + newconn->addr4 = 0; newconn->port = 1; newconn->address = tor_strdup(conn->address); } else { tor_assert(0); - }; + } if (connection_add(newconn) < 0) { /* no space, forget it */ connection_free(newconn); @@ -1161,6 +1280,96 @@ return inprogress ? 0 : 1; } +/** Take conn, make a nonblocking socket; try to connect to + * addr:port (they arrive in *host order*). If fail, return -1. Else + * assign s to conn-\>s: if connected return 1, if EAGAIN return 0. + * + * address is used to make the logs useful. + * + * On success, add conn to the list of polled connections. + */ +int +connection_connect6(connection_t *conn, const char *address, + struct in6_addr addr6, uint16_t port) +{ + int s, inprogress = 0; + struct sockaddr_in6 dest_addr6; + or_options_t *options = get_options(); + + if (get_n_open_sockets() >= get_options()->_ConnLimit-1) { + int n_conns = get_n_open_sockets(); + log_warn(LD_NET,"Failing because we have %d connections already. Please " + "raise your ulimit -n.", n_conns); + control_event_general_status(LOG_WARN, "TOO_MANY_CONNECTIONS CURRENT=%d", + n_conns); + return -1; + } + + s = tor_open_socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP); + if (s < 0) { + log_warn(LD_NET,"Error creating network socket: %s", + tor_socket_strerror(tor_socket_errno(-1))); + return -1; + } + + if (options->OutboundBindAddress) { + struct sockaddr_in6 ext_addr6; + + memset(&ext_addr6, 0, sizeof(ext_addr6)); + ext_addr6.sin6_family = AF_INET6; + ext_addr6.sin6_port = 0; + if (!tor_inet_aton6(options->OutboundBindAddress, &ext_addr6.sin6_addr)) { + log_warn(LD_CONFIG,"Outbound ipv6 bind address '%s' didn't parse. Ignoring.", + options->OutboundBindAddress); + } else { + if (bind(s, (struct sockaddr*)&ext_addr6, sizeof(ext_addr6)) < 0) { + log_warn(LD_NET,"Error binding network ipv6 socket: %s", + tor_socket_strerror(tor_socket_errno(s))); + tor_close_socket(s); + return -1; + } + } + } + + set_socket_nonblocking(s); + + if (options->ConstrainedSockets) + set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize); + + memset(&dest_addr6, 0, sizeof(dest_addr6)); + dest_addr6.sin6_family = AF_INET6; + dest_addr6.sin6_port = htons(port); + dest_addr6.sin6_addr = addr6; + + log_debug(LD_NET, "Connecting to ipv6 %s:%u.", escaped_safe_str(address), port); + + if (connect(s, (struct sockaddr *)&dest_addr6, sizeof(dest_addr6)) < 0) { + int e = tor_socket_errno(s); + if (!ERRNO_IS_CONN_EINPROGRESS(e)) { + /* yuck. kill it. */ + log_info(LD_NET, + "connect() to ipv6 %s:%u failed: %s", escaped_safe_str(address), + port, tor_socket_strerror(e)); + tor_close_socket(s); + return -1; + } else { + inprogress = 1; + } + } + + if (!server_mode(options)) + client_check_address_changed(s); + + /* it succeeded. we're connected. */ + log_fn(inprogress?LOG_DEBUG:LOG_INFO, LD_NET, + "Connection to ipv6 %s:%u %s (sock %d).", escaped_safe_str(address), + port, inprogress?"in progress":"established", s); + conn->s = s; + if (connection_add(conn) < 0) /* no space, forget it */ + return -1; + return inprogress ? 0 : 1; +} + /** * Launch any configured listener connections of type <b>type</b>. (A * listener is configured if <b>port_option</b> is non-zero. If any @@ -1190,7 +1399,7 @@ connection_t *conn; config_line_t *line; - tor_assert(socket_family == AF_INET || socket_family == AF_UNIX); + tor_assert(socket_family == AF_INET || socket_family == AF_INET6 || socket_family == AF_UNIX); if (cfg && port_option) { for (c = cfg; c; c = c->next) { @@ -1223,6 +1432,19 @@ char *address=NULL; uint16_t port; switch (socket_family) { + case AF_INET6: + if (!parse_addr6_port(LOG_WARN, + wanted->value, &address, NULL, &port)) { + int addr_matches = !strcasecmp(address, conn->address); + tor_free(address); + if (! port) + port = port_option; + if (port == conn->port && addr_matches) { + line = wanted; + break; + } + } + break; case AF_INET: if (!parse_addr_port(LOG_WARN, wanted->value, &address, NULL, &port)) { @@ -1275,6 +1497,12 @@ struct sockaddr *listensockaddr; switch (socket_family) { + case AF_INET6: + listensockaddr = (struct sockaddr *) + create_inet6_sockaddr(cfg_line->value, + (uint16_t) port_option, + &address); + break; case AF_INET: listensockaddr = (struct sockaddr *) create_inet_sockaddr(cfg_line->value, @@ -1342,7 +1570,12 @@ options->SocksPort, "127.0.0.1", replaced_conns, new_conns, 0, AF_INET)<0) - return -1; + // maybe the user deliberately configured an ipv6-address to listen on + if (retry_listeners(CONN_TYPE_AP_LISTENER, options->SocksListenAddress, + options->SocksPort, "::1", + replaced_conns, new_conns, 0, + AF_INET6)<0) + return -1; if (retry_listeners(CONN_TYPE_AP_TRANS_LISTENER, options->TransListenAddress, options->TransPort, "127.0.0.1", replaced_conns, new_conns, 0, @@ -1380,7 +1613,7 @@ static int connection_is_rate_limited(connection_t *conn) { - if (conn->linked || is_internal_IP(conn->addr, 0)) + if (conn->linked || (conn->socket_family == AF_INET && is_internal_IP(conn->addr4, 0))) return 0; else return 1; @@ -2328,7 +2561,8 @@ SMARTLIST_FOREACH(conns, connection_t *, conn, { if (conn->type == CONN_TYPE_OR && - conn->addr == addr && + conn->socket_family == AF_INET && + conn->addr4 == addr && conn->port == port && !conn->marked_for_close && (!best || best->_base.timestamp_created < conn->timestamp_created)) @@ -2348,7 +2582,8 @@ SMARTLIST_FOREACH(conns, connection_t *, conn, { if (conn->type == type && - conn->addr == addr && + conn->socket_family == AF_INET && + conn->addr4 == addr && conn->port == port && conn->purpose == purpose && !conn->marked_for_close) Index: or/rendcommon.c =================================================================== --- or/rendcommon.c (Revision 12621) +++ or/rendcommon.c (Arbeitskopie) @@ -227,7 +227,11 @@ goto done; } /* Assemble everything for this introduction point. */ - address = tor_dup_addr(info->addr); + if (info->family == AF_INET6) { + address = tor_dup_addr6(info->addr6); + } else { + address = tor_dup_addr(info->addr4); + } res = tor_snprintf(unenc + unenc_written, unenc_len - unenc_written, "introduction-point %s\n" "ip-address %s\n" @@ -760,8 +764,11 @@ { char key[REND_SERVICE_ID_LEN_BASE32+2]; /* <version><query>\0 */ tor_assert(rend_cache); - if (!rend_valid_service_id(query)) + if (!rend_valid_service_id(query)) { + log_warn(LD_REND, "hidden service descriptor '%s.onion' ID is not legal.", + query); return -1; + } *e = NULL; if (version != 0) { tor_snprintf(key, sizeof(key), "2%s", query); @@ -771,8 +778,13 @@ tor_snprintf(key, sizeof(key), "0%s", query); *e = strmap_get_lc(rend_cache, key); } - if (!*e) + if (!*e) { + log_warn(LD_REND, "no cached rend_cache_entry_t for hidden service '%s.onion' with version %i.", + query,version); return 0; + } + log_warn(LD_REND, "we have a cached rend_cache_entry_t for hidden service '%s.onion' with version %i.", + query, version); return 1; } Index: or/directory.c =================================================================== --- or/directory.c (Revision 12621) +++ or/directory.c (Arbeitskopie) @@ -478,7 +478,7 @@ routerinfo_t *me = router_get_my_routerinfo(); if (me && router_digest_is_me(conn->identity_digest) && - me->addr == conn->_base.addr && + me->addr == conn->_base.addr4 && //TODO: support directories on IPv6 me->dir_port == conn->_base.port) return 1; } @@ -644,7 +644,8 @@ conn = TO_DIR_CONN(connection_new(CONN_TYPE_DIR, AF_INET)); /* set up conn so it's got all the data we need to remember */ - conn->_base.addr = addr; + conn->_base.socket_family = AF_INET; + conn->_base.addr4 = addr; conn->_base.port = use_begindir ? or_port : dir_port; conn->_base.address = tor_strdup(address); memcpy(conn->identity_digest, digest, DIGEST_LEN); @@ -1940,7 +1941,7 @@ tor_snprintf(cp, sizeof(tmp)-(cp-tmp), "Content-Type: %s\r\n", type); cp += strlen(cp); } - if (!is_internal_IP(conn->_base.addr, 0)) { + if (conn->_base.socket_family == AF_INET && !is_internal_IP(conn->_base.addr4, 0)) { //TODO: support ipv6 /* Don't report the source address for a localhost/private connection. */ tor_snprintf(cp, sizeof(tmp)-(cp-tmp), X_ADDRESS_HEADER "%s\r\n", conn->_base.address); @@ -3121,7 +3122,7 @@ /* Determine responsible dirs. */ if (hid_serv_get_responsible_directories(responsible_dirs, desc_id) < 0) { log_warn(LD_REND, "Could not determine the responsible hidden service " - "directories to post descriptors to."); + "directories to post descriptors to. desc_id=%s", desc_id); smartlist_free(responsible_dirs); return; } @@ -3169,7 +3170,7 @@ if (hid_serv_get_responsible_directories(responsible_dirs, desc_id) < 0) { /* XXX020 make this louder once we have some v2hidservs */ log_info(LD_REND, "Could not determine the responsible hidden service " - "directories to fetch descriptors."); + "directories to fetch descriptors. desc_id=%s", desc_id); smartlist_free(responsible_dirs); return; } Index: or/routerparse.c =================================================================== --- or/routerparse.c (Revision 12621) +++ or/routerparse.c (Arbeitskopie) @@ -3454,7 +3454,8 @@ tor_free(info); goto err; } - info->addr = ntohl(ip.s_addr); + info->family = AF_INET; + info->addr4 = ntohl(ip.s_addr); /* Parse onion port. */ tok = find_first_by_keyword(tokens, R_IPO_ONION_PORT); info->port = (uint16_t) atoi(tok->args[0]); Index: or/command.c =================================================================== --- or/command.c (Revision 12621) +++ or/command.c (Arbeitskopie) @@ -560,7 +560,7 @@ } if (other_addr_type == RESOLVED_TYPE_IPV4 && other_addr_len == 4) { uint32_t addr = ntohl(get_uint32(cp)); - if (addr == conn->real_addr) { + if (conn->real_socket_family == AF_INET && addr == conn->real_addr4) { conn->handshake_state->apparently_canonical = 1; break; } Index: or/circuituse.c =================================================================== --- or/circuituse.c (Revision 12621) +++ or/circuituse.c (Arbeitskopie) @@ -1261,7 +1261,7 @@ conn_age = time(NULL) - conn->_base.timestamp_created; if (conn_age >= get_options()->SocksTimeout) { - int severity = (!conn->_base.addr && !conn->_base.port) ? + int severity = ((conn->_base.socket_family == AF_INET && !conn->_base.addr4) && !conn->_base.port) ? LOG_INFO : LOG_NOTICE; log_fn(severity, LD_APP, "Tried for %d seconds to get a connection to %s:%d. Giving up.", Index: or/test.c =================================================================== --- or/test.c (Revision 12621) +++ or/test.c (Arbeitskopie) @@ -3311,7 +3311,8 @@ info->nickname[0] = '$'; base16_encode(info->nickname + 1, sizeof(info->nickname) - 1, info->identity_digest, DIGEST_LEN); - info->addr = crypto_rand_int(65536); /* Does not cover all IP addresses. */ + info->family = AF_INET; + info->addr4 = crypto_rand_int(65536); /* Does not cover all IP addresses. */ info->port = crypto_rand_int(65536); generated->intro_points[i] = tor_strdup(info->nickname); generated->intro_point_extend_info[i] = info; @@ -3346,7 +3347,7 @@ DIGEST_LEN); test_streq(gen_info->nickname, par_info->nickname); test_streq(generated->intro_points[i], parsed->intro_points[i]); - test_eq(gen_info->addr, par_info->addr); + test_eq(gen_info->addr4, par_info->addr4); test_eq(gen_info->port, par_info->port); } tor_free(intro_points_encrypted); Index: or/router.c =================================================================== --- or/router.c (Revision 12621) +++ or/router.c (Arbeitskopie) @@ -1049,11 +1049,13 @@ /* make sure it's resolved to something. this way we can't get a 'maybe' below. */ - if (!conn->_base.addr) + if (conn->_base.socket_family == AF_INET && !conn->_base.addr4) return -1; - return compare_addr_to_addr_policy(conn->_base.addr, conn->_base.port, - desc_routerinfo->exit_policy) != ADDR_POLICY_ACCEPTED; + if (conn->_base.socket_family == AF_INET) + return compare_addr_to_addr_policy(conn->_base.addr4, conn->_base.port, + desc_routerinfo->exit_policy) != ADDR_POLICY_ACCEPTED; + return 0; //TODO: support an ipv6 exit-policy } /** Return true iff I'm a server and <b>digest</b> is equal to Index: or/cpuworker.c =================================================================== --- or/cpuworker.c (Revision 12621) +++ or/cpuworker.c (Arbeitskopie) @@ -468,7 +468,11 @@ log_info(LD_OR,"circ->p_conn gone. Failing circ."); return -1; } - tag_pack(tag, circ->p_conn->_base.addr, circ->p_conn->_base.port, + if (circ->p_conn->_base.socket_family == AF_INET6) { + log_info(LD_OR,"we do not support ipv6 in assign_to_cpuworker()."); + return -1; + } + tag_pack(tag, circ->p_conn->_base.addr4, circ->p_conn->_base.port, circ->p_circ_id); cpuworker->state = CPUWORKER_STATE_BUSY_ONION; Index: or/circuitbuild.c =================================================================== --- or/circuitbuild.c (Revision 12621) +++ or/circuitbuild.c (Arbeitskopie) @@ -350,7 +350,11 @@ tor_assert(firsthop->extend_info); /* now see if we're already connected to the first OR in 'route' */ - in.s_addr = htonl(firsthop->extend_info->addr); + if (firsthop->extend_info->family == AF_INET6) { + log_info(LD_CIRC,"we do not support Ipv6 for firsthop yet. Closing."); + return -END_CIRC_REASON_CONNECTFAILED; + } + in.s_addr = htonl(firsthop->extend_info->addr4); tor_inet_ntoa(&in, tmpbuf, sizeof(tmpbuf)); log_debug(LD_CIRC,"Looking for firsthop '%s:%u'",tmpbuf, firsthop->extend_info->port); @@ -367,11 +371,13 @@ router_digest_version_as_new_as(firsthop->extend_info->identity_digest, "0.1.1.9-alpha-cvs"))) { /* not currently connected */ - circ->_base.n_addr = firsthop->extend_info->addr; - circ->_base.n_port = firsthop->extend_info->port; + circ->_base.n_family = firsthop->extend_info->family; + circ->_base.n_addr4 = firsthop->extend_info->addr4; + circ->_base.n_addr6 = firsthop->extend_info->addr6; + circ->_base.n_port = firsthop->extend_info->port; if (!n_conn || n_conn->_base.or_is_obsolete) { /* launch the connection */ - n_conn = connection_or_connect(firsthop->extend_info->addr, + n_conn = connection_or_connect(firsthop->extend_info->addr4, firsthop->extend_info->port, firsthop->extend_info->identity_digest); if (!n_conn) { /* connect failed, forget the whole thing */ @@ -387,7 +393,9 @@ */ return 0; } else { /* it's already open. use it. */ - circ->_base.n_addr = n_conn->_base.addr; + circ->_base.n_addr6 = n_conn->_base.addr6; + circ->_base.n_addr4 = n_conn->_base.addr4; + circ->_base.n_family = n_conn->_base.socket_family; circ->_base.n_port = n_conn->_base.port; circ->_base.n_conn = n_conn; log_debug(LD_CIRC,"Conn open. Delivering first onion skin."); @@ -399,6 +407,19 @@ return 0; } +/** compare the 2 given ipv6-addresses + * + * returns 0 if they are equal. + */ +int compare_in6_addr(struct in6_addr a, struct in6_addr b) { + int i; + for (i=0; i<16; i++) { + if (a.s6_addr[i] != b.s6_addr[i]) + return 1; + } + return 0; +} + /** Find any circuits that are waiting on <b>or_conn</b> to become * open and get them to send their create cells forward. * @@ -426,7 +447,9 @@ continue; if (tor_digest_is_zero(circ->n_conn_id_digest)) { /* Look at addr/port. This is an unkeyed connection. */ - if (circ->n_addr != or_conn->_base.addr || + if (circ->n_family != or_conn->_base.socket_family || + (circ->n_family == AF_INET && circ->n_addr4 != or_conn->_base.addr4) || + (circ->n_family == AF_INET6 && compare_in6_addr(circ->n_addr6, or_conn->_base.addr6) != 0) || circ->n_port != or_conn->_base.port) continue; /* now teach circ the right identity_digest */ @@ -652,7 +675,12 @@ return 0; } - set_uint32(payload, htonl(hop->extend_info->addr)); + if (hop->extend_info->family == AF_INET6) { + log(LOG_NOTICE, LD_GENERAL, + "circuit_send_next_onion_skin() - we do not support ipv6 for next hops yet. Ignoring."); + return 0; + } + set_uint32(payload, htonl(hop->extend_info->addr4)); set_uint16(payload+4, htons(hop->extend_info->port)); onionskin = payload+2+4; @@ -733,7 +761,8 @@ return -1; } - circ->n_addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE)); + circ->n_family = AF_INET; + circ->n_addr4 = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE)); circ->n_port = ntohs(get_uint16(cell->payload+RELAY_HEADER_SIZE+4)); onionskin = cell->payload+RELAY_HEADER_SIZE+4+2; @@ -748,7 +777,11 @@ router_digest_version_as_new_as(id_digest,"0.1.1.9-alpha-cvs"))) { struct in_addr in; char tmpbuf[INET_NTOA_BUF_LEN]; - in.s_addr = htonl(circ->n_addr); + if (circ->n_family == AF_INET6) { + log_info(LD_CIRC|LD_OR, "Next router is on an ipv6-address. we do not support this yet."); + return 0; + } + in.s_addr = htonl(circ->n_addr4); tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf)); log_info(LD_CIRC|LD_OR,"Next router (%s:%d) not connected. Connecting.", tmpbuf, circ->n_port); @@ -761,11 +794,18 @@ memcpy(circ->n_conn_id_digest, id_digest, DIGEST_LEN); if (n_conn && !n_conn->_base.or_is_obsolete) { - circ->n_addr = n_conn->_base.addr; + circ->n_family = n_conn->_base.socket_family; + circ->n_addr4 = n_conn->_base.addr4; + circ->n_addr6 = n_conn->_base.addr6; circ->n_port = n_conn->_base.port; } else { /* we should try to open a connection */ - n_conn = connection_or_connect(circ->n_addr, circ->n_port, id_digest); + if (circ->n_family == AF_INET6) { + log_info(LD_CIRC,"Cannot launch n_conn because we do not support ipv6 between nodes yet. Closing circuit."); + circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED); + return 0; + } + n_conn = connection_or_connect(circ->n_addr4, circ->n_port, id_digest); if (!n_conn) { log_info(LD_CIRC,"Launching n_conn failed. Closing circuit."); circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED); @@ -781,7 +821,9 @@ } /* these may be different if the router connected to us from elsewhere */ - circ->n_addr = n_conn->_base.addr; + circ->n_family = n_conn->_base.socket_family; + circ->n_addr4 = n_conn->_base.addr4; + circ->n_addr6 = n_conn->_base.addr6; circ->n_port = n_conn->_base.port; circ->n_conn = n_conn; @@ -1008,7 +1050,16 @@ circ->p_conn, &cell, CELL_DIRECTION_IN); log_debug(LD_CIRC,"Finished sending 'created' cell."); - if (!is_local_IP(circ->p_conn->_base.addr) && + if (circ->p_conn->_base.socket_family == AF_INET6) { + log_debug(LD_CIRC,"not checking is_local_IP because we do not support ipv6 yet."); + if(connection_or_nonopen_was_started_here(circ->p_conn)) { + /* record that we could process create cells from a non-local conn + * that we didn't initiate; presumably this means that create cells + * can reach us too. */ + router_orport_found_reachable(); + } + } else + if (!is_local_IP(circ->p_conn->_base.addr4) && !connection_or_nonopen_was_started_here(circ->p_conn)) { /* record that we could process create cells from a non-local conn * that we didn't initiate; presumably this means that create cells @@ -1749,7 +1800,8 @@ strlcpy(info->nickname, nickname, sizeof(info->nickname)); if (onion_key) info->onion_key = crypto_pk_dup_key(onion_key); - info->addr = addr; + info->family = AF_INET; + info->addr4 = addr; info->port = port; return info; } Index: or/dnsserv.c =================================================================== --- or/dnsserv.c (Revision 12621) +++ or/dnsserv.c (Arbeitskopie) @@ -116,9 +116,10 @@ conn->_base.state = AP_CONN_STATE_RESOLVE_WAIT; conn->is_dns_request = 1; - TO_CONN(conn)->addr = ntohl(sin->sin_addr.s_addr); + TO_CONN(conn)->socket_family = AF_INET; + TO_CONN(conn)->addr4 = ntohl(sin->sin_addr.s_addr); TO_CONN(conn)->port = ntohs(sin->sin_port); - TO_CONN(conn)->address = tor_dup_addr(TO_CONN(conn)->addr); + TO_CONN(conn)->address = tor_dup_addr(TO_CONN(conn)->addr4); if (q->type == EVDNS_TYPE_A) conn->socks_request->command = SOCKS_COMMAND_RESOLVE; Index: or/rendclient.c =================================================================== --- or/rendclient.c (Revision 12621) +++ or/rendclient.c (Arbeitskopie) @@ -117,10 +117,14 @@ if (entry->parsed->protocols & (1<<2)) { /* version 2 format */ extend_info_t *extend_info = rendcirc->build_state->chosen_exit; + if (extend_info->family == AF_INET6) { + log_warn(LD_BUG, "we do not support ipv6 in rend_client_send_introduction"); + goto err; + } int klen; tmp[0] = 2; /* version 2 of the cell format */ /* nul pads */ - set_uint32(tmp+1, htonl(extend_info->addr)); + set_uint32(tmp+1, htonl(extend_info->addr4)); set_uint16(tmp+5, htons(extend_info->port)); memcpy(tmp+7, extend_info->identity_digest, DIGEST_LEN); klen = crypto_pk_asn1_encode(extend_info->onion_key, tmp+7+DIGEST_LEN+2, @@ -505,7 +509,7 @@ entry->parsed->n_intro_points > 0) { /* either this fetch worked, or it failed but there was a * valid entry from before which we should reuse */ - log_info(LD_REND,"Rend desc is usable. Launching circuits."); + log_info(LD_REND,"Rend desc for hidden service '%s.onion' is usable. Launching circuits.", safe_str(query)); conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT; /* restart their timeout values, so they get a fair shake at @@ -516,12 +520,12 @@ if (connection_ap_handshake_attach_circuit(conn) < 0) { /* it will never work */ - log_warn(LD_REND,"Rendezvous attempt failed. Closing."); + log_warn(LD_REND,"Rendezvous attempt for hidden service '%s.onion' failed. Closing.", safe_str(query)); connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH); } } else { /* 404, or fetch didn't get that far */ log_notice(LD_REND,"Closing stream for '%s.onion': hidden service is " - "unavailable (try again later).", safe_str(query)); + "unavailable (try again later). entry->parsed->n_intro_points=%i", safe_str(query), entry->parsed->n_intro_points); connection_mark_unattached_ap(conn, END_STREAM_REASON_RESOLVEFAILED); } }); Index: common/util.c =================================================================== --- common/util.c (Revision 12621) +++ common/util.c (Arbeitskopie) @@ -2223,13 +2223,13 @@ _address = tor_strndup(addrport, colon-addrport); _port = (int) tor_parse_long(colon+1,10,1,65535,NULL,NULL); if (!_port) { - log_fn(severity, LD_GENERAL, "Port %s out of range", escaped(colon+1)); + log_fn(severity, LD_GENERAL, "ipv4-Port %s out of range", escaped(colon+1)); ok = 0; } if (!port_out) { char *esc_addrport = esc_for_log(addrport); log_fn(severity, LD_GENERAL, - "Port %s given on %s when not required", + "ipv4-Port %s given on %s when not required", escaped(colon+1), esc_addrport); tor_free(esc_addrport); ok = 0; @@ -2241,8 +2241,8 @@ if (addr) { /* There's an addr pointer, so we need to resolve the hostname. */ - if (tor_lookup_hostname(_address,addr)) { - log_fn(severity, LD_NET, "Couldn't look up %s", escaped(_address)); + if (tor_lookup_hostname(_address, addr)) { + log_fn(severity, LD_NET, "Couldn't look up ipv4 %s", escaped(_address)); ok = 0; *addr = 0; } @@ -2260,7 +2260,81 @@ return ok ? 0 : -1; } +/** Parse a string of the form "[host]" and "[host]:port" from <b>addrport</b>. If + * <b>address</b> is provided, set *<b>address</b> to a copy of the + * host portion of the string. If <b>addr</b> is provided, try to + * resolve the host portion of the string and store it into + * *<b>addr</b>. If <b>port_out</b> is provided, + * store the port number into *<b>port_out</b>, or 0 if no port is given. + * If <b>port_out</b> is NULL, then there must be no port number in + * <b>addrport</b>. + * Return 0 on success, -1 on failure. + */ +int +parse_addr6_port(int severity, const char *addrport, char **address, + struct in6_addr *addr, uint16_t *port_out) +{ + const char *colon; + char *_address = NULL; + int _port; + int ok = 1; + tor_assert(addrport); + + colon = strstr(addrport, "]:"); + if (colon) { + _address = tor_strndup(addrport, colon - addrport); + _port = (int) tor_parse_long(colon + 2, 10, 1, 65535, NULL, NULL); + log_fn(severity, LD_NET, "DEBUG ipv6 incl [ and ] is: %s port is %i", escaped(_address), _port); + if (!_port) { + log_fn(severity, LD_GENERAL, "ipv6-Port %s out of range", escaped(colon+1)); + ok = 0; + } + if (!port_out) { + char *esc_addrport = esc_for_log(addrport); + log_fn(severity, LD_GENERAL, + "ipv6-Port %s given on %s when not required", + escaped(colon+1), esc_addrport); + tor_free(esc_addrport); + ok = 0; + } + } else { + _address = tor_strdup(addrport); + _port = 0; + log_fn(severity, LD_NET, "DEBUG ipv6 incl [ and ] is: %s port is default", escaped(_address)); + } + log_fn(severity, LD_NET, "DEBUG ipv6 incl [ and ] is: %s", escaped(_address)); + const char *end = strstr(_address, "]"); + if (end) + _address = tor_strndup(_address, end - _address); + log_fn(severity, LD_NET, "DEBUG ipv6 incl [ is: %s", escaped(_address)); + const char *start = strstr(_address, "["); + if (start) + _address = (char *) start + 1; + log_fn(severity, LD_NET, "DEBUG ipv6 without [ is: %s", escaped(_address)); + + if (addr) { + /* There's an addr pointer, so we need to resolve the hostname. */ + if (tor_lookup_hostname6(_address, addr)) { + log_fn(severity, LD_NET, "Couldn't look up ipv6 %s", escaped(_address)); + ok = 0; + //*addr = 0; + } + } + + if (address && ok) { + *address = _address; + } else { + if (address) + *address = NULL; +//TODO tor_free(_address); + } + if (port_out) + *port_out = ok ? ((uint16_t) _port) : 0; + + return ok ? 0 : -1; +} + /** If <b>mask</b> is an address mask for a bit-prefix, return the number of * bits. Otherwise, return -1. */ int @@ -2827,6 +2901,18 @@ * and return a strdup of the resulting address. */ char * +tor_dup_addr6(struct in6_addr addr) +{ + char buf[42]; + + tor_inet_ntop(AF_INET6, &addr, buf, sizeof(buf)); + return tor_strdup(buf); +} + +/** Given a host-order <b>addr</b>, call tor_inet_ntop() on it + * and return a strdup of the resulting address. + */ +char * tor_dup_addr(uint32_t addr) { char buf[TOR_ADDR_BUF_LEN]; Index: common/util.h =================================================================== --- common/util.h (Revision 12621) +++ common/util.h (Arbeitskopie) @@ -271,6 +271,8 @@ int is_internal_IP(uint32_t ip, int for_listening) ATTR_PURE; int parse_addr_port(int severity, const char *addrport, char **address, uint32_t *addr, uint16_t *port_out); +int parse_addr6_port(int severity, const char *addrport, char **address, + struct in6_addr *addr, uint16_t *port_out); int parse_port_range(const char *port, uint16_t *port_min_out, uint16_t *port_max_out); int parse_addr_and_port_range(const char *s, uint32_t *addr_out, @@ -280,6 +282,7 @@ int addr_mask_cmp_bits(uint32_t a1, uint32_t a2, maskbits_t bits); int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len); char *tor_dup_addr(uint32_t addr) ATTR_MALLOC; +char *tor_dup_addr6(struct in6_addr addr) ATTR_MALLOC; int get_interface_address(int severity, uint32_t *addr); int get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr); Index: common/compat.c =================================================================== --- common/compat.c (Revision 12621) +++ common/compat.c (Arbeitskopie) @@ -834,6 +834,16 @@ * but works on Windows and Solaris.) */ int +tor_inet_aton6(const char *c, struct in6_addr* addr) +{ + return tor_inet_pton(AF_INET6, c, addr); +} + +/** Set *addr to the IP address (in dotted-quad notation) stored in c. + * Return 1 on success, 0 if c is badly formatted. (Like inet_aton(c,addr), + * but works on Windows and Solaris.) + */ +int tor_inet_aton(const char *c, struct in_addr* addr) { #ifdef HAVE_INET_ATON @@ -1052,6 +1062,30 @@ * doesn't treat raw IP addresses properly.) */ int +tor_lookup_hostname6(const char *name, struct in6_addr *addr) +{ + tor_addr_t myaddr; + int ret; + + if ((ret = tor_addr_lookup(name, AF_INET6, &myaddr))) + return ret; + + if (IN_FAMILY(&myaddr) == AF_INET6) { + *addr = myaddr.sa6.sin6_addr; + return ret; + } + + return -1; +} + +/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set + * *<b>addr</b> to the proper IP address, in host byte order. Returns 0 + * on success, -1 on failure; 1 on transient failure. + * + * (This function exists because standard windows gethostbyname + * doesn't treat raw IP addresses properly.) + */ +int tor_lookup_hostname(const char *name, uint32_t *addr) { tor_addr_t myaddr; @@ -1086,7 +1120,7 @@ struct in6_addr iaddr6; tor_assert(name); tor_assert(addr); - tor_assert(family == AF_INET || family == AF_UNSPEC); + tor_assert(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC); memset(addr, 0, sizeof(addr)); /* Clear the extraneous fields. */ if (!*name) { /* Empty address is an error. */ Index: common/compat.h =================================================================== --- common/compat.h (Revision 12621) +++ common/compat.h (Arbeitskopie) @@ -389,9 +389,11 @@ #define TOR_ADDR_BUF_LEN 46 /* ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255 */ int tor_inet_aton(const char *cp, struct in_addr *addr) ATTR_NONNULL((1,2)); +int tor_inet_aton6(const char *cp, struct in6_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)); +int tor_lookup_hostname6(const char *name, struct in6_addr *addr) ATTR_NONNULL((1,2)); void set_socket_nonblocking(int socket); int tor_socketpair(int family, int type, int protocol, int fd[2]); int network_init(void);
Attachment:
signature.asc
Description: OpenPGP digital signature