circuit.c 31.1 KB
Newer Older
1
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
2
3
/* See LICENSE for licensing information */
/* $Id$ */
Roger Dingledine's avatar
Roger Dingledine committed
4
5
6

#include "or.h"

7
8
extern or_options_t options; /* command-line and config-file options */

Roger Dingledine's avatar
Roger Dingledine committed
9
10
static void circuit_free_cpath(crypt_path_t *cpath);
static void circuit_free_cpath_node(crypt_path_t *victim);
11
static circ_id_t get_unique_circ_id_by_addr_port(uint32_t addr, uint16_t port, int circ_id_type);  
Roger Dingledine's avatar
Roger Dingledine committed
12

13
14
15
unsigned long stats_n_relay_cells_relayed = 0;
unsigned long stats_n_relay_cells_delivered = 0;

Roger Dingledine's avatar
Roger Dingledine committed
16
17
/********* START VARIABLES **********/

Roger Dingledine's avatar
Roger Dingledine committed
18
static circuit_t *global_circuitlist=NULL;
Roger Dingledine's avatar
Roger Dingledine committed
19

20
21
char *circuit_state_to_string[] = {
  "receiving the onion",    /* 0 */
22
23
24
  "waiting to process create", /* 1 */
  "connecting to firsthop", /* 2 */
  "open"                    /* 3 */
25
26
};

Roger Dingledine's avatar
Roger Dingledine committed
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/********* END VARIABLES ************/

void circuit_add(circuit_t *circ) {

  if(!global_circuitlist) { /* first one */
    global_circuitlist = circ;
    circ->next = NULL;
  } else {
    circ->next = global_circuitlist;
    global_circuitlist = circ;
  }

}

void circuit_remove(circuit_t *circ) {
  circuit_t *tmpcirc;

Roger Dingledine's avatar
Roger Dingledine committed
44
  assert(circ && global_circuitlist);
Roger Dingledine's avatar
Roger Dingledine committed
45
46
47
48
49
50
51
52
53
54
55
56
57
58

  if(global_circuitlist == circ) {
    global_circuitlist = global_circuitlist->next;
    return;
  }

  for(tmpcirc = global_circuitlist;tmpcirc->next;tmpcirc = tmpcirc->next) {
    if(tmpcirc->next == circ) {
      tmpcirc->next = circ->next;
      return;
    }
  }
}

59
circuit_t *circuit_new(circ_id_t p_circ_id, connection_t *p_conn) {
Roger Dingledine's avatar
Roger Dingledine committed
60
61
  circuit_t *circ; 

62
  circ = (circuit_t *)tor_malloc(sizeof(circuit_t));
Roger Dingledine's avatar
Roger Dingledine committed
63
64
  memset(circ,0,sizeof(circuit_t)); /* zero it out */

65
  circ->timestamp_created = time(NULL);
66

67
  circ->p_circ_id = p_circ_id;
Roger Dingledine's avatar
Roger Dingledine committed
68
69
  circ->p_conn = p_conn;

70
  circ->state = CIRCUIT_STATE_ONIONSKIN_PENDING;
Roger Dingledine's avatar
Roger Dingledine committed
71

72
73
74
  /* CircIDs */
  circ->p_circ_id = p_circ_id;
  /* circ->n_circ_id remains 0 because we haven't identified the next hop yet */
Roger Dingledine's avatar
Roger Dingledine committed
75

76
77
  circ->package_window = CIRCWINDOW_START;
  circ->deliver_window = CIRCWINDOW_START;
78

Roger Dingledine's avatar
Roger Dingledine committed
79
80
81
82
83
84
  circuit_add(circ);

  return circ;
}

void circuit_free(circuit_t *circ) {
85
86
87
88
  if (circ->n_crypto)
    crypto_free_cipher_env(circ->n_crypto);
  if (circ->p_crypto)
    crypto_free_cipher_env(circ->p_crypto);
89
  circuit_free_cpath(circ->cpath);
Roger Dingledine's avatar
Roger Dingledine committed
90
  free(circ);
91
92
}

Roger Dingledine's avatar
Roger Dingledine committed
93
static void circuit_free_cpath(crypt_path_t *cpath) {
94
  crypt_path_t *victim, *head=cpath;
95

96
97
98
99
100
101
102
103
104
105
106
107
108
  if(!cpath)
    return;

  /* it's a doubly linked list, so we have to notice when we've
   * gone through it once. */
  while(cpath->next && cpath->next != head) {
    victim = cpath;
    cpath = victim->next;
    circuit_free_cpath_node(victim);
  }

  circuit_free_cpath_node(cpath);
}
Roger Dingledine's avatar
Roger Dingledine committed
109

Roger Dingledine's avatar
Roger Dingledine committed
110
static void circuit_free_cpath_node(crypt_path_t *victim) {
111
112
113
114
  if(victim->f_crypto)
    crypto_free_cipher_env(victim->f_crypto);
  if(victim->b_crypto)
    crypto_free_cipher_env(victim->b_crypto);
115
116
  if(victim->handshake_state)
    crypto_dh_free(victim->handshake_state);
117
  free(victim);
Roger Dingledine's avatar
Roger Dingledine committed
118
119
}

120
121
122
/* return 0 if can't get a unique circ_id. */
static circ_id_t get_unique_circ_id_by_addr_port(uint32_t addr, uint16_t port, int circ_id_type) {
  circ_id_t test_circ_id;
Roger Dingledine's avatar
Roger Dingledine committed
123
  connection_t *conn;
124
  uint16_t high_bit;
125

126
  high_bit = (circ_id_type == CIRC_ID_TYPE_HIGHER) ? 1<<15 : 0;
127
  conn = connection_exact_get_by_addr_port(addr,port);
128
  /* XXX race condition: if conn is marked_for_close it won't be noticed */
129
  if (!conn)
Roger Dingledine's avatar
Roger Dingledine committed
130
    return (1|high_bit); /* No connection exists; conflict is impossible. */
131

132
  do {
133
134
135
    /* Sequentially iterate over test_circ_id=1...1<<15-1 until we find an
     * circID such that (high_bit|test_circ_id) is not already used. */
    /* XXX Will loop forever if all circ_id's in our range are used.
Roger Dingledine's avatar
Roger Dingledine committed
136
     * This matters because it's an external DoS vulnerability. */
137
138
139
140
    test_circ_id = conn->next_circ_id++;
    if (test_circ_id == 0 || test_circ_id >= 1<<15) {
      test_circ_id = 1;
      conn->next_circ_id = 2;
141
    }
142
143
144
    test_circ_id |= high_bit;
  } while(circuit_get_by_circ_id_conn(test_circ_id, conn));
  return test_circ_id;
Roger Dingledine's avatar
Roger Dingledine committed
145
146
}

147
circuit_t *circuit_enumerate_by_naddr_nport(circuit_t *circ, uint32_t naddr, uint16_t nport) {
148

149
150
151
152
153
  if(!circ) /* use circ if it's defined, else start from the beginning */
    circ = global_circuitlist; 
  else
    circ = circ->next;

154
  for( ; circ; circ = circ->next) {
155
156
157
158
159
160
    if(circ->n_addr == naddr && circ->n_port == nport)
       return circ;
  }
  return NULL;
}

161
circuit_t *circuit_get_by_circ_id_conn(circ_id_t circ_id, connection_t *conn) {
Roger Dingledine's avatar
Roger Dingledine committed
162
  circuit_t *circ;
163
  connection_t *tmpconn;
Roger Dingledine's avatar
Roger Dingledine committed
164
165

  for(circ=global_circuitlist;circ;circ = circ->next) {
166
    if(circ->p_circ_id == circ_id) {
167
168
169
      if(circ->p_conn == conn)
        return circ;
      for(tmpconn = circ->p_streams; tmpconn; tmpconn = tmpconn->next_stream) {
170
171
172
173
        if(tmpconn == conn)
          return circ;
      }
    }
174
    if(circ->n_circ_id == circ_id) {
175
176
177
      if(circ->n_conn == conn)
        return circ;
      for(tmpconn = circ->n_streams; tmpconn; tmpconn = tmpconn->next_stream) {
178
179
180
181
        if(tmpconn == conn)
          return circ;
      }
    }
Roger Dingledine's avatar
Roger Dingledine committed
182
183
184
185
186
187
  }
  return NULL;
}

circuit_t *circuit_get_by_conn(connection_t *conn) {
  circuit_t *circ;
188
  connection_t *tmpconn;
Roger Dingledine's avatar
Roger Dingledine committed
189
190

  for(circ=global_circuitlist;circ;circ = circ->next) {
191
192
193
194
195
    if(circ->p_conn == conn)
      return circ;
    if(circ->n_conn == conn)
      return circ;
    for(tmpconn = circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream)
196
197
      if(tmpconn == conn)
        return circ;
198
    for(tmpconn = circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream)
199
200
      if(tmpconn == conn)
        return circ;
Roger Dingledine's avatar
Roger Dingledine committed
201
202
203
204
  }
  return NULL;
}

Roger Dingledine's avatar
Roger Dingledine committed
205
circuit_t *circuit_get_newest_open(void) {
206
  circuit_t *circ, *bestcirc=NULL;
207
208

  for(circ=global_circuitlist;circ;circ = circ->next) {
Roger Dingledine's avatar
Roger Dingledine committed
209
    if(circ->cpath && circ->state == CIRCUIT_STATE_OPEN && circ->n_conn && (!bestcirc ||
210
      bestcirc->timestamp_created < circ->timestamp_created)) {
211
212
      log_fn(LOG_DEBUG,"Choosing circuit %s:%d:%d.", circ->n_conn->address, circ->n_port, circ->n_circ_id);
      assert(circ->n_circ_id);
213
      bestcirc = circ;
214
215
    }
  }
216
  return bestcirc;
217
218
}

219
220
221
222
223
int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ,
                               int cell_direction, crypt_path_t *layer_hint) {
  connection_t *conn=NULL;
  char recognized=0;
  char buf[256];
224
225
226
227

  assert(cell && circ);
  assert(cell_direction == CELL_DIRECTION_OUT || cell_direction == CELL_DIRECTION_IN); 

228
229
  buf[0] = cell->length;
  memcpy(buf+1, cell->payload, CELL_PAYLOAD_SIZE);
Roger Dingledine's avatar
Roger Dingledine committed
230

231
  log_fn(LOG_DEBUG,"direction %d, streamid %d before crypt.", cell_direction, *(int*)(cell->payload+1));
232

233
  if(relay_crypt(circ, buf, 1+CELL_PAYLOAD_SIZE, cell_direction, &layer_hint, &recognized, &conn) < 0) {
Roger Dingledine's avatar
Roger Dingledine committed
234
    log_fn(LOG_WARN,"relay crypt failed. Dropping connection.");
Roger Dingledine's avatar
Roger Dingledine committed
235
236
237
    return -1;
  }

238
239
240
241
242
  cell->length = buf[0];
  memcpy(cell->payload, buf+1, CELL_PAYLOAD_SIZE);

  if(recognized) {
    if(cell_direction == CELL_DIRECTION_OUT) {
243
      ++stats_n_relay_cells_delivered;
244
      log_fn(LOG_DEBUG,"Sending to exit.");
245
      return connection_edge_process_relay_cell(cell, circ, conn, EDGE_EXIT, NULL);
246
247
    }
    if(cell_direction == CELL_DIRECTION_IN) {
248
      ++stats_n_relay_cells_delivered;
249
      log_fn(LOG_DEBUG,"Sending to AP.");
250
      return connection_edge_process_relay_cell(cell, circ, conn, EDGE_AP, layer_hint);
251
    }
Roger Dingledine's avatar
Roger Dingledine committed
252
  }
253

254
  ++stats_n_relay_cells_relayed;
255
256
257
258
259
260
  /* not recognized. pass it on. */
  if(cell_direction == CELL_DIRECTION_OUT)
    conn = circ->n_conn;
  else
    conn = circ->p_conn;

261
  if(!conn) { //|| !connection_speaks_cells(conn)) {
262
    log_fn(LOG_INFO,"Didn't recognize cell (%d), but circ stops here! Dropping.", *(int *)(cell->payload+1));
263
    return 0;
264
  }
265

266
  log_fn(LOG_DEBUG,"Passing on unrecognized cell.");
Nick Mathewson's avatar
Nick Mathewson committed
267
  connection_or_write_cell_to_buf(cell, conn);
268
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
269
270
}

271
int relay_crypt(circuit_t *circ, char *in, int inlen, char cell_direction,
272
                crypt_path_t **layer_hint, char *recognized, connection_t **conn) {
273
  crypt_path_t *thishop;
274
  char out[256];
Roger Dingledine's avatar
Roger Dingledine committed
275

276
  assert(circ && in && recognized && conn);
Roger Dingledine's avatar
Roger Dingledine committed
277

278
  assert(inlen < 256);
Roger Dingledine's avatar
Roger Dingledine committed
279

Roger Dingledine's avatar
Roger Dingledine committed
280
  if(cell_direction == CELL_DIRECTION_IN) { 
281
    if(circ->cpath) { /* we're at the beginning of the circuit. We'll want to do layered crypts. */
282
      thishop = circ->cpath;
283
      if(thishop->state != CPATH_STATE_OPEN) {
Roger Dingledine's avatar
Roger Dingledine committed
284
        log_fn(LOG_WARN,"Relay cell before first created cell?");
285
286
        return -1;
      }
287
      do { /* Remember: cpath is in forward order, that is, first hop first. */
288
        assert(thishop);
289

290
        log_fn(LOG_DEBUG,"before decrypt: %d",*(int*)(in+2));
291
292
        /* decrypt */
        if(crypto_cipher_decrypt(thishop->b_crypto, in, inlen, out)) {
Roger Dingledine's avatar
Roger Dingledine committed
293
          log_fn(LOG_WARN,"Error performing onion decryption: %s", crypto_perror());
294
295
296
          return -1;
        }
        memcpy(in,out,inlen);
297
        log_fn(LOG_DEBUG,"after decrypt: %d",*(int*)(in+2));
298

299
300
        if( (*recognized = relay_check_recognized(circ, cell_direction, in+2, conn))) {
          *layer_hint = thishop;
301
          return 0;
302
        }
303

304
        thishop = thishop->next;
305
      } while(thishop != circ->cpath && thishop->state == CPATH_STATE_OPEN);
306
      log_fn(LOG_INFO,"in-cell at OP not recognized. Dropping.");
307
      return 0;
308
    } else { /* we're in the middle. Just one crypt. */
309

310
      log_fn(LOG_DEBUG,"before encrypt: %d",*(int*)(in+2));
311
      if(crypto_cipher_encrypt(circ->p_crypto, in, inlen, out)) {
312
313
        log_fn(LOG_WARN,"Onion encryption failed for circID %u: %s",
               circ->p_circ_id, crypto_perror());
314
315
316
        return -1;
      }
      memcpy(in,out,inlen);
317
      log_fn(LOG_DEBUG,"after encrypt: %d",*(int*)(in+2));
318

319
      log_fn(LOG_DEBUG,"Skipping recognized check, because we're not the OP.");
320
321
      /* don't check for recognized. only the OP can recognize a stream on the way back. */

Roger Dingledine's avatar
Roger Dingledine committed
322
    }
Roger Dingledine's avatar
Roger Dingledine committed
323
  } else if(cell_direction == CELL_DIRECTION_OUT) { 
324
    if(circ->cpath) { /* we're at the beginning of the circuit. We'll want to do layered crypts. */
325

326
      thishop = *layer_hint; /* we already know which layer, from when we package_raw_inbuf'ed */
327
328
329
      /* moving from last to first hop */
      do {
        assert(thishop);
330

331
        log_fn(LOG_DEBUG,"before encrypt: %d",*(int*)(in+2));
332
        if(crypto_cipher_encrypt(thishop->f_crypto, in, inlen, out)) {
Roger Dingledine's avatar
Roger Dingledine committed
333
          log_fn(LOG_WARN,"Error performing encryption: %s", crypto_perror());
334
335
336
          return -1;
        }
        memcpy(in,out,inlen);
337
        log_fn(LOG_DEBUG,"after encrypt: %d",*(int*)(in+2));
338

339
340
        thishop = thishop->prev;
      } while(thishop != circ->cpath->prev);
341
    } else { /* we're in the middle. Just one crypt. */
342

343
      if(crypto_cipher_decrypt(circ->n_crypto,in, inlen, out)) {
344
345
        log_fn(LOG_WARN,"Decryption failed for circID %u: %s",
               circ->n_circ_id, crypto_perror());
346
347
348
        return -1;
      }
      memcpy(in,out,inlen);
349
350
351
352

      if( (*recognized = relay_check_recognized(circ, cell_direction, in+2, conn)))
        return 0;

Roger Dingledine's avatar
Roger Dingledine committed
353
    }
354
  } else {
355
    log_fn(LOG_ERR,"unknown cell direction %d.", cell_direction);
356
    assert(0);
Roger Dingledine's avatar
Roger Dingledine committed
357
358
  }

359
360
361
  return 0;
}

362
363
364
365
int relay_check_recognized(circuit_t *circ, int cell_direction, char *stream, connection_t **conn) {
/* FIXME can optimize by passing thishop in */
  connection_t *tmpconn;

366
  if(!memcmp(stream,ZERO_STREAM,STREAM_ID_SIZE)) {
367
    log_fn(LOG_DEBUG,"It's the zero stream. Recognized.");
368
    return 1; /* the zero stream is always recognized */
369
  }
370
  log_fn(LOG_DEBUG,"not the zero stream.");
371
372

  if(cell_direction == CELL_DIRECTION_OUT)
373
    tmpconn = circ->n_streams;
374
  else
375
    tmpconn = circ->p_streams;
376

377
  if(!tmpconn) {
378
    log_fn(LOG_DEBUG,"No conns. Not recognized.");
379
    return 0;
380
381
382
383
  }

  for( ; tmpconn; tmpconn=tmpconn->next_stream) {
    if(!memcmp(stream,tmpconn->stream_id, STREAM_ID_SIZE)) {
384
      log_fn(LOG_DEBUG,"recognized stream %d.", *(int*)stream);
385
386
387
      *conn = tmpconn;
      return 1;
    }
388
    log_fn(LOG_DEBUG,"considered stream %d, not it.",*(int*)tmpconn->stream_id);
389
390
  }

391
  log_fn(LOG_DEBUG,"Didn't recognize on this iteration of decryption.");
392
393
394
395
  return 0;

}

396
void circuit_resume_edge_reading(circuit_t *circ, int edge_type, crypt_path_t *layer_hint) {
397
398
399
400
  connection_t *conn;

  assert(edge_type == EDGE_EXIT || edge_type == EDGE_AP);

401
  log_fn(LOG_DEBUG,"resuming");
402

Roger Dingledine's avatar
   
Roger Dingledine committed
403
  if(edge_type == EDGE_EXIT)
404
    conn = circ->n_streams;
Roger Dingledine's avatar
   
Roger Dingledine committed
405
  else
406
    conn = circ->p_streams;
Roger Dingledine's avatar
   
Roger Dingledine committed
407

408
  for( ; conn; conn=conn->next_stream) {
409
410
    if((edge_type == EDGE_EXIT && conn->package_window > 0) ||
       (edge_type == EDGE_AP   && conn->package_window > 0 && conn->cpath_layer == layer_hint)) {
411
      connection_start_reading(conn);
Nick Mathewson's avatar
Nick Mathewson committed
412
      connection_edge_package_raw_inbuf(conn); /* handle whatever might still be on the inbuf */
413
414
415

      /* If the circuit won't accept any more data, return without looking
       * at any more of the streams. Any connections that should be stopped
Nick Mathewson's avatar
Nick Mathewson committed
416
       * have already been stopped by connection_edge_package_raw_inbuf. */
417
418
      if(circuit_consider_stop_edge_reading(circ, edge_type, layer_hint))
        return;
419
420
421
422
423
    }
  }
}

/* returns 1 if the window is empty, else 0. If it's empty, tell edge conns to stop reading. */
424
int circuit_consider_stop_edge_reading(circuit_t *circ, int edge_type, crypt_path_t *layer_hint) {
425
426
427
  connection_t *conn = NULL;

  assert(edge_type == EDGE_EXIT || edge_type == EDGE_AP);
428
  assert(edge_type == EDGE_EXIT || layer_hint);
429

430
  log_fn(LOG_DEBUG,"considering");
431
  if(edge_type == EDGE_EXIT && circ->package_window <= 0)
432
    conn = circ->n_streams;
433
  else if(edge_type == EDGE_AP && layer_hint->package_window <= 0)
434
    conn = circ->p_streams;
435
436
437
  else
    return 0;

438
  for( ; conn; conn=conn->next_stream)
439
440
    if(!layer_hint || conn->cpath_layer == layer_hint)
      connection_stop_reading(conn);
441

442
  log_fn(LOG_DEBUG,"yes. stopped.");
443
444
445
  return 1;
}

446
447
int circuit_consider_sending_sendme(circuit_t *circ, int edge_type, crypt_path_t *layer_hint) {
  cell_t cell;
Roger Dingledine's avatar
Roger Dingledine committed
448

449
450
  assert(circ);

451
452
453
454
  memset(&cell, 0, sizeof(cell_t));
  cell.command = CELL_RELAY;
  SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_SENDME);
  SET_CELL_STREAM_ID(cell, ZERO_STREAM);
455

456
  cell.length = RELAY_HEADER_SIZE;
457
  if(edge_type == EDGE_AP) { /* i'm the AP */
458
    cell.circ_id = circ->n_circ_id;
459
    while(layer_hint->deliver_window < CIRCWINDOW_START-CIRCWINDOW_INCREMENT) {
460
      log_fn(LOG_DEBUG,"deliver_window %d, Queueing sendme forward.", layer_hint->deliver_window);
461
      layer_hint->deliver_window += CIRCWINDOW_INCREMENT;
462
      if(circuit_deliver_relay_cell(&cell, circ, CELL_DIRECTION_OUT, layer_hint) < 0) {
Roger Dingledine's avatar
   
Roger Dingledine committed
463
464
        return -1;
      }
465
466
    }
  } else if(edge_type == EDGE_EXIT) { /* i'm the exit */
467
    cell.circ_id = circ->p_circ_id;
468
    while(circ->deliver_window < CIRCWINDOW_START-CIRCWINDOW_INCREMENT) {
469
      log_fn(LOG_DEBUG,"deliver_window %d, Queueing sendme back.", circ->deliver_window);
470
      circ->deliver_window += CIRCWINDOW_INCREMENT;
471
      if(circuit_deliver_relay_cell(&cell, circ, CELL_DIRECTION_IN, layer_hint) < 0) {
Roger Dingledine's avatar
   
Roger Dingledine committed
472
473
        return -1;
      }
474
475
    }
  }
Roger Dingledine's avatar
Roger Dingledine committed
476
477
478
479
  return 0;
}

void circuit_close(circuit_t *circ) {
480
  connection_t *conn;
481
  circuit_t *youngest=NULL;
482

483
  assert(circ);
484
  if(options.SocksPort) {
Roger Dingledine's avatar
Roger Dingledine committed
485
    youngest = circuit_get_newest_open();
486
    log_fn(LOG_DEBUG,"youngest %d, circ %d.",(int)youngest, (int)circ);
487
  }
Roger Dingledine's avatar
Roger Dingledine committed
488
  circuit_remove(circ);
489
  if(circ->n_conn)
490
    connection_send_destroy(circ->n_circ_id, circ->n_conn);
491
  for(conn=circ->n_streams; conn; conn=conn->next_stream) {
492
    connection_send_destroy(circ->n_circ_id, conn); 
493
  }
494
  if(circ->p_conn)
495
    connection_send_destroy(circ->n_circ_id, circ->p_conn);
496
  for(conn=circ->p_streams; conn; conn=conn->next_stream) {
497
    connection_send_destroy(circ->p_circ_id, conn); 
498
  }
499
  if(options.SocksPort && youngest == circ) { /* check this after we've sent the destroys, to reduce races */
500
    /* our current circuit just died. Launch another one pronto. */
501
    log_fn(LOG_INFO,"Youngest circuit dying. Launching a replacement.");
502
503
    circuit_launch_new(1);
  }
Roger Dingledine's avatar
Roger Dingledine committed
504
505
506
507
508
509
510
511
512
  circuit_free(circ);
}

void circuit_about_to_close_connection(connection_t *conn) {
  /* send destroys for all circuits using conn */
  /* currently, we assume it's too late to flush conn's buf here.
   * down the road, maybe we'll consider that eof doesn't mean can't-write
   */
  circuit_t *circ;
513
  connection_t *prevconn;
514

515
516
517
518
519
520
521
522
523
524
  switch(conn->type) {
    case CONN_TYPE_OR:
      /* We must close all the circuits on it. */
      while((circ = circuit_get_by_conn(conn))) {
        if(circ->n_conn == conn) /* it's closing in front of us */
          circ->n_conn = NULL;
        if(circ->p_conn == conn) /* it's closing behind us */
          circ->p_conn = NULL;
        circuit_close(circ);
      }  
525
      return;
526
527
    case CONN_TYPE_AP:
    case CONN_TYPE_EXIT:
528

529
530
531
532
      /* It's an edge conn. Need to remove it from the linked list of
       * conn's for this circuit. Confirm that 'end' relay command has
       * been sent. But don't kill the circuit.
       */
Roger Dingledine's avatar
Roger Dingledine committed
533

534
535
536
537
538
539
      circ = circuit_get_by_conn(conn);
      if(!circ)
        return;

      if(!conn->has_sent_end) {
        log_fn(LOG_INFO,"Edge connection hasn't sent end yet? Bug.");
Roger Dingledine's avatar
Roger Dingledine committed
540
        connection_edge_end(conn, END_STREAM_REASON_MISC, conn->cpath_layer);
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
      }

      if(conn == circ->p_streams) {
        circ->p_streams = conn->next_stream;
        return;
      }
      if(conn == circ->n_streams) {
        circ->n_streams = conn->next_stream;
        return;
      }
      for(prevconn = circ->p_streams; prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn = prevconn->next_stream) ;
      if(prevconn && prevconn->next_stream) {
        prevconn->next_stream = conn->next_stream;
        return;
      }
      for(prevconn = circ->n_streams; prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn = prevconn->next_stream) ;
      if(prevconn && prevconn->next_stream) {
        prevconn->next_stream = conn->next_stream;
        return;
      }
      log_fn(LOG_ERR,"edge conn not in circuit's list?");
      assert(0); /* should never get here */
  } /* end switch */
Roger Dingledine's avatar
Roger Dingledine committed
564
565
}

566

567
/* FIXME this now leaves some out */
568
void circuit_dump_by_conn(connection_t *conn, int severity) {
569
  circuit_t *circ;
570
  connection_t *tmpconn;
571
572

  for(circ=global_circuitlist;circ;circ = circ->next) {
573
    if(circ->p_conn == conn)
574
575
      log(severity, "Conn %d has App-ward circuit:  circID %d (other side %d), state %d (%s)",
        conn->poll_index, circ->p_circ_id, circ->n_circ_id, circ->state, circuit_state_to_string[circ->state]);
576
    for(tmpconn=circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream) {
577
      if(tmpconn == conn) {
578
579
        log(severity,"Conn %d has App-ward circuit:  circID %d (other side %d), state %d (%s)",
          conn->poll_index, circ->p_circ_id, circ->n_circ_id, circ->state, circuit_state_to_string[circ->state]);
580
      }
581
    }
582
    if(circ->n_conn == conn)
583
584
      log(severity,"Conn %d has Exit-ward circuit: circID %d (other side %d), state %d (%s)",
        conn->poll_index, circ->n_circ_id, circ->p_circ_id, circ->state, circuit_state_to_string[circ->state]);
585
    for(tmpconn=circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream) {
586
      if(tmpconn == conn) {
587
588
        log(severity,"Conn %d has Exit-ward circuit: circID %d (other side %d), state %d (%s)",
          conn->poll_index, circ->n_circ_id, circ->p_circ_id, circ->state, circuit_state_to_string[circ->state]);
589
      }
590
591
592
593
    }
  }
}

594
595
596
597
void circuit_expire_unused_circuits(void) {
  circuit_t *circ, *tmpcirc;
  circuit_t *youngest;

Roger Dingledine's avatar
Roger Dingledine committed
598
  youngest = circuit_get_newest_open();
599
600
601
602
603

  circ = global_circuitlist;
  while(circ) {
    tmpcirc = circ;
    circ = circ->next;
604
    if(tmpcirc != youngest && !tmpcirc->p_conn && !tmpcirc->p_streams) {
605
      log_fn(LOG_DEBUG,"Closing n_circ_id %d",tmpcirc->n_circ_id);
606
607
608
609
610
611
612
613
614
615
616
617
      circuit_close(tmpcirc);
    }
  }
}

/* failure_status code: negative means reset failures to 0. Other values mean
 * add that value to the current number of failures, then if we don't have too
 * many failures on record, try to make a new circuit.
 */
void circuit_launch_new(int failure_status) {
  static int failures=0;

618
  if(!options.SocksPort) /* we're not an application proxy. no need for circuits. */
619
620
    return;

621
622
623
624
625
626
627
628
629
630
  if(failure_status == -1) { /* I was called because a circuit succeeded */
    failures = 0;
    return;
  }

  failures += failure_status;

retry_circuit:

  if(failures > 5) {
631
    log_fn(LOG_INFO,"Giving up for now, %d failures.", failures);
632
633
634
    return;
  }

635
  if(circuit_establish_circuit() < 0) {
636
637
638
639
640
641
642
643
    failures++;
    goto retry_circuit;
  }

  failures = 0;
  return;
}

644
int circuit_establish_circuit(void) {
645
646
647
648
  routerinfo_t *firsthop;
  connection_t *n_conn;
  circuit_t *circ;

649
  circ = circuit_new(0, NULL); /* sets circ->p_circ_id and circ->p_conn */
650
  circ->state = CIRCUIT_STATE_OR_WAIT;
651
652
  circ->cpath = onion_generate_cpath(&firsthop);
  if(!circ->cpath) {
653
    log_fn(LOG_INFO,"Generating cpath failed.");
654
655
656
657
658
    circuit_close(circ);
    return -1;
  }

  /* now see if we're already connected to the first OR in 'route' */
659

660
  log_fn(LOG_DEBUG,"Looking for firsthop '%s:%u'",
661
662
663
664
665
      firsthop->address,firsthop->or_port);
  n_conn = connection_twin_get_by_addr_port(firsthop->addr,firsthop->or_port);
  if(!n_conn || n_conn->state != OR_CONN_STATE_OPEN) { /* not currently connected */
    circ->n_addr = firsthop->addr;
    circ->n_port = firsthop->or_port;
666
    if(options.OnionRouter) { /* we would be connected if he were up. but he's not. */
667
      log_fn(LOG_INFO,"Route's firsthop isn't connected.");
668
669
670
671
672
      circuit_close(circ); 
      return -1;
    }

    if(!n_conn) { /* launch the connection */
673
      n_conn = connection_or_connect(firsthop);
674
      if(!n_conn) { /* connect failed, forget the whole thing */
675
        log_fn(LOG_INFO,"connect to firsthop failed. Closing.");
676
677
678
679
680
        circuit_close(circ);
        return -1;
      }
    }

681
    log_fn(LOG_DEBUG,"connecting in progress (or finished). Good.");
682
683
684
685
686
687
    return 0; /* return success. The onion/circuit/etc will be taken care of automatically
               * (may already have been) whenever n_conn reaches OR_CONN_STATE_OPEN.
               */ 
  } else { /* it (or a twin) is already open. use it. */
    circ->n_addr = n_conn->addr;
    circ->n_port = n_conn->port;
688
    circ->n_conn = n_conn;
689
    log_fn(LOG_DEBUG,"Conn open. Delivering first onion skin.");
690
    if(circuit_send_next_onion_skin(circ) < 0) {
691
      log_fn(LOG_INFO,"circuit_send_next_onion_skin failed.");
692
693
694
      circuit_close(circ);
      return -1;
    }
695
  }
696
  return 0;
697
698
699
700
701
702
}

/* find circuits that are waiting on me, if any, and get them to send the onion */
void circuit_n_conn_open(connection_t *or_conn) {
  circuit_t *circ;

703
  log_fn(LOG_DEBUG,"Starting.");
704
705
706
707
708
  circ = circuit_enumerate_by_naddr_nport(NULL, or_conn->addr, or_conn->port);
  for(;;) {
    if(!circ)
      return;

709
    log_fn(LOG_DEBUG,"Found circ, sending onion skin.");
710
711
    circ->n_conn = or_conn;
    if(circuit_send_next_onion_skin(circ) < 0) {
712
      log_fn(LOG_INFO,"send_next_onion_skin failed; circuit marked for closing.");
713
714
715
716
717
718
719
      circuit_close(circ);
      return; /* FIXME will want to try the other circuits too? */
    }
    circ = circuit_enumerate_by_naddr_nport(circ, or_conn->addr, or_conn->port);
  }
}

720
int circuit_send_next_onion_skin(circuit_t *circ) {
721
  cell_t cell;
722
723
  crypt_path_t *hop;
  routerinfo_t *router;
724

725
  assert(circ && circ->cpath);
726

727
  if(circ->cpath->state == CPATH_STATE_CLOSED) {
728

729
    log_fn(LOG_DEBUG,"First skin; sending create cell.");
730
    circ->n_circ_id = get_unique_circ_id_by_addr_port(circ->n_addr, circ->n_port, CIRC_ID_TYPE_BOTH);
731

732
    memset(&cell, 0, sizeof(cell_t));
733
    cell.command = CELL_CREATE;
734
    cell.circ_id = circ->n_circ_id;
735
    cell.length = DH_ONIONSKIN_LEN;
736

737
    if(onion_skin_create(circ->n_conn->onion_pkey, &(circ->cpath->handshake_state), cell.payload) < 0) {
Roger Dingledine's avatar
Roger Dingledine committed
738
      log_fn(LOG_WARN,"onion_skin_create (first hop) failed.");
739
740
741
      return -1;
    }

Nick Mathewson's avatar
Nick Mathewson committed
742
    connection_or_write_cell_to_buf(&cell, circ->n_conn);
743
744
745

    circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
    circ->state = CIRCUIT_STATE_BUILDING;
746
    log_fn(LOG_DEBUG,"first skin; finished sending create cell.");
747
748
749
  } else {
    assert(circ->cpath->state == CPATH_STATE_OPEN);
    assert(circ->state == CIRCUIT_STATE_BUILDING);
750
    log_fn(LOG_DEBUG,"starting to send subsequent skin.");
751
752
753
754
755
    for(hop=circ->cpath->next;
        hop != circ->cpath && hop->state == CPATH_STATE_OPEN;
        hop=hop->next) ;
    if(hop == circ->cpath) { /* done building the circuit. whew. */
      circ->state = CIRCUIT_STATE_OPEN;
756
      log_fn(LOG_INFO,"circuit built!");
757
758
759
      /* Tell any AP connections that have been waiting for a new
       * circuit that one is ready. */
      connection_ap_attach_pending();
760
761
762
763
764
      return 0;
    }

    router = router_get_by_addr_port(hop->addr,hop->port);
    if(!router) {
Roger Dingledine's avatar
Roger Dingledine committed
765
      log_fn(LOG_WARN,"couldn't lookup router %d:%d",hop->addr,hop->port);
766
767
768
769
770
      return -1;
    }

    memset(&cell, 0, sizeof(cell_t));
    cell.command = CELL_RELAY; 
771
    cell.circ_id = circ->n_circ_id;
772
773
774
    SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_EXTEND);
    SET_CELL_STREAM_ID(cell, ZERO_STREAM);

775
    cell.length = RELAY_HEADER_SIZE + 6 + DH_ONIONSKIN_LEN;
776
    *(uint32_t*)(cell.payload+RELAY_HEADER_SIZE) = htonl(hop->addr);
Nick Mathewson's avatar
Nick Mathewson committed
777
    *(uint16_t*)(cell.payload+RELAY_HEADER_SIZE+4) = htons(hop->port);
778
    if(onion_skin_create(router->onion_pkey, &(hop->handshake_state), cell.payload+RELAY_HEADER_SIZE+6) < 0) {
Roger Dingledine's avatar
Roger Dingledine committed
779
      log_fn(LOG_WARN,"onion_skin_create failed.");
780
781
782
      return -1;
    }

783
    log_fn(LOG_DEBUG,"Sending extend relay cell.");
784
    /* send it to hop->prev, because it will transfer it to a create cell and then send to hop */
785
    if(circuit_deliver_relay_cell(&cell, circ, CELL_DIRECTION_OUT, hop->prev) < 0) {
Roger Dingledine's avatar
Roger Dingledine committed
786
      log_fn(LOG_WARN,"failed to deliver extend cell. Closing.");
787
788
789
790
791
792
793
      return -1;
    }
    hop->state = CPATH_STATE_AWAITING_KEYS;
  }
  return 0;
}

794
795
796
/* take the 'extend' cell, pull out addr/port plus the onion skin. Make
 * sure we're connected to the next hop, and pass it the onion skin in
 * a create cell.
797
798
799
 */
int circuit_extend(cell_t *cell, circuit_t *circ) {
  connection_t *n_conn;
800
  int circ_id_type;
801
802
  cell_t newcell;

803
  if(circ->n_conn) {
Roger Dingledine's avatar
Roger Dingledine committed
804
    log_fn(LOG_WARN,"n_conn already set. Bug/attack. Closing.");
805
806
807
    return -1;
  }

808
809
810
811
812
813
814
815
816
817
818
  circ->n_addr = ntohl(*(uint32_t*)(cell->payload+RELAY_HEADER_SIZE));
  circ->n_port = ntohs(*(uint16_t*)(cell->payload+RELAY_HEADER_SIZE+4));

  n_conn = connection_twin_get_by_addr_port(circ->n_addr,circ->n_port);
  if(!n_conn || n_conn->type != CONN_TYPE_OR) {
    /* i've disabled making connections through OPs, but it's definitely
     * possible here. I'm not sure if it would be a bug or a feature. -RD
     */
    /* note also that this will close circuits where the onion has the same
     * router twice in a row in the path. i think that's ok. -RD
     */
819
820
821
    struct in_addr in;
    in.s_addr = htonl(circ->n_addr);
    log_fn(LOG_DEBUG,"Next router (%s:%d) not connected. Closing.", inet_ntoa(in), circ->n_port);
822
823
824
825
826
827
828
829
    /* XXX later we should fail more gracefully here, like with a 'truncated' */
    return -1;
  }

  circ->n_addr = n_conn->addr; /* these are different if we found a twin instead */
  circ->n_port = n_conn->port;

  circ->n_conn = n_conn;
830
  log_fn(LOG_DEBUG,"n_conn is %s:%u",n_conn->address,n_conn->port);
831

832
  circ_id_type = decide_circ_id_type(options.Nickname, n_conn->nickname);
833

834
835
836
837
  log_fn(LOG_DEBUG,"circ_id_type = %u.",circ_id_type);
  circ->n_circ_id = get_unique_circ_id_by_addr_port(circ->n_addr, circ->n_port, circ_id_type);
  if(!circ->n_circ_id) {
    log_fn(LOG_WARN,"failed to get unique circID.");
838
839
    return -1;
  }
840
  log_fn(LOG_DEBUG,"Chosen circID %u.",circ->n_circ_id);
841
842
843

  memset(&newcell, 0, sizeof(cell_t));
  newcell.command = CELL_CREATE;
844
  newcell.circ_id = circ->n_circ_id;
845
  newcell.length = DH_ONIONSKIN_LEN;
846

847
  memcpy(newcell.payload, cell->payload+RELAY_HEADER_SIZE+6, DH_ONIONSKIN_LEN);
848

Nick Mathewson's avatar
Nick Mathewson committed
849
  connection_or_write_cell_to_buf(&newcell, circ->n_conn);
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
  return 0;
}

int circuit_finish_handshake(circuit_t *circ, char *reply) {
  unsigned char iv[16];
  unsigned char keys[32];
  crypt_path_t *hop;

  memset(iv, 0, 16);

  assert(circ->cpath);
  if(circ->cpath->state == CPATH_STATE_AWAITING_KEYS)
    hop = circ->cpath;
  else {
    for(hop=circ->cpath->next;
        hop != circ->cpath && hop->state == CPATH_STATE_OPEN;
        hop=hop->next) ;
    if(hop == circ->cpath) { /* got an extended when we're all done? */
Roger Dingledine's avatar
Roger Dingledine committed
868
      log_fn(LOG_WARN,"got extended when circ already built? Closing.");
869
      return -1;
870
871
872
873
874
    }
  }
  assert(hop->state == CPATH_STATE_AWAITING_KEYS);

  if(onion_skin_client_handshake(hop->handshake_state, reply, keys, 32) < 0) {
Roger Dingledine's avatar
Roger Dingledine committed
875
    log_fn(LOG_WARN,"onion_skin_client_handshake failed.");
876
877
878
879
880
881
    return -1;
  }

  crypto_dh_free(hop->handshake_state); /* don't need it anymore */
  hop->handshake_state = NULL;

882
  log_fn(LOG_DEBUG,"hop %d init cipher forward %d, backward %d.", (uint32_t)hop, *(uint32_t*)keys, *(uint32_t*)(keys+16));
883
  if (!(hop->f_crypto =
Nick Mathewson's avatar
src/or    
Nick Mathewson committed
884
        crypto_create_init_cipher(CIRCUIT_CIPHER,keys,iv,1))) {
Roger Dingledine's avatar
Roger Dingledine committed
885
    log(LOG_WARN,"forward cipher initialization failed.");
886
887
888
889
    return -1;
  }

  if (!(hop->b_crypto =
Nick Mathewson's avatar
src/or    
Nick Mathewson committed
890
        crypto_create_init_cipher(CIRCUIT_CIPHER,keys+16,iv,0))) {
Roger Dingledine's avatar
Roger Dingledine committed
891
    log(LOG_WARN,"backward cipher initialization failed.");
892
893
    return -1;
  }
894

895
  hop->state = CPATH_STATE_OPEN;
896
  log_fn(LOG_INFO,"finished");
897
898
899
  return 0;
}

900
901
902
903
904
905
906
907
908
909
int circuit_truncated(circuit_t *circ, crypt_path_t *layer) {
  crypt_path_t *victim;
  connection_t *stream;

  assert(circ);
  assert(layer);

  while(layer->next != circ->cpath) {
    /* we need to clear out layer->next */
    victim = layer->next;
910
    log_fn(LOG_DEBUG, "Killing a layer of the cpath.");
911
912
913

    for(stream = circ-&g