[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[PATCH]: Export END_CIRC_REASON_* to controler



Attached is a patch to export circuit failure reasons to the
controller. I had to convert several END_CIRC_AT_ORIGIN reason
codes to the real reason codes for calls to circuit_mark_for_close().

As far as I can tell, this shouldn't break anything because 
circuit_mark_for_close() actually does an expicit check and
if the circuit is an origin circuit, it resets the reason code
to NONE. 

Note that I did not do anything with the conn->use_extended_events
setting since that requires some pretty substantial infrastructure
changes..

The patch to the spec file is included in the diff. I've been testing
it for a while with a new version of my scanner and it seems to be OK.

-- 
Mike Perry
Mad Computer Scientist
fscked.org evil labs
Index: src/or/circuitlist.c
===================================================================
--- src/or/circuitlist.c	(revision 8642)
+++ src/or/circuitlist.c	(working copy)
@@ -796,7 +796,7 @@
     if (CIRCUIT_IS_ORIGIN(circ) &&
         !circ->marked_for_close &&
         !circ->timestamp_dirty)
-      circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+      circuit_mark_for_close(circ, END_CIRC_REASON_REQUESTED);
   }
 }
 
@@ -840,6 +840,7 @@
 _circuit_mark_for_close(circuit_t *circ, int reason, int line,
                         const char *file)
 {
+  int orig_reason = reason;
   assert_circuit_ok(circ);
   tor_assert(line);
   tor_assert(file);
@@ -861,11 +862,13 @@
   } else if (CIRCUIT_IS_ORIGIN(circ) && reason != END_CIRC_REASON_NONE) {
     /* Don't warn about this; there are plenty of places where our code
      * is origin-agnostic. */
+	/* In fact, due to the desire to export reason information to the 
+	 * controller, it has been made even more "origin-agnostic" than before */
     reason = END_CIRC_REASON_NONE;
   }
   if (reason < _END_CIRC_REASON_MIN || reason > _END_CIRC_REASON_MAX) {
     log_warn(LD_BUG, "Reason %d out of range at %s:%d", reason, file, line);
-    reason = END_CIRC_REASON_NONE;
+    orig_reason = reason = END_CIRC_REASON_NONE;
   }
 
   if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
@@ -888,7 +891,8 @@
   }
   if (CIRCUIT_IS_ORIGIN(circ)) {
     control_event_circuit_status(TO_ORIGIN_CIRCUIT(circ),
-     (circ->state == CIRCUIT_STATE_OPEN)?CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED);
+     (circ->state == CIRCUIT_STATE_OPEN)?CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED,
+     orig_reason);
   }
   if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
     origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
Index: src/or/rendservice.c
===================================================================
--- src/or/rendservice.c	(revision 8642)
+++ src/or/rendservice.c	(working copy)
@@ -612,7 +612,7 @@
  err:
   if (dh) crypto_dh_free(dh);
   if (launched)
-    circuit_mark_for_close(TO_CIRCUIT(launched), END_CIRC_AT_ORIGIN);
+    circuit_mark_for_close(TO_CIRCUIT(launched), END_CIRC_REASON_TORPROTOCOL);
   if (extend_info) extend_info_free(extend_info);
   return -1;
 }
@@ -763,7 +763,7 @@
 
   return;
  err:
-  circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_AT_ORIGIN);
+  circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_REASON_TORPROTOCOL);
 }
 
 /** Called when we get an INTRO_ESTABLISHED cell; mark the circuit as a
@@ -793,7 +793,7 @@
 
   return 0;
  err:
-  circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_AT_ORIGIN);
+  circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_REASON_TORPROTOCOL);
   return -1;
 }
 
@@ -869,7 +869,7 @@
 
   return;
  err:
-  circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_AT_ORIGIN);
+  circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_REASON_TORPROTOCOL);
 }
 
 /*
Index: src/or/control.c
===================================================================
--- src/or/control.c	(revision 8642)
+++ src/or/control.c	(working copy)
@@ -1859,8 +1859,9 @@
 
   /* now that we've populated the cpath, start extending */
   if (zero_circ) {
-    if (circuit_handle_first_hop(circ) < 0) {
-      circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
+	int err_reason = 0;
+    if ((err_reason = circuit_handle_first_hop(circ)) < 0) {
+      circuit_mark_for_close(TO_CIRCUIT(circ), err_reason);
       if (v0)
         send_control0_error(conn, ERR_INTERNAL, "couldn't start circuit");
       else
@@ -1869,11 +1870,12 @@
     }
   } else {
     if (circ->_base.state == CIRCUIT_STATE_OPEN) {
+	  int err_reason = 0;
       circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
-      if (circuit_send_next_onion_skin(circ) < 0) {
+      if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) {
         log_info(LD_CONTROL,
                  "send_next_onion_skin failed; circuit marked for closing.");
-        circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
+        circuit_mark_for_close(TO_CIRCUIT(circ), err_reason);
         if (v0)
           send_control0_error(conn, ERR_INTERNAL, "couldn't send onion skin");
         else
@@ -2737,7 +2739,8 @@
 /** Something has happened to circuit <b>circ</b>: tell any interested
  * control connections. */
 int
-control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp)
+control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp,
+		int rsn)
 {
   char *path=NULL, *msg;
   if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS))
@@ -2759,7 +2762,8 @@
   }
   if (EVENT_IS_INTERESTING1(EVENT_CIRCUIT_STATUS)) {
     const char *status;
-    switch (tp)
+    const char *reason = "";
+	switch (tp)
       {
       case CIRC_EVENT_LAUNCHED: status = "LAUNCHED"; break;
       case CIRC_EVENT_BUILT: status = "BUILT"; break;
@@ -2770,18 +2774,37 @@
         log_warn(LD_BUG, "Unrecognized status code %d", (int)tp);
         return 0;
       }
+
+    if(tp == CIRC_EVENT_FAILED || tp == CIRC_EVENT_CLOSED) {
+        switch (rsn)
+          {
+		  case END_CIRC_AT_ORIGIN: reason = " REASON=ORIGIN"; break;
+          case END_CIRC_REASON_NONE: reason = " REASON=NONE"; break;
+          case END_CIRC_REASON_TORPROTOCOL: reason = " REASON=TORPROTOCOL"; break;
+          case END_CIRC_REASON_INTERNAL: reason = " REASON=INTERNAL"; break;
+          case END_CIRC_REASON_REQUESTED: reason = " REASON=REQUESTED"; break;
+          case END_CIRC_REASON_HIBERNATING: reason = " REASON=HIBERNATING"; break;
+          case END_CIRC_REASON_RESOURCELIMIT: reason = " REASON=RESOURCELIMIT"; break;
+          case END_CIRC_REASON_CONNECTFAILED: reason = " REASON=CONNECTFAILED"; break;
+          case END_CIRC_REASON_OR_IDENTITY: reason = " REASON=OR_IDENTITY"; break;
+          case END_CIRC_REASON_OR_CONN_CLOSED: reason = " REASON=OR_CONN_CLOSED"; break;
+		  default:
+		    log_warn(LD_BUG, "Unrecognized reason code %d", (int)rsn);
+          }
+    }
+
     if (EVENT_IS_INTERESTING1S(EVENT_CIRCUIT_STATUS)) {
       send_control1_event(EVENT_CIRCUIT_STATUS, SHORT_NAMES,
-                          "650 CIRC %lu %s %s\r\n",
+                          "650 CIRC %lu %s %s%s\r\n",
                           (unsigned long)circ->global_identifier,
-                          status, path);
+                          status, path, reason);
     }
     if (EVENT_IS_INTERESTING1L(EVENT_CIRCUIT_STATUS)) {
       char *vpath = circuit_list_path_for_controller(circ);
       send_control1_event(EVENT_CIRCUIT_STATUS, LONG_NAMES,
-                          "650 CIRC %lu %s %s\r\n",
+                          "650 CIRC %lu %s %s%s\r\n",
                           (unsigned long)circ->global_identifier,
-                          status, vpath);
+                          status, vpath, reason);
       tor_free(vpath);
     }
   }
Index: src/or/or.h
===================================================================
--- src/or/or.h	(revision 8642)
+++ src/or/or.h	(working copy)
@@ -2070,7 +2070,7 @@
 int connection_control_process_inbuf(control_connection_t *conn);
 
 int control_event_circuit_status(origin_circuit_t *circ,
-                                 circuit_status_event_t e);
+                                 circuit_status_event_t e, int rsn);
 int control_event_stream_status(edge_connection_t *conn,
                                 stream_status_event_t e);
 int control_event_or_conn_status(or_connection_t *conn,
Index: src/or/command.c
===================================================================
--- src/or/command.c	(revision 8642)
+++ src/or/command.c	(working copy)
@@ -273,18 +273,19 @@
 
   if (CIRCUIT_IS_ORIGIN(circ)) { /* we're the OP. Handshake this. */
     origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
+	int err_reason = 0;
     log_debug(LD_OR,"at OP. Finishing handshake.");
-    if (circuit_finish_handshake(origin_circ, cell->command,
-                                 cell->payload) < 0) {
+    if ((err_reason = circuit_finish_handshake(origin_circ, cell->command,
+                                 cell->payload)) < 0) {
       log_warn(LD_OR,"circuit_finish_handshake failed.");
-      circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+      circuit_mark_for_close(circ, err_reason);
       return;
     }
     log_debug(LD_OR,"Moving to next skin.");
-    if (circuit_send_next_onion_skin(origin_circ) < 0) {
+    if ((err_reason = circuit_send_next_onion_skin(origin_circ)) < 0) {
       log_info(LD_OR,"circuit_send_next_onion_skin failed.");
       /* XXX push this circuit_close lower */
-      circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+      circuit_mark_for_close(circ, err_reason);
       return;
     }
   } else { /* pack it into an extended relay cell, and send it. */
Index: src/or/circuituse.c
===================================================================
--- src/or/circuituse.c	(revision 8642)
+++ src/or/circuituse.c	(working copy)
@@ -265,7 +265,7 @@
                circuit_state_to_string(victim->state), victim->purpose);
 
     circuit_log_path(LOG_INFO,LD_CIRC,TO_ORIGIN_CIRCUIT(victim));
-    circuit_mark_for_close(victim, END_CIRC_AT_ORIGIN);
+    circuit_mark_for_close(victim, END_CIRC_REASON_CONNECTFAILED);
   }
 }
 
@@ -591,7 +591,7 @@
         log_debug(LD_CIRC,
                   "Closing circuit that has been unused for %d seconds.",
                   (int)(now - circ->timestamp_created));
-        circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+        circuit_mark_for_close(circ, END_CIRC_REASON_REQUESTED);
       }
     }
   }
@@ -674,7 +674,7 @@
 void
 circuit_has_opened(origin_circuit_t *circ)
 {
-  control_event_circuit_status(circ, CIRC_EVENT_BUILT);
+  control_event_circuit_status(circ, CIRC_EVENT_BUILT, 0);
 
   switch (TO_CIRCUIT(circ)->purpose) {
     case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
Index: src/or/rendmid.c
===================================================================
--- src/or/rendmid.c	(revision 8642)
+++ src/or/rendmid.c	(working copy)
@@ -90,7 +90,7 @@
   while ((c = circuit_get_intro_point(pk_digest))) {
     log_info(LD_REND, "Replacing old circuit for service %s",
              safe_str(serviceid));
-    circuit_mark_for_close(TO_CIRCUIT(c), END_CIRC_REASON_REQUESTED);
+    circuit_mark_for_close(TO_CIRCUIT(c), END_CIRC_AT_ORIGIN);
     /* Now it's marked, and it won't be returned next time. */
   }
 
Index: src/or/circuitbuild.c
===================================================================
--- src/or/circuitbuild.c	(revision 8642)
+++ src/or/circuitbuild.c	(working copy)
@@ -298,19 +298,20 @@
                           int need_uptime, int need_capacity, int internal)
 {
   origin_circuit_t *circ;
+  int err_reason = 0;
 
   circ = origin_circuit_init(purpose, need_uptime, need_capacity, internal);
 
   if (onion_pick_cpath_exit(circ, info) < 0 ||
       onion_populate_cpath(circ) < 0) {
-    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
     return NULL;
   }
 
-  control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED);
+  control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED, 0);
 
-  if (circuit_handle_first_hop(circ) < 0) {
-    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
+  if ((err_reason = circuit_handle_first_hop(circ)) < 0) {
+    circuit_mark_for_close(TO_CIRCUIT(circ), err_reason);
     return NULL;
   }
   return circ;
@@ -327,6 +328,7 @@
   or_connection_t *n_conn;
   char tmpbuf[INET_NTOA_BUF_LEN];
   struct in_addr in;
+  int err_reason = 0;
 
   firsthop = onion_next_hop_in_cpath(circ->cpath);
   tor_assert(firsthop);
@@ -359,7 +361,7 @@
                                      firsthop->extend_info->identity_digest);
       if (!n_conn) { /* connect failed, forget the whole thing */
         log_info(LD_CIRC,"connect to firsthop failed. Closing.");
-        return -1;
+        return -END_CIRC_REASON_CONNECTFAILED;
       }
     }
 
@@ -374,9 +376,9 @@
     circ->_base.n_port = n_conn->_base.port;
     circ->_base.n_conn = n_conn;
     log_debug(LD_CIRC,"Conn open. Delivering first onion skin.");
-    if (circuit_send_next_onion_skin(circ) < 0) {
+    if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) {
       log_info(LD_CIRC,"circuit_send_next_onion_skin failed.");
-      return -1;
+      return err_reason;
     }
   }
   return 0;
@@ -393,6 +395,7 @@
 circuit_n_conn_done(or_connection_t *or_conn, int status)
 {
   smartlist_t *changed_circs;
+  int err_reason = 0;
 
   log_debug(LD_CIRC,"or_conn to %s, status=%d",
             or_conn->nickname ? or_conn->nickname : "NULL", status);
@@ -421,10 +424,10 @@
        * set_circid_orconn here. */
       circ->n_conn = or_conn;
       if (CIRCUIT_IS_ORIGIN(circ)) {
-        if (circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)) < 0) {
+        if ((err_reason = circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ))) < 0) {
           log_info(LD_CIRC,
                    "send_next_onion_skin failed; circuit marked for closing.");
-          circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+          circuit_mark_for_close(circ, err_reason);
           continue;
           /* XXX could this be bad, eg if next_onion_skin failed because conn
            *     died? */
@@ -864,7 +867,7 @@
   log_info(LD_CIRC,"Finished building %scircuit hop:",
            (reply_type == CELL_CREATED_FAST) ? "fast " : "");
   circuit_log_path(LOG_INFO,LD_CIRC,circ);
-  control_event_circuit_status(circ, CIRC_EVENT_EXTENDED);
+  control_event_circuit_status(circ, CIRC_EVENT_EXTENDED, 0);
 
   return 0;
 }
@@ -888,7 +891,7 @@
    *     means that a connection broke or an extend failed. For now,
    *     just give up.
    */
-  circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
+  circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
   return 0;
 
 #if 0
@@ -1392,12 +1395,13 @@
 int
 circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info)
 {
+  int err_reason = 0;
   circuit_append_new_exit(circ, info);
   circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
-  if (circuit_send_next_onion_skin(circ)<0) {
+  if ((err_reason = circuit_send_next_onion_skin(circ))<0) {
     log_warn(LD_CIRC, "Couldn't extend circuit to new point '%s'.",
              info->nickname);
-    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
+    circuit_mark_for_close(TO_CIRCUIT(circ), err_reason);
     return -1;
   }
   return 0;
Index: src/or/rendclient.c
===================================================================
--- src/or/rendclient.c	(revision 8642)
+++ src/or/rendclient.c	(working copy)
@@ -34,7 +34,7 @@
 
   if (crypto_rand(circ->rend_cookie, REND_COOKIE_LEN) < 0) {
     log_warn(LD_BUG, "Internal error: Couldn't produce random cookie.");
-    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
     return -1;
   }
   if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
@@ -157,8 +157,8 @@
 
   return 0;
 err:
-  circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_AT_ORIGIN);
-  circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_AT_ORIGIN);
+  circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_REASON_INTERNAL);
+  circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_REASON_INTERNAL);
   return -1;
 }
 
@@ -190,7 +190,7 @@
     log_warn(LD_PROTOCOL,
              "Received REND_INTRODUCE_ACK on unexpected circuit %d.",
              circ->_base.n_circ_id);
-    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
     return -1;
   }
 
@@ -229,7 +229,7 @@
       if (!extend_info) {
         log_warn(LD_REND, "No introduction points left for %s. Closing.",
                  escaped_safe_str(circ->rend_query));
-        circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
+        circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
         return -1;
       }
       log_info(LD_REND,
@@ -349,7 +349,7 @@
   if (circ->_base.purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
     log_warn(LD_PROTOCOL,"Got a rendezvous ack when we weren't expecting one. "
              "Closing circ.");
-    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
     return -1;
   }
   log_info(LD_REND,"Got rendezvous ack. This circuit is now ready for "
@@ -371,7 +371,7 @@
       || !circ->build_state->pending_final_cpath) {
     log_warn(LD_PROTOCOL,"Got rendezvous2 cell from hidden service, but not "
              "expecting it. Closing.");
-    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
     return -1;
   }
 
@@ -417,7 +417,7 @@
   circ->build_state->pending_final_cpath = NULL; /* prevent double-free */
   return 0;
  err:
-  circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
+  circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
   return -1;
 }
 
Index: doc/control-spec.txt
===================================================================
--- doc/control-spec.txt	(revision 8642)
+++ doc/control-spec.txt	(working copy)
@@ -751,7 +751,8 @@
 
    The syntax is:
 
-     "650" SP "CIRC" SP CircuitID SP CircStatus [SP Path]
+     "650" SP "CIRC" SP CircuitID SP CircStatus [SP Path] 
+          [SP "REASON=" Reason] CRLF
 
       CircStatus =
                "LAUNCHED" / ; circuit ID assigned to new circuit
@@ -762,9 +763,15 @@
 
       Path = ServerID *("," ServerID)
 
+      Reason = "NONE" / "TORPROTOCOL" / "INTERNAL" / "REQUESTED" / 
+               "HIBERNATING" / "RESOURCELIMIT" / "CONNECTFAILED" /
+               "OR_IDENTITY" / "OR_CONN_CLOSED"
+
    The path is provided only when the circuit has been extended at least one
    hop.
 
+   Reason is provided only for FAILED and CLOSED events.
+
 4.1.2. Stream status changed
 
     The syntax is: