]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
Specify and implement close-stream and close-circuit control messages
authorNick Mathewson <nickm@torproject.org>
Tue, 22 Mar 2005 19:36:38 +0000 (19:36 +0000)
committerNick Mathewson <nickm@torproject.org>
Tue, 22 Mar 2005 19:36:38 +0000 (19:36 +0000)
svn:r3814

doc/TODO
doc/control-spec.txt
src/or/control.c
src/or/or.h
src/or/relay.c

index 0f19b860c60ccdb2a8197eca8dc8d3ac51ba721f..77fd8adc3c5c6e76dcb25e9f0eb311c7c74473d8 100644 (file)
--- a/doc/TODO
+++ b/doc/TODO
@@ -62,7 +62,7 @@ N . Switch to libevent
 R  o Reset uptime when IP changes.
 
  Functionality
-N  . Implement pending controller features.
+  o Implement pending controller features.
     o Stubs for new functions.
     o GETINFO
       o Version
@@ -84,9 +84,9 @@ N  . Implement pending controller features.
     o Event for "new descriptors"
     o Better stream IDs
     o Stream status changed: "new" state.
-    - EXTENDCIRCUIT
-R     - revised circ selection stuff.
-      - Implement controller interface.
+    o EXTENDCIRCUIT
+      o revised circ selection stuff.
+      o Implement controller interface.
     o ATTACHSTREAM
       o Make streams have an 'unattached and not-automatically-attachable'
         state. ("Controller managed.")
@@ -96,8 +96,13 @@ R     - revised circ selection stuff.
       o Time out never-attached streams.
       o If we never get a CONNECTED back, we should put the stream back in
         CONTROLLER_WAIT, not in CIRCUIT_WAIT.
-      - Add a way for the controller to say, "Hey, nuke this stream."
-    - Tests for new controller features
+      o Add a way for the controller to say, "Hey, nuke this stream."
+        o Specify
+        o Implement
+      o Add a way for the controller to say, "Hey, nuke this circuit."
+        o Specify
+        o Implement
+  - Tests for new controller features
 R o HTTPS proxy for OR CONNECT stuff. (For outgoing SSL connections to
     other ORs.)
   o Changes for forward compatibility
index b1092eeb347e8927ec896791f562b2aaa8705b55..ed7ec4bfd57506ec206b7debe3ca3b7ea09cb5ac 100644 (file)
@@ -417,6 +417,29 @@ the message.
   after a new stream event is received, and before attaching this stream to
   a circuit.
 
+3.20 CLOSESTREAM (Type 0x0013)
+
+  Sent from the client to the server.  The message body contains three
+  fields:
+      Stream ID [4 octets]
+      Reason    [1 octet]
+      Flags     [1 octet]
+
+  Tells the server to close the specified stream.  The reason should be one
+  of the Tor RELAY_END reasons given in tor-spec.txt.  If the LSB of the
+  flags field is nonzero, and the stream wants to write data, Tor tries to
+  hold the stream open for a while until it can be flushed.
+
+3.21 CLOSECIRCUIT (Type 0x0014)
+
+  Sent from the client to the server.  The message body contains two
+  fields:
+     Circuit ID [4 octets]
+     Flags      [1 octet]
+
+  Tells the server to close the specified circuit.  If the LSB of the flags
+  field is nonzero, do not close the circuit unless it is unused.
+
 4. Implementation notes
 
 4.1. There are four ways we could authenticate, for now:
index a655521ec99e9fa78b3645916a9e6b2fad0262ff..3114dbf2d3ac3e46004c2573550ac9a2a0bd3d23 100644 (file)
@@ -48,8 +48,10 @@ const char control_c_id[] = "$Id$";
 #define CONTROL_CMD_POSTDESCRIPTOR 0x000F
 #define CONTROL_CMD_FRAGMENTHEADER 0x0010
 #define CONTROL_CMD_FRAGMENT       0x0011
-#define CONTROL_CMD_REDIRECTSTREAM  0x0012
-#define _CONTROL_CMD_MAX_RECOGNIZED 0x0012
+#define CONTROL_CMD_REDIRECTSTREAM 0x0012
+#define CONTROL_CMD_CLOSESTREAM    0x0013
+#define CONTROL_CMD_CLOSECIRCUIT   0x0014
+#define _CONTROL_CMD_MAX_RECOGNIZED 0x0014
 
 /* Recognized error codes. */
 #define ERR_UNSPECIFIED             0x0000
@@ -152,6 +154,10 @@ static int handle_control_postdescriptor(connection_t *conn, uint32_t len,
                                          const char *body);
 static int handle_control_redirectstream(connection_t *conn, uint32_t len,
                                          const char *body);
+static int handle_control_closestream(connection_t *conn, uint32_t len,
+                                      const char *body);
+static int handle_control_closecircuit(connection_t *conn, uint32_t len,
+                                       const char *body);
 
 /** Given a possibly invalid message type code <b>cmd</b>, return a
  * human-readable string equivalent. */
@@ -772,7 +778,72 @@ handle_control_redirectstream(connection_t *conn, uint32_t len,
   send_control_done(conn);
   return 0;
 }
+static int
+handle_control_closestream(connection_t *conn, uint32_t len,
+                           const char *body)
+{
+  uint32_t conn_id;
+  connection_t *ap_conn;
+  uint8_t reason;
+  int hold_open;
+
+  if (len < 6) {
+    send_control_error(conn, ERR_SYNTAX, "closestream message too short");
+    return 0;
+  }
+
+  conn_id = ntohl(get_uint32(body));
+  reason = *(uint8_t*)(body+4);
+  hold_open = (*(uint8_t*)(body+5)) & 1;
+
+  if (!(ap_conn = connection_get_by_global_id(conn_id))
+      || ap_conn->state != CONN_TYPE_AP
+      || !ap_conn->socks_request) {
+    send_control_error(conn, ERR_NO_STREAM,
+                       "No AP connection found with given ID");
+    return 0;
+  }
+
+  if (!ap_conn->socks_request->has_finished) {
+    socks5_reply_status_t status =
+      connection_edge_end_reason_socks5_response(reason);
+    connection_ap_handshake_socks_reply(ap_conn, NULL, 0, status);
+  }
+  if (hold_open)
+    ap_conn->hold_open_until_flushed = 1;
+  connection_mark_for_close(ap_conn);
+
+  send_control_done(conn);
+  return 0;
+}
+static int
+handle_control_closecircuit(connection_t *conn, uint32_t len,
+                            const char *body)
+{
+  uint32_t circ_id;
+  circuit_t *circ;
+  int safe;
 
+  if (len < 5) {
+    send_control_error(conn, ERR_SYNTAX, "closecircuit message too short");
+    return 0;
+  }
+  circ_id = ntohl(get_uint32(body));
+  safe = (*(uint8_t*)(body+4)) & 1;
+
+  if (!(circ = circuit_get_by_global_id(circ_id))) {
+    send_control_error(conn, ERR_NO_CIRC,
+                       "No circuit found with given ID");
+    return 0;
+  }
+
+  if (!safe || !circ->p_streams) {
+    circuit_mark_for_close(circ);
+  }
+
+  send_control_done(conn);
+  return 0;
+}
 
 /** Called when <b>conn</b> has no more bytes left on its outbuf. */
 int
@@ -882,6 +953,14 @@ connection_control_process_inbuf(connection_t *conn) {
       if (handle_control_redirectstream(conn, body_len, body))
         return -1;
       break;
+    case CONTROL_CMD_CLOSESTREAM:
+      if (handle_control_closestream(conn, body_len, body))
+        return -1;
+      break;
+    case CONTROL_CMD_CLOSECIRCUIT:
+      if (handle_control_closecircuit(conn, body_len, body))
+        return -1;
+      break;
     case CONTROL_CMD_ERROR:
     case CONTROL_CMD_DONE:
     case CONTROL_CMD_CONFVALUE:
index 19efee27600dfa71ced66ddfb2c80e8e032081a3..c4e7f4f28d80dcde52b0acdf448628f2c485ce2b 100644 (file)
@@ -1560,7 +1560,7 @@ int connection_edge_send_command(connection_t *fromconn, circuit_t *circ,
                                  size_t payload_len, crypt_path_t *cpath_layer);
 int connection_edge_package_raw_inbuf(connection_t *conn, int package_partial);
 void connection_edge_consider_sending_sendme(connection_t *conn);
-socks5_reply_status_t connection_edge_end_reason_sock5_response(char *payload, uint16_t length);
+socks5_reply_status_t connection_edge_end_reason_socks5_response(int reason);
 int errno_to_end_reason(int e);
 
 extern uint64_t stats_n_data_cells_packaged;
index 5fd5be9097cb3fde73176e6199812d7cff08083c..5651fd35e1f91ace7b6d5de015a902be5c9c9bae 100644 (file)
@@ -476,16 +476,13 @@ connection_edge_end_reason_str(char *payload, uint16_t length) {
   }
 }
 
-/** Translate the <b>payload</b> of length <b>length</b>, which
- * came from a relay 'end' cell, into an appropriate SOCKS5 reply code.
+/** Translate <b>reason</b> (as from a relay 'end' cell) into an
+ * appropriate SOCKS5 reply code.
  */
-static socks5_reply_status_t
-connection_edge_end_reason_socks5_response(char *payload, uint16_t length) {
-  if (length < 1) {
-    log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1.");
-    return SOCKS5_GENERAL_ERROR;
-  }
-  switch (*payload) {
+socks5_reply_status_t
+connection_edge_end_reason_socks5_response(int reason)
+{
+  switch (reason) {
     case END_STREAM_REASON_MISC:
       return SOCKS5_GENERAL_ERROR;
     case END_STREAM_REASON_RESOLVEFAILED:
@@ -511,7 +508,7 @@ connection_edge_end_reason_socks5_response(char *payload, uint16_t length) {
     case END_STREAM_REASON_TORPROTOCOL:
       return SOCKS5_GENERAL_ERROR;
     default:
-      log_fn(LOG_WARN,"Reason for ending (%d) not recognized.",*payload);
+      log_fn(LOG_WARN,"Reason for ending (%d) not recognized.",reason);
       return SOCKS5_GENERAL_ERROR;
   }
 }
@@ -817,9 +814,14 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
                                             rh.length),
              conn->stream_id, (int)conn->stream_size);
       if (conn->socks_request && !conn->socks_request->has_finished) {
-        socks5_reply_status_t status =
-          connection_edge_end_reason_socks5_response(
-                              cell->payload+RELAY_HEADER_SIZE, rh.length);
+        socks5_reply_status_t status;
+        if (rh.length < 1) {
+          log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1.");
+          status = SOCKS5_GENERAL_ERROR;
+        } else {
+          status = connection_edge_end_reason_socks5_response(
+                        *(uint8_t*)cell->payload+RELAY_HEADER_SIZE);
+        }
         connection_ap_handshake_socks_reply(conn, NULL, 0, status);
       }
 #ifdef HALF_OPEN