~ubuntu-branches/ubuntu/edgy/tor/edgy

« back to all changes in this revision

Viewing changes to src/or/rendclient.c

  • Committer: Bazaar Package Importer
  • Author(s): Peter Palfrader
  • Date: 2006-07-06 02:55:37 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20060706025537-77irayomswemsl63
Tags: 0.1.1.22-1
New upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright 2004-2005 Roger Dingledine, Nick Mathewson. */
 
1
/* Copyright 2004-2006 Roger Dingledine, Nick Mathewson. */
2
2
/* See LICENSE for licensing information */
3
 
/* $Id: rendclient.c,v 1.86 2005/05/03 10:04:08 arma Exp $ */
4
 
const char rendclient_c_id[] = "$Id: rendclient.c,v 1.86 2005/05/03 10:04:08 arma Exp $";
 
3
/* $Id: rendclient.c,v 1.107 2006/03/06 00:25:39 nickm Exp $ */
 
4
const char rendclient_c_id[] =
 
5
  "$Id: rendclient.c,v 1.107 2006/03/06 00:25:39 nickm Exp $";
5
6
 
6
7
/**
7
8
 * \file rendclient.c
19
20
  tor_assert(CIRCUIT_IS_ORIGIN(circ));
20
21
  tor_assert(circ->cpath);
21
22
 
22
 
  log_fn(LOG_INFO,"introcirc is open");
 
23
  log_info(LD_REND,"introcirc is open");
23
24
  connection_ap_attach_pending();
24
25
}
25
26
 
30
31
rend_client_send_establish_rendezvous(circuit_t *circ)
31
32
{
32
33
  tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
33
 
  log_fn(LOG_INFO, "Sending an ESTABLISH_RENDEZVOUS cell");
 
34
  log_info(LD_REND, "Sending an ESTABLISH_RENDEZVOUS cell");
34
35
 
35
36
  if (crypto_rand(circ->rend_cookie, REND_COOKIE_LEN) < 0) {
36
 
    log_fn(LOG_WARN, "Couldn't get random cookie");
37
 
    circuit_mark_for_close(circ);
 
37
    log_warn(LD_BUG, "Internal error: Couldn't produce random cookie.");
 
38
    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
38
39
    return -1;
39
40
  }
40
41
  if (connection_edge_send_command(NULL,circ,
42
43
                                   circ->rend_cookie, REND_COOKIE_LEN,
43
44
                                   circ->cpath->prev)<0) {
44
45
    /* circ is already marked for close */
45
 
    log_fn(LOG_WARN, "Couldn't send ESTABLISH_RENDEZVOUS cell");
 
46
    log_warn(LD_GENERAL, "Couldn't send ESTABLISH_RENDEZVOUS cell");
46
47
    return -1;
47
48
  }
48
49
 
53
54
 * down introcirc if possible.
54
55
 */
55
56
int
56
 
rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc) {
 
57
rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc)
 
58
{
57
59
  size_t payload_len;
58
60
  int r;
59
61
  char payload[RELAY_PAYLOAD_SIZE];
60
 
  char tmp[1+(MAX_HEX_NICKNAME_LEN+1)+REND_COOKIE_LEN+DH_KEY_LEN];
 
62
  char tmp[RELAY_PAYLOAD_SIZE];
61
63
  rend_cache_entry_t *entry;
62
64
  crypt_path_t *cpath;
 
65
  off_t dh_offset;
63
66
 
64
67
  tor_assert(introcirc->purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
65
68
  tor_assert(rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY);
66
 
  tor_assert(!rend_cmp_service_ids(introcirc->rend_query, rendcirc->rend_query));
 
69
  tor_assert(!rend_cmp_service_ids(introcirc->rend_query,
 
70
                                   rendcirc->rend_query));
67
71
 
68
 
  if (rend_cache_lookup_entry(introcirc->rend_query, &entry) < 1) {
69
 
    log_fn(LOG_WARN,"query '%s' didn't have valid rend desc in cache. Failing.",
70
 
           safe_str(introcirc->rend_query));
 
72
  if (rend_cache_lookup_entry(introcirc->rend_query, -1, &entry) < 1) {
 
73
    log_warn(LD_REND,
 
74
             "query %s didn't have valid rend desc in cache. Failing.",
 
75
             escaped_safe_str(introcirc->rend_query));
71
76
    goto err;
72
77
  }
73
78
 
74
79
  /* first 20 bytes of payload are the hash of bob's pk */
75
80
  if (crypto_pk_get_digest(entry->parsed->pk, payload)<0) {
76
 
    log_fn(LOG_WARN, "Couldn't hash public key.");
 
81
    log_warn(LD_BUG, "Internal error: couldn't hash public key.");
77
82
    goto err;
78
83
  }
79
84
 
84
89
      tor_malloc_zero(sizeof(crypt_path_t));
85
90
    cpath->magic = CRYPT_PATH_MAGIC;
86
91
    if (!(cpath->dh_handshake_state = crypto_dh_new())) {
87
 
      log_fn(LOG_WARN, "Couldn't allocate DH");
 
92
      log_warn(LD_BUG, "Internal error: couldn't allocate DH.");
88
93
      goto err;
89
94
    }
90
95
    if (crypto_dh_generate_public(cpath->dh_handshake_state)<0) {
91
 
      log_fn(LOG_WARN, "Couldn't generate g^x");
 
96
      log_warn(LD_BUG, "Internal error: couldn't generate g^x.");
92
97
      goto err;
93
98
    }
94
99
  }
95
100
 
96
101
  /* write the remaining items into tmp */
97
 
#if 0
98
 
  tmp[0] = 1; /* version 1 of the cell format */
99
 
  /* nul pads */
100
 
  strncpy(tmp+1, rendcirc->build_state->chosen_exit_name, (MAX_HEX_NICKNAME_LEN+1));
101
 
  memcpy(tmp+1+MAX_HEX_NICKNAME_LEN+1, rendcirc->rend_cookie, REND_COOKIE_LEN);
102
 
#else
103
 
  strncpy(tmp, rendcirc->build_state->chosen_exit_name, (MAX_NICKNAME_LEN+1)); /* nul pads */
104
 
  memcpy(tmp+MAX_NICKNAME_LEN+1, rendcirc->rend_cookie, REND_COOKIE_LEN);
105
 
#endif
106
 
  if (crypto_dh_get_public(cpath->dh_handshake_state,
107
 
#if 0
108
 
                           tmp+1+MAX_HEX_NICKNAME_LEN+1+REND_COOKIE_LEN,
109
 
#else
110
 
                           tmp+MAX_NICKNAME_LEN+1+REND_COOKIE_LEN,
111
 
#endif
 
102
  if (entry->parsed->protocols & (1<<2)) {
 
103
    /* version 2 format */
 
104
    extend_info_t *extend_info = rendcirc->build_state->chosen_exit;
 
105
    int klen;
 
106
    tmp[0] = 2; /* version 2 of the cell format */
 
107
    /* nul pads */
 
108
    set_uint32(tmp+1, htonl(extend_info->addr));
 
109
    set_uint16(tmp+5, htons(extend_info->port));
 
110
    memcpy(tmp+7, extend_info->identity_digest, DIGEST_LEN);
 
111
    klen = crypto_pk_asn1_encode(extend_info->onion_key, tmp+7+DIGEST_LEN+2,
 
112
                                 sizeof(tmp)-(7+DIGEST_LEN+2));
 
113
    set_uint16(tmp+7+DIGEST_LEN, htons(klen));
 
114
    memcpy(tmp+7+DIGEST_LEN+2+klen, rendcirc->rend_cookie, REND_COOKIE_LEN);
 
115
    dh_offset = 7+DIGEST_LEN+2+klen+REND_COOKIE_LEN;
 
116
  } else {
 
117
    /* Version 0. */
 
118
    strncpy(tmp, rendcirc->build_state->chosen_exit->nickname,
 
119
            (MAX_NICKNAME_LEN+1)); /* nul pads */
 
120
    memcpy(tmp+MAX_NICKNAME_LEN+1, rendcirc->rend_cookie, REND_COOKIE_LEN);
 
121
    dh_offset = MAX_NICKNAME_LEN+1+REND_COOKIE_LEN;
 
122
  }
112
123
 
 
124
  if (crypto_dh_get_public(cpath->dh_handshake_state, tmp+dh_offset,
113
125
                           DH_KEY_LEN)<0) {
114
 
    log_fn(LOG_WARN, "Couldn't extract g^x");
 
126
    log_warn(LD_BUG, "Internal error: couldn't extract g^x.");
115
127
    goto err;
116
128
  }
117
129
 
118
130
  /*XXX maybe give crypto_pk_public_hybrid_encrypt a max_len arg,
119
131
   * to avoid buffer overflows? */
120
 
  r = crypto_pk_public_hybrid_encrypt(entry->parsed->pk, payload+DIGEST_LEN, tmp,
121
 
#if 0
122
 
                           1+MAX_HEX_NICKNAME_LEN+1+REND_COOKIE_LEN+DH_KEY_LEN,
123
 
#else
124
 
                           MAX_NICKNAME_LEN+1+REND_COOKIE_LEN+DH_KEY_LEN,
125
 
#endif
 
132
  r = crypto_pk_public_hybrid_encrypt(entry->parsed->pk, payload+DIGEST_LEN,
 
133
                                      tmp,
 
134
                                      dh_offset+DH_KEY_LEN,
126
135
                                      PK_PKCS1_OAEP_PADDING, 0);
127
136
  if (r<0) {
128
 
    log_fn(LOG_WARN,"hybrid pk encrypt failed.");
 
137
    log_warn(LD_BUG,"Internal error: hybrid pk encrypt failed.");
129
138
    goto err;
130
139
  }
131
140
 
137
146
                                   payload, payload_len,
138
147
                                   introcirc->cpath->prev)<0) {
139
148
    /* introcirc is already marked for close. leave rendcirc alone. */
140
 
    log_fn(LOG_WARN, "Couldn't send INTRODUCE1 cell");
 
149
    log_warn(LD_BUG, "Couldn't send INTRODUCE1 cell");
141
150
    return -1;
142
151
  }
143
152
 
146
155
 
147
156
  return 0;
148
157
err:
149
 
  circuit_mark_for_close(introcirc);
150
 
  circuit_mark_for_close(rendcirc);
 
158
  circuit_mark_for_close(introcirc, END_CIRC_AT_ORIGIN);
 
159
  circuit_mark_for_close(rendcirc, END_CIRC_AT_ORIGIN);
151
160
  return -1;
152
161
}
153
162
 
159
168
  tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
160
169
  tor_assert(CIRCUIT_IS_ORIGIN(circ));
161
170
 
162
 
  log_fn(LOG_INFO,"rendcirc is open");
 
171
  log_info(LD_REND,"rendcirc is open");
163
172
 
164
173
  /* generate a rendezvous cookie, store it in circ */
165
174
  if (rend_client_send_establish_rendezvous(circ) < 0) {
173
182
rend_client_introduction_acked(circuit_t *circ,
174
183
                               const char *request, size_t request_len)
175
184
{
176
 
  char *nickname;
177
185
  circuit_t *rendcirc;
178
186
 
179
187
  if (circ->purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
180
 
    log_fn(LOG_WARN, "Received REND_INTRODUCE_ACK on unexpected circuit %d",
181
 
           circ->n_circ_id);
182
 
    circuit_mark_for_close(circ);
 
188
    log_warn(LD_PROTOCOL,
 
189
             "Received REND_INTRODUCE_ACK on unexpected circuit %d.",
 
190
             circ->n_circ_id);
 
191
    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
183
192
    return -1;
184
193
  }
185
194
 
186
 
  tor_assert(circ->build_state->chosen_exit_name);
 
195
  tor_assert(circ->build_state->chosen_exit);
 
196
  tor_assert(circ->build_state->chosen_exit->nickname);
187
197
 
188
198
  if (request_len == 0) {
189
199
    /* It's an ACK; the introduction point relayed our introduction request. */
190
200
    /* Locate the rend circ which is waiting to hear about this ack,
191
201
     * and tell it.
192
202
     */
193
 
    log_fn(LOG_INFO,"Received ack. Telling rend circ...");
 
203
    log_info(LD_REND,"Received ack. Telling rend circ...");
194
204
    rendcirc = circuit_get_by_rend_query_and_purpose(
195
205
               circ->rend_query, CIRCUIT_PURPOSE_C_REND_READY);
196
206
    if (rendcirc) { /* remember the ack */
197
207
      rendcirc->purpose = CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED;
198
208
    } else {
199
 
      log_fn(LOG_INFO,"...Found no rend circ. Dropping on the floor.");
 
209
      log_info(LD_REND,"...Found no rend circ. Dropping on the floor.");
200
210
    }
201
211
    /* close the circuit: we won't need it anymore. */
202
212
    circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACKED;
203
 
    circuit_mark_for_close(circ);
 
213
    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
204
214
  } else {
205
215
    /* It's a NAK; the introduction point didn't relay our request. */
206
216
    circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
208
218
     * points. If any remain, extend to a new one and try again.
209
219
     * If none remain, refetch the service descriptor.
210
220
     */
211
 
    if (rend_client_remove_intro_point(circ->build_state->chosen_exit_name,
 
221
    if (rend_client_remove_intro_point(circ->build_state->chosen_exit,
212
222
                                       circ->rend_query) > 0) {
213
 
      /* There are introduction points left. re-extend the circuit to
 
223
      /* There are introduction points left. Re-extend the circuit to
214
224
       * another intro point and try again. */
215
 
      routerinfo_t *r;
216
 
      nickname = rend_client_get_random_intro(circ->rend_query);
217
 
      tor_assert(nickname);
218
 
      log_fn(LOG_INFO,"Got nack for %s from %s, extending to %s.",
219
 
             safe_str(circ->rend_query),
220
 
             circ->build_state->chosen_exit_name, nickname);
221
 
      if (!(r = router_get_by_nickname(nickname))) {
222
 
        log_fn(LOG_WARN, "Advertised intro point '%s' for %s is not known. Closing.",
223
 
               nickname, safe_str(circ->rend_query));
224
 
        tor_free(nickname);
225
 
        circuit_mark_for_close(circ);
 
225
      extend_info_t *extend_info;
 
226
      int result;
 
227
      extend_info = rend_client_get_random_intro(circ->rend_query);
 
228
      if (!extend_info) {
 
229
        log_warn(LD_REND, "No introduction points left for %s. Closing.",
 
230
                 escaped_safe_str(circ->rend_query));
 
231
        circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
226
232
        return -1;
227
233
      }
228
 
      log_fn(LOG_INFO, "Chose new intro point %s for %s (circ %d)",
229
 
             nickname, safe_str(circ->rend_query), circ->n_circ_id);
230
 
      tor_free(nickname);
231
 
      return circuit_extend_to_new_exit(circ, r);
 
234
      log_info(LD_REND,
 
235
               "Got nack for %s from %s. Re-extending circ %d, "
 
236
               "this time to %s.",
 
237
               escaped_safe_str(circ->rend_query),
 
238
               circ->build_state->chosen_exit->nickname, circ->n_circ_id,
 
239
               extend_info->nickname);
 
240
      result = circuit_extend_to_new_exit(circ, extend_info);
 
241
      extend_info_free(extend_info);
 
242
      return result;
232
243
    }
233
244
  }
234
245
  return 0;
241
252
void
242
253
rend_client_refetch_renddesc(const char *query)
243
254
{
 
255
  if (!get_options()->FetchHidServDescriptors)
 
256
    return;
244
257
  if (connection_get_by_type_state_rendquery(CONN_TYPE_DIR, 0, query)) {
245
 
    log_fn(LOG_INFO,"Would fetch a new renddesc here (for %s), but one is already in progress.", safe_str(query));
 
258
    log_info(LD_REND,"Would fetch a new renddesc here (for %s), but one is "
 
259
             "already in progress.", escaped_safe_str(query));
246
260
  } else {
247
261
    /* not one already; initiate a dir rend desc lookup */
248
262
    directory_get_from_dirserver(DIR_PURPOSE_FETCH_RENDDESC, query, 1);
249
263
  }
250
264
}
251
265
 
252
 
/** remove failed_intro from ent. if ent now has no intro points, or
 
266
/** Remove failed_intro from ent. If ent now has no intro points, or
253
267
 * service is unrecognized, then launch a new renddesc fetch.
254
268
 *
255
269
 * Return -1 if error, 0 if no intro points remain or service
256
270
 * unrecognized, 1 if recognized and some intro points remain.
257
271
 */
258
272
int
259
 
rend_client_remove_intro_point(char *failed_intro, const char *query)
 
273
rend_client_remove_intro_point(extend_info_t *failed_intro, const char *query)
260
274
{
261
275
  int i, r;
262
276
  rend_cache_entry_t *ent;
263
277
  connection_t *conn;
264
278
 
265
 
  r = rend_cache_lookup_entry(query, &ent);
 
279
  r = rend_cache_lookup_entry(query, -1, &ent);
266
280
  if (r<0) {
267
 
    log_fn(LOG_WARN, "Malformed service ID '%s'", safe_str(query));
 
281
    log_warn(LD_BUG, "Bug: malformed service ID %s.", escaped_safe_str(query));
268
282
    return -1;
269
283
  }
270
284
  if (r==0) {
271
 
    log_fn(LOG_INFO, "Unknown service %s. Re-fetching descriptor.",
272
 
           safe_str(query));
 
285
    log_info(LD_REND, "Unknown service %s. Re-fetching descriptor.",
 
286
             escaped_safe_str(query));
273
287
    rend_client_refetch_renddesc(query);
274
288
    return 0;
275
289
  }
276
290
 
277
 
  for (i=0; i < ent->parsed->n_intro_points; ++i) {
278
 
    if (!strcasecmp(ent->parsed->intro_points[i], failed_intro)) {
279
 
      tor_free(ent->parsed->intro_points[i]);
280
 
      ent->parsed->intro_points[i] =
281
 
        ent->parsed->intro_points[--ent->parsed->n_intro_points];
282
 
      break;
 
291
  if (ent->parsed->intro_point_extend_info) {
 
292
    for (i=0; i < ent->parsed->n_intro_points; ++i) {
 
293
      if (!memcmp(failed_intro->identity_digest,
 
294
                  ent->parsed->intro_point_extend_info[i]->identity_digest,
 
295
                  DIGEST_LEN)) {
 
296
        tor_assert(!strcmp(ent->parsed->intro_points[i],
 
297
                           ent->parsed->intro_point_extend_info[i]->nickname));
 
298
        tor_free(ent->parsed->intro_points[i]);
 
299
        extend_info_free(ent->parsed->intro_point_extend_info[i]);
 
300
        --ent->parsed->n_intro_points;
 
301
        ent->parsed->intro_points[i] =
 
302
          ent->parsed->intro_points[ent->parsed->n_intro_points];
 
303
        ent->parsed->intro_point_extend_info[i] =
 
304
          ent->parsed->intro_point_extend_info[ent->parsed->n_intro_points];
 
305
        break;
 
306
      }
 
307
    }
 
308
  } else {
 
309
    for (i=0; i < ent->parsed->n_intro_points; ++i) {
 
310
      if (!strcasecmp(ent->parsed->intro_points[i], failed_intro->nickname)) {
 
311
        tor_free(ent->parsed->intro_points[i]);
 
312
        ent->parsed->intro_points[i] =
 
313
          ent->parsed->intro_points[--ent->parsed->n_intro_points];
 
314
        break;
 
315
      }
283
316
    }
284
317
  }
285
318
 
286
319
  if (!ent->parsed->n_intro_points) {
287
 
    log_fn(LOG_INFO,"No more intro points remain for %s. Re-fetching descriptor.",
288
 
           safe_str(query));
 
320
    log_info(LD_REND,
 
321
             "No more intro points remain for %s. Re-fetching descriptor.",
 
322
             escaped_safe_str(query));
289
323
    rend_client_refetch_renddesc(query);
290
324
 
291
325
    /* move all pending streams back to renddesc_wait */
296
330
 
297
331
    return 0;
298
332
  }
299
 
  log_fn(LOG_INFO,"%d options left for %s.",
300
 
         ent->parsed->n_intro_points, safe_str(query));
 
333
  log_info(LD_REND,"%d options left for %s.",
 
334
           ent->parsed->n_intro_points, escaped_safe_str(query));
301
335
  return 1;
302
336
}
303
337
 
305
339
 * the circuit to C_REND_READY.
306
340
 */
307
341
int
308
 
rend_client_rendezvous_acked(circuit_t *circ, const char *request, size_t request_len)
 
342
rend_client_rendezvous_acked(circuit_t *circ, const char *request,
 
343
                             size_t request_len)
309
344
{
310
345
  /* we just got an ack for our establish-rendezvous. switch purposes. */
311
346
  if (circ->purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
312
 
    log_fn(LOG_WARN,"Got a rendezvous ack when we weren't expecting one. Closing circ.");
313
 
    circuit_mark_for_close(circ);
 
347
    log_warn(LD_PROTOCOL,"Got a rendezvous ack when we weren't expecting one. "
 
348
             "Closing circ.");
 
349
    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
314
350
    return -1;
315
351
  }
316
 
  log_fn(LOG_INFO,"Got rendezvous ack. This circuit is now ready for rendezvous.");
 
352
  log_info(LD_REND,"Got rendezvous ack. This circuit is now ready for "
 
353
           "rendezvous.");
317
354
  circ->purpose = CIRCUIT_PURPOSE_C_REND_READY;
318
355
  return 0;
319
356
}
320
357
 
321
358
/** Bob sent us a rendezvous cell; join the circuits. */
322
359
int
323
 
rend_client_receive_rendezvous(circuit_t *circ, const char *request, size_t request_len)
 
360
rend_client_receive_rendezvous(circuit_t *circ, const char *request,
 
361
                               size_t request_len)
324
362
{
325
363
  crypt_path_t *hop;
326
364
  char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];
328
366
  if ((circ->purpose != CIRCUIT_PURPOSE_C_REND_READY &&
329
367
       circ->purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
330
368
      || !circ->build_state->pending_final_cpath) {
331
 
    log_fn(LOG_WARN,"Got rendezvous2 cell from Bob, but not expecting it. Closing.");
332
 
    circuit_mark_for_close(circ);
 
369
    log_warn(LD_PROTOCOL,"Got rendezvous2 cell from hidden service, but not "
 
370
             "expecting it. Closing.");
 
371
    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
333
372
    return -1;
334
373
  }
335
374
 
336
375
  if (request_len != DH_KEY_LEN+DIGEST_LEN) {
337
 
    log_fn(LOG_WARN,"Incorrect length (%d) on RENDEZVOUS2 cell.",(int)request_len);
 
376
    log_warn(LD_PROTOCOL,"Incorrect length (%d) on RENDEZVOUS2 cell.",
 
377
             (int)request_len);
338
378
    goto err;
339
379
  }
340
380
 
345
385
  tor_assert(hop->dh_handshake_state);
346
386
  if (crypto_dh_compute_secret(hop->dh_handshake_state, request, DH_KEY_LEN,
347
387
                               keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
348
 
    log_fn(LOG_WARN, "Couldn't complete DH handshake");
 
388
    log_warn(LD_GENERAL, "Couldn't complete DH handshake.");
349
389
    goto err;
350
390
  }
351
391
  /* ... and set up cpath. */
354
394
 
355
395
  /* Check whether the digest is right... */
356
396
  if (memcmp(keys, request+DH_KEY_LEN, DIGEST_LEN)) {
357
 
    log_fn(LOG_WARN, "Incorrect digest of key material");
 
397
    log_warn(LD_PROTOCOL, "Incorrect digest of key material.");
358
398
    goto err;
359
399
  }
360
400
 
374
414
  circ->build_state->pending_final_cpath = NULL; /* prevent double-free */
375
415
  return 0;
376
416
 err:
377
 
  circuit_mark_for_close(circ);
 
417
  circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
378
418
  return -1;
379
419
}
380
420
 
383
423
 * with at least one intro point, move them to the next state;
384
424
 * else fail them.
385
425
 */
386
 
void rend_client_desc_here(char *query) {
 
426
void
 
427
rend_client_desc_here(const char *query)
 
428
{
387
429
  connection_t *conn;
388
430
  rend_cache_entry_t *entry;
389
431
  time_t now = time(NULL);
390
 
 
391
 
  while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP,
392
 
                                 AP_CONN_STATE_RENDDESC_WAIT, query))) {
393
 
    if (rend_cache_lookup_entry(conn->rend_query, &entry) == 1 &&
 
432
  int i, n_conns;
 
433
  connection_t **carray;
 
434
 
 
435
  get_connection_array(&carray, &n_conns);
 
436
 
 
437
  for (i = 0; i < n_conns; ++i) {
 
438
    conn = carray[i];
 
439
    if (conn->type != CONN_TYPE_AP ||
 
440
        conn->state != AP_CONN_STATE_RENDDESC_WAIT ||
 
441
        conn->marked_for_close ||
 
442
        rend_cmp_service_ids(query, conn->rend_query))
 
443
      continue;
 
444
    assert_connection_ok(conn, now);
 
445
    if (rend_cache_lookup_entry(conn->rend_query, -1, &entry) == 1 &&
394
446
        entry->parsed->n_intro_points > 0) {
395
447
      /* either this fetch worked, or it failed but there was a
396
448
       * valid entry from before which we should reuse */
397
 
      log_fn(LOG_INFO,"Rend desc is usable. Launching circuits.");
 
449
      log_info(LD_REND,"Rend desc is usable. Launching circuits.");
398
450
      conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
399
451
 
400
452
      /* restart their timeout values, so they get a fair shake at
405
457
 
406
458
      if (connection_ap_handshake_attach_circuit(conn) < 0) {
407
459
        /* it will never work */
408
 
        log_fn(LOG_WARN,"attaching to a rend circ failed. Closing conn.");
 
460
        log_warn(LD_REND,"Rendezvous attempt failed. Closing.");
409
461
        connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
410
462
      }
411
 
      tor_assert(conn->state != AP_CONN_STATE_RENDDESC_WAIT); /* avoid loop */
412
463
    } else { /* 404, or fetch didn't get that far */
413
 
      log_fn(LOG_NOTICE,"Closing stream for '%s.onion': hidden service is unavailable (try again later).", safe_str(query));
 
464
      log_notice(LD_REND,"Closing stream for '%s.onion': hidden service is "
 
465
                 "unavailable (try again later).", safe_str(query));
414
466
      connection_mark_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
415
467
    }
416
468
  }
417
469
}
418
470
 
419
 
/** strdup a nickname for a random introduction
420
 
 * point of query. return NULL if error.
 
471
/** Return a newly allocated extend_info_t* for a randomly chosen introduction
 
472
 * point for the named hidden service.  Return NULL if all introduction points
 
473
 * have been tried and failed.
421
474
 */
422
 
char *rend_client_get_random_intro(char *query) {
 
475
extend_info_t *
 
476
rend_client_get_random_intro(const char *query)
 
477
{
423
478
  int i;
424
 
  smartlist_t *sl;
425
 
  char *choice;
426
 
  char *nickname;
427
479
  rend_cache_entry_t *entry;
428
480
 
429
 
  if (rend_cache_lookup_entry(query, &entry) < 1) {
430
 
    log_fn(LOG_WARN,"query '%s' didn't have valid rend desc in cache. Failing.",
431
 
           safe_str(query));
432
 
    return NULL;
433
 
  }
434
 
 
435
 
  sl = smartlist_create();
436
 
 
437
 
  /* add the intro point nicknames */
438
 
  for (i=0;i<entry->parsed->n_intro_points;i++)
439
 
    smartlist_add(sl,entry->parsed->intro_points[i]);
440
 
 
441
 
  choice = smartlist_choose(sl);
442
 
  if (!choice) {
443
 
    smartlist_free(sl);
444
 
    return NULL;
445
 
  }
446
 
  nickname = tor_strdup(choice);
447
 
  smartlist_free(sl);
448
 
  return nickname;
 
481
  if (rend_cache_lookup_entry(query, -1, &entry) < 1) {
 
482
    log_warn(LD_REND,
 
483
             "Query '%s' didn't have valid rend desc in cache. Failing.",
 
484
             safe_str(query));
 
485
    return NULL;
 
486
  }
 
487
 
 
488
 again:
 
489
  if (!entry->parsed->n_intro_points)
 
490
    return NULL;
 
491
 
 
492
  i = crypto_rand_int(entry->parsed->n_intro_points);
 
493
 
 
494
  if (entry->parsed->intro_point_extend_info) {
 
495
    return extend_info_dup(entry->parsed->intro_point_extend_info[i]);
 
496
  } else {
 
497
    /* add the intro point nicknames */
 
498
    char *choice = entry->parsed->intro_points[i];
 
499
    routerinfo_t *router = router_get_by_nickname(choice, 0);
 
500
    if (!router) {
 
501
      log_info(LD_REND, "Unknown router with nickname '%s'; trying another.",
 
502
               choice);
 
503
      tor_free(choice);
 
504
      entry->parsed->intro_points[i] =
 
505
        entry->parsed->intro_points[--entry->parsed->n_intro_points];
 
506
      goto again;
 
507
    }
 
508
    return extend_info_from_router(router);
 
509
  }
449
510
}
450
511