Loading src/or/hs_cell.c +2 −3 Original line number Diff line number Diff line Loading @@ -363,7 +363,6 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, uint8_t *decrypted = NULL; size_t encrypted_section_len; const uint8_t *encrypted_section; curve25519_public_key_t client_pk; trn_cell_introduce1_t *cell = NULL; trn_cell_introduce_encrypted_t *enc_cell = NULL; hs_ntor_intro_cell_keys_t *intro_keys = NULL; Loading Loading @@ -404,7 +403,8 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, /* Build the key material out of the key material found in the cell. */ intro_keys = get_introduce2_key_material(data->auth_pk, data->enc_kp, data->subcredential, encrypted_section, &client_pk); encrypted_section, &data->client_pk); if (intro_keys == NULL) { log_info(LD_REND, "Invalid INTRODUCE2 encrypted data. Unable to " "compute key material on circuit %u for service %s", Loading Loading @@ -490,7 +490,6 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, log_info(LD_REND, "Valid INTRODUCE2 cell. Launching rendezvous circuit."); done: memwipe(&client_pk, 0, sizeof(client_pk)); if (intro_keys) { memwipe(intro_keys, 0, sizeof(hs_ntor_intro_cell_keys_t)); tor_free(intro_keys); Loading src/or/hs_circuit.c +257 −17 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ #include "circuitlist.h" #include "circuituse.h" #include "config.h" #include "policies.h" #include "relay.h" #include "rephist.h" #include "router.h" Loading @@ -22,6 +23,7 @@ #include "hs_service.h" /* Trunnel. */ #include "ed25519_cert.h" #include "hs/cell_common.h" #include "hs/cell_establish_intro.h" Loading Loading @@ -240,6 +242,46 @@ count_opened_desc_intro_point_circuits(const hs_service_t *service, return count; } /* From a given service, rendezvous cookie and handshake infor, create a * rendezvous point circuit identifier. This can't fail. */ static hs_ident_circuit_t * create_rp_circuit_identifier(const hs_service_t *service, const uint8_t *rendezvous_cookie, const curve25519_public_key_t *server_pk, const hs_ntor_rend_cell_keys_t *keys) { hs_ident_circuit_t *ident; uint8_t handshake_info[CURVE25519_PUBKEY_LEN + DIGEST256_LEN]; tor_assert(service); tor_assert(rendezvous_cookie); tor_assert(server_pk); tor_assert(keys); ident = hs_ident_circuit_new(&service->keys.identity_pk, HS_IDENT_CIRCUIT_RENDEZVOUS); /* Copy the RENDEZVOUS_COOKIE which is the unique identifier. */ memcpy(ident->rendezvous_cookie, rendezvous_cookie, sizeof(ident->rendezvous_cookie)); /* Build the HANDSHAKE_INFO which looks like this: * SERVER_PK [32 bytes] * AUTH_INPUT_MAC [32 bytes] */ memcpy(handshake_info, server_pk->public_key, CURVE25519_PUBKEY_LEN); memcpy(handshake_info + CURVE25519_PUBKEY_LEN, keys->rend_cell_auth_mac, DIGEST256_LEN); tor_assert(sizeof(ident->rendezvous_handshake_info) == sizeof(handshake_info)); memcpy(ident->rendezvous_handshake_info, handshake_info, sizeof(ident->rendezvous_handshake_info)); /* Finally copy the NTOR_KEY_SEED for e2e encryption on the circuit. */ tor_assert(sizeof(ident->rendezvous_ntor_key_seed) == sizeof(keys->ntor_key_seed)); memcpy(ident->rendezvous_ntor_key_seed, keys->ntor_key_seed, sizeof(ident->rendezvous_ntor_key_seed)); return ident; } /* From a given service and service intro point, create an introduction point * circuit identifier. This can't fail. */ static hs_ident_circuit_t * Loading Loading @@ -308,22 +350,225 @@ send_establish_intro(const hs_service_t *service, memwipe(payload, 0, sizeof(payload)); } /* ========== */ /* Public API */ /* ========== */ /* From a list of link specifier, an onion key and if we are requesting a * direct connection (ex: single onion service), return a newly allocated * extend_info_t object. This function checks the firewall policies and if we * are allowed to extend to the chosen address. * * if either IPv4 or legacy ID is missing, error. * if not direct_conn, IPv4 is prefered. * if direct_conn, IPv6 is prefered if we have one available. * if firewall does not allow the chosen address, error. * * Return NULL if we can fulfill the conditions. */ static extend_info_t * get_rp_extend_info(const smartlist_t *link_specifiers, const curve25519_public_key_t *onion_key, int direct_conn) { int have_v4 = 0, have_v6 = 0, have_legacy_id = 0, have_ed25519_id = 0; char legacy_id[DIGEST_LEN] = {0}; uint16_t port_v4 = 0, port_v6 = 0, port = 0; tor_addr_t addr_v4, addr_v6, *addr = NULL; ed25519_public_key_t ed25519_pk; extend_info_t *info = NULL; tor_assert(link_specifiers); tor_assert(onion_key); int hs_circ_launch_rendezvous_point(const hs_service_t *service, const curve25519_public_key_t *onion_key, const uint8_t *rendezvous_cookie) SMARTLIST_FOREACH_BEGIN(link_specifiers, const link_specifier_t *, ls) { switch (link_specifier_get_ls_type(ls)) { case LS_IPV4: /* Skip if we already seen a v4. */ if (have_v4) continue; tor_addr_from_ipv4h(&addr_v4, link_specifier_get_un_ipv4_addr(ls)); port_v4 = link_specifier_get_un_ipv4_port(ls); have_v4 = 1; break; case LS_IPV6: /* Skip if we already seen a v6. */ if (have_v6) continue; tor_addr_from_ipv6_bytes(&addr_v6, (const char *) link_specifier_getconstarray_un_ipv6_addr(ls)); port_v6 = link_specifier_get_un_ipv6_port(ls); have_v6 = 1; break; case LS_LEGACY_ID: /* Make sure we do have enough bytes for the legacy ID. */ if (link_specifier_getlen_un_legacy_id(ls) < sizeof(legacy_id)) { break; } memcpy(legacy_id, link_specifier_getconstarray_un_legacy_id(ls), sizeof(legacy_id)); have_legacy_id = 1; break; case LS_ED25519_ID: memcpy(ed25519_pk.pubkey, link_specifier_getconstarray_un_ed25519_id(ls), ED25519_PUBKEY_LEN); have_ed25519_id = 1; break; default: /* Ignore unknown. */ break; } } SMARTLIST_FOREACH_END(ls); /* IPv4, legacy ID and ed25519 are mandatory. */ if (!have_v4 || !have_legacy_id || !have_ed25519_id) { goto done; } /* By default, we pick IPv4 but this might change to v6 if certain * conditions are met. */ addr = &addr_v4; port = port_v4; /* If we are NOT in a direct connection, we'll use our Guard and a 3-hop * circuit so we can't extend in IPv6. And at this point, we do have an IPv4 * address available so go to validation. */ if (!direct_conn) { goto validate; } /* From this point on, we have a request for a direct connection to the * rendezvous point so make sure we can actually connect through our * firewall. We'll prefer IPv6. */ /* IPv6 test. */ if (have_v6 && fascist_firewall_allows_address_addr(&addr_v6, port_v6, FIREWALL_OR_CONNECTION, 1, 1)) { /* Direct connection and we can reach it in IPv6 so go for it. */ addr = &addr_v6; port = port_v6; goto validate; } /* IPv4 test and we are sure we have a v4 because of the check above. */ if (fascist_firewall_allows_address_addr(&addr_v4, port_v4, FIREWALL_OR_CONNECTION, 0, 0)) { /* Direct connection and we can reach it in IPv4 so go for it. */ addr = &addr_v4; port = port_v4; goto validate; } validate: /* We'll validate now that the address we've picked isn't a private one. If * it is, are we allowing to extend to private address? */ if (!extend_info_addr_is_allowed(addr)) { log_warn(LD_REND, "Rendezvous point address is private and it is not " "allowed to extend to it: %s:%u", fmt_addr(&addr_v4), port_v4); goto done; } /* We do have everything for which we think we can connect successfully. */ info = extend_info_new(NULL, legacy_id, &ed25519_pk, NULL, onion_key, addr, port); done: return info; } /* For a given service, the ntor onion key and a rendezvous cookie, launch a * circuit to the rendezvous point specified by the link specifiers. On * success, a circuit identifier is attached to the circuit with the needed * data. This function will try to open a circuit for a maximum value of * MAX_REND_FAILURES then it will give up. */ static void launch_rendezvous_point_circuit(const hs_service_t *service, const hs_service_intro_point_t *ip, const hs_cell_introduce2_data_t *data) { int circ_needs_uptime; time_t now = time(NULL); extend_info_t *info = NULL; origin_circuit_t *circ; tor_assert(service); tor_assert(onion_key); tor_assert(rendezvous_cookie); /* XXX: Implement rendezvous launch support. */ return 0; tor_assert(ip); tor_assert(data); circ_needs_uptime = hs_service_requires_uptime_circ(service->config.ports); /* Help predict this next time */ rep_hist_note_used_internal(now, circ_needs_uptime, 1); /* Get the extend info data structure for the chosen rendezvous point * specified by the given link specifiers. */ info = get_rp_extend_info(data->link_specifiers, &data->onion_pk, service->config.is_single_onion); if (info == NULL) { /* We are done here, we can't extend to the rendezvous point. */ goto end; } for (int i = 0; i < MAX_REND_FAILURES; i++) { int circ_flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL; if (circ_needs_uptime) { circ_flags |= CIRCLAUNCH_NEED_UPTIME; } /* Firewall and policies are checked when getting the extend info. */ if (service->config.is_single_onion) { circ_flags |= CIRCLAUNCH_ONEHOP_TUNNEL; } circ = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND, info, circ_flags); if (circ != NULL) { /* Stop retrying, we have a circuit! */ break; } } if (circ == NULL) { log_warn(LD_REND, "Giving up on launching rendezvous circuit to %s " "for service %s", safe_str_client(extend_info_describe(info)), safe_str_client(service->onion_address)); goto end; } log_info(LD_REND, "Rendezvous circuit launched to %s with cookie %s " "for service %s", safe_str_client(extend_info_describe(info)), safe_str_client(hex_str((const char *) data->rendezvous_cookie, REND_COOKIE_LEN)), safe_str_client(service->onion_address)); tor_assert(circ->build_state); /* Rendezvous circuit have a specific timeout for the time spent on trying * to connect to the rendezvous point. */ circ->build_state->expiry_time = now + MAX_REND_TIMEOUT; /* Create circuit identifier and key material. */ { hs_ntor_rend_cell_keys_t keys; curve25519_keypair_t ephemeral_kp; /* No need for extra strong, this is only for this circuit life time. This * key will be used for the RENDEZVOUS1 cell that will be sent on the * circuit once opened. */ curve25519_keypair_generate(&ephemeral_kp, 0); if (hs_ntor_service_get_rendezvous1_keys(&ip->auth_key_kp.pubkey, &ip->enc_key_kp, &ephemeral_kp, &data->client_pk, &keys) < 0) { /* This should not really happened but just in case, don't make tor * freak out, close the circuit and move on. */ log_info(LD_REND, "Unable to get RENDEZVOUS1 key material for " "service %s", safe_str_client(service->onion_address)); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); goto end; } circ->hs_ident = create_rp_circuit_identifier(service, data->rendezvous_cookie, &ephemeral_kp.pubkey, &keys); memwipe(&ephemeral_kp, 0, sizeof(ephemeral_kp)); memwipe(&keys, 0, sizeof(keys)); tor_assert(circ->hs_ident); } end: extend_info_free(info); } /* ========== */ /* Public API */ /* ========== */ /* For a given service and a service intro point, launch a circuit to the * extend info ei. If the service is a single onion, a one-hop circuit will be * requested. Return 0 if the circuit was successfully launched and tagged Loading Loading @@ -517,12 +762,7 @@ hs_circ_handle_introduce2(const hs_service_t *service, ip->introduce2_count++; /* Launch rendezvous circuit with the onion key and rend cookie. */ ret = hs_circ_launch_rendezvous_point(service, &data.onion_pk, data.rendezvous_cookie); if (ret < 0) { goto done; } launch_rendezvous_point_circuit(service, ip, &data); /* Success. */ ret = 0; Loading src/or/hs_common.c +16 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include "hs_common.h" #include "hs_service.h" #include "rendcommon.h" #include "rendservice.h" /* Ed25519 Basepoint value. Taken from section 5 of * https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03 */ Loading Loading @@ -724,7 +725,22 @@ hs_overlap_mode_is_active(const networkstatus_t *consensus, time_t now) if (valid_after_tm.tm_hour > 0 && valid_after_tm.tm_hour < 12) { return 1; } return 0; } /* Return 1 if any virtual port in ports needs a circuit with good uptime. * Else return 0. */ int hs_service_requires_uptime_circ(const smartlist_t *ports) { tor_assert(ports); SMARTLIST_FOREACH_BEGIN(ports, rend_service_port_config_t *, p) { if (smartlist_contains_int_as_string(get_options()->LongLivedPorts, p->virtual_port)) { return 1; } } SMARTLIST_FOREACH_END(p); return 0; } Loading src/or/hs_common.h +16 −0 Original line number Diff line number Diff line Loading @@ -107,6 +107,21 @@ typedef enum { HS_AUTH_KEY_TYPE_ED25519 = 2, } hs_auth_key_type_t; /* Represents the mapping from a virtual port of a rendezvous service to a * real port on some IP. */ typedef struct rend_service_port_config_t { /* The incoming HS virtual port we're mapping */ uint16_t virtual_port; /* Is this an AF_UNIX port? */ unsigned int is_unix_addr:1; /* The outgoing TCP port to use, if !is_unix_addr */ uint16_t real_port; /* The outgoing IPv4 or IPv6 address to use, if !is_unix_addr */ tor_addr_t real_addr; /* The socket path to connect to, if is_unix_addr */ char unix_addr[FLEXIBLE_ARRAY_MEMBER]; } rend_service_port_config_t; void hs_init(void); void hs_free_all(void); Loading @@ -128,6 +143,7 @@ void hs_build_blinded_keypair(const ed25519_keypair_t *kp, const uint8_t *secret, size_t secret_len, uint64_t time_period_num, ed25519_keypair_t *kp_out); int hs_service_requires_uptime_circ(const smartlist_t *ports); void rend_data_free(rend_data_t *data); rend_data_t *rend_data_dup(const rend_data_t *data); Loading src/or/rendservice.c +1 −35 Original line number Diff line number Diff line Loading @@ -83,22 +83,6 @@ static smartlist_t* rend_get_service_list_mutable( smartlist_t* substitute_service_list); static int rend_max_intro_circs_per_period(unsigned int n_intro_points_wanted); /** Represents the mapping from a virtual port of a rendezvous service to * a real port on some IP. */ struct rend_service_port_config_s { /* The incoming HS virtual port we're mapping */ uint16_t virtual_port; /* Is this an AF_UNIX port? */ unsigned int is_unix_addr:1; /* The outgoing TCP port to use, if !is_unix_addr */ uint16_t real_port; /* The outgoing IPv4 or IPv6 address to use, if !is_unix_addr */ tor_addr_t real_addr; /* The socket path to connect to, if is_unix_addr */ char unix_addr[FLEXIBLE_ARRAY_MEMBER]; }; /* Hidden service directory file names: * new file names should be added to rend_service_add_filenames_to_list() * for sandboxing purposes. */ Loading Loading @@ -1694,24 +1678,6 @@ rend_service_get_by_service_id(const char *id) return NULL; } /** Return 1 if any virtual port in <b>service</b> wants a circuit * to have good uptime. Else return 0. */ static int rend_service_requires_uptime(rend_service_t *service) { int i; rend_service_port_config_t *p; for (i=0; i < smartlist_len(service->ports); ++i) { p = smartlist_get(service->ports, i); if (smartlist_contains_int_as_string(get_options()->LongLivedPorts, p->virtual_port)) return 1; } return 0; } /** Check client authorization of a given <b>descriptor_cookie</b> of * length <b>cookie_len</b> for <b>service</b>. Return 1 for success * and 0 for failure. */ Loading Loading @@ -2029,7 +1995,7 @@ rend_service_receive_introduction(origin_circuit_t *circuit, goto err; } circ_needs_uptime = rend_service_requires_uptime(service); circ_needs_uptime = hs_service_requires_uptime_circ(service->ports); /* help predict this next time */ rep_hist_note_used_internal(now, circ_needs_uptime, 1); Loading Loading
src/or/hs_cell.c +2 −3 Original line number Diff line number Diff line Loading @@ -363,7 +363,6 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, uint8_t *decrypted = NULL; size_t encrypted_section_len; const uint8_t *encrypted_section; curve25519_public_key_t client_pk; trn_cell_introduce1_t *cell = NULL; trn_cell_introduce_encrypted_t *enc_cell = NULL; hs_ntor_intro_cell_keys_t *intro_keys = NULL; Loading Loading @@ -404,7 +403,8 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, /* Build the key material out of the key material found in the cell. */ intro_keys = get_introduce2_key_material(data->auth_pk, data->enc_kp, data->subcredential, encrypted_section, &client_pk); encrypted_section, &data->client_pk); if (intro_keys == NULL) { log_info(LD_REND, "Invalid INTRODUCE2 encrypted data. Unable to " "compute key material on circuit %u for service %s", Loading Loading @@ -490,7 +490,6 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, log_info(LD_REND, "Valid INTRODUCE2 cell. Launching rendezvous circuit."); done: memwipe(&client_pk, 0, sizeof(client_pk)); if (intro_keys) { memwipe(intro_keys, 0, sizeof(hs_ntor_intro_cell_keys_t)); tor_free(intro_keys); Loading
src/or/hs_circuit.c +257 −17 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ #include "circuitlist.h" #include "circuituse.h" #include "config.h" #include "policies.h" #include "relay.h" #include "rephist.h" #include "router.h" Loading @@ -22,6 +23,7 @@ #include "hs_service.h" /* Trunnel. */ #include "ed25519_cert.h" #include "hs/cell_common.h" #include "hs/cell_establish_intro.h" Loading Loading @@ -240,6 +242,46 @@ count_opened_desc_intro_point_circuits(const hs_service_t *service, return count; } /* From a given service, rendezvous cookie and handshake infor, create a * rendezvous point circuit identifier. This can't fail. */ static hs_ident_circuit_t * create_rp_circuit_identifier(const hs_service_t *service, const uint8_t *rendezvous_cookie, const curve25519_public_key_t *server_pk, const hs_ntor_rend_cell_keys_t *keys) { hs_ident_circuit_t *ident; uint8_t handshake_info[CURVE25519_PUBKEY_LEN + DIGEST256_LEN]; tor_assert(service); tor_assert(rendezvous_cookie); tor_assert(server_pk); tor_assert(keys); ident = hs_ident_circuit_new(&service->keys.identity_pk, HS_IDENT_CIRCUIT_RENDEZVOUS); /* Copy the RENDEZVOUS_COOKIE which is the unique identifier. */ memcpy(ident->rendezvous_cookie, rendezvous_cookie, sizeof(ident->rendezvous_cookie)); /* Build the HANDSHAKE_INFO which looks like this: * SERVER_PK [32 bytes] * AUTH_INPUT_MAC [32 bytes] */ memcpy(handshake_info, server_pk->public_key, CURVE25519_PUBKEY_LEN); memcpy(handshake_info + CURVE25519_PUBKEY_LEN, keys->rend_cell_auth_mac, DIGEST256_LEN); tor_assert(sizeof(ident->rendezvous_handshake_info) == sizeof(handshake_info)); memcpy(ident->rendezvous_handshake_info, handshake_info, sizeof(ident->rendezvous_handshake_info)); /* Finally copy the NTOR_KEY_SEED for e2e encryption on the circuit. */ tor_assert(sizeof(ident->rendezvous_ntor_key_seed) == sizeof(keys->ntor_key_seed)); memcpy(ident->rendezvous_ntor_key_seed, keys->ntor_key_seed, sizeof(ident->rendezvous_ntor_key_seed)); return ident; } /* From a given service and service intro point, create an introduction point * circuit identifier. This can't fail. */ static hs_ident_circuit_t * Loading Loading @@ -308,22 +350,225 @@ send_establish_intro(const hs_service_t *service, memwipe(payload, 0, sizeof(payload)); } /* ========== */ /* Public API */ /* ========== */ /* From a list of link specifier, an onion key and if we are requesting a * direct connection (ex: single onion service), return a newly allocated * extend_info_t object. This function checks the firewall policies and if we * are allowed to extend to the chosen address. * * if either IPv4 or legacy ID is missing, error. * if not direct_conn, IPv4 is prefered. * if direct_conn, IPv6 is prefered if we have one available. * if firewall does not allow the chosen address, error. * * Return NULL if we can fulfill the conditions. */ static extend_info_t * get_rp_extend_info(const smartlist_t *link_specifiers, const curve25519_public_key_t *onion_key, int direct_conn) { int have_v4 = 0, have_v6 = 0, have_legacy_id = 0, have_ed25519_id = 0; char legacy_id[DIGEST_LEN] = {0}; uint16_t port_v4 = 0, port_v6 = 0, port = 0; tor_addr_t addr_v4, addr_v6, *addr = NULL; ed25519_public_key_t ed25519_pk; extend_info_t *info = NULL; tor_assert(link_specifiers); tor_assert(onion_key); int hs_circ_launch_rendezvous_point(const hs_service_t *service, const curve25519_public_key_t *onion_key, const uint8_t *rendezvous_cookie) SMARTLIST_FOREACH_BEGIN(link_specifiers, const link_specifier_t *, ls) { switch (link_specifier_get_ls_type(ls)) { case LS_IPV4: /* Skip if we already seen a v4. */ if (have_v4) continue; tor_addr_from_ipv4h(&addr_v4, link_specifier_get_un_ipv4_addr(ls)); port_v4 = link_specifier_get_un_ipv4_port(ls); have_v4 = 1; break; case LS_IPV6: /* Skip if we already seen a v6. */ if (have_v6) continue; tor_addr_from_ipv6_bytes(&addr_v6, (const char *) link_specifier_getconstarray_un_ipv6_addr(ls)); port_v6 = link_specifier_get_un_ipv6_port(ls); have_v6 = 1; break; case LS_LEGACY_ID: /* Make sure we do have enough bytes for the legacy ID. */ if (link_specifier_getlen_un_legacy_id(ls) < sizeof(legacy_id)) { break; } memcpy(legacy_id, link_specifier_getconstarray_un_legacy_id(ls), sizeof(legacy_id)); have_legacy_id = 1; break; case LS_ED25519_ID: memcpy(ed25519_pk.pubkey, link_specifier_getconstarray_un_ed25519_id(ls), ED25519_PUBKEY_LEN); have_ed25519_id = 1; break; default: /* Ignore unknown. */ break; } } SMARTLIST_FOREACH_END(ls); /* IPv4, legacy ID and ed25519 are mandatory. */ if (!have_v4 || !have_legacy_id || !have_ed25519_id) { goto done; } /* By default, we pick IPv4 but this might change to v6 if certain * conditions are met. */ addr = &addr_v4; port = port_v4; /* If we are NOT in a direct connection, we'll use our Guard and a 3-hop * circuit so we can't extend in IPv6. And at this point, we do have an IPv4 * address available so go to validation. */ if (!direct_conn) { goto validate; } /* From this point on, we have a request for a direct connection to the * rendezvous point so make sure we can actually connect through our * firewall. We'll prefer IPv6. */ /* IPv6 test. */ if (have_v6 && fascist_firewall_allows_address_addr(&addr_v6, port_v6, FIREWALL_OR_CONNECTION, 1, 1)) { /* Direct connection and we can reach it in IPv6 so go for it. */ addr = &addr_v6; port = port_v6; goto validate; } /* IPv4 test and we are sure we have a v4 because of the check above. */ if (fascist_firewall_allows_address_addr(&addr_v4, port_v4, FIREWALL_OR_CONNECTION, 0, 0)) { /* Direct connection and we can reach it in IPv4 so go for it. */ addr = &addr_v4; port = port_v4; goto validate; } validate: /* We'll validate now that the address we've picked isn't a private one. If * it is, are we allowing to extend to private address? */ if (!extend_info_addr_is_allowed(addr)) { log_warn(LD_REND, "Rendezvous point address is private and it is not " "allowed to extend to it: %s:%u", fmt_addr(&addr_v4), port_v4); goto done; } /* We do have everything for which we think we can connect successfully. */ info = extend_info_new(NULL, legacy_id, &ed25519_pk, NULL, onion_key, addr, port); done: return info; } /* For a given service, the ntor onion key and a rendezvous cookie, launch a * circuit to the rendezvous point specified by the link specifiers. On * success, a circuit identifier is attached to the circuit with the needed * data. This function will try to open a circuit for a maximum value of * MAX_REND_FAILURES then it will give up. */ static void launch_rendezvous_point_circuit(const hs_service_t *service, const hs_service_intro_point_t *ip, const hs_cell_introduce2_data_t *data) { int circ_needs_uptime; time_t now = time(NULL); extend_info_t *info = NULL; origin_circuit_t *circ; tor_assert(service); tor_assert(onion_key); tor_assert(rendezvous_cookie); /* XXX: Implement rendezvous launch support. */ return 0; tor_assert(ip); tor_assert(data); circ_needs_uptime = hs_service_requires_uptime_circ(service->config.ports); /* Help predict this next time */ rep_hist_note_used_internal(now, circ_needs_uptime, 1); /* Get the extend info data structure for the chosen rendezvous point * specified by the given link specifiers. */ info = get_rp_extend_info(data->link_specifiers, &data->onion_pk, service->config.is_single_onion); if (info == NULL) { /* We are done here, we can't extend to the rendezvous point. */ goto end; } for (int i = 0; i < MAX_REND_FAILURES; i++) { int circ_flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL; if (circ_needs_uptime) { circ_flags |= CIRCLAUNCH_NEED_UPTIME; } /* Firewall and policies are checked when getting the extend info. */ if (service->config.is_single_onion) { circ_flags |= CIRCLAUNCH_ONEHOP_TUNNEL; } circ = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND, info, circ_flags); if (circ != NULL) { /* Stop retrying, we have a circuit! */ break; } } if (circ == NULL) { log_warn(LD_REND, "Giving up on launching rendezvous circuit to %s " "for service %s", safe_str_client(extend_info_describe(info)), safe_str_client(service->onion_address)); goto end; } log_info(LD_REND, "Rendezvous circuit launched to %s with cookie %s " "for service %s", safe_str_client(extend_info_describe(info)), safe_str_client(hex_str((const char *) data->rendezvous_cookie, REND_COOKIE_LEN)), safe_str_client(service->onion_address)); tor_assert(circ->build_state); /* Rendezvous circuit have a specific timeout for the time spent on trying * to connect to the rendezvous point. */ circ->build_state->expiry_time = now + MAX_REND_TIMEOUT; /* Create circuit identifier and key material. */ { hs_ntor_rend_cell_keys_t keys; curve25519_keypair_t ephemeral_kp; /* No need for extra strong, this is only for this circuit life time. This * key will be used for the RENDEZVOUS1 cell that will be sent on the * circuit once opened. */ curve25519_keypair_generate(&ephemeral_kp, 0); if (hs_ntor_service_get_rendezvous1_keys(&ip->auth_key_kp.pubkey, &ip->enc_key_kp, &ephemeral_kp, &data->client_pk, &keys) < 0) { /* This should not really happened but just in case, don't make tor * freak out, close the circuit and move on. */ log_info(LD_REND, "Unable to get RENDEZVOUS1 key material for " "service %s", safe_str_client(service->onion_address)); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); goto end; } circ->hs_ident = create_rp_circuit_identifier(service, data->rendezvous_cookie, &ephemeral_kp.pubkey, &keys); memwipe(&ephemeral_kp, 0, sizeof(ephemeral_kp)); memwipe(&keys, 0, sizeof(keys)); tor_assert(circ->hs_ident); } end: extend_info_free(info); } /* ========== */ /* Public API */ /* ========== */ /* For a given service and a service intro point, launch a circuit to the * extend info ei. If the service is a single onion, a one-hop circuit will be * requested. Return 0 if the circuit was successfully launched and tagged Loading Loading @@ -517,12 +762,7 @@ hs_circ_handle_introduce2(const hs_service_t *service, ip->introduce2_count++; /* Launch rendezvous circuit with the onion key and rend cookie. */ ret = hs_circ_launch_rendezvous_point(service, &data.onion_pk, data.rendezvous_cookie); if (ret < 0) { goto done; } launch_rendezvous_point_circuit(service, ip, &data); /* Success. */ ret = 0; Loading
src/or/hs_common.c +16 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include "hs_common.h" #include "hs_service.h" #include "rendcommon.h" #include "rendservice.h" /* Ed25519 Basepoint value. Taken from section 5 of * https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03 */ Loading Loading @@ -724,7 +725,22 @@ hs_overlap_mode_is_active(const networkstatus_t *consensus, time_t now) if (valid_after_tm.tm_hour > 0 && valid_after_tm.tm_hour < 12) { return 1; } return 0; } /* Return 1 if any virtual port in ports needs a circuit with good uptime. * Else return 0. */ int hs_service_requires_uptime_circ(const smartlist_t *ports) { tor_assert(ports); SMARTLIST_FOREACH_BEGIN(ports, rend_service_port_config_t *, p) { if (smartlist_contains_int_as_string(get_options()->LongLivedPorts, p->virtual_port)) { return 1; } } SMARTLIST_FOREACH_END(p); return 0; } Loading
src/or/hs_common.h +16 −0 Original line number Diff line number Diff line Loading @@ -107,6 +107,21 @@ typedef enum { HS_AUTH_KEY_TYPE_ED25519 = 2, } hs_auth_key_type_t; /* Represents the mapping from a virtual port of a rendezvous service to a * real port on some IP. */ typedef struct rend_service_port_config_t { /* The incoming HS virtual port we're mapping */ uint16_t virtual_port; /* Is this an AF_UNIX port? */ unsigned int is_unix_addr:1; /* The outgoing TCP port to use, if !is_unix_addr */ uint16_t real_port; /* The outgoing IPv4 or IPv6 address to use, if !is_unix_addr */ tor_addr_t real_addr; /* The socket path to connect to, if is_unix_addr */ char unix_addr[FLEXIBLE_ARRAY_MEMBER]; } rend_service_port_config_t; void hs_init(void); void hs_free_all(void); Loading @@ -128,6 +143,7 @@ void hs_build_blinded_keypair(const ed25519_keypair_t *kp, const uint8_t *secret, size_t secret_len, uint64_t time_period_num, ed25519_keypair_t *kp_out); int hs_service_requires_uptime_circ(const smartlist_t *ports); void rend_data_free(rend_data_t *data); rend_data_t *rend_data_dup(const rend_data_t *data); Loading
src/or/rendservice.c +1 −35 Original line number Diff line number Diff line Loading @@ -83,22 +83,6 @@ static smartlist_t* rend_get_service_list_mutable( smartlist_t* substitute_service_list); static int rend_max_intro_circs_per_period(unsigned int n_intro_points_wanted); /** Represents the mapping from a virtual port of a rendezvous service to * a real port on some IP. */ struct rend_service_port_config_s { /* The incoming HS virtual port we're mapping */ uint16_t virtual_port; /* Is this an AF_UNIX port? */ unsigned int is_unix_addr:1; /* The outgoing TCP port to use, if !is_unix_addr */ uint16_t real_port; /* The outgoing IPv4 or IPv6 address to use, if !is_unix_addr */ tor_addr_t real_addr; /* The socket path to connect to, if is_unix_addr */ char unix_addr[FLEXIBLE_ARRAY_MEMBER]; }; /* Hidden service directory file names: * new file names should be added to rend_service_add_filenames_to_list() * for sandboxing purposes. */ Loading Loading @@ -1694,24 +1678,6 @@ rend_service_get_by_service_id(const char *id) return NULL; } /** Return 1 if any virtual port in <b>service</b> wants a circuit * to have good uptime. Else return 0. */ static int rend_service_requires_uptime(rend_service_t *service) { int i; rend_service_port_config_t *p; for (i=0; i < smartlist_len(service->ports); ++i) { p = smartlist_get(service->ports, i); if (smartlist_contains_int_as_string(get_options()->LongLivedPorts, p->virtual_port)) return 1; } return 0; } /** Check client authorization of a given <b>descriptor_cookie</b> of * length <b>cookie_len</b> for <b>service</b>. Return 1 for success * and 0 for failure. */ Loading Loading @@ -2029,7 +1995,7 @@ rend_service_receive_introduction(origin_circuit_t *circuit, goto err; } circ_needs_uptime = rend_service_requires_uptime(service); circ_needs_uptime = hs_service_requires_uptime_circ(service->ports); /* help predict this next time */ rep_hist_note_used_internal(now, circ_needs_uptime, 1); Loading