connection_edge.c 46 KB
Newer Older
1
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
2
3
4
5
/* See LICENSE for licensing information */
/* $Id$ */

#include "or.h"
6
#include "tree.h"
7
8

extern or_options_t options; /* command-line and config-file options */
9
extern char *conn_state_to_string[][_CONN_TYPE_MAX+1];
10

11
12
13
static int connection_ap_handshake_process_socks(connection_t *conn);

static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ);
14
static void connection_edge_consider_sending_sendme(connection_t *conn);
15

16
17
18
static uint32_t client_dns_lookup_entry(const char *address);
static void client_dns_set_entry(const char *address, uint32_t val);

19
void relay_header_pack(char *dest, const relay_header_t *src) {
20
21
  *(uint8_t*)(dest) = src->command;

22
23
  set_uint16(dest+1, htons(src->recognized));
  set_uint16(dest+3, htons(src->stream_id));
24
  memcpy(dest+5, src->integrity, 4);
25
  set_uint16(dest+9, htons(src->length));
26
27
28
}

void relay_header_unpack(relay_header_t *dest, const char *src) {
29
30
  dest->command = *(uint8_t*)(src);

31
32
  dest->recognized = ntohs(get_uint16(src+1));
  dest->stream_id = ntohs(get_uint16(src+3));
33
  memcpy(dest->integrity, src+5, 4);
34
  dest->length = ntohs(get_uint16(src+9));
35
36
}

37
38
39
/* mark and return -1 if there was an unexpected error with the conn,
 * else return 0.
 */
40
41
42
43
44
45
46
int connection_edge_process_inbuf(connection_t *conn) {

  assert(conn);
  assert(conn->type == CONN_TYPE_AP || conn->type == CONN_TYPE_EXIT);

  if(conn->inbuf_reached_eof) {
#ifdef HALF_OPEN
Roger Dingledine's avatar
Roger Dingledine committed
47
    /* eof reached; we're done reading, but we might want to write more. */
48
49
    conn->done_receiving = 1;
    shutdown(conn->s, 0); /* XXX check return, refactor NM */
50
    if (conn->done_sending) {
51
      connection_mark_for_close(conn, END_STREAM_REASON_DONE);
52
53
54
55
    } else {
      connection_edge_send_command(conn, circuit_get_by_conn(conn), RELAY_COMMAND_END,
                                   NULL, 0, conn->cpath_layer);
    }
56
    return 0;
Roger Dingledine's avatar
Roger Dingledine committed
57
#else
58
    /* eof reached, kill it. */
59
    log_fn(LOG_INFO,"conn (fd %d) reached eof. Closing.", conn->s);
60
    connection_mark_for_close(conn, END_STREAM_REASON_DONE);
61
62
    conn->hold_open_until_flushed = 1; /* just because we shouldn't read
                                          doesn't mean we shouldn't write */
63
    return 0;
64
65
66
67
68
#endif
  }

  switch(conn->state) {
    case AP_CONN_STATE_SOCKS_WAIT:
69
      if(connection_ap_handshake_process_socks(conn) < 0) {
70
        connection_mark_for_close(conn, END_STREAM_REASON_MISC);
71
        conn->hold_open_until_flushed = 1;
72
73
74
        return -1;
      }
      return 0;
75
76
    case AP_CONN_STATE_OPEN:
    case EXIT_CONN_STATE_OPEN:
77
      if(conn->package_window <= 0) {
78
        /* XXX this is still getting called rarely :( */
79
80
81
        log_fn(LOG_WARN,"called with package_window %d. Tell Roger.", conn->package_window);
        return 0;
      }
82
      if(connection_edge_package_raw_inbuf(conn) < 0) {
83
        connection_mark_for_close(conn, END_STREAM_REASON_MISC);
84
85
        return -1;
      }
86
87
      return 0;
    case EXIT_CONN_STATE_CONNECTING:
88
    case AP_CONN_STATE_RENDDESC_WAIT:
89
90
91
92
    case AP_CONN_STATE_CIRCUIT_WAIT:
    case AP_CONN_STATE_CONNECT_WAIT:
      log_fn(LOG_INFO,"data from edge while in '%s' state. Leaving it on buffer.",
                      conn_state_to_string[conn->type][conn->state]);
93
94
      return 0;
  }
95
  log_fn(LOG_WARN,"Got unexpected state %d. Closing.",conn->state);
96
  connection_mark_for_close(conn, END_STREAM_REASON_MISC);
97
  return -1;
98
99
}

100
101
102
int connection_edge_destroy(uint16_t circ_id, connection_t *conn) {
  assert(conn->type == CONN_TYPE_AP || conn->type == CONN_TYPE_EXIT);

103
104
  if(conn->marked_for_close)
    return 0; /* already marked; probably got an 'end' */
105
106
107
108
  log_fn(LOG_INFO,"CircID %d: At an edge. Marking connection for close.",
         circ_id);
  conn->has_sent_end = 1; /* we're closing the circuit, nothing to send to */
  connection_mark_for_close(conn, END_STREAM_REASON_DESTROY);
109
  conn->hold_open_until_flushed = 1;
110
111
112
  return 0;
}

Roger Dingledine's avatar
Roger Dingledine committed
113
static char *connection_edge_end_reason(char *payload, uint16_t length) {
114
115
116
117
  if(length < 1) {
    log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1.");
    return "MALFORMED";
  }
118
  if(*payload < _MIN_END_STREAM_REASON || *payload > _MAX_END_STREAM_REASON) {
119
120
121
122
123
124
125
126
127
128
    log_fn(LOG_WARN,"Reason for ending (%d) not recognized.",*payload);
    return "MALFORMED";
  }
  switch(*payload) {
    case END_STREAM_REASON_MISC:           return "misc error";
    case END_STREAM_REASON_RESOLVEFAILED:  return "resolve failed";
    case END_STREAM_REASON_CONNECTFAILED:  return "connect failed";
    case END_STREAM_REASON_EXITPOLICY:     return "exit policy failed";
    case END_STREAM_REASON_DESTROY:        return "destroyed";
    case END_STREAM_REASON_DONE:           return "closed normally";
129
    case END_STREAM_REASON_TIMEOUT:        return "gave up (timeout)";
130
131
132
133
134
  }
  assert(0);
  return "";
}

135
int connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_layer) {
136
137
138
  char payload[5];
  int payload_len=1;
  circuit_t *circ;
139
140
141

  if(conn->has_sent_end) {
    log_fn(LOG_WARN,"It appears I've already sent the end. Are you calling me twice?");
142
    return -1;
143
144
  }

145
146
  payload[0] = reason;
  if(reason == END_STREAM_REASON_EXITPOLICY) {
147
148
    /* this is safe even for rend circs, because they never fail
     * because of exitpolicy */
149
    set_uint32(payload+1, htonl(conn->addr));
Roger Dingledine's avatar
Roger Dingledine committed
150
    payload_len += 4;
151
152
153
  }

  circ = circuit_get_by_conn(conn);
154
  if(circ && !circ->marked_for_close) {
155
156
157
    log_fn(LOG_DEBUG,"Marking conn (fd %d) and sending end.",conn->s);
    connection_edge_send_command(conn, circ, RELAY_COMMAND_END,
                                 payload, payload_len, cpath_layer);
158
159
  } else {
    log_fn(LOG_DEBUG,"Marking conn (fd %d); no circ to send end.",conn->s);
160
161
162
  }

  conn->has_sent_end = 1;
163
  return 0;
164
165
}

166
167
168
169
170
171
172
173
174
/* Make a relay cell out of 'relay_command' and 'payload', and
 * send it onto the open circuit 'circ'. If it's a control cell,
 * set fromconn to NULL, else it's the stream that's sending the
 * relay cell. Use cpath_layer NULL if you're responding to the OP;
 * If it's an outgoing cell it must specify the destination hop.
 *
 * If you can't send the cell, mark the circuit for close and
 * return -1. Else return 0.
 */
175
int connection_edge_send_command(connection_t *fromconn, circuit_t *circ,
Nick Mathewson's avatar
Nick Mathewson committed
176
                                 int relay_command, const char *payload,
177
                                 int payload_len, crypt_path_t *cpath_layer) {
178
  cell_t cell;
179
  relay_header_t rh;
180
  int cell_direction;
181
182

  if(!circ) {
183
    log_fn(LOG_WARN,"no circ. Closing conn.");
184
    assert(fromconn);
185
    connection_mark_for_close(fromconn, 0);
186
    return -1;
187
188
189
  }

  memset(&cell, 0, sizeof(cell_t));
190
  cell.command = CELL_RELAY;
191
  if(cpath_layer) {
192
    cell.circ_id = circ->n_circ_id;
193
194
    cell_direction = CELL_DIRECTION_OUT;
  } else {
195
    cell.circ_id = circ->p_circ_id;
196
197
198
    cell_direction = CELL_DIRECTION_IN;
  }

199
200
201
202
203
204
205
206
  memset(&rh, 0, sizeof(rh));
  rh.command = relay_command;
  if(fromconn)
    rh.stream_id = fromconn->stream_id; /* else it's 0 */
  rh.length = payload_len;
  relay_header_pack(cell.payload, &rh);
  if(payload_len)
    memcpy(cell.payload+RELAY_HEADER_SIZE, payload, payload_len);
207

Roger Dingledine's avatar
Roger Dingledine committed
208
  log_fn(LOG_DEBUG,"delivering %d cell %s.", relay_command,
209
         cell_direction == CELL_DIRECTION_OUT ? "forward" : "backward");
210

211
212
  if(circuit_package_relay_cell(&cell, circ, cell_direction, cpath_layer) < 0) {
    log_fn(LOG_WARN,"circuit_package_relay_cell failed. Closing.");
213
    circuit_mark_for_close(circ);
214
    return -1;
215
  }
216
  return 0;
217
218
}

219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
int connection_edge_process_relay_cell_not_open(
    relay_header_t *rh, cell_t *cell, circuit_t *circ,
    connection_t *conn, crypt_path_t *layer_hint) {
  uint32_t addr;

  if(rh->command == RELAY_COMMAND_END) {
    log_fn(LOG_INFO,"Edge got end (%s) before we're connected. Marking for close.",
      connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, rh->length));
    if(CIRCUIT_IS_ORIGIN(circ))
      circuit_log_path(LOG_INFO,circ);
    conn->has_sent_end = 1; /* we just got an 'end', don't need to send one */
    connection_mark_for_close(conn, 0);
    /* XXX This is where we should check if reason is EXITPOLICY, and reattach */
    /* XXX here we should send a socks reject back if necessary, and hold
     * open til flushed */
    return 0;
  }
  if(conn->type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_CONNECTED) {
    if(conn->state != AP_CONN_STATE_CONNECT_WAIT) {
      log_fn(LOG_WARN,"Got 'connected' while not in state connect_wait. Dropping.");
      return 0;
    }
//    log_fn(LOG_INFO,"Connected! Notifying application.");
    conn->state = AP_CONN_STATE_OPEN;
    if (rh->length >= 4) {
      addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE));
      client_dns_set_entry(conn->socks_request->address, addr);
    }
    log_fn(LOG_INFO,"'connected' received after %d seconds.",
           (int)(time(NULL) - conn->timestamp_lastread));
    circuit_log_path(LOG_INFO,circ);
    connection_ap_handshake_socks_reply(conn, NULL, 0, 1);
    conn->socks_request->has_finished = 1;
    /* handle anything that might have queued */
    if (connection_edge_package_raw_inbuf(conn) < 0) {
      connection_mark_for_close(conn, END_STREAM_REASON_MISC);
      return 0;
    }
    return 0;
  } else {
    log_fn(LOG_WARN,"Got an unexpected relay command %d, in state %d (%s). Closing.",
           rh->command, conn->state, conn_state_to_string[conn->type][conn->state]);
    connection_mark_for_close(conn, END_STREAM_REASON_MISC);
    return -1;
  }
}

266
267
/* an incoming relay cell has arrived. return -1 if you want to tear down the
 * circuit, else 0. */
268
int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
269
                                       connection_t *conn,
270
                                       crypt_path_t *layer_hint) {
271
  static int num_seen=0;
272
  uint32_t addr;
273
  relay_header_t rh;
274
275
276

  assert(cell && circ);

277
278
  relay_header_unpack(&rh, cell->payload);
//  log_fn(LOG_DEBUG,"command %d stream %d", rh.command, rh.stream_id);
279
  num_seen++;
280
  log_fn(LOG_DEBUG,"Now seen %d relay cells here.", num_seen);
281

282
283
  /* either conn is NULL, in which case we've got a control cell, or else
   * conn points to the recognized stream. */
284

285
286
287
288
289
  if(conn &&
     conn->state != AP_CONN_STATE_OPEN &&
     conn->state != EXIT_CONN_STATE_OPEN) {
    return connection_edge_process_relay_cell_not_open(
             &rh, cell, circ, conn, layer_hint);
290
291
  }

292
  switch(rh.command) {
293
294
295
    case RELAY_COMMAND_DROP:
      log_fn(LOG_INFO,"Got a relay-level padding cell. Dropping.");
      return 0;
296
    case RELAY_COMMAND_BEGIN:
297
      if (layer_hint &&
298
          circ->purpose != CIRCUIT_PURPOSE_S_REND_JOINED) {
Roger Dingledine's avatar
Roger Dingledine committed
299
        log_fn(LOG_WARN,"relay begin request unsupported at AP. Dropping.");
300
301
        return 0;
      }
302
      if(conn) {
Roger Dingledine's avatar
Roger Dingledine committed
303
        log_fn(LOG_WARN,"begin cell for known stream. Dropping.");
304
305
        return 0;
      }
306
307
      connection_exit_begin_conn(cell, circ);
      return 0;
308
    case RELAY_COMMAND_DATA:
309
      ++stats_n_data_cells_received;
310
311
      if((layer_hint && --layer_hint->deliver_window < 0) ||
         (!layer_hint && --circ->deliver_window < 0)) {
Roger Dingledine's avatar
Roger Dingledine committed
312
        log_fn(LOG_WARN,"(relay data) circ deliver_window below 0. Killing.");
313
        connection_mark_for_close(conn, END_STREAM_REASON_MISC);
314
        return -1;
315
      }
316
      log_fn(LOG_DEBUG,"circ deliver_window now %d.", layer_hint ?
317
             layer_hint->deliver_window : circ->deliver_window);
318

319
      circuit_consider_sending_sendme(circ, layer_hint);
320

321
      if(!conn) {
322
        log_fn(LOG_INFO,"data cell dropped, unknown stream.");
323
324
        return 0;
      }
325
326

      if(--conn->deliver_window < 0) { /* is it below 0 after decrement? */
Roger Dingledine's avatar
Roger Dingledine committed
327
        log_fn(LOG_WARN,"(relay data) conn deliver_window below 0. Killing.");
328
329
330
        return -1; /* somebody's breaking protocol. kill the whole circuit. */
      }

331
      stats_n_data_bytes_received += rh.length;
332
      connection_write_to_buf(cell->payload + RELAY_HEADER_SIZE,
333
                              rh.length, conn);
334
      connection_edge_consider_sending_sendme(conn);
335
      return 0;
336
    case RELAY_COMMAND_END:
337
      if(!conn) {
338
339
        log_fn(LOG_INFO,"end cell (%s) dropped, unknown stream.",
          connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, rh.length));
340
341
        return 0;
      }
342
      if(rh.length >= 5 &&
343
         *(cell->payload+RELAY_HEADER_SIZE) == END_STREAM_REASON_EXITPOLICY) {
344
345
346
347

        /* XXX this will never be reached, since we're in 'connect_wait' state
         * but this is only reached when we're in 'open' state. Put it higher. */

348
349
        /* No need to close the connection. We'll hold it open while
         * we try a new exit node.
Roger Dingledine's avatar
Roger Dingledine committed
350
         * cell->payload+RELAY_HEADER_SIZE+1 holds the destination addr.
351
         */
352
        addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+1));
Roger Dingledine's avatar
Roger Dingledine committed
353
        client_dns_set_entry(conn->socks_request->address, addr);
354
        conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
355
        if(connection_ap_handshake_attach_circuit(conn) >= 0)
356
357
          return 0;
        /* else, conn will get closed below */
358
      }
359
/* XXX add to this log_fn the exit node's nickname? */
360
      log_fn(LOG_INFO,"end cell (%s) for stream %d. Removing stream.",
361
362
        connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, rh.length),
        conn->stream_id);
363
364
365
366

#ifdef HALF_OPEN
      conn->done_sending = 1;
      shutdown(conn->s, 1); /* XXX check return; refactor NM */
367
      if (conn->done_receiving) {
Roger Dingledine's avatar
Roger Dingledine committed
368
369
370
        /* We just *got* an end; no reason to send one. */
        conn->has_sent_end = 1;
        connection_mark_for_close(conn, 0);
371
        conn->hold_open_until_flushed = 1;
372
373
      }
#else
374
375
376
      /* We just *got* an end; no reason to send one. */
      conn->has_sent_end = 1;
      connection_mark_for_close(conn, 0);
377
      conn->hold_open_until_flushed = 1;
378
#endif
379
      return 0;
380
381
    case RELAY_COMMAND_EXTEND:
      if(conn) {
Roger Dingledine's avatar
Roger Dingledine committed
382
        log_fn(LOG_WARN,"'extend' for non-zero stream. Dropping.");
383
384
385
386
        return 0;
      }
      return circuit_extend(cell, circ);
    case RELAY_COMMAND_EXTENDED:
387
388
      if(!layer_hint) {
        log_fn(LOG_WARN,"'extended' unsupported at non-origin. Dropping.");
389
390
        return 0;
      }
391
      log_fn(LOG_DEBUG,"Got an extended cell! Yay.");
392
      if(circuit_finish_handshake(circ, cell->payload+RELAY_HEADER_SIZE) < 0) {
Roger Dingledine's avatar
Roger Dingledine committed
393
        log_fn(LOG_WARN,"circuit_finish_handshake failed.");
394
395
        return -1;
      }
396
      if (circuit_send_next_onion_skin(circ)<0) {
397
        log_fn(LOG_INFO,"circuit_send_next_onion_skin() failed.");
398
399
400
        return -1;
      }
      return 0;
401
    case RELAY_COMMAND_TRUNCATE:
402
403
      if(layer_hint) {
        log_fn(LOG_WARN,"'truncate' unsupported at origin. Dropping.");
404
405
406
        return 0;
      }
      if(circ->n_conn) {
407
        connection_send_destroy(circ->n_circ_id, circ->n_conn);
408
409
        circ->n_conn = NULL;
      }
410
      log_fn(LOG_DEBUG, "Processed 'truncate', replying.");
411
412
413
      connection_edge_send_command(NULL, circ, RELAY_COMMAND_TRUNCATED,
                                   NULL, 0, NULL);
      return 0;
414
    case RELAY_COMMAND_TRUNCATED:
415
416
      if(!layer_hint) {
        log_fn(LOG_WARN,"'truncated' unsupported at non-origin. Dropping.");
417
418
        return 0;
      }
419
420
      circuit_truncated(circ, layer_hint);
      return 0;
421
    case RELAY_COMMAND_CONNECTED:
422
      if(conn) {
423
        log_fn(LOG_WARN,"'connected' unsupported while open. Closing circ.");
424
425
426
427
        return -1;
      }
      log_fn(LOG_INFO,"'connected' received, no conn attached anymore. Ignoring.");
      return 0;
428
    case RELAY_COMMAND_SENDME:
429
      if(!conn) {
430
        if(layer_hint) {
431
          layer_hint->package_window += CIRCWINDOW_INCREMENT;
432
          log_fn(LOG_DEBUG,"circ-level sendme at origin, packagewindow %d.",
433
                 layer_hint->package_window);
434
          circuit_resume_edge_reading(circ, layer_hint);
435
436
        } else {
          circ->package_window += CIRCWINDOW_INCREMENT;
437
          log_fn(LOG_DEBUG,"circ-level sendme at non-origin, packagewindow %d.",
438
                 circ->package_window);
439
          circuit_resume_edge_reading(circ, layer_hint);
440
        }
441
442
        return 0;
      }
443
      conn->package_window += STREAMWINDOW_INCREMENT;
444
      log_fn(LOG_DEBUG,"stream-level sendme, packagewindow now %d.", conn->package_window);
445
      connection_start_reading(conn);
Nick Mathewson's avatar
Nick Mathewson committed
446
      connection_edge_package_raw_inbuf(conn); /* handle whatever might still be on the inbuf */
447
      return 0;
Nick Mathewson's avatar
Nick Mathewson committed
448
449
450
451
452
453
    case RELAY_COMMAND_ESTABLISH_INTRO:
    case RELAY_COMMAND_ESTABLISH_RENDEZVOUS:
    case RELAY_COMMAND_INTRODUCE1:
    case RELAY_COMMAND_INTRODUCE2:
    case RELAY_COMMAND_RENDEZVOUS1:
    case RELAY_COMMAND_RENDEZVOUS2:
Nick Mathewson's avatar
Nick Mathewson committed
454
455
    case RELAY_COMMAND_INTRO_ESTABLISHED:
    case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED:
Nick Mathewson's avatar
Nick Mathewson committed
456
457
458
      rend_process_relay_cell(circ, rh.command, rh.length,
                              cell->payload+RELAY_HEADER_SIZE);
      return 0;
459
  }
460
  log_fn(LOG_WARN,"unknown relay command %d.",rh.command);
461
  return -1;
462
463
464
}

int connection_edge_finished_flushing(connection_t *conn) {
465
  unsigned char connected_payload[4];
466
467
468
469
470
471
472
  int e, len=sizeof(e);

  assert(conn);
  assert(conn->type == CONN_TYPE_AP || conn->type == CONN_TYPE_EXIT);

  switch(conn->state) {
    case EXIT_CONN_STATE_CONNECTING:
473
      if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0)  { /* not yet */
474
        if(!ERRNO_CONN_EINPROGRESS(errno)) {
475
          /* yuck. kill it. */
476
          log_fn(LOG_DEBUG,"in-progress exit connect failed. Removing.");
477
          connection_mark_for_close(conn, END_STREAM_REASON_CONNECTFAILED);
478
479
          return -1;
        } else {
480
          log_fn(LOG_DEBUG,"in-progress exit connect still waiting.");
481
482
483
484
485
          return 0; /* no change, see if next time is better */
        }
      }
      /* the connect has finished. */

486
      log_fn(LOG_INFO,"Exit connection to %s:%u established.",
487
488
489
490
          conn->address,conn->port);

      conn->state = EXIT_CONN_STATE_OPEN;
      connection_watch_events(conn, POLLIN); /* stop writing, continue reading */
491
      if(connection_wants_to_flush(conn)) /* in case there are any queued relay cells */
492
        connection_start_writing(conn);
493
      /* deliver a 'connected' relay cell back through the circuit. */
494
      if(connection_edge_is_rendezvous_stream(conn)) {
495
496
497
498
499
500
501
502
503
        if(connection_edge_send_command(conn, circuit_get_by_conn(conn),
           RELAY_COMMAND_CONNECTED, NULL, 0, conn->cpath_layer) < 0)
          return 0; /* circuit is closed, don't continue */
      } else {
        *(uint32_t*)connected_payload = htonl(conn->addr);
        if(connection_edge_send_command(conn, circuit_get_by_conn(conn),
           RELAY_COMMAND_CONNECTED, connected_payload, 4, conn->cpath_layer) < 0)
          return 0; /* circuit is closed, don't continue */
      }
Roger Dingledine's avatar
Roger Dingledine committed
504
505
      assert(conn->package_window > 0);
      return connection_edge_process_inbuf(conn); /* in case the server has written anything */
506
507
508
    case AP_CONN_STATE_OPEN:
    case EXIT_CONN_STATE_OPEN:
      connection_stop_writing(conn);
509
      connection_edge_consider_sending_sendme(conn);
510
      return 0;
Roger Dingledine's avatar
Roger Dingledine committed
511
    case AP_CONN_STATE_SOCKS_WAIT:
512
    case AP_CONN_STATE_RENDDESC_WAIT:
513
    case AP_CONN_STATE_CIRCUIT_WAIT:
514
    case AP_CONN_STATE_CONNECT_WAIT:
Roger Dingledine's avatar
Roger Dingledine committed
515
516
      connection_stop_writing(conn);
      return 0;
517
    default:
518
      log_fn(LOG_WARN,"BUG: called in unexpected state %d.", conn->state);
519
      return -1;
520
521
522
523
  }
  return 0;
}

524
525
526
527
528
uint64_t stats_n_data_cells_packaged = 0;
uint64_t stats_n_data_bytes_packaged = 0;
uint64_t stats_n_data_cells_received = 0;
uint64_t stats_n_data_bytes_received = 0;

Nick Mathewson's avatar
Nick Mathewson committed
529
int connection_edge_package_raw_inbuf(connection_t *conn) {
530
531
  int amount_to_process, length;
  char payload[CELL_PAYLOAD_SIZE];
532
  circuit_t *circ;
Roger Dingledine's avatar
Roger Dingledine committed
533

534
535
  assert(conn);
  assert(!connection_speaks_cells(conn));
Roger Dingledine's avatar
Roger Dingledine committed
536

Nick Mathewson's avatar
Nick Mathewson committed
537
repeat_connection_edge_package_raw_inbuf:
Roger Dingledine's avatar
Roger Dingledine committed
538

539
540
  circ = circuit_get_by_conn(conn);
  if(!circ) {
541
    log_fn(LOG_INFO,"conn has no circuits! Closing.");
542
543
    return -1;
  }
Roger Dingledine's avatar
Roger Dingledine committed
544

545
  if(circuit_consider_stop_edge_reading(circ, conn->cpath_layer))
546
    return 0;
Roger Dingledine's avatar
Roger Dingledine committed
547

548
  if(conn->package_window <= 0) {
Roger Dingledine's avatar
Roger Dingledine committed
549
    log_fn(LOG_WARN,"called with package_window %d. Tell Roger.", conn->package_window);
550
551
552
    connection_stop_reading(conn);
    return 0;
  }
Roger Dingledine's avatar
Roger Dingledine committed
553

554
  amount_to_process = buf_datalen(conn->inbuf);
Roger Dingledine's avatar
Roger Dingledine committed
555

556
557
  if(!amount_to_process)
    return 0;
Roger Dingledine's avatar
Roger Dingledine committed
558
559
560

  if(amount_to_process > RELAY_PAYLOAD_SIZE) {
    length = RELAY_PAYLOAD_SIZE;
561
  } else {
562
    length = amount_to_process;
563
  }
564
  stats_n_data_bytes_packaged += length;
565
  stats_n_data_cells_packaged += 1;
Roger Dingledine's avatar
Roger Dingledine committed
566

567
568
  connection_fetch_from_buf(payload, length, conn);

Roger Dingledine's avatar
Roger Dingledine committed
569
  log_fn(LOG_DEBUG,"(%d) Packaging %d bytes (%d waiting).", conn->s, length,
570
         (int)buf_datalen(conn->inbuf));
Roger Dingledine's avatar
Roger Dingledine committed
571

572
573
574
  if(connection_edge_send_command(conn, circ, RELAY_COMMAND_DATA,
                               payload, length, conn->cpath_layer) < 0)
    return 0; /* circuit is closed, don't continue */
575

576
  if(!conn->cpath_layer) { /* non-rendezvous exit */
577
578
    assert(circ->package_window > 0);
    circ->package_window--;
579
  } else { /* we're an AP, or an exit on a rendezvous circ */
580
581
582
    assert(conn->cpath_layer->package_window > 0);
    conn->cpath_layer->package_window--;
  }
Roger Dingledine's avatar
Roger Dingledine committed
583

584
585
586
  if(--conn->package_window <= 0) { /* is it 0 after decrement? */
    connection_stop_reading(conn);
    log_fn(LOG_DEBUG,"conn->package_window reached 0.");
587
    circuit_consider_stop_edge_reading(circ, conn->cpath_layer);
588
589
590
    return 0; /* don't process the inbuf any more */
  }
  log_fn(LOG_DEBUG,"conn->package_window is now %d",conn->package_window);
Roger Dingledine's avatar
Roger Dingledine committed
591

592
  /* handle more if there's more, or return 0 if there isn't */
Nick Mathewson's avatar
Nick Mathewson committed
593
  goto repeat_connection_edge_package_raw_inbuf;
594
595
}

596
#define MAX_STREAM_RETRIES 4
597
598
599
void connection_ap_expire_beginning(void) {
  connection_t **carray;
  connection_t *conn;
600
  circuit_t *circ;
601
602
603
604
605
606
607
608
  int n, i;
  time_t now = time(NULL);

  get_connection_array(&carray, &n);

  for (i = 0; i < n; ++i) {
    conn = carray[i];
    if (conn->type != CONN_TYPE_AP ||
609
        conn->state != AP_CONN_STATE_CONNECT_WAIT)
610
      continue;
611
612
613
614
    if (now - conn->timestamp_lastread < 15)
      continue;
    conn->num_retries++;
    circ = circuit_get_by_conn(conn);
615
616
617
618
619
620
621
622
623
    if(circ->purpose == CIRCUIT_PURPOSE_C_REND_JOINED) {
      if (now - conn->timestamp_lastread > 45) {
        log_fn(LOG_WARN,"Rend stream is %d seconds late. Giving up.",
               (int)(now - conn->timestamp_lastread));
        connection_mark_for_close(conn,END_STREAM_REASON_TIMEOUT);
      }
      continue;
    }
    assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL);
624
625
626
627
628
629
    if(conn->num_retries >= MAX_STREAM_RETRIES) {
      log_fn(LOG_WARN,"Stream is %d seconds late. Giving up.",
             15*conn->num_retries);
      circuit_log_path(LOG_WARN, circ);
      connection_mark_for_close(conn,END_STREAM_REASON_TIMEOUT);
    } else {
630
      log_fn(LOG_WARN,"Stream is %d seconds late. Retrying.",
631
             (int)(now - conn->timestamp_lastread));
632
      circuit_log_path(LOG_WARN, circ);
633
634
635
636
      /* send an end down the circuit */
      connection_edge_end(conn, END_STREAM_REASON_TIMEOUT, conn->cpath_layer);
      /* un-mark it as ending, since we're going to reuse it */
      conn->has_sent_end = 0;
637
      /* move it back into 'pending' state. */
638
      conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
639
      circuit_detach_stream(circ, conn);
640
641
642
643
644
645
      /* kludge to make us not try this circuit again, yet to allow
       * current streams on it to survive if they can: make it
       * unattractive to use for new streams */
      assert(circ->timestamp_dirty);
      circ->timestamp_dirty -= options.NewCircuitPeriod;
      /* give our stream another 15 seconds to try */
646
      conn->timestamp_lastread += 15;
647
      /* attaching to a dirty circuit is fine */
648
      if(connection_ap_handshake_attach_circuit(conn)<0) {
649
        /* it will never work */
650
        /* Don't need to send end -- we're not connected */
651
        connection_mark_for_close(conn, 0);
652
      }
653
654
    } /* end if max_retries */
  } /* end for */
655
656
}

657
658
659
/* Tell any APs that are waiting for a new circuit that one is available */
void connection_ap_attach_pending(void)
{
660
  connection_t **carray;
661
  connection_t *conn;
662
663
664
665
666
  int n, i;

  get_connection_array(&carray, &n);

  for (i = 0; i < n; ++i) {
667
668
    conn = carray[i];
    if (conn->type != CONN_TYPE_AP ||
669
        conn->state != AP_CONN_STATE_CIRCUIT_WAIT)
670
      continue;
671
    if(connection_ap_handshake_attach_circuit(conn) < 0) {
672
      /* -1 means it will never work */
673
      /* Don't send end; there is no 'other side' yet */
674
      connection_mark_for_close(conn,0);
675
    }
676
677
678
  }
}

679
static void connection_edge_consider_sending_sendme(connection_t *conn) {
680
  circuit_t *circ;
681

682
  if(connection_outbuf_too_full(conn))
683
    return;
684

685
686
  circ = circuit_get_by_conn(conn);
  if(!circ) {
687
688
    /* this can legitimately happen if the destroy has already
     * arrived and torn down the circuit */
689
    log_fn(LOG_INFO,"No circuit associated with conn. Skipping.");
690
    return;
691
  }
692

693
694
695
  while(conn->deliver_window < STREAMWINDOW_START - STREAMWINDOW_INCREMENT) {
    log_fn(LOG_DEBUG,"Outbuf %d, Queueing stream sendme.", conn->outbuf_flushlen);
    conn->deliver_window += STREAMWINDOW_INCREMENT;
696
697
698
699
    if(connection_edge_send_command(conn, circ, RELAY_COMMAND_SENDME,
                                    NULL, 0, conn->cpath_layer) < 0) {
      log_fn(LOG_WARN,"connection_edge_send_command failed. Returning.");
      return; /* the circuit's closed, don't continue */
700
701
702
703
    }
  }
}

704
/* return -1 if an unexpected error with conn, else 0. */
705
static int connection_ap_handshake_process_socks(connection_t *conn) {
706
  socks_request_t *socks;
Roger Dingledine's avatar
Roger Dingledine committed
707
  int sockshere;
708
709

  assert(conn);
710
711
712
713
  assert(conn->type == CONN_TYPE_AP);
  assert(conn->state == AP_CONN_STATE_SOCKS_WAIT);
  assert(conn->socks_request);
  socks = conn->socks_request;
714
715
716

  log_fn(LOG_DEBUG,"entered.");

717
  sockshere = fetch_from_buf_socks(conn->inbuf, socks);
Roger Dingledine's avatar
Roger Dingledine committed
718
  if(sockshere == -1 || sockshere == 0) {
719
    if(socks->replylen) { /* we should send reply back */
Roger Dingledine's avatar
Roger Dingledine committed
720
      log_fn(LOG_DEBUG,"reply is already set for us. Using it.");
721
      connection_ap_handshake_socks_reply(conn, socks->reply, socks->replylen, 0);
Roger Dingledine's avatar
Roger Dingledine committed
722
    } else if(sockshere == -1) { /* send normal reject */
Roger Dingledine's avatar
Roger Dingledine committed
723
      log_fn(LOG_WARN,"Fetching socks handshake failed. Closing.");
Roger Dingledine's avatar
Roger Dingledine committed
724
725
726
727
      connection_ap_handshake_socks_reply(conn, NULL, 0, 0);
    } else {
      log_fn(LOG_DEBUG,"socks handshake not all here yet.");
    }
Roger Dingledine's avatar
Roger Dingledine committed
728
729
    if (sockshere == -1)
      conn->socks_request->has_finished = 1;
Roger Dingledine's avatar
Roger Dingledine committed
730
731
    return sockshere;
  } /* else socks handshake is done, continue processing */
732

733
734
735
736
  /* this call _modifies_ socks->address iff it's a hidden-service request */
  if (rend_parse_rendezvous_address(socks->address) < 0) {
    /* normal request */
    conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
737
    return connection_ap_handshake_attach_circuit(conn);
738
739
  } else {
    /* it's a hidden-service request */
740
    rend_cache_entry_t *entry;
741

742
    strcpy(conn->rend_query, socks->address); /* this strcpy is safe -RD */
743
    log_fn(LOG_INFO,"Got a hidden service request for ID '%s'", conn->rend_query);
744
    /* see if we already have it cached */
745
746
747
    if (rend_cache_lookup_entry(conn->rend_query, &entry) == 1 &&
#define NUM_SECONDS_BEFORE_REFETCH (60*15)
      entry->received + NUM_SECONDS_BEFORE_REFETCH < time(NULL)) {
748
      conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
749
      return connection_ap_handshake_attach_circuit(conn);
750
    } else {
751
752
753
754
755
756
757
      conn->state = AP_CONN_STATE_RENDDESC_WAIT;
      if(!connection_get_by_type_rendquery(CONN_TYPE_DIR, conn->rend_query)) {
        /* not one already; initiate a dir rend desc lookup */
        directory_initiate_command(router_pick_directory_server(),
                                   DIR_PURPOSE_FETCH_RENDDESC,
                                   conn->rend_query, strlen(conn->rend_query));
      }
758
      return 0;
759
760
761
    }
  }
  return 0;
762
763
}

764
765
766
767
/* Find an open circ that we're happy with: return 1. if there isn't
 * one, and there isn't one on the way, launch one and return 0. if it
 * will never work, return -1.
 * write the found or in-progress or launched circ into *circp.
768
769
 */
static int
770
771
772
circuit_get_open_circ_or_launch(connection_t *conn,
                                uint8_t desired_circuit_purpose,
                                circuit_t **circp) {
773
774
775
776
777
  circuit_t *circ;
  uint32_t addr;

  assert(conn);
  assert(circp);
778
  assert(conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
779

780
  circ = circuit_get_best(conn, 1, desired_circuit_purpose);
781
782
783
784
785
786

  if(circ) {
    *circp = circ;
    return 1; /* we're happy */
  }

787
  if(!connection_edge_is_rendezvous_stream(conn)) { /* general purpose circ */
788
789
790
791
792
793
794
    addr = client_dns_lookup_entry(conn->socks_request->address);
    if(router_exit_policy_all_routers_reject(addr, conn->socks_request->port)) {
      log_fn(LOG_WARN,"No Tor server exists that allows exit to %s:%d. Rejecting.",
             conn->socks_request->address, conn->socks_request->port);
      return -1;
    }
  }
795
796
797
798
799
800
801
802
803

  /* is one already on the way? */
  circ = circuit_get_best(conn, 0, desired_circuit_purpose);
  if(!circ) {
    char *exitname=NULL;
    uint8_t new_circ_purpose;

    if(desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCING) {
      /* need to pick an intro point */
804
      exitname = rend_client_get_random_intro(conn->rend_query);
805
806
807
808
809
      if(!exitname) {
        log_fn(LOG_WARN,"Couldn't get an intro point for '%s'. Closing conn.",
               conn->rend_query);
        return -1;
      }
810
811
812
813
      if(!router_get_by_nickname(exitname)) {
        log_fn(LOG_WARN,"Advertised intro point '%s' is not known. Closing.", exitname);
        return -1;
      }
814
815
816
817
818
819
820
821
822
      log_fn(LOG_INFO,"Chose %s as intro point for %s.", exitname, conn->rend_query);
    }

    if(desired_circuit_purpose == CIRCUIT_PURPOSE_C_REND_JOINED)
      new_circ_purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND;
    else
      new_circ_purpose = desired_circuit_purpose;

    circ = circuit_launch_new(new_circ_purpose, exitname);
823
    tor_free(exitname);
824

825
    if(circ &&
826
       (desired_circuit_purpose != CIRCUIT_PURPOSE_C_GENERAL)) {
827
828
829
830
      /* then write the service_id into circ */
      strcpy(circ->rend_query, conn->rend_query);
    }
  }
831
832
833
  if(!circ)
    log_fn(LOG_INFO,"No safe circuit (purpose %d) ready for edge connection; delaying.",
           desired_circuit_purpose);
834
835
836
837
  *circp = circ;
  return 0;
}

838
839
840
841
842
843
844
void link_apconn_to_circ(connection_t *apconn, circuit_t *circ) {
  /* add it into the linked list of streams on this circuit */
  log_fn(LOG_DEBUG,"attaching new conn to circ. n_circ_id %d.", circ->n_circ_id);
  apconn->next_stream = circ->p_streams;
  /* assert_connection_ok(conn, time(NULL)); */
  circ->p_streams = apconn;

845
  assert(CIRCUIT_IS_ORIGIN(circ) && circ->cpath && circ->cpath->prev);
846
847
848
849
  assert(circ->cpath->prev->state == CPATH_STATE_OPEN);
  apconn->cpath_layer = circ->cpath->prev;
}

850
851
/* Try to find a safe live circuit for CONN_TYPE_AP connection conn. If
 * we don't find one: if conn cannot be handled by any known nodes,
852
 * warn and return -1 (conn needs to die);
853
 * else launch new circuit (if necessary) and return 0.
854
855
 * Otherwise, associate conn with a safe live circuit, do the
 * right next step, and return 1.
856
 */
857
int connection_ap_handshake_attach_circuit(connection_t *conn) {
858
  int retval;
859

860
861
862
863
  assert(conn);
  assert(conn->type == CONN_TYPE_AP);
  assert(conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
  assert(conn->socks_request);
864

865
  if(!connection_edge_is_rendezvous_stream(conn)) { /* we're a general conn */
866
    circuit_t *circ=NULL;
867

868
869
870
871
872
873
874
875
876
877
878
879
880
    /* find the circuit that we should use, if there is one. */
    retval = circuit_get_open_circ_or_launch(conn, CIRCUIT_PURPOSE_C_GENERAL, &circ);
    if(retval < 1)
      return retval;

    /* We have found a suitable circuit for our conn. Hurray. */

    /* here, print the circ's path. so people can figure out which circs are sucking. */
    circuit_log_path(LOG_INFO,circ);

    if(!circ->timestamp_dirty)
      circ->timestamp_dirty = time(NULL);

881
    link_apconn_to_circ(conn, circ);
882
883
884
885
886
887
888
    connection_ap_handshake_send_begin(conn, circ);

    return 1;

  } else { /* we're a rendezvous conn */
    circuit_t *rendcirc=NULL, *introcirc=NULL;

889
890
891
892
893
894
895
    /* before anything else, see if we've already been attached
     * to a rendezvous circuit */
    if(conn->cpath_layer) {
      return 1;
    }

    /* else, start by finding a rendezvous circuit for us */
896
897
898
899
900
901

    retval = circuit_get_open_circ_or_launch(conn, CIRCUIT_PURPOSE_C_REND_JOINED, &rendcirc);
    if(retval < 0) return -1; /* failed */

    if(retval > 0) {
      /* one is already established, attach */
902
903
904
905
906
      log_fn(LOG_INFO,"rend joined circ already here. reusing.");
      link_apconn_to_circ(conn, rendcirc);
      if(connection_ap_handshake_send_begin(conn, rendcirc) < 0)
        return 0; /* already marked, let them fade away */
      return 1;
907
908
909
910
911
    }

    if(rendcirc &&
       rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY &&
       rendcirc->build_state->pending_final_cpath) {
912
913
914
915
      log_fn(LOG_INFO,"pending-join circ already here. reusing.");
      link_apconn_to_circ(conn, rendcirc);
      /* don't send the begin, because we're still waiting for contact from bob */
      return 1;
916
917
918
919
920
921
922
923
924
925
926
    }

    /* it's on its way. find an intro circ. */
    retval = circuit_get_open_circ_or_launch(conn, CIRCUIT_PURPOSE_C_INTRODUCING, &introcirc);
    if(retval < 0) return -1; /* failed */

    if(retval > 0) {
      log_fn(LOG_INFO,"Intro circ is ready for us");
      if(rendcirc &&
         rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY) {
        /* then we know !pending_final_cpath, from above */
927
        log_fn(LOG_INFO,"intro and rend circs are both ready. introducing.");
928
        /* this call marks introcirc for close */
929
930
931
932
933
        if(rend_client_send_introduction(introcirc, rendcirc) < 0) {
          return -1;
        }
        /* now attach conn to rendcirc */
        link_apconn_to_circ(conn, rendcirc);