r14602@catbus: nickm | 2007-08-16 13:33:27 -0400
[tor.git] / src / or / rendservice.c
blob3b509a0e4b0a49e12826539c107dadb1f5f4706e
1 /* Copyright 2004-2007 Roger Dingledine, Nick Mathewson. */
2 /* See LICENSE for licensing information */
3 /* $Id$ */
4 const char rendservice_c_id[] =
5 "$Id$";
7 /**
8 * \file rendservice.c
9 * \brief The hidden-service side of rendezvous functionality.
10 **/
12 #include "or.h"
14 static origin_circuit_t *find_intro_circuit(routerinfo_t *router,
15 const char *pk_digest);
17 /** Represents the mapping from a virtual port of a rendezvous service to
18 * a real port on some IP.
20 typedef struct rend_service_port_config_t {
21 uint16_t virtual_port;
22 uint16_t real_port;
23 uint32_t real_addr;
24 } rend_service_port_config_t;
26 /** Try to maintain this many intro points per service if possible. */
27 #define NUM_INTRO_POINTS 3
29 /** If we can't build our intro circuits, don't retry for this long. */
30 #define INTRO_CIRC_RETRY_PERIOD (60*5)
31 /** Don't try to build more than this many circuits before giving up
32 * for a while.*/
33 #define MAX_INTRO_CIRCS_PER_PERIOD 10
34 /** How many times will a hidden service operator attempt to connect to
35 * a requested rendezvous point before giving up? */
36 #define MAX_REND_FAILURES 30
37 /** How many seconds should we spend trying to connect to a requested
38 * rendezvous point before giving up? */
39 #define MAX_REND_TIMEOUT 30
41 /** Represents a single hidden service running at this OP. */
42 typedef struct rend_service_t {
43 /** Fields specified in config file */
44 char *directory; /**< where in the filesystem it stores it */
45 smartlist_t *ports; /**< List of rend_service_port_config_t */
46 char *intro_prefer_nodes; /**< comma-separated list of nicknames */
47 char *intro_exclude_nodes; /**< comma-separated list of nicknames */
48 /* Other fields */
49 crypto_pk_env_t *private_key;
50 char service_id[REND_SERVICE_ID_LEN+1];
51 char pk_digest[DIGEST_LEN];
52 smartlist_t *intro_nodes; /**< list of hexdigests for intro points we have,
53 * or are trying to establish. */
54 time_t intro_period_started;
55 int n_intro_circuits_launched; /**< count of intro circuits we have
56 * established in this period. */
57 rend_service_descriptor_t *desc;
58 time_t desc_is_dirty;
59 time_t next_upload_time;
60 } rend_service_t;
62 /** A list of rend_service_t's for services run on this OP.
64 static smartlist_t *rend_service_list = NULL;
66 /** Return the number of rendezvous services we have configured. */
67 int
68 num_rend_services(void)
70 if (!rend_service_list)
71 return 0;
72 return smartlist_len(rend_service_list);
75 /** Release the storage held by <b>service</b>.
77 static void
78 rend_service_free(rend_service_t *service)
80 if (!service) return;
81 tor_free(service->directory);
82 SMARTLIST_FOREACH(service->ports, void*, p, tor_free(p));
83 smartlist_free(service->ports);
84 if (service->private_key)
85 crypto_free_pk_env(service->private_key);
86 tor_free(service->intro_prefer_nodes);
87 tor_free(service->intro_exclude_nodes);
88 SMARTLIST_FOREACH(service->intro_nodes, void*, p, tor_free(p));
89 smartlist_free(service->intro_nodes);
90 if (service->desc)
91 rend_service_descriptor_free(service->desc);
92 tor_free(service);
95 /** Release all the storage held in rend_service_list.
97 void
98 rend_service_free_all(void)
100 if (!rend_service_list) {
101 return;
103 SMARTLIST_FOREACH(rend_service_list, rend_service_t*, ptr,
104 rend_service_free(ptr));
105 smartlist_free(rend_service_list);
106 rend_service_list = NULL;
109 /** Validate <b>service</b> and add it to rend_service_list if possible.
111 static void
112 add_service(rend_service_t *service)
114 int i;
115 rend_service_port_config_t *p;
116 struct in_addr addr;
118 if (!service->intro_prefer_nodes)
119 service->intro_prefer_nodes = tor_strdup("");
120 if (!service->intro_exclude_nodes)
121 service->intro_exclude_nodes = tor_strdup("");
123 if (!smartlist_len(service->ports)) {
124 log_warn(LD_CONFIG, "Hidden service with no ports configured; ignoring.");
125 rend_service_free(service);
126 } else {
127 smartlist_set_capacity(service->ports, -1);
128 smartlist_add(rend_service_list, service);
129 log_debug(LD_REND,"Configuring service with directory \"%s\"",
130 service->directory);
131 for (i = 0; i < smartlist_len(service->ports); ++i) {
132 char addrbuf[INET_NTOA_BUF_LEN];
133 p = smartlist_get(service->ports, i);
134 addr.s_addr = htonl(p->real_addr);
135 tor_inet_ntoa(&addr, addrbuf, sizeof(addrbuf));
136 log_debug(LD_REND,"Service maps port %d to %s:%d",
137 p->virtual_port, addrbuf, p->real_port);
142 /** Parses a real-port to virtual-port mapping and returns a new
143 * rend_service_port_config_t.
145 * The format is: VirtualPort (IP|RealPort|IP:RealPort)?
147 * IP defaults to 127.0.0.1; RealPort defaults to VirtualPort.
149 static rend_service_port_config_t *
150 parse_port_config(const char *string)
152 smartlist_t *sl;
153 int virtport;
154 int realport;
155 uint16_t p;
156 uint32_t addr;
157 const char *addrport;
158 rend_service_port_config_t *result = NULL;
160 sl = smartlist_create();
161 smartlist_split_string(sl, string, " ",
162 SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
163 if (smartlist_len(sl) < 1 || smartlist_len(sl) > 2) {
164 log_warn(LD_CONFIG, "Bad syntax in hidden service port configuration.");
165 goto err;
168 virtport = atoi(smartlist_get(sl,0));
169 if (virtport < 1 || virtport > 65535) {
170 log_warn(LD_CONFIG, "Missing or invalid port in hidden service port "
171 "configuration.");
172 goto err;
175 if (smartlist_len(sl) == 1) {
176 /* No addr:port part; use default. */
177 realport = virtport;
178 addr = 0x7F000001u; /* 127.0.0.1 */
179 } else {
180 addrport = smartlist_get(sl,1);
181 if (strchr(addrport, ':') || strchr(addrport, '.')) {
182 if (parse_addr_port(LOG_WARN, addrport, NULL, &addr, &p)<0) {
183 log_warn(LD_CONFIG,"Unparseable address in hidden service port "
184 "configuration.");
185 goto err;
187 realport = p?p:virtport;
188 } else {
189 /* No addr:port, no addr -- must be port. */
190 realport = atoi(addrport);
191 if (realport < 1 || realport > 65535)
192 goto err;
193 addr = 0x7F000001u; /* Default to 127.0.0.1 */
197 result = tor_malloc(sizeof(rend_service_port_config_t));
198 result->virtual_port = virtport;
199 result->real_port = realport;
200 result->real_addr = addr;
201 err:
202 SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
203 smartlist_free(sl);
204 return result;
207 /** Set up rend_service_list, based on the values of HiddenServiceDir and
208 * HiddenServicePort in <b>options</b>. Return 0 on success and -1 on
209 * failure. (If <b>validate_only</b> is set, parse, warn and return as
210 * normal, but don't actually change the configured services.)
213 rend_config_services(or_options_t *options, int validate_only)
215 config_line_t *line;
216 rend_service_t *service = NULL;
217 rend_service_port_config_t *portcfg;
219 if (!validate_only) {
220 rend_service_free_all();
221 rend_service_list = smartlist_create();
224 for (line = options->RendConfigLines; line; line = line->next) {
225 if (!strcasecmp(line->key, "HiddenServiceDir")) {
226 if (service) {
227 if (validate_only)
228 rend_service_free(service);
229 else
230 add_service(service);
232 service = tor_malloc_zero(sizeof(rend_service_t));
233 service->directory = tor_strdup(line->value);
234 service->ports = smartlist_create();
235 service->intro_nodes = smartlist_create();
236 service->intro_period_started = time(NULL);
237 continue;
239 if (!service) {
240 log_warn(LD_CONFIG, "%s with no preceding HiddenServiceDir directive",
241 line->key);
242 rend_service_free(service);
243 return -1;
245 if (!strcasecmp(line->key, "HiddenServicePort")) {
246 portcfg = parse_port_config(line->value);
247 if (!portcfg) {
248 rend_service_free(service);
249 return -1;
251 smartlist_add(service->ports, portcfg);
252 } else if (!strcasecmp(line->key, "HiddenServiceNodes")) {
253 if (service->intro_prefer_nodes) {
254 log_warn(LD_CONFIG,
255 "Got multiple HiddenServiceNodes lines for a single "
256 "service.");
257 return -1;
259 service->intro_prefer_nodes = tor_strdup(line->value);
260 } else {
261 tor_assert(!strcasecmp(line->key, "HiddenServiceExcludeNodes"));
262 if (service->intro_exclude_nodes) {
263 log_warn(LD_CONFIG,
264 "Got multiple HiddenServiceExcludedNodes lines for "
265 "a single service.");
266 return -1;
268 service->intro_exclude_nodes = tor_strdup(line->value);
271 if (service) {
272 if (validate_only)
273 rend_service_free(service);
274 else
275 add_service(service);
278 return 0;
281 /** Replace the old value of <b>service</b>-\>desc with one that reflects
282 * the other fields in service.
284 static void
285 rend_service_update_descriptor(rend_service_t *service)
287 rend_service_descriptor_t *d;
288 origin_circuit_t *circ;
289 int i,n;
290 routerinfo_t *router;
292 if (service->desc) {
293 rend_service_descriptor_free(service->desc);
294 service->desc = NULL;
296 d = service->desc = tor_malloc(sizeof(rend_service_descriptor_t));
297 d->pk = crypto_pk_dup_key(service->private_key);
298 d->timestamp = time(NULL);
299 d->version = 1;
300 n = smartlist_len(service->intro_nodes);
301 d->n_intro_points = 0;
302 d->intro_points = tor_malloc_zero(sizeof(char*)*n);
303 d->intro_point_extend_info = tor_malloc_zero(sizeof(extend_info_t*)*n);
304 d->protocols = (1<<2) | (1<<0); /* We support protocol 2 and protocol 0. */
305 for (i=0; i < n; ++i) {
306 router = router_get_by_nickname(smartlist_get(service->intro_nodes, i),1);
307 if (!router) {
308 log_info(LD_REND,"Router '%s' not found for intro point %d. Skipping.",
309 safe_str((char*)smartlist_get(service->intro_nodes, i)), i);
310 continue;
312 circ = find_intro_circuit(router, service->pk_digest);
313 if (circ && circ->_base.purpose == CIRCUIT_PURPOSE_S_INTRO) {
314 /* We have an entirely established intro circuit. */
315 d->intro_points[d->n_intro_points] = tor_strdup(router->nickname);
316 d->intro_point_extend_info[d->n_intro_points] =
317 extend_info_from_router(router);
318 d->n_intro_points++;
323 /** Load and/or generate private keys for all hidden services. Return 0 on
324 * success, -1 on failure.
327 rend_service_load_keys(void)
329 int i;
330 rend_service_t *s;
331 char fname[512];
332 char buf[128];
334 for (i=0; i < smartlist_len(rend_service_list); ++i) {
335 s = smartlist_get(rend_service_list,i);
336 if (s->private_key)
337 continue;
338 log_info(LD_REND, "Loading hidden-service keys from \"%s\"",
339 s->directory);
341 /* Check/create directory */
342 if (check_private_dir(s->directory, CPD_CREATE) < 0)
343 return -1;
345 /* Load key */
346 if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) ||
347 strlcat(fname,"/private_key",sizeof(fname)) >= sizeof(fname)) {
348 log_warn(LD_CONFIG, "Directory name too long to store key file: \"%s\".",
349 s->directory);
350 return -1;
352 s->private_key = init_key_from_file(fname);
353 if (!s->private_key)
354 return -1;
356 /* Create service file */
357 if (rend_get_service_id(s->private_key, s->service_id)<0) {
358 log_warn(LD_BUG, "Internal error: couldn't encode service ID.");
359 return -1;
361 if (crypto_pk_get_digest(s->private_key, s->pk_digest)<0) {
362 log_warn(LD_BUG, "Bug: Couldn't compute hash of public key.");
363 return -1;
365 if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) ||
366 strlcat(fname,"/hostname",sizeof(fname)) >= sizeof(fname)) {
367 log_warn(LD_CONFIG, "Directory name too long to store hostname file:"
368 " \"%s\".", s->directory);
369 return -1;
371 tor_snprintf(buf, sizeof(buf),"%s.onion\n", s->service_id);
372 if (write_str_to_file(fname,buf,0)<0)
373 return -1;
375 return 0;
378 /** Return the service whose public key has a digest of <b>digest</b>. Return
379 * NULL if no such service exists.
381 static rend_service_t *
382 rend_service_get_by_pk_digest(const char* digest)
384 SMARTLIST_FOREACH(rend_service_list, rend_service_t*, s,
385 if (!memcmp(s->pk_digest,digest,DIGEST_LEN)) return s);
386 return NULL;
389 /** Return 1 if any virtual port in <b>service</b> wants a circuit
390 * to have good uptime. Else return 0.
392 static int
393 rend_service_requires_uptime(rend_service_t *service)
395 int i;
396 rend_service_port_config_t *p;
398 for (i=0; i < smartlist_len(service->ports); ++i) {
399 p = smartlist_get(service->ports, i);
400 if (smartlist_string_num_isin(get_options()->LongLivedPorts,
401 p->virtual_port))
402 return 1;
404 return 0;
407 /******
408 * Handle cells
409 ******/
411 /** Respond to an INTRODUCE2 cell by launching a circuit to the chosen
412 * rendezvous point.
415 rend_service_introduce(origin_circuit_t *circuit, const char *request,
416 size_t request_len)
418 char *ptr, *r_cookie;
419 extend_info_t *extend_info = NULL;
420 char buf[RELAY_PAYLOAD_SIZE];
421 char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN]; /* Holds KH, Df, Db, Kf, Kb */
422 rend_service_t *service;
423 int r, i;
424 size_t len, keylen;
425 crypto_dh_env_t *dh = NULL;
426 origin_circuit_t *launched = NULL;
427 crypt_path_t *cpath = NULL;
428 char serviceid[REND_SERVICE_ID_LEN+1];
429 char hexcookie[9];
430 int circ_needs_uptime;
431 int reason = END_CIRC_REASON_TORPROTOCOL;
433 base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
434 circuit->rend_pk_digest,10);
435 log_info(LD_REND, "Received INTRODUCE2 cell for service %s on circ %d.",
436 escaped(serviceid), circuit->_base.n_circ_id);
438 if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_INTRO) {
439 log_warn(LD_PROTOCOL,
440 "Got an INTRODUCE2 over a non-introduction circuit %d.",
441 circuit->_base.n_circ_id);
442 return -1;
445 /* min key length plus digest length plus nickname length */
446 if (request_len < DIGEST_LEN+REND_COOKIE_LEN+(MAX_NICKNAME_LEN+1)+
447 DH_KEY_LEN+42) {
448 log_warn(LD_PROTOCOL, "Got a truncated INTRODUCE2 cell on circ %d.",
449 circuit->_base.n_circ_id);
450 return -1;
453 /* first DIGEST_LEN bytes of request is service pk digest */
454 service = rend_service_get_by_pk_digest(request);
455 if (!service) {
456 log_warn(LD_REND, "Got an INTRODUCE2 cell for an unrecognized service %s.",
457 escaped(serviceid));
458 return -1;
460 if (memcmp(circuit->rend_pk_digest, request, DIGEST_LEN)) {
461 base32_encode(serviceid, REND_SERVICE_ID_LEN+1, request, 10);
462 log_warn(LD_REND, "Got an INTRODUCE2 cell for the wrong service (%s).",
463 escaped(serviceid));
464 return -1;
467 keylen = crypto_pk_keysize(service->private_key);
468 if (request_len < keylen+DIGEST_LEN) {
469 log_warn(LD_PROTOCOL,
470 "PK-encrypted portion of INTRODUCE2 cell was truncated.");
471 return -1;
473 /* Next N bytes is encrypted with service key */
474 note_crypto_pk_op(REND_SERVER);
475 r = crypto_pk_private_hybrid_decrypt(
476 service->private_key,buf,request+DIGEST_LEN,request_len-DIGEST_LEN,
477 PK_PKCS1_OAEP_PADDING,1);
478 if (r<0) {
479 log_warn(LD_PROTOCOL, "Couldn't decrypt INTRODUCE2 cell.");
480 return -1;
482 len = r;
483 if (*buf == 2) {
484 /* Version 2 INTRODUCE2 cell. */
485 int klen;
486 extend_info = tor_malloc_zero(sizeof(extend_info_t));
487 extend_info->addr = ntohl(get_uint32(buf+1));
488 extend_info->port = ntohs(get_uint16(buf+5));
489 memcpy(extend_info->identity_digest, buf+7, DIGEST_LEN);
490 extend_info->nickname[0] = '$';
491 base16_encode(extend_info->nickname+1, sizeof(extend_info->nickname)-1,
492 extend_info->identity_digest, DIGEST_LEN);
494 klen = ntohs(get_uint16(buf+7+DIGEST_LEN));
495 if ((int)len != 7+DIGEST_LEN+2+klen+20+128) {
496 log_warn(LD_PROTOCOL, "Bad length %u for version 2 INTRODUCE2 cell.",
497 (int)len);
498 reason = END_CIRC_REASON_TORPROTOCOL;
499 goto err;
501 extend_info->onion_key = crypto_pk_asn1_decode(buf+7+DIGEST_LEN+2, klen);
502 if (!extend_info->onion_key) {
503 log_warn(LD_PROTOCOL,
504 "Error decoding onion key in version 2 INTRODUCE2 cell.");
505 reason = END_CIRC_REASON_TORPROTOCOL;
506 goto err;
508 ptr = buf+7+DIGEST_LEN+2+klen;
509 len -= 7+DIGEST_LEN+2+klen;
510 } else {
511 char *rp_nickname;
512 size_t nickname_field_len;
513 routerinfo_t *router;
514 int version;
515 if (*buf == 1) {
516 rp_nickname = buf+1;
517 nickname_field_len = MAX_HEX_NICKNAME_LEN+1;
518 version = 1;
519 } else {
520 nickname_field_len = MAX_NICKNAME_LEN+1;
521 rp_nickname = buf;
522 version = 0;
524 ptr=memchr(rp_nickname,0,nickname_field_len);
525 if (!ptr || ptr == rp_nickname) {
526 log_warn(LD_PROTOCOL,
527 "Couldn't find a nul-padded nickname in INTRODUCE2 cell.");
528 return -1;
530 if ((version == 0 && !is_legal_nickname(rp_nickname)) ||
531 (version == 1 && !is_legal_nickname_or_hexdigest(rp_nickname))) {
532 log_warn(LD_PROTOCOL, "Bad nickname in INTRODUCE2 cell.");
533 return -1;
535 /* Okay, now we know that a nickname is at the start of the buffer. */
536 ptr = rp_nickname+nickname_field_len;
537 len -= nickname_field_len;
538 len -= rp_nickname - buf; /* also remove header space used by version, if
539 * any */
540 router = router_get_by_nickname(rp_nickname, 0);
541 if (!router) {
542 log_info(LD_REND, "Couldn't find router %s named in rendezvous cell.",
543 escaped_safe_str(rp_nickname));
544 /* XXXX Add a no-such-router reason? */
545 reason = END_CIRC_REASON_TORPROTOCOL;
546 goto err;
549 extend_info = extend_info_from_router(router);
552 if (len != REND_COOKIE_LEN+DH_KEY_LEN) {
553 log_warn(LD_PROTOCOL, "Bad length %u for INTRODUCE2 cell.", (int)len);
554 reason = END_CIRC_REASON_TORPROTOCOL;
555 return -1;
558 r_cookie = ptr;
559 base16_encode(hexcookie,9,r_cookie,4);
561 /* Try DH handshake... */
562 dh = crypto_dh_new();
563 if (!dh || crypto_dh_generate_public(dh)<0) {
564 log_warn(LD_BUG,"Internal error: couldn't build DH state "
565 "or generate public key.");
566 reason = END_CIRC_REASON_INTERNAL;
567 goto err;
569 if (crypto_dh_compute_secret(dh, ptr+REND_COOKIE_LEN, DH_KEY_LEN, keys,
570 DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
571 log_warn(LD_BUG, "Internal error: couldn't complete DH handshake");
572 reason = END_CIRC_REASON_INTERNAL;
573 goto err;
576 circ_needs_uptime = rend_service_requires_uptime(service);
578 /* help predict this next time */
579 rep_hist_note_used_internal(time(NULL), circ_needs_uptime, 1);
581 /* Launch a circuit to alice's chosen rendezvous point.
583 for (i=0;i<MAX_REND_FAILURES;i++) {
584 launched = circuit_launch_by_extend_info(
585 CIRCUIT_PURPOSE_S_CONNECT_REND, 0, extend_info,
586 circ_needs_uptime, 1, 1);
588 if (launched)
589 break;
591 if (!launched) { /* give up */
592 log_warn(LD_REND, "Giving up launching first hop of circuit to rendezvous "
593 "point %s for service %s.",
594 escaped_safe_str(extend_info->nickname), serviceid);
595 reason = END_CIRC_REASON_CONNECTFAILED;
596 goto err;
598 log_info(LD_REND,
599 "Accepted intro; launching circuit to %s "
600 "(cookie %s) for service %s.",
601 escaped_safe_str(extend_info->nickname), hexcookie, serviceid);
602 tor_assert(launched->build_state);
603 /* Fill in the circuit's state. */
604 memcpy(launched->rend_pk_digest, circuit->rend_pk_digest,
605 DIGEST_LEN);
606 memcpy(launched->rend_cookie, r_cookie, REND_COOKIE_LEN);
607 strlcpy(launched->rend_query, service->service_id,
608 sizeof(launched->rend_query));
609 launched->build_state->pending_final_cpath = cpath =
610 tor_malloc_zero(sizeof(crypt_path_t));
611 cpath->magic = CRYPT_PATH_MAGIC;
612 launched->build_state->expiry_time = time(NULL) + MAX_REND_TIMEOUT;
614 cpath->dh_handshake_state = dh;
615 dh = NULL;
616 if (circuit_init_cpath_crypto(cpath,keys+DIGEST_LEN,1)<0)
617 goto err;
618 memcpy(cpath->handshake_digest, keys, DIGEST_LEN);
619 if (extend_info) extend_info_free(extend_info);
621 return 0;
622 err:
623 if (dh) crypto_dh_free(dh);
624 if (launched)
625 circuit_mark_for_close(TO_CIRCUIT(launched), reason);
626 if (extend_info) extend_info_free(extend_info);
627 return -1;
630 /** Called when we fail building a rendezvous circuit at some point other
631 * than the last hop: launches a new circuit to the same rendezvous point.
633 void
634 rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc)
636 origin_circuit_t *newcirc;
637 cpath_build_state_t *newstate, *oldstate;
639 tor_assert(oldcirc->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
641 if (!oldcirc->build_state ||
642 oldcirc->build_state->failure_count > MAX_REND_FAILURES ||
643 oldcirc->build_state->expiry_time < time(NULL)) {
644 log_info(LD_REND,
645 "Attempt to build circuit to %s for rendezvous has failed "
646 "too many times or expired; giving up.",
647 oldcirc->build_state ?
648 oldcirc->build_state->chosen_exit->nickname : "*unknown*");
649 return;
652 oldstate = oldcirc->build_state;
653 tor_assert(oldstate);
655 if (oldstate->pending_final_cpath == NULL) {
656 log_info(LD_REND,"Skipping relaunch of circ that failed on its first hop. "
657 "Initiator will retry.");
658 return;
661 log_info(LD_REND,"Reattempting rendezvous circuit to '%s'",
662 oldstate->chosen_exit->nickname);
664 newcirc = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND, 0,
665 oldstate->chosen_exit, 0, 1, 1);
666 if (!newcirc) {
667 log_warn(LD_REND,"Couldn't relaunch rendezvous circuit to '%s'.",
668 oldstate->chosen_exit->nickname);
669 return;
671 newstate = newcirc->build_state;
672 tor_assert(newstate);
673 newstate->failure_count = oldstate->failure_count+1;
674 newstate->expiry_time = oldstate->expiry_time;
675 newstate->pending_final_cpath = oldstate->pending_final_cpath;
676 oldstate->pending_final_cpath = NULL;
678 memcpy(newcirc->rend_query, oldcirc->rend_query, REND_SERVICE_ID_LEN+1);
679 memcpy(newcirc->rend_pk_digest, oldcirc->rend_pk_digest,
680 DIGEST_LEN);
681 memcpy(newcirc->rend_cookie, oldcirc->rend_cookie,
682 REND_COOKIE_LEN);
685 /** Launch a circuit to serve as an introduction point for the service
686 * <b>service</b> at the introduction point <b>nickname</b>
688 static int
689 rend_service_launch_establish_intro(rend_service_t *service,
690 const char *nickname)
692 origin_circuit_t *launched;
694 log_info(LD_REND,
695 "Launching circuit to introduction point %s for service %s",
696 escaped_safe_str(nickname), service->service_id);
698 rep_hist_note_used_internal(time(NULL), 1, 0);
700 ++service->n_intro_circuits_launched;
701 launched = circuit_launch_by_nickname(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, 0,
702 nickname, 1, 0, 1);
703 if (!launched) {
704 log_info(LD_REND,
705 "Can't launch circuit to establish introduction at %s.",
706 escaped_safe_str(nickname));
707 return -1;
709 strlcpy(launched->rend_query, service->service_id,
710 sizeof(launched->rend_query));
711 memcpy(launched->rend_pk_digest, service->pk_digest, DIGEST_LEN);
713 if (launched->_base.state == CIRCUIT_STATE_OPEN)
714 rend_service_intro_has_opened(launched);
715 return 0;
718 /** Called when we're done building a circuit to an introduction point:
719 * sends a RELAY_ESTABLISH_INTRO cell.
721 void
722 rend_service_intro_has_opened(origin_circuit_t *circuit)
724 rend_service_t *service;
725 size_t len;
726 int r;
727 char buf[RELAY_PAYLOAD_SIZE];
728 char auth[DIGEST_LEN + 9];
729 char serviceid[REND_SERVICE_ID_LEN+1];
730 int reason = END_CIRC_REASON_TORPROTOCOL;
732 tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
733 tor_assert(circuit->cpath);
735 base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
736 circuit->rend_pk_digest,10);
738 service = rend_service_get_by_pk_digest(circuit->rend_pk_digest);
739 if (!service) {
740 log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %d.",
741 serviceid, circuit->_base.n_circ_id);
742 reason = END_CIRC_REASON_NOSUCHSERVICE;
743 goto err;
746 log_info(LD_REND,
747 "Established circuit %d as introduction point for service %s",
748 circuit->_base.n_circ_id, serviceid);
750 /* Build the payload for a RELAY_ESTABLISH_INTRO cell. */
751 len = crypto_pk_asn1_encode(service->private_key, buf+2,
752 RELAY_PAYLOAD_SIZE-2);
753 set_uint16(buf, htons((uint16_t)len));
754 len += 2;
755 memcpy(auth, circuit->cpath->prev->handshake_digest, DIGEST_LEN);
756 memcpy(auth+DIGEST_LEN, "INTRODUCE", 9);
757 if (crypto_digest(buf+len, auth, DIGEST_LEN+9))
758 goto err;
759 len += 20;
760 note_crypto_pk_op(REND_SERVER);
761 r = crypto_pk_private_sign_digest(service->private_key, buf+len, buf, len);
762 if (r<0) {
763 log_warn(LD_BUG, "Internal error: couldn't sign introduction request.");
764 reason = END_CIRC_REASON_INTERNAL;
765 goto err;
767 len += r;
769 if (connection_edge_send_command(NULL, TO_CIRCUIT(circuit),
770 RELAY_COMMAND_ESTABLISH_INTRO,
771 buf, len, circuit->cpath->prev)<0) {
772 log_info(LD_GENERAL,
773 "Couldn't send introduction request for service %s on circuit %d",
774 serviceid, circuit->_base.n_circ_id);
775 reason = END_CIRC_REASON_INTERNAL;
776 goto err;
779 return;
780 err:
781 circuit_mark_for_close(TO_CIRCUIT(circuit), reason);
784 /** Called when we get an INTRO_ESTABLISHED cell; mark the circuit as a
785 * live introduction point, and note that the service descriptor is
786 * now out-of-date.*/
788 rend_service_intro_established(origin_circuit_t *circuit, const char *request,
789 size_t request_len)
791 rend_service_t *service;
792 (void) request;
793 (void) request_len;
795 if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
796 log_warn(LD_PROTOCOL,
797 "received INTRO_ESTABLISHED cell on non-intro circuit.");
798 goto err;
800 service = rend_service_get_by_pk_digest(circuit->rend_pk_digest);
801 if (!service) {
802 log_warn(LD_REND, "Unknown service on introduction circuit %d.",
803 circuit->_base.n_circ_id);
804 goto err;
806 service->desc_is_dirty = time(NULL);
807 circuit->_base.purpose = CIRCUIT_PURPOSE_S_INTRO;
809 return 0;
810 err:
811 circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_REASON_TORPROTOCOL);
812 return -1;
815 /** Called once a circuit to a rendezvous point is established: sends a
816 * RELAY_COMMAND_RENDEZVOUS1 cell.
818 void
819 rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
821 rend_service_t *service;
822 char buf[RELAY_PAYLOAD_SIZE];
823 crypt_path_t *hop;
824 char serviceid[REND_SERVICE_ID_LEN+1];
825 char hexcookie[9];
826 int reason;
828 tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
829 tor_assert(circuit->cpath);
830 tor_assert(circuit->build_state);
831 hop = circuit->build_state->pending_final_cpath;
832 tor_assert(hop);
834 base16_encode(hexcookie,9,circuit->rend_cookie,4);
835 base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
836 circuit->rend_pk_digest,10);
838 log_info(LD_REND,
839 "Done building circuit %d to rendezvous with "
840 "cookie %s for service %s",
841 circuit->_base.n_circ_id, hexcookie, serviceid);
843 service = rend_service_get_by_pk_digest(circuit->rend_pk_digest);
844 if (!service) {
845 log_warn(LD_GENERAL, "Internal error: unrecognized service ID on "
846 "introduction circuit.");
847 reason = END_CIRC_REASON_INTERNAL;
848 goto err;
851 /* All we need to do is send a RELAY_RENDEZVOUS1 cell... */
852 memcpy(buf, circuit->rend_cookie, REND_COOKIE_LEN);
853 if (crypto_dh_get_public(hop->dh_handshake_state,
854 buf+REND_COOKIE_LEN, DH_KEY_LEN)<0) {
855 log_warn(LD_GENERAL,"Couldn't get DH public key.");
856 reason = END_CIRC_REASON_INTERNAL;
857 goto err;
859 memcpy(buf+REND_COOKIE_LEN+DH_KEY_LEN, hop->handshake_digest,
860 DIGEST_LEN);
862 /* Send the cell */
863 if (connection_edge_send_command(NULL, TO_CIRCUIT(circuit),
864 RELAY_COMMAND_RENDEZVOUS1,
865 buf, REND_COOKIE_LEN+DH_KEY_LEN+DIGEST_LEN,
866 circuit->cpath->prev)<0) {
867 log_warn(LD_GENERAL, "Couldn't send RENDEZVOUS1 cell.");
868 reason = END_CIRC_REASON_INTERNAL;
869 goto err;
872 crypto_dh_free(hop->dh_handshake_state);
873 hop->dh_handshake_state = NULL;
875 /* Append the cpath entry. */
876 hop->state = CPATH_STATE_OPEN;
877 /* set the windows to default. these are the windows
878 * that bob thinks alice has.
880 hop->package_window = CIRCWINDOW_START;
881 hop->deliver_window = CIRCWINDOW_START;
883 onion_append_to_cpath(&circuit->cpath, hop);
884 circuit->build_state->pending_final_cpath = NULL; /* prevent double-free */
886 /* Change the circuit purpose. */
887 circuit->_base.purpose = CIRCUIT_PURPOSE_S_REND_JOINED;
889 return;
890 err:
891 circuit_mark_for_close(TO_CIRCUIT(circuit), reason);
895 * Manage introduction points
898 /** Return the (possibly non-open) introduction circuit ending at
899 * <b>router</b> for the service whose public key is <b>pk_digest</b>. Return
900 * NULL if no such service is found.
902 static origin_circuit_t *
903 find_intro_circuit(routerinfo_t *router, const char *pk_digest)
905 origin_circuit_t *circ = NULL;
907 tor_assert(router);
908 while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest,
909 CIRCUIT_PURPOSE_S_INTRO))) {
910 if (!strcasecmp(circ->build_state->chosen_exit->nickname,
911 router->nickname)) {
912 return circ;
916 circ = NULL;
917 while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest,
918 CIRCUIT_PURPOSE_S_ESTABLISH_INTRO))) {
919 if (!strcasecmp(circ->build_state->chosen_exit->nickname,
920 router->nickname)) {
921 return circ;
924 return NULL;
927 /** Encode and sign an up-to-date service descriptor for <b>service</b>,
928 * and upload it to all the dirservers.
930 static void
931 upload_service_descriptor(rend_service_t *service, int version)
933 char *desc;
934 size_t desc_len;
936 /* Update the descriptor. */
937 rend_service_update_descriptor(service);
938 if (rend_encode_service_descriptor(service->desc,
939 version,
940 service->private_key,
941 &desc, &desc_len)<0) {
942 log_warn(LD_BUG, "Internal error: couldn't encode service descriptor; "
943 "not uploading.");
944 return;
947 /* Post it to the dirservers */
948 directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_RENDDESC, desc, desc_len);
949 tor_free(desc);
951 service->desc_is_dirty = 0;
954 /** For every service, check how many intro points it currently has, and:
955 * - Pick new intro points as necessary.
956 * - Launch circuits to any new intro points.
958 void
959 rend_services_introduce(void)
961 int i,j,r;
962 routerinfo_t *router;
963 rend_service_t *service;
964 char *intro;
965 int changed, prev_intro_nodes;
966 smartlist_t *intro_routers, *exclude_routers;
967 time_t now;
969 intro_routers = smartlist_create();
970 exclude_routers = smartlist_create();
971 now = time(NULL);
973 for (i=0; i < smartlist_len(rend_service_list); ++i) {
974 smartlist_clear(intro_routers);
975 service = smartlist_get(rend_service_list, i);
977 tor_assert(service);
978 changed = 0;
979 if (now > service->intro_period_started+INTRO_CIRC_RETRY_PERIOD) {
980 /* One period has elapsed; we can try building circuits again. */
981 service->intro_period_started = now;
982 service->n_intro_circuits_launched = 0;
983 } else if (service->n_intro_circuits_launched >=
984 MAX_INTRO_CIRCS_PER_PERIOD) {
985 /* We have failed too many times in this period; wait for the next
986 * one before we try again. */
987 continue;
990 /* Find out which introduction points we have in progress for this
991 service. */
992 for (j=0; j < smartlist_len(service->intro_nodes); ++j) {
993 intro = smartlist_get(service->intro_nodes, j);
994 router = router_get_by_nickname(intro, 0);
995 if (!router || !find_intro_circuit(router,service->pk_digest)) {
996 log_info(LD_REND,"Giving up on %s as intro point for %s.",
997 intro, service->service_id);
998 tor_free(intro);
999 smartlist_del(service->intro_nodes,j--);
1000 changed = 1;
1001 service->desc_is_dirty = now;
1003 smartlist_add(intro_routers, router);
1006 /* We have enough intro points, and the intro points we thought we had were
1007 * all connected.
1009 if (!changed && smartlist_len(service->intro_nodes) >= NUM_INTRO_POINTS) {
1010 /* We have all our intro points! Start a fresh period and reset the
1011 * circuit count. */
1012 service->intro_period_started = now;
1013 service->n_intro_circuits_launched = 0;
1014 continue;
1017 /* Remember how many introduction circuits we started with. */
1018 prev_intro_nodes = smartlist_len(service->intro_nodes);
1020 smartlist_add_all(exclude_routers, intro_routers);
1021 /* The directory is now here. Pick three ORs as intro points. */
1022 for (j=prev_intro_nodes; j < NUM_INTRO_POINTS; ++j) {
1023 char *hex_digest;
1024 router = router_choose_random_node(service->intro_prefer_nodes,
1025 service->intro_exclude_nodes, exclude_routers, 1, 0, 0,
1026 get_options()->_AllowInvalid & ALLOW_INVALID_INTRODUCTION,
1027 0, 0);
1028 if (!router) {
1029 log_warn(LD_REND,
1030 "Could only establish %d introduction points for %s.",
1031 smartlist_len(service->intro_nodes), service->service_id);
1032 break;
1034 changed = 1;
1035 hex_digest = tor_malloc_zero(HEX_DIGEST_LEN+2);
1036 hex_digest[0] = '$';
1037 base16_encode(hex_digest+1, HEX_DIGEST_LEN+1,
1038 router->cache_info.identity_digest,
1039 DIGEST_LEN);
1040 smartlist_add(intro_routers, router);
1041 smartlist_add(exclude_routers, router);
1042 smartlist_add(service->intro_nodes, hex_digest);
1043 log_info(LD_REND, "Picked router %s as an intro point for %s.",
1044 router->nickname, service->service_id);
1047 /* Reset exclude_routers, for the next time around the loop. */
1048 smartlist_clear(exclude_routers);
1050 /* If there's no need to launch new circuits, stop here. */
1051 if (!changed)
1052 continue;
1054 /* Establish new introduction points. */
1055 for (j=prev_intro_nodes; j < smartlist_len(service->intro_nodes); ++j) {
1056 intro = smartlist_get(service->intro_nodes, j);
1057 r = rend_service_launch_establish_intro(service, intro);
1058 if (r<0) {
1059 log_warn(LD_REND, "Error launching circuit to node %s for service %s.",
1060 intro, service->service_id);
1064 smartlist_free(intro_routers);
1065 smartlist_free(exclude_routers);
1068 /** Regenerate and upload rendezvous service descriptors for all
1069 * services, if necessary. If the descriptor has been dirty enough
1070 * for long enough, definitely upload; else only upload when the
1071 * periodic timeout has expired.
1073 * For the first upload, pick a random time between now and two periods
1074 * from now, and pick it independently for each service.
1076 void
1077 rend_consider_services_upload(time_t now)
1079 int i;
1080 rend_service_t *service;
1081 int rendpostperiod = get_options()->RendPostPeriod;
1083 if (!get_options()->PublishHidServDescriptors)
1084 return;
1086 for (i=0; i < smartlist_len(rend_service_list); ++i) {
1087 service = smartlist_get(rend_service_list, i);
1088 if (!service->next_upload_time) { /* never been uploaded yet */
1089 service->next_upload_time =
1090 now + crypto_rand_int(2*rendpostperiod);
1092 if (service->next_upload_time < now ||
1093 (service->desc_is_dirty &&
1094 service->desc_is_dirty < now-30)) {
1095 /* if it's time, or if the directory servers have a wrong service
1096 * descriptor and ours has been stable for 30 seconds, upload a
1097 * new one of each format. */
1098 upload_service_descriptor(service, 0);
1099 service->next_upload_time = now + rendpostperiod;
1104 /** Log the status of introduction points for all rendezvous services
1105 * at log severity <b>severity</b>.
1107 void
1108 rend_service_dump_stats(int severity)
1110 int i,j;
1111 routerinfo_t *router;
1112 rend_service_t *service;
1113 const char *nickname, *safe_name;
1114 char nn_buf[MAX_VERBOSE_NICKNAME_LEN];
1115 origin_circuit_t *circ;
1117 for (i=0; i < smartlist_len(rend_service_list); ++i) {
1118 service = smartlist_get(rend_service_list, i);
1119 log(severity, LD_GENERAL, "Service configured in \"%s\":",
1120 service->directory);
1121 for (j=0; j < smartlist_len(service->intro_nodes); ++j) {
1122 nickname = smartlist_get(service->intro_nodes, j);
1123 router = router_get_by_nickname(nickname,1);
1124 if (router) {
1125 router_get_verbose_nickname(nn_buf, router);
1126 nickname = nn_buf;
1128 safe_name = safe_str(nickname);
1130 if (!router) {
1131 log(severity, LD_GENERAL,
1132 " Intro point %d at %s: unrecognized router", j, safe_name);
1133 continue;
1135 circ = find_intro_circuit(router, service->pk_digest);
1136 if (!circ) {
1137 log(severity, LD_GENERAL, " Intro point %d at %s: no circuit",
1138 j, safe_name);
1139 continue;
1141 log(severity, LD_GENERAL, " Intro point %d at %s: circuit is %s",
1142 j, safe_name, circuit_state_to_string(circ->_base.state));
1147 /** Given <b>conn</b>, a rendezvous exit stream, look up the hidden service for
1148 * 'circ', and look up the port and address based on conn-\>port.
1149 * Assign the actual conn-\>addr and conn-\>port. Return -1 if failure,
1150 * or 0 for success.
1153 rend_service_set_connection_addr_port(edge_connection_t *conn,
1154 origin_circuit_t *circ)
1156 rend_service_t *service;
1157 int i;
1158 rend_service_port_config_t *p;
1159 char serviceid[REND_SERVICE_ID_LEN+1];
1161 tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_S_REND_JOINED);
1162 log_debug(LD_REND,"beginning to hunt for addr/port");
1163 base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
1164 circ->rend_pk_digest,10);
1165 service = rend_service_get_by_pk_digest(circ->rend_pk_digest);
1166 if (!service) {
1167 log_warn(LD_REND, "Couldn't find any service associated with pk %s on "
1168 "rendezvous circuit %d; closing.",
1169 serviceid, circ->_base.n_circ_id);
1170 return -1;
1172 for (i = 0; i < smartlist_len(service->ports); ++i) {
1173 p = smartlist_get(service->ports, i);
1174 if (conn->_base.port == p->virtual_port) {
1175 conn->_base.addr = p->real_addr;
1176 conn->_base.port = p->real_port;
1177 return 0;
1180 log_info(LD_REND, "No virtual port mapping exists for port %d on service %s",
1181 conn->_base.port,serviceid);
1182 return -1;