stop complaining as loudly when a dns resolve fails
[tor.git] / src / or / connection_edge.c
blob9a563bf9b491998549b6d2e84f3641183bddebd2
1 /* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
2 /* See LICENSE for licensing information */
3 /* $Id$ */
5 #include "or.h"
6 #include "tree.h"
8 extern or_options_t options; /* command-line and config-file options */
10 static int connection_ap_handshake_process_socks(connection_t *conn);
11 static int connection_ap_handshake_attach_circuit(connection_t *conn);
12 static void connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ);
13 static int connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
14 int replylen, char success);
16 static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ);
17 static void connection_edge_consider_sending_sendme(connection_t *conn);
19 static uint32_t client_dns_lookup_entry(const char *address);
20 static void client_dns_set_entry(const char *address, uint32_t val);
22 int connection_edge_process_inbuf(connection_t *conn) {
24 assert(conn);
25 assert(conn->type == CONN_TYPE_AP || conn->type == CONN_TYPE_EXIT);
27 if(conn->inbuf_reached_eof) {
28 #ifdef HALF_OPEN
29 /* eof reached; we're done reading, but we might want to write more. */
30 conn->done_receiving = 1;
31 shutdown(conn->s, 0); /* XXX check return, refactor NM */
32 if (conn->done_sending) {
33 connection_edge_end(conn, END_STREAM_REASON_DONE, conn->cpath_layer);
34 } else {
35 connection_edge_send_command(conn, circuit_get_by_conn(conn), RELAY_COMMAND_END,
36 NULL, 0, conn->cpath_layer);
38 return 0;
39 #else
40 /* eof reached, kill it. */
41 log_fn(LOG_INFO,"conn (fd %d) reached eof. Closing.", conn->s);
42 connection_edge_end(conn, END_STREAM_REASON_DONE, conn->cpath_layer);
43 return -1;
44 #endif
47 switch(conn->state) {
48 case AP_CONN_STATE_SOCKS_WAIT:
49 if(connection_ap_handshake_process_socks(conn) < 0) {
50 connection_edge_end(conn, END_STREAM_REASON_MISC, conn->cpath_layer);
51 return -1;
53 return 0;
54 case AP_CONN_STATE_OPEN:
55 case EXIT_CONN_STATE_OPEN:
56 if(connection_edge_package_raw_inbuf(conn) < 0) {
57 connection_edge_end(conn, END_STREAM_REASON_MISC, conn->cpath_layer);
58 return -1;
60 return 0;
61 case EXIT_CONN_STATE_CONNECTING:
62 log_fn(LOG_INFO,"text from server while in 'connecting' state at exit. Leaving it on buffer.");
63 return 0;
66 return 0;
69 char *connection_edge_end_reason(char *payload, unsigned char length) {
70 if(length < 1) {
71 log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1.");
72 return "MALFORMED";
74 if(*payload < END_STREAM_REASON_MISC || *payload > END_STREAM_REASON_DONE) {
75 log_fn(LOG_WARN,"Reason for ending (%d) not recognized.",*payload);
76 return "MALFORMED";
78 switch(*payload) {
79 case END_STREAM_REASON_MISC: return "misc error";
80 case END_STREAM_REASON_RESOLVEFAILED: return "resolve failed";
81 case END_STREAM_REASON_CONNECTFAILED: return "connect failed";
82 case END_STREAM_REASON_EXITPOLICY: return "exit policy failed";
83 case END_STREAM_REASON_DESTROY: return "destroyed";
84 case END_STREAM_REASON_DONE: return "closed normally";
86 assert(0);
87 return "";
90 void connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_layer) {
91 char payload[5];
92 int payload_len=1;
93 circuit_t *circ;
95 if(conn->has_sent_end) {
96 log_fn(LOG_WARN,"It appears I've already sent the end. Are you calling me twice?");
97 return;
100 payload[0] = reason;
101 if(reason == END_STREAM_REASON_EXITPOLICY) {
102 *(uint32_t *)(payload+1) = htonl(conn->addr);
103 payload_len += 4;
106 circ = circuit_get_by_conn(conn);
107 if(circ) {
108 log_fn(LOG_DEBUG,"Marking conn (fd %d) and sending end.",conn->s);
109 connection_edge_send_command(conn, circ, RELAY_COMMAND_END,
110 payload, payload_len, cpath_layer);
113 conn->marked_for_close = 1;
114 conn->has_sent_end = 1;
117 int connection_edge_send_command(connection_t *fromconn, circuit_t *circ, int relay_command,
118 void *payload, int payload_len, crypt_path_t *cpath_layer) {
119 cell_t cell;
120 int cell_direction;
121 int is_control_cell=0;
123 if(!circ) {
124 log_fn(LOG_WARN,"no circ. Closing.");
125 return 0;
128 if(!fromconn || relay_command == RELAY_COMMAND_BEGIN) /* XXX more */
129 is_control_cell = 1;
131 memset(&cell, 0, sizeof(cell_t));
132 if(fromconn && fromconn->type == CONN_TYPE_AP) {
133 cell.circ_id = circ->n_circ_id;
134 cell_direction = CELL_DIRECTION_OUT;
135 } else {
136 /* NOTE: if !fromconn, we assume that it's heading towards the OP */
137 cell.circ_id = circ->p_circ_id;
138 cell_direction = CELL_DIRECTION_IN;
141 cell.command = CELL_RELAY;
142 SET_CELL_RELAY_COMMAND(cell, relay_command);
143 if(is_control_cell)
144 SET_CELL_STREAM_ID(cell, ZERO_STREAM);
145 else
146 SET_CELL_STREAM_ID(cell, fromconn->stream_id);
148 cell.length = RELAY_HEADER_SIZE + payload_len;
149 if(payload_len) {
150 memcpy(cell.payload+RELAY_HEADER_SIZE,payload,payload_len);
152 log_fn(LOG_DEBUG,"delivering %d cell %s.", relay_command,
153 cell_direction == CELL_DIRECTION_OUT ? "forward" : "backward");
155 if(circuit_deliver_relay_cell(&cell, circ, cell_direction, cpath_layer) < 0) {
156 log_fn(LOG_WARN,"circuit_deliver_relay_cell failed. Closing.");
157 circuit_close(circ);
158 return -1;
160 return 0;
163 /* an incoming relay cell has arrived. return -1 if you want to tear down the
164 * circuit, else 0. */
165 int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection_t *conn,
166 int edge_type, crypt_path_t *layer_hint) {
167 int relay_command;
168 static int num_seen=0;
169 uint32_t addr;
171 assert(cell && circ);
173 relay_command = CELL_RELAY_COMMAND(*cell);
174 // log_fn(LOG_DEBUG,"command %d stream %d", relay_command, stream_id);
175 num_seen++;
176 log_fn(LOG_DEBUG,"Now seen %d relay cells here.", num_seen);
178 /* either conn is NULL, in which case we've got a control cell, or else
179 * conn points to the recognized stream. */
181 if(conn && conn->state != AP_CONN_STATE_OPEN && conn->state != EXIT_CONN_STATE_OPEN) {
182 if(conn->type == CONN_TYPE_EXIT && relay_command == RELAY_COMMAND_END) {
183 log_fn(LOG_INFO,"Exit got end (%s) before we're connected. Marking for close.",
184 connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, cell->length));
185 if(conn->state == EXIT_CONN_STATE_RESOLVING) {
186 log_fn(LOG_INFO,"...and informing resolver we don't want the answer anymore.");
187 dns_cancel_pending_resolve(conn->address, conn);
189 conn->marked_for_close = 1;
190 conn->has_sent_end = 1;
191 return 0;
192 } else {
193 log_fn(LOG_WARN,"Got an unexpected relay cell, not in 'open' state. Closing.");
194 connection_edge_end(conn, END_STREAM_REASON_MISC, conn->cpath_layer);
195 return -1;
199 switch(relay_command) {
200 case RELAY_COMMAND_BEGIN:
201 if(edge_type == EDGE_AP) {
202 log_fn(LOG_WARN,"relay begin request unsupported at AP. Dropping.");
203 return 0;
205 if(conn) {
206 log_fn(LOG_WARN,"begin cell for known stream. Dropping.");
207 return 0;
209 connection_exit_begin_conn(cell, circ);
210 return 0;
211 case RELAY_COMMAND_DATA:
212 ++stats_n_data_cells_received;
213 if((edge_type == EDGE_AP && --layer_hint->deliver_window < 0) ||
214 (edge_type == EDGE_EXIT && --circ->deliver_window < 0)) {
215 log_fn(LOG_WARN,"(relay data) circ deliver_window below 0. Killing.");
216 connection_edge_end(conn, END_STREAM_REASON_MISC, conn->cpath_layer);
217 return -1;
219 log_fn(LOG_DEBUG,"circ deliver_window now %d.", edge_type == EDGE_AP ? layer_hint->deliver_window : circ->deliver_window);
221 if(circuit_consider_sending_sendme(circ, edge_type, layer_hint) < 0) {
222 log_fn(LOG_WARN,"circuit_consider_sending_sendme() failed.");
223 conn->has_sent_end = 1; /* we failed because conn is broken. can't send end. */
224 return -1;
227 if(!conn) {
228 log_fn(LOG_INFO,"relay cell dropped, unknown stream %d.",*(int*)conn->stream_id);
229 return 0;
232 if(--conn->deliver_window < 0) { /* is it below 0 after decrement? */
233 log_fn(LOG_WARN,"(relay data) conn deliver_window below 0. Killing.");
234 return -1; /* somebody's breaking protocol. kill the whole circuit. */
237 // printf("New text for buf (%d bytes): '%s'", cell->length - RELAY_HEADER_SIZE, cell->payload + RELAY_HEADER_SIZE);
238 stats_n_data_bytes_received += (cell->length - RELAY_HEADER_SIZE);
239 connection_write_to_buf(cell->payload + RELAY_HEADER_SIZE,
240 cell->length - RELAY_HEADER_SIZE, conn);
241 connection_edge_consider_sending_sendme(conn);
242 return 0;
243 case RELAY_COMMAND_END:
244 if(!conn) {
245 log_fn(LOG_INFO,"end cell (%s) dropped, unknown stream %d.",
246 connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, cell->length),
247 *(int*)conn->stream_id);
248 return 0;
250 if(cell->length-RELAY_HEADER_SIZE >= 5 &&
251 *(cell->payload+RELAY_HEADER_SIZE) == END_STREAM_REASON_EXITPOLICY) {
252 /* No need to close the connection. We'll hold it open while
253 * we try a new exit node.
254 * cell->payload+RELAY_HEADER_SIZE+1 holds the destination addr.
256 addr = ntohl(*(uint32_t*)(cell->payload+RELAY_HEADER_SIZE+1));
257 client_dns_set_entry(conn->socks_request->address, addr);
258 conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
259 if(connection_ap_handshake_attach_circuit(conn) < 0)
260 circuit_launch_new(); /* Build another circuit to handle this stream */
261 return 0;
263 log_fn(LOG_INFO,"end cell (%s) for stream %d. Removing stream.",
264 connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, cell->length),
265 *(int*)conn->stream_id);
267 #ifdef HALF_OPEN
268 conn->done_sending = 1;
269 shutdown(conn->s, 1); /* XXX check return; refactor NM */
270 if (conn->done_receiving) {
271 conn->marked_for_close = 1;
272 conn->has_sent_end = 1; /* no need to send end, we just got one! */
274 #else
275 conn->marked_for_close = 1;
276 conn->has_sent_end = 1; /* no need to send end, we just got one! */
277 #endif
278 return 0;
279 case RELAY_COMMAND_EXTEND:
280 if(conn) {
281 log_fn(LOG_WARN,"'extend' for non-zero stream. Dropping.");
282 return 0;
284 return circuit_extend(cell, circ);
285 case RELAY_COMMAND_EXTENDED:
286 if(edge_type == EDGE_EXIT) {
287 log_fn(LOG_WARN,"'extended' unsupported at exit. Dropping.");
288 return 0;
290 log_fn(LOG_DEBUG,"Got an extended cell! Yay.");
291 if(circuit_finish_handshake(circ, cell->payload+RELAY_HEADER_SIZE) < 0) {
292 log_fn(LOG_WARN,"circuit_finish_handshake failed.");
293 return -1;
295 if (circuit_send_next_onion_skin(circ)<0) {
296 log_fn(LOG_WARN,"circuit_send_next_onion_skin() failed.");
297 return -1;
299 return 0;
300 case RELAY_COMMAND_TRUNCATE:
301 if(edge_type == EDGE_AP) {
302 log_fn(LOG_WARN,"'truncate' unsupported at AP. Dropping.");
303 return 0;
305 if(circ->n_conn) {
306 connection_send_destroy(circ->n_circ_id, circ->n_conn);
307 circ->n_conn = NULL;
309 log_fn(LOG_DEBUG, "Processed 'truncate', replying.");
310 connection_edge_send_command(NULL, circ, RELAY_COMMAND_TRUNCATED,
311 NULL, 0, NULL);
312 return 0;
313 case RELAY_COMMAND_TRUNCATED:
314 if(edge_type == EDGE_EXIT) {
315 log_fn(LOG_WARN,"'truncated' unsupported at exit. Dropping.");
316 return 0;
318 circuit_truncated(circ, layer_hint);
319 return 0;
320 case RELAY_COMMAND_CONNECTED:
321 if(edge_type == EDGE_EXIT) {
322 log_fn(LOG_WARN,"'connected' unsupported at exit. Dropping.");
323 return 0;
325 if(!conn) {
326 log_fn(LOG_INFO,"connected cell dropped, unknown stream %d.",*(int*)conn->stream_id);
327 return 0;
329 log_fn(LOG_INFO,"Connected! Notifying application.");
330 if (cell->length-RELAY_HEADER_SIZE == 4) {
331 addr = ntohl(*(uint32_t*)(cell->payload + RELAY_HEADER_SIZE));
332 client_dns_set_entry(conn->socks_request->address, addr);
334 if(connection_ap_handshake_socks_reply(conn, NULL, 0, 1) < 0) {
335 log_fn(LOG_INFO,"Writing to socks-speaking application failed. Closing.");
336 connection_edge_end(conn, END_STREAM_REASON_MISC, conn->cpath_layer);
338 return 0;
339 case RELAY_COMMAND_SENDME:
340 if(!conn) {
341 if(edge_type == EDGE_AP) {
342 assert(layer_hint);
343 layer_hint->package_window += CIRCWINDOW_INCREMENT;
344 log_fn(LOG_DEBUG,"circ-level sendme at AP, packagewindow %d.", layer_hint->package_window);
345 circuit_resume_edge_reading(circ, EDGE_AP, layer_hint);
346 } else {
347 assert(!layer_hint);
348 circ->package_window += CIRCWINDOW_INCREMENT;
349 log_fn(LOG_DEBUG,"circ-level sendme at exit, packagewindow %d.", circ->package_window);
350 circuit_resume_edge_reading(circ, EDGE_EXIT, layer_hint);
352 return 0;
354 conn->package_window += STREAMWINDOW_INCREMENT;
355 log_fn(LOG_DEBUG,"stream-level sendme, packagewindow now %d.", conn->package_window);
356 connection_start_reading(conn);
357 connection_edge_package_raw_inbuf(conn); /* handle whatever might still be on the inbuf */
358 return 0;
359 default:
360 log_fn(LOG_WARN,"unknown relay command %d.",relay_command);
361 return -1;
363 assert(0);
364 return -1;
367 int connection_edge_finished_flushing(connection_t *conn) {
368 unsigned char connected_payload[4];
369 int e, len=sizeof(e);
371 assert(conn);
372 assert(conn->type == CONN_TYPE_AP || conn->type == CONN_TYPE_EXIT);
374 switch(conn->state) {
375 case EXIT_CONN_STATE_CONNECTING:
376 if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { /* not yet */
377 if(!ERRNO_CONN_EINPROGRESS(errno)) {
378 /* yuck. kill it. */
379 log_fn(LOG_DEBUG,"in-progress exit connect failed. Removing.");
380 return -1;
381 } else {
382 log_fn(LOG_DEBUG,"in-progress exit connect still waiting.");
383 return 0; /* no change, see if next time is better */
386 /* the connect has finished. */
388 log_fn(LOG_INFO,"Exit connection to %s:%u established.",
389 conn->address,conn->port);
391 conn->state = EXIT_CONN_STATE_OPEN;
392 connection_watch_events(conn, POLLIN); /* stop writing, continue reading */
393 if(connection_wants_to_flush(conn)) /* in case there are any queued relay cells */
394 connection_start_writing(conn);
395 /* deliver a 'connected' relay cell back through the circuit. */
396 *(uint32_t*)connected_payload = htonl(conn->addr);
397 if(connection_edge_send_command(conn, circuit_get_by_conn(conn),
398 RELAY_COMMAND_CONNECTED, NULL, 0, conn->cpath_layer) < 0)
399 return 0; /* circuit is closed, don't continue */
400 return connection_process_inbuf(conn); /* in case the server has written anything */
401 case AP_CONN_STATE_OPEN:
402 case EXIT_CONN_STATE_OPEN:
403 connection_stop_writing(conn);
404 connection_edge_consider_sending_sendme(conn);
405 return 0;
406 case AP_CONN_STATE_SOCKS_WAIT:
407 connection_stop_writing(conn);
408 return 0;
409 default:
410 log_fn(LOG_WARN,"BUG: called in unexpected state: %d", conn->state);
411 return -1;
413 return 0;
416 uint64_t stats_n_data_cells_packaged = 0;
417 uint64_t stats_n_data_bytes_packaged = 0;
418 uint64_t stats_n_data_cells_received = 0;
419 uint64_t stats_n_data_bytes_received = 0;
421 int connection_edge_package_raw_inbuf(connection_t *conn) {
422 int amount_to_process, length;
423 char payload[CELL_PAYLOAD_SIZE];
424 circuit_t *circ;
426 assert(conn);
427 assert(!connection_speaks_cells(conn));
429 repeat_connection_edge_package_raw_inbuf:
431 circ = circuit_get_by_conn(conn);
432 if(!circ) {
433 log_fn(LOG_INFO,"conn has no circuits! Closing.");
434 return -1;
437 if(circuit_consider_stop_edge_reading(circ, conn->type, conn->cpath_layer))
438 return 0;
440 if(conn->package_window <= 0) {
441 log_fn(LOG_WARN,"called with package_window %d. Tell Roger.", conn->package_window);
442 connection_stop_reading(conn);
443 return 0;
446 amount_to_process = buf_datalen(conn->inbuf);
448 if(!amount_to_process)
449 return 0;
451 if(amount_to_process > CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE) {
452 length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE;
453 } else {
454 length = amount_to_process;
456 stats_n_data_bytes_packaged += length;
457 stats_n_data_cells_packaged += 1;
459 connection_fetch_from_buf(payload, length, conn);
461 log_fn(LOG_DEBUG,"(%d) Packaging %d bytes (%d waiting).",conn->s,length,
462 (int)buf_datalen(conn->inbuf));
464 if(connection_edge_send_command(conn, circ, RELAY_COMMAND_DATA,
465 payload, length, conn->cpath_layer) < 0)
466 return 0; /* circuit is closed, don't continue */
468 if(conn->type == CONN_TYPE_EXIT) {
469 assert(circ->package_window > 0);
470 circ->package_window--;
471 } else { /* we're an AP */
472 assert(conn->type == CONN_TYPE_AP);
473 assert(conn->cpath_layer->package_window > 0);
474 conn->cpath_layer->package_window--;
477 if(--conn->package_window <= 0) { /* is it 0 after decrement? */
478 connection_stop_reading(conn);
479 log_fn(LOG_DEBUG,"conn->package_window reached 0.");
480 circuit_consider_stop_edge_reading(circ, conn->type, conn->cpath_layer);
481 return 0; /* don't process the inbuf any more */
483 log_fn(LOG_DEBUG,"conn->package_window is now %d",conn->package_window);
485 /* handle more if there's more, or return 0 if there isn't */
486 goto repeat_connection_edge_package_raw_inbuf;
489 /* Tell any APs that are waiting for a new circuit that one is available */
490 void connection_ap_attach_pending(void)
492 connection_t **carray;
493 int n, i;
495 get_connection_array(&carray, &n);
497 for (i = 0; i < n; ++i) {
498 if (carray[i]->type != CONN_TYPE_AP ||
499 carray[i]->type != AP_CONN_STATE_CIRCUIT_WAIT)
500 continue;
501 if (connection_ap_handshake_attach_circuit(carray[i])<0) {
502 if(!circuit_get_newest(carray[i], 0)) {
503 /* if there are no acceptable clean or not-very-dirty circs on the way */
504 circuit_launch_new();
510 static void connection_edge_consider_sending_sendme(connection_t *conn) {
511 circuit_t *circ;
513 if(connection_outbuf_too_full(conn))
514 return;
516 circ = circuit_get_by_conn(conn);
517 if(!circ) {
518 /* this can legitimately happen if the destroy has already
519 * arrived and torn down the circuit */
520 log_fn(LOG_INFO,"No circuit associated with conn. Skipping.");
521 return;
524 while(conn->deliver_window < STREAMWINDOW_START - STREAMWINDOW_INCREMENT) {
525 log_fn(LOG_DEBUG,"Outbuf %d, Queueing stream sendme.", conn->outbuf_flushlen);
526 conn->deliver_window += STREAMWINDOW_INCREMENT;
527 if(connection_edge_send_command(conn, circ, RELAY_COMMAND_SENDME,
528 NULL, 0, conn->cpath_layer) < 0) {
529 log_fn(LOG_WARN,"connection_edge_send_command failed. Returning.");
530 return; /* the circuit's closed, don't continue */
535 static int connection_ap_handshake_process_socks(connection_t *conn) {
536 socks_request_t *socks;
537 int sockshere;
539 assert(conn);
540 assert(conn->type == CONN_TYPE_AP);
541 assert(conn->state == AP_CONN_STATE_SOCKS_WAIT);
542 assert(conn->socks_request);
543 socks = conn->socks_request;
545 log_fn(LOG_DEBUG,"entered.");
547 sockshere = fetch_from_buf_socks(conn->inbuf, socks);
548 if(sockshere == -1 || sockshere == 0) {
549 if(socks->replylen) { /* we should send reply back */
550 log_fn(LOG_DEBUG,"reply is already set for us. Using it.");
551 connection_ap_handshake_socks_reply(conn, socks->reply, socks->replylen, 0);
552 } else if(sockshere == -1) { /* send normal reject */
553 log_fn(LOG_WARN,"Fetching socks handshake failed. Closing.");
554 connection_ap_handshake_socks_reply(conn, NULL, 0, 0);
555 } else {
556 log_fn(LOG_DEBUG,"socks handshake not all here yet.");
558 return sockshere;
559 } /* else socks handshake is done, continue processing */
561 conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
562 if(connection_ap_handshake_attach_circuit(conn) < 0)
563 circuit_launch_new(); /* Build another circuit to handle this stream */
564 return 0;
567 /* Try to find a live circuit. If we don't find one, tell 'conn' to
568 * stop reading and return 0. Otherwise, associate the CONN_TYPE_AP
569 * connection 'conn' with a safe live circuit, start sending a
570 * BEGIN cell down the circuit, and return 1.
572 static int connection_ap_handshake_attach_circuit(connection_t *conn) {
573 circuit_t *circ;
575 assert(conn);
576 assert(conn->type == CONN_TYPE_AP);
577 assert(conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
578 assert(conn->socks_request);
580 /* find the circuit that we should use, if there is one. */
581 circ = circuit_get_newest(conn, 1);
583 if(!circ) {
584 log_fn(LOG_INFO,"No safe circuit ready for edge connection; delaying.");
585 connection_stop_reading(conn); /* don't read until the connected cell arrives */
586 return -1;
589 connection_start_reading(conn);
591 if(!circ->timestamp_dirty)
592 circ->timestamp_dirty = time(NULL);
594 /* add it into the linked list of streams on this circuit */
595 log_fn(LOG_DEBUG,"attaching new conn to circ. n_circ_id %d.", circ->n_circ_id);
596 conn->next_stream = circ->p_streams;
597 /* assert_connection_ok(conn, time(NULL)); */
598 circ->p_streams = conn;
600 assert(circ->cpath && circ->cpath->prev);
601 assert(circ->cpath->prev->state == CPATH_STATE_OPEN);
602 conn->cpath_layer = circ->cpath->prev;
604 connection_ap_handshake_send_begin(conn, circ);
606 return 0;
609 /* deliver the destaddr:destport in a relay cell */
610 static void connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
612 char payload[CELL_PAYLOAD_SIZE];
613 int payload_len;
614 struct in_addr in;
615 const char *string_addr;
617 assert(ap_conn->type == CONN_TYPE_AP);
618 assert(ap_conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
619 assert(ap_conn->socks_request);
621 crypto_pseudo_rand(STREAM_ID_SIZE, ap_conn->stream_id);
622 /* FIXME check for collisions */
624 in.s_addr = htonl(client_dns_lookup_entry(ap_conn->socks_request->address));
625 string_addr = in.s_addr ? inet_ntoa(in) : NULL;
627 memcpy(payload, ap_conn->stream_id, STREAM_ID_SIZE);
628 payload_len = STREAM_ID_SIZE + 1 +
629 snprintf(payload+STREAM_ID_SIZE,CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE-STREAM_ID_SIZE,
630 "%s:%d",
631 string_addr ? string_addr : ap_conn->socks_request->address,
632 ap_conn->socks_request->port);
634 log_fn(LOG_DEBUG,"Sending relay cell to begin stream %d.",*(int *)ap_conn->stream_id);
636 if(connection_edge_send_command(ap_conn, circ, RELAY_COMMAND_BEGIN,
637 payload, payload_len, ap_conn->cpath_layer) < 0)
638 return; /* circuit is closed, don't continue */
640 ap_conn->package_window = STREAMWINDOW_START;
641 ap_conn->deliver_window = STREAMWINDOW_START;
642 ap_conn->state = AP_CONN_STATE_OPEN;
643 /* XXX Right now, we rely on the socks client not to send us any data
644 * XXX until we've sent back a socks reply. (If it does, we could wind
645 * XXX up packaging that data and sending it to the exit, then later having
646 * XXX the exit refuse us.)
647 * XXX Perhaps we should grow an AP_CONN_STATE_CONNECTING state.
649 log_fn(LOG_INFO,"Address/port sent, ap socket %d, n_circ_id %d",ap_conn->s,circ->n_circ_id);
650 return;
653 static int connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
654 int replylen, char success) {
655 char buf[256];
657 if(replylen) { /* we already have a reply in mind */
658 connection_write_to_buf(reply, replylen, conn);
659 return flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen); /* try to flush it */
661 assert(conn->socks_request);
662 if(conn->socks_request->socks_version == 4) {
663 memset(buf,0,SOCKS4_NETWORK_LEN);
664 #define SOCKS4_GRANTED 90
665 #define SOCKS4_REJECT 91
666 buf[1] = (success ? SOCKS4_GRANTED : SOCKS4_REJECT);
667 /* leave version, destport, destip zero */
668 connection_write_to_buf(buf, SOCKS4_NETWORK_LEN, conn);
669 return flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen); /* try to flush it */
671 if(conn->socks_request->socks_version == 5) {
672 buf[0] = 5; /* version 5 */
673 #define SOCKS5_SUCCESS 0
674 #define SOCKS5_GENERIC_ERROR 1
675 buf[1] = success ? SOCKS5_SUCCESS : SOCKS5_GENERIC_ERROR;
676 buf[2] = 0;
677 buf[3] = 1; /* ipv4 addr */
678 memset(buf+4,0,6); /* Set external addr/port to 0.
679 The spec doesn't seem to say what to do here. -RD */
680 connection_write_to_buf(buf,10,conn);
681 return flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen); /* try to flush it */
683 return 0; /* if socks_version isn't 4 or 5, don't send anything */
686 static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
687 connection_t *n_stream;
688 char *colon;
690 /* XXX currently we don't send an end cell back if we drop the
691 * begin because it's malformed.
694 if(!memchr(cell->payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE,0,
695 cell->length-RELAY_HEADER_SIZE-STREAM_ID_SIZE)) {
696 log_fn(LOG_WARN,"relay begin cell has no \\0. Dropping.");
697 return 0;
699 colon = strchr(cell->payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE, ':');
700 if(!colon) {
701 log_fn(LOG_WARN,"relay begin cell has no colon. Dropping.");
702 return 0;
704 *colon = 0;
706 if(!atoi(colon+1)) { /* bad port */
707 log_fn(LOG_WARN,"relay begin cell has invalid port. Dropping.");
708 return 0;
711 log_fn(LOG_DEBUG,"Creating new exit connection.");
712 n_stream = connection_new(CONN_TYPE_EXIT);
714 memcpy(n_stream->stream_id, cell->payload + RELAY_HEADER_SIZE, STREAM_ID_SIZE);
715 n_stream->address = tor_strdup(cell->payload + RELAY_HEADER_SIZE + STREAM_ID_SIZE);
716 n_stream->port = atoi(colon+1);
717 n_stream->state = EXIT_CONN_STATE_RESOLVING;
718 /* leave n_stream->s at -1, because it's not yet valid */
719 n_stream->package_window = STREAMWINDOW_START;
720 n_stream->deliver_window = STREAMWINDOW_START;
721 if(connection_add(n_stream) < 0) { /* no space, forget it */
722 log_fn(LOG_WARN,"connection_add failed. Dropping.");
723 connection_free(n_stream);
724 return 0;
727 /* add it into the linked list of streams on this circuit */
728 n_stream->next_stream = circ->n_streams;
729 circ->n_streams = n_stream;
731 /* send it off to the gethostbyname farm */
732 switch(dns_resolve(n_stream)) {
733 case 1: /* resolve worked */
734 connection_exit_connect(n_stream);
735 return 0;
736 case -1: /* resolve failed */
737 log_fn(LOG_INFO,"Resolve failed (%s).", n_stream->address);
738 connection_edge_end(n_stream, END_STREAM_REASON_RESOLVEFAILED, NULL);
739 /* case 0, resolve added to pending list */
741 return 0;
744 void connection_exit_connect(connection_t *conn) {
745 unsigned char connected_payload[4];
747 if(router_compare_to_exit_policy(conn) < 0) {
748 log_fn(LOG_INFO,"%s:%d failed exit policy. Closing.", conn->address, conn->port);
749 connection_edge_end(conn, END_STREAM_REASON_EXITPOLICY, NULL);
750 return;
753 switch(connection_connect(conn, conn->address, conn->addr, conn->port)) {
754 case -1:
755 connection_edge_end(conn, END_STREAM_REASON_CONNECTFAILED, NULL);
756 return;
757 case 0:
758 connection_set_poll_socket(conn);
759 conn->state = EXIT_CONN_STATE_CONNECTING;
761 connection_watch_events(conn, POLLOUT | POLLIN | POLLERR);
762 /* writable indicates finish, readable indicates broken link,
763 error indicates broken link in windowsland. */
764 return;
765 /* case 1: fall through */
768 connection_set_poll_socket(conn);
769 conn->state = EXIT_CONN_STATE_OPEN;
770 if(connection_wants_to_flush(conn)) { /* in case there are any queued data cells */
771 log_fn(LOG_WARN,"tell roger: newly connected conn had data waiting!");
772 // connection_start_writing(conn);
774 // connection_process_inbuf(conn);
775 connection_watch_events(conn, POLLIN);
777 /* also, deliver a 'connected' cell back through the circuit. */
778 *((uint32_t*) connected_payload) = htonl(conn->addr);
779 connection_edge_send_command(conn, circuit_get_by_conn(conn), RELAY_COMMAND_CONNECTED,
780 connected_payload, 4, conn->cpath_layer);
783 int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit)
785 uint32_t addr;
787 assert(conn);
788 assert(conn->type == CONN_TYPE_AP);
789 assert(conn->socks_request);
791 addr = client_dns_lookup_entry(conn->socks_request->address);
792 return router_supports_exit_address(addr, conn->port, exit);
795 /* ***** Client DNS code ***** */
796 #define MAX_DNS_ENTRY_AGE 30*60
798 /* XXX Perhaps this should get merged with the dns.c code somehow. */
799 struct client_dns_entry {
800 SPLAY_ENTRY(client_dns_entry) node;
801 char *address;
802 uint32_t addr;
803 time_t expires;
805 static int client_dns_size = 0;
806 static SPLAY_HEAD(client_dns_tree, client_dns_entry) client_dns_root;
808 static int compare_client_dns_entries(struct client_dns_entry *a,
809 struct client_dns_entry *b)
811 return strcasecmp(a->address, b->address);
814 static void client_dns_entry_free(struct client_dns_entry *ent)
816 tor_free(ent->address);
817 tor_free(ent);
820 SPLAY_PROTOTYPE(client_dns_tree, client_dns_entry, node, compare_client_dns_entries);
821 SPLAY_GENERATE(client_dns_tree, client_dns_entry, node, compare_client_dns_entries);
823 void client_dns_init(void) {
824 SPLAY_INIT(&client_dns_root);
825 client_dns_size = 0;
828 static uint32_t client_dns_lookup_entry(const char *address)
830 struct client_dns_entry *ent;
831 struct client_dns_entry search;
832 struct in_addr in;
833 time_t now;
835 assert(address);
837 if (inet_aton(address, &in)) {
838 log_fn(LOG_DEBUG, "Using static address %s (%08X)", address,
839 ntohl(in.s_addr));
840 return ntohl(in.s_addr);
842 search.address = (char*)address;
843 ent = SPLAY_FIND(client_dns_tree, &client_dns_root, &search);
844 if (!ent) {
845 log_fn(LOG_DEBUG, "No entry found for address %s", address);
846 return 0;
847 } else {
848 now = time(NULL);
849 if (ent->expires < now) {
850 log_fn(LOG_DEBUG, "Expired entry found for address %s", address);
851 SPLAY_REMOVE(client_dns_tree, &client_dns_root, ent);
852 client_dns_entry_free(ent);
853 --client_dns_size;
854 return 0;
856 in.s_addr = htonl(ent->addr);
857 log_fn(LOG_DEBUG, "Found cached entry for address %s: %s", address,
858 inet_ntoa(in));
859 return ent->addr;
862 static void client_dns_set_entry(const char *address, uint32_t val)
864 struct client_dns_entry *ent;
865 struct client_dns_entry search;
866 struct in_addr in;
867 time_t now;
869 assert(address);
870 assert(val);
872 if (inet_aton(address, &in)) {
873 if (ntohl(in.s_addr) == val)
874 return;
875 in.s_addr = htonl(val);
876 log_fn(LOG_WARN,
877 "Trying to store incompatible cached value %s for static address %s",
878 inet_ntoa(in), address);
879 return;
881 search.address = (char*) address;
882 now = time(NULL);
883 ent = SPLAY_FIND(client_dns_tree, &client_dns_root, &search);
884 if (ent) {
885 in.s_addr = htonl(val);
886 log_fn(LOG_DEBUG, "Updating entry for address %s: %s", address,
887 inet_ntoa(in));
888 ent->addr = val;
889 ent->expires = now+MAX_DNS_ENTRY_AGE;
890 } else {
891 in.s_addr = htonl(val);
892 log_fn(LOG_DEBUG, "Caching result for address %s: %s", address,
893 inet_ntoa(in));
894 ent = tor_malloc(sizeof(struct client_dns_entry));
895 ent->address = tor_strdup(address);
896 ent->addr = val;
897 ent->expires = now+MAX_DNS_ENTRY_AGE;
898 SPLAY_INSERT(client_dns_tree, &client_dns_root, ent);
899 ++client_dns_size;
903 void client_dns_clean(void)
905 struct client_dns_entry **expired_entries;
906 int n_expired_entries = 0;
907 struct client_dns_entry *ent;
908 time_t now;
909 int i;
911 if(!client_dns_size)
912 return;
913 expired_entries = tor_malloc(client_dns_size *
914 sizeof(struct client_dns_entry *));
916 now = time(NULL);
917 SPLAY_FOREACH(ent, client_dns_tree, &client_dns_root) {
918 if (ent->expires < now) {
919 expired_entries[n_expired_entries++] = ent;
922 for (i = 0; i < n_expired_entries; ++i) {
923 SPLAY_REMOVE(client_dns_tree, &client_dns_root, expired_entries[i]);
924 client_dns_entry_free(expired_entries[i]);
926 tor_free(expired_entries);
930 Local Variables:
931 mode:c
932 indent-tabs-mode:nil
933 c-basic-offset:2
934 End: