Revert r13301 and part of r13304. I guess nick's svk messed up.
[tor.git] / src / or / rendclient.c
blobc8f6f43f04b38d0bc99cf3218a6d9018af2f340e
1 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
2 * Copyright (c) 2007, The Tor Project, Inc. */
3 /* See LICENSE for licensing information */
4 /* $Id$ */
5 const char rendclient_c_id[] =
6 "$Id$";
8 /**
9 * \file rendclient.c
10 * \brief Client code to access location-hidden services.
11 **/
13 #include "or.h"
15 /** Called when we've established a circuit to an introduction point:
16 * send the introduction request. */
17 void
18 rend_client_introcirc_has_opened(origin_circuit_t *circ)
20 tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
21 tor_assert(circ->cpath);
23 log_info(LD_REND,"introcirc is open");
24 connection_ap_attach_pending();
27 /** Send the establish-rendezvous cell along a rendezvous circuit. if
28 * it fails, mark the circ for close and return -1. else return 0.
30 static int
31 rend_client_send_establish_rendezvous(origin_circuit_t *circ)
33 tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
34 log_info(LD_REND, "Sending an ESTABLISH_RENDEZVOUS cell");
36 if (crypto_rand(circ->rend_cookie, REND_COOKIE_LEN) < 0) {
37 log_warn(LD_BUG, "Internal error: Couldn't produce random cookie.");
38 circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
39 return -1;
41 if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
42 RELAY_COMMAND_ESTABLISH_RENDEZVOUS,
43 circ->rend_cookie, REND_COOKIE_LEN,
44 circ->cpath->prev)<0) {
45 /* circ is already marked for close */
46 log_warn(LD_GENERAL, "Couldn't send ESTABLISH_RENDEZVOUS cell");
47 return -1;
50 return 0;
53 /** Called when we're trying to connect an ap conn; sends an INTRODUCE1 cell
54 * down introcirc if possible.
56 int
57 rend_client_send_introduction(origin_circuit_t *introcirc,
58 origin_circuit_t *rendcirc)
60 size_t payload_len;
61 int r;
62 char payload[RELAY_PAYLOAD_SIZE];
63 char tmp[RELAY_PAYLOAD_SIZE];
64 rend_cache_entry_t *entry;
65 crypt_path_t *cpath;
66 off_t dh_offset;
67 crypto_pk_env_t *intro_key; /* either Bob's public key or an intro key. */
69 tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
70 tor_assert(rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY);
71 tor_assert(!rend_cmp_service_ids(introcirc->rend_query,
72 rendcirc->rend_query));
74 if (rend_cache_lookup_entry(introcirc->rend_query, -1, &entry) < 1) {
75 log_warn(LD_REND,
76 "query %s didn't have valid rend desc in cache. Failing.",
77 escaped_safe_str(introcirc->rend_query));
78 goto err;
81 /* first 20 bytes of payload are the hash of bob's pk */
82 if (entry->parsed->version == 0) { /* unversioned descriptor */
83 intro_key = entry->parsed->pk;
84 } else { /* versioned descriptor */
85 intro_key = NULL;
86 SMARTLIST_FOREACH(entry->parsed->intro_nodes, rend_intro_point_t *,
87 intro, {
88 if (!memcmp(introcirc->build_state->chosen_exit->identity_digest,
89 intro->extend_info->identity_digest, DIGEST_LEN)) {
90 intro_key = intro->intro_key;
91 break;
93 });
94 if (!intro_key) {
95 log_warn(LD_BUG, "Internal error: could not find intro key.");
96 goto err;
99 if (crypto_pk_get_digest(intro_key, payload)<0) {
100 log_warn(LD_BUG, "Internal error: couldn't hash public key.");
101 goto err;
104 /* Initialize the pending_final_cpath and start the DH handshake. */
105 cpath = rendcirc->build_state->pending_final_cpath;
106 if (!cpath) {
107 cpath = rendcirc->build_state->pending_final_cpath =
108 tor_malloc_zero(sizeof(crypt_path_t));
109 cpath->magic = CRYPT_PATH_MAGIC;
110 if (!(cpath->dh_handshake_state = crypto_dh_new())) {
111 log_warn(LD_BUG, "Internal error: couldn't allocate DH.");
112 goto err;
114 if (crypto_dh_generate_public(cpath->dh_handshake_state)<0) {
115 log_warn(LD_BUG, "Internal error: couldn't generate g^x.");
116 goto err;
120 /* write the remaining items into tmp */
121 if (entry->parsed->protocols & (1<<2)) {
122 /* version 2 format */
123 extend_info_t *extend_info = rendcirc->build_state->chosen_exit;
124 int klen;
125 tmp[0] = 2; /* version 2 of the cell format */
126 /* nul pads */
127 set_uint32(tmp+1, htonl(extend_info->addr));
128 set_uint16(tmp+5, htons(extend_info->port));
129 memcpy(tmp+7, extend_info->identity_digest, DIGEST_LEN);
130 klen = crypto_pk_asn1_encode(extend_info->onion_key, tmp+7+DIGEST_LEN+2,
131 sizeof(tmp)-(7+DIGEST_LEN+2));
132 set_uint16(tmp+7+DIGEST_LEN, htons(klen));
133 memcpy(tmp+7+DIGEST_LEN+2+klen, rendcirc->rend_cookie,
134 REND_COOKIE_LEN);
135 dh_offset = 7+DIGEST_LEN+2+klen+REND_COOKIE_LEN;
136 } else {
137 /* Version 0. */
138 strncpy(tmp, rendcirc->build_state->chosen_exit->nickname,
139 (MAX_NICKNAME_LEN+1)); /* nul pads */
140 memcpy(tmp+MAX_NICKNAME_LEN+1, rendcirc->rend_cookie,
141 REND_COOKIE_LEN);
142 dh_offset = MAX_NICKNAME_LEN+1+REND_COOKIE_LEN;
145 if (crypto_dh_get_public(cpath->dh_handshake_state, tmp+dh_offset,
146 DH_KEY_LEN)<0) {
147 log_warn(LD_BUG, "Internal error: couldn't extract g^x.");
148 goto err;
151 note_crypto_pk_op(REND_CLIENT);
152 /*XXX maybe give crypto_pk_public_hybrid_encrypt a max_len arg,
153 * to avoid buffer overflows? */
154 r = crypto_pk_public_hybrid_encrypt(intro_key, payload+DIGEST_LEN,
155 tmp,
156 (int)(dh_offset+DH_KEY_LEN),
157 PK_PKCS1_OAEP_PADDING, 0);
158 if (r<0) {
159 log_warn(LD_BUG,"Internal error: hybrid pk encrypt failed.");
160 goto err;
163 payload_len = DIGEST_LEN + r;
164 tor_assert(payload_len <= RELAY_PAYLOAD_SIZE); /* we overran something */
166 log_info(LD_REND, "Sending an INTRODUCE1 cell");
167 if (relay_send_command_from_edge(0, TO_CIRCUIT(introcirc),
168 RELAY_COMMAND_INTRODUCE1,
169 payload, payload_len,
170 introcirc->cpath->prev)<0) {
171 /* introcirc is already marked for close. leave rendcirc alone. */
172 log_warn(LD_BUG, "Couldn't send INTRODUCE1 cell");
173 return -1;
176 /* Now, we wait for an ACK or NAK on this circuit. */
177 introcirc->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT;
179 return 0;
180 err:
181 circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_REASON_INTERNAL);
182 circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_REASON_INTERNAL);
183 return -1;
186 /** Called when a rendezvous circuit is open; sends a establish
187 * rendezvous circuit as appropriate. */
188 void
189 rend_client_rendcirc_has_opened(origin_circuit_t *circ)
191 tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
193 log_info(LD_REND,"rendcirc is open");
195 /* generate a rendezvous cookie, store it in circ */
196 if (rend_client_send_establish_rendezvous(circ) < 0) {
197 return;
201 /** Called when get an ACK or a NAK for a REND_INTRODUCE1 cell.
204 rend_client_introduction_acked(origin_circuit_t *circ,
205 const char *request, size_t request_len)
207 origin_circuit_t *rendcirc;
208 (void) request; // XXXX Use this.
210 if (circ->_base.purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
211 log_warn(LD_PROTOCOL,
212 "Received REND_INTRODUCE_ACK on unexpected circuit %d.",
213 circ->_base.n_circ_id);
214 circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
215 return -1;
218 tor_assert(circ->build_state->chosen_exit);
220 if (request_len == 0) {
221 /* It's an ACK; the introduction point relayed our introduction request. */
222 /* Locate the rend circ which is waiting to hear about this ack,
223 * and tell it.
225 log_info(LD_REND,"Received ack. Telling rend circ...");
226 rendcirc = circuit_get_by_rend_query_and_purpose(
227 circ->rend_query, CIRCUIT_PURPOSE_C_REND_READY);
228 if (rendcirc) { /* remember the ack */
229 rendcirc->_base.purpose = CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED;
230 } else {
231 log_info(LD_REND,"...Found no rend circ. Dropping on the floor.");
233 /* close the circuit: we won't need it anymore. */
234 circ->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACKED;
235 circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
236 } else {
237 /* It's a NAK; the introduction point didn't relay our request. */
238 circ->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
239 /* Remove this intro point from the set of viable introduction
240 * points. If any remain, extend to a new one and try again.
241 * If none remain, refetch the service descriptor.
243 if (rend_client_remove_intro_point(circ->build_state->chosen_exit,
244 circ->rend_query) > 0) {
245 /* There are introduction points left. Re-extend the circuit to
246 * another intro point and try again. */
247 extend_info_t *extend_info;
248 int result;
249 extend_info = rend_client_get_random_intro(circ->rend_query);
250 if (!extend_info) {
251 log_warn(LD_REND, "No introduction points left for %s. Closing.",
252 escaped_safe_str(circ->rend_query));
253 circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
254 return -1;
256 log_info(LD_REND,
257 "Got nack for %s from %s. Re-extending circ %d, "
258 "this time to %s.",
259 escaped_safe_str(circ->rend_query),
260 circ->build_state->chosen_exit->nickname, circ->_base.n_circ_id,
261 extend_info->nickname);
262 result = circuit_extend_to_new_exit(circ, extend_info);
263 extend_info_free(extend_info);
264 return result;
267 return 0;
270 /** The period for which a hidden service directory cannot be queried for
271 * the same descriptor ID again. */
272 #define REND_HID_SERV_DIR_REQUERY_PERIOD (15 * 60)
274 /** Contains the last request times to hidden service directories for
275 * certain queries; keys are strings consisting of base32-encoded
276 * hidden service directory identities and base32-encoded descriptor IDs;
277 * values are pointers to timestamps of the last requests. */
278 static strmap_t *last_hid_serv_requests = NULL;
280 /** Look up the last request time to hidden service directory <b>hs_dir</b>
281 * for descriptor ID <b>desc_id_base32</b>. If <b>set</b> is non-zero,
282 * assign the current time <b>now</b> and return that. Otherwise, return
283 * the most recent request time, or 0 if no such request has been sent
284 * before. */
285 static time_t
286 lookup_last_hid_serv_request(routerstatus_t *hs_dir,
287 const char *desc_id_base32, time_t now, int set)
289 char hsdir_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
290 char hsdir_desc_comb_id[2 * REND_DESC_ID_V2_LEN_BASE32 + 1];
291 time_t *last_request_ptr;
292 base32_encode(hsdir_id_base32, sizeof(hsdir_id_base32),
293 hs_dir->identity_digest, DIGEST_LEN);
294 tor_snprintf(hsdir_desc_comb_id, sizeof(hsdir_desc_comb_id), "%s%s",
295 hsdir_id_base32, desc_id_base32);
296 if (set) {
297 last_request_ptr = tor_malloc_zero(sizeof(time_t *));
298 *last_request_ptr = now;
299 strmap_set(last_hid_serv_requests, hsdir_desc_comb_id, last_request_ptr);
300 } else
301 last_request_ptr = strmap_get_lc(last_hid_serv_requests,
302 hsdir_desc_comb_id);
303 return (last_request_ptr) ? *last_request_ptr : 0;
306 /** Clean the history of request times to hidden service directories, so that
307 * it does not contain requests older than REND_HID_SERV_DIR_REQUERY_PERIOD
308 * seconds any more. */
309 static void
310 directory_clean_last_hid_serv_requests(void)
312 strmap_iter_t *iter;
313 time_t cutoff = time(NULL) - REND_HID_SERV_DIR_REQUERY_PERIOD;
314 if (!last_hid_serv_requests)
315 last_hid_serv_requests = strmap_new();
316 for (iter = strmap_iter_init(last_hid_serv_requests);
317 !strmap_iter_done(iter); ) {
318 const char *key;
319 void *val;
320 time_t *ent;
321 strmap_iter_get(iter, &key, &val);
322 ent = (time_t *) val;
323 if (*ent < cutoff) {
324 iter = strmap_iter_next_rmv(last_hid_serv_requests, iter);
325 tor_free(ent);
326 } else {
327 iter = strmap_iter_next(last_hid_serv_requests, iter);
332 /** Determine the responsible hidden service directories for <b>desc_id</b>
333 * and fetch the descriptor belonging to that ID from one of them. Only
334 * send a request to hidden service directories that we did not try within
335 * the last REND_HID_SERV_DIR_REQUERY_PERIOD seconds; on success, return 1,
336 * in the case that no hidden service directory is left to ask for the
337 * descriptor, return 0, and in case of a failure -1. <b>query</b> is only
338 * passed for pretty log statements. */
339 static int
340 directory_get_from_hs_dir(const char *desc_id, const char *query)
342 smartlist_t *responsible_dirs = smartlist_create();
343 routerstatus_t *hs_dir;
344 char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
345 time_t now = time(NULL);
346 tor_assert(desc_id);
347 tor_assert(query);
348 tor_assert(strlen(query) == REND_SERVICE_ID_LEN_BASE32);
349 /* Determine responsible dirs. Even if we can't get all we want,
350 * work with the ones we have. If it's empty, we'll notice below. */
351 (int) hid_serv_get_responsible_directories(responsible_dirs, desc_id);
353 base32_encode(desc_id_base32, sizeof(desc_id_base32),
354 desc_id, DIGEST_LEN);
356 /* Only select those hidden service directories to which we did not send
357 * a request recently. */
358 directory_clean_last_hid_serv_requests(); /* Clean request history first. */
360 SMARTLIST_FOREACH(responsible_dirs, routerstatus_t *, dir, {
361 if (lookup_last_hid_serv_request(dir, desc_id_base32, 0, 0) +
362 REND_HID_SERV_DIR_REQUERY_PERIOD >= now)
363 SMARTLIST_DEL_CURRENT(responsible_dirs, dir);
366 hs_dir = smartlist_choose(responsible_dirs);
367 smartlist_free(responsible_dirs);
368 if (!hs_dir) {
369 log_info(LD_REND, "Could not pick one of the responsible hidden "
370 "service directories, because we requested them all "
371 "recently without success.");
372 return 0;
375 /* Remember, that we are requesting a descriptor from this hidden service
376 * directory now. */
377 lookup_last_hid_serv_request(hs_dir, desc_id_base32, now, 1);
379 /* Send fetch request. (Pass query as payload to write it to the directory
380 * connection so that it can be referred to when the response arrives.) */
381 directory_initiate_command_routerstatus(hs_dir,
382 DIR_PURPOSE_FETCH_RENDDESC_V2,
383 ROUTER_PURPOSE_GENERAL,
384 1, desc_id_base32, query, 0, 0);
385 log_info(LD_REND, "Sending fetch request for v2 descriptor for "
386 "service '%s' with descriptor ID '%s' to hidden "
387 "service directory '%s' on port %d.",
388 query, desc_id_base32, hs_dir->nickname, hs_dir->dir_port);
389 return 1;
392 /** If we are not currently fetching a rendezvous service descriptor
393 * for the service ID <b>query</b>, start a directory connection to fetch a
394 * new one.
396 void
397 rend_client_refetch_renddesc(const char *query)
399 if (!get_options()->FetchHidServDescriptors)
400 return;
401 log_info(LD_REND, "Fetching rendezvous descriptor for service %s", query);
402 if (connection_get_by_type_state_rendquery(CONN_TYPE_DIR, 0, query)) {
403 log_info(LD_REND,"Would fetch a new renddesc here (for %s), but one is "
404 "already in progress.", escaped_safe_str(query));
405 } else {
406 /* not one already; initiate a dir rend desc lookup */
407 directory_get_from_dirserver(DIR_PURPOSE_FETCH_RENDDESC,
408 ROUTER_PURPOSE_GENERAL, query, 1);
412 /** Start a connection to a hidden service directory to fetch a v2
413 * rendezvous service descriptor for the base32-encoded service ID
414 * <b>query</b>.
416 void
417 rend_client_refetch_v2_renddesc(const char *query)
419 char descriptor_id[DIGEST_LEN];
420 int replicas_left_to_try[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS];
421 int i, tries_left;
422 tor_assert(query);
423 tor_assert(strlen(query) == REND_SERVICE_ID_LEN_BASE32);
424 /* Are we configured to fetch descriptors? */
425 if (!get_options()->FetchHidServDescriptors) {
426 log_warn(LD_REND, "We received an onion address for a v2 rendezvous "
427 "service descriptor, but are not fetching service descriptors.");
428 return;
430 log_debug(LD_REND, "Fetching v2 rendezvous descriptor for service %s",
431 query);
432 /* Randomly iterate over the replicas until a descriptor can be fetched
433 * from one of the consecutive nodes, or no options are left. */
434 tries_left = REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS;
435 for (i = 0; i < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; i++)
436 replicas_left_to_try[i] = i;
437 while (tries_left > 0) {
438 int rand = crypto_rand_int(tries_left);
439 int chosen_replica = replicas_left_to_try[rand];
440 replicas_left_to_try[rand] = replicas_left_to_try[--tries_left];
442 if (rend_compute_v2_desc_id(descriptor_id, query, NULL, time(NULL),
443 chosen_replica) < 0) {
444 log_warn(LD_REND, "Internal error: Computing v2 rendezvous "
445 "descriptor ID did not succeed.");
446 return;
448 if (directory_get_from_hs_dir(descriptor_id, query) != 0)
449 return; /* either success or failure, but we're done */
451 /* If we come here, there are no hidden service directories left. */
452 log_info(LD_REND, "Could not pick one of the responsible hidden "
453 "service directories to fetch descriptors, because "
454 "we already tried them all unsuccessfully.");
455 return;
458 /** Remove failed_intro from ent. If ent now has no intro points, or
459 * service is unrecognized, then launch a new renddesc fetch.
461 * Return -1 if error, 0 if no intro points remain or service
462 * unrecognized, 1 if recognized and some intro points remain.
465 rend_client_remove_intro_point(extend_info_t *failed_intro, const char *query)
467 int i, r;
468 rend_cache_entry_t *ent;
469 connection_t *conn;
471 r = rend_cache_lookup_entry(query, -1, &ent);
472 if (r<0) {
473 log_warn(LD_BUG, "Malformed service ID %s.", escaped_safe_str(query));
474 return -1;
476 if (r==0) {
477 log_info(LD_REND, "Unknown service %s. Re-fetching descriptor.",
478 escaped_safe_str(query));
479 /* Fetch both, v0 and v2 rend descriptors in parallel. Use whichever
480 * arrives first. */
481 rend_client_refetch_v2_renddesc(query);
482 rend_client_refetch_renddesc(query);
483 return 0;
486 for (i = 0; i < smartlist_len(ent->parsed->intro_nodes); i++) {
487 rend_intro_point_t *intro = smartlist_get(ent->parsed->intro_nodes, i);
488 if (!memcmp(failed_intro->identity_digest,
489 intro->extend_info->identity_digest, DIGEST_LEN)) {
490 rend_intro_point_free(intro);
491 smartlist_del(ent->parsed->intro_nodes, i);
492 break;
496 if (smartlist_len(ent->parsed->intro_nodes) == 0) {
497 log_info(LD_REND,
498 "No more intro points remain for %s. Re-fetching descriptor.",
499 escaped_safe_str(query));
500 /* Fetch both, v0 and v2 rend descriptors in parallel. Use whichever
501 * arrives first. */
502 rend_client_refetch_v2_renddesc(query);
503 rend_client_refetch_renddesc(query);
505 /* move all pending streams back to renddesc_wait */
506 while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP,
507 AP_CONN_STATE_CIRCUIT_WAIT, query))) {
508 conn->state = AP_CONN_STATE_RENDDESC_WAIT;
511 return 0;
513 log_info(LD_REND,"%d options left for %s.",
514 smartlist_len(ent->parsed->intro_nodes), escaped_safe_str(query));
515 return 1;
518 /** Called when we receive a RENDEZVOUS_ESTABLISHED cell; changes the state of
519 * the circuit to C_REND_READY.
522 rend_client_rendezvous_acked(origin_circuit_t *circ, const char *request,
523 size_t request_len)
525 (void) request;
526 (void) request_len;
527 /* we just got an ack for our establish-rendezvous. switch purposes. */
528 if (circ->_base.purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
529 log_warn(LD_PROTOCOL,"Got a rendezvous ack when we weren't expecting one. "
530 "Closing circ.");
531 circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
532 return -1;
534 log_info(LD_REND,"Got rendezvous ack. This circuit is now ready for "
535 "rendezvous.");
536 circ->_base.purpose = CIRCUIT_PURPOSE_C_REND_READY;
537 return 0;
540 /** Bob sent us a rendezvous cell; join the circuits. */
542 rend_client_receive_rendezvous(origin_circuit_t *circ, const char *request,
543 size_t request_len)
545 crypt_path_t *hop;
546 char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];
548 if ((circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY &&
549 circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
550 || !circ->build_state->pending_final_cpath) {
551 log_warn(LD_PROTOCOL,"Got rendezvous2 cell from hidden service, but not "
552 "expecting it. Closing.");
553 circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
554 return -1;
557 if (request_len != DH_KEY_LEN+DIGEST_LEN) {
558 log_warn(LD_PROTOCOL,"Incorrect length (%d) on RENDEZVOUS2 cell.",
559 (int)request_len);
560 goto err;
563 log_info(LD_REND,"Got RENDEZVOUS2 cell from hidden service.");
565 /* first DH_KEY_LEN bytes are g^y from bob. Finish the dh handshake...*/
566 tor_assert(circ->build_state);
567 tor_assert(circ->build_state->pending_final_cpath);
568 hop = circ->build_state->pending_final_cpath;
569 tor_assert(hop->dh_handshake_state);
570 if (crypto_dh_compute_secret(hop->dh_handshake_state, request, DH_KEY_LEN,
571 keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
572 log_warn(LD_GENERAL, "Couldn't complete DH handshake.");
573 goto err;
575 /* ... and set up cpath. */
576 if (circuit_init_cpath_crypto(hop, keys+DIGEST_LEN, 0)<0)
577 goto err;
579 /* Check whether the digest is right... */
580 if (memcmp(keys, request+DH_KEY_LEN, DIGEST_LEN)) {
581 log_warn(LD_PROTOCOL, "Incorrect digest of key material.");
582 goto err;
585 crypto_dh_free(hop->dh_handshake_state);
586 hop->dh_handshake_state = NULL;
588 /* All is well. Extend the circuit. */
589 circ->_base.purpose = CIRCUIT_PURPOSE_C_REND_JOINED;
590 hop->state = CPATH_STATE_OPEN;
591 /* set the windows to default. these are the windows
592 * that alice thinks bob has.
594 hop->package_window = CIRCWINDOW_START;
595 hop->deliver_window = CIRCWINDOW_START;
597 onion_append_to_cpath(&circ->cpath, hop);
598 circ->build_state->pending_final_cpath = NULL; /* prevent double-free */
599 return 0;
600 err:
601 circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
602 return -1;
605 /** Find all the apconns in state AP_CONN_STATE_RENDDESC_WAIT that
606 * are waiting on query. If there's a working cache entry here
607 * with at least one intro point, move them to the next state;
608 * else fail them.
610 void
611 rend_client_desc_here(const char *query)
613 edge_connection_t *conn;
614 rend_cache_entry_t *entry;
615 time_t now = time(NULL);
617 smartlist_t *conns = get_connection_array();
618 SMARTLIST_FOREACH(conns, connection_t *, _conn,
620 if (_conn->type != CONN_TYPE_AP ||
621 _conn->state != AP_CONN_STATE_RENDDESC_WAIT ||
622 _conn->marked_for_close)
623 continue;
624 conn = TO_EDGE_CONN(_conn);
625 if (rend_cmp_service_ids(query, conn->rend_query))
626 continue;
627 assert_connection_ok(TO_CONN(conn), now);
628 if (rend_cache_lookup_entry(conn->rend_query, -1, &entry) == 1 &&
629 smartlist_len(entry->parsed->intro_nodes) > 0) {
630 /* either this fetch worked, or it failed but there was a
631 * valid entry from before which we should reuse */
632 log_info(LD_REND,"Rend desc is usable. Launching circuits.");
633 conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
635 /* restart their timeout values, so they get a fair shake at
636 * connecting to the hidden service. */
637 conn->_base.timestamp_created = now;
638 conn->_base.timestamp_lastread = now;
639 conn->_base.timestamp_lastwritten = now;
641 if (connection_ap_handshake_attach_circuit(conn) < 0) {
642 /* it will never work */
643 log_warn(LD_REND,"Rendezvous attempt failed. Closing.");
644 connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
646 } else { /* 404, or fetch didn't get that far */
647 log_notice(LD_REND,"Closing stream for '%s.onion': hidden service is "
648 "unavailable (try again later).", safe_str(query));
649 connection_mark_unattached_ap(conn, END_STREAM_REASON_RESOLVEFAILED);
654 /** Return a newly allocated extend_info_t* for a randomly chosen introduction
655 * point for the named hidden service. Return NULL if all introduction points
656 * have been tried and failed.
658 extend_info_t *
659 rend_client_get_random_intro(const char *query)
661 int i;
662 rend_cache_entry_t *entry;
663 rend_intro_point_t *intro;
664 routerinfo_t *router;
666 if (rend_cache_lookup_entry(query, -1, &entry) < 1) {
667 log_warn(LD_REND,
668 "Query '%s' didn't have valid rend desc in cache. Failing.",
669 safe_str(query));
670 return NULL;
673 again:
674 if (smartlist_len(entry->parsed->intro_nodes) == 0)
675 return NULL;
677 i = crypto_rand_int(smartlist_len(entry->parsed->intro_nodes));
678 intro = smartlist_get(entry->parsed->intro_nodes, i);
679 /* Do we need to look up the router or is the extend info complete? */
680 if (!intro->extend_info->onion_key) {
681 router = router_get_by_nickname(intro->extend_info->nickname, 0);
682 if (!router) {
683 log_info(LD_REND, "Unknown router with nickname '%s'; trying another.",
684 intro->extend_info->nickname);
685 rend_intro_point_free(intro);
686 smartlist_del(entry->parsed->intro_nodes, i);
687 goto again;
689 extend_info_free(intro->extend_info);
690 intro->extend_info = extend_info_from_router(router);
692 return extend_info_dup(intro->extend_info);