Browse Source

r11824@Kushana: nickm | 2007-01-03 17:15:28 -0500
control-spec: upcase arguments in status events; note unimplemented events individually
r11825@Kushana: nickm | 2007-01-03 17:41:43 -0500
Implement EXTERNAL IP server status event.
r11826@Kushana: nickm | 2007-01-03 17:47:10 -0500
Implement BAD_SERVER_DESCRIPTOR server status event.
r11827@Kushana: nickm | 2007-01-03 18:01:56 -0500
Implement SOCKS_UNKNOWN_PROTOCOL and DANGEROUS_SOCKS client events.
r11828@Kushana: nickm | 2007-01-03 18:23:22 -0500
Implement BUG controller events. Also, flush ERR-level status events just like ERR-level log messages.
r11829@Kushana: nickm | 2007-01-03 23:37:27 -0500
Yet more status events: CLOCK_SKEW, GOOD/ACCEPTED_SERVER_DESCRIPTOR, {CHECKING_}REACHABILITY_{SUCCEEDED|FAILED}
r11833@Kushana: nickm | 2007-01-05 16:56:37 -0500
Note some unimplementedness in control-spec.txt


svn:r9279

Nick Mathewson 18 years ago
parent
commit
c8466c5919
10 changed files with 242 additions and 51 deletions
  1. 26 0
      ChangeLog
  2. 67 33
      doc/control-spec.txt
  3. 13 0
      src/or/buffers.c
  4. 5 0
      src/or/circuituse.c
  5. 21 0
      src/or/config.c
  6. 21 3
      src/or/control.c
  7. 62 15
      src/or/directory.c
  8. 3 0
      src/or/or.h
  9. 21 0
      src/or/router.c
  10. 3 0
      src/or/routerlist.c

+ 26 - 0
ChangeLog

@@ -1,3 +1,26 @@
+Changes in version 0.1.2.6-alpha - 2007-??-??
+  o Minor features (controller):
+    - Implement EXTERNAL_ADDRESS server status event so controllers can
+      learn when our address changes.
+    - Implement BAD_SERVER_DESCRIPTOR server status event so controllers
+      can learn when directories reject our descriptor.
+    - Implement SOCKS_UNKNOWN_PROTOCOL client status event so controllers
+      can learn when a client application is speaking a non-socks protocol
+      to our SocksPort.
+    - Implement DANGEROUS_SOCKS client status event so controllers
+      can learn when a client application is leaking DNS addresses.
+    - Implement BUG general status event so controllers can learn when
+      Tor is unhappy about its internal invariants.
+    - Implement CLOCK_SKEW general status event so controllers can learn
+      when Tor thinks the system clock is set incorrectly.
+    - Implement GOOD_SERVER_DESCRIPTOR and ACCEPTED_SERVER_DESCRIPTOR
+      server status events so controllers can learn when their descriptors
+      are accepted by a directory.
+    - Implement CHECKING_REACHABILITY and REACHABILITY_{SUCCEEDED|FAILED}
+      server status events so controllers can learn about Tor's progress in
+      deciding whether it's reachable from the outside.
+
+
 Changes in version 0.1.2.5-alpha - 2007-01-06
 Changes in version 0.1.2.5-alpha - 2007-01-06
   o Major features:
   o Major features:
     - Enable write limiting as well as read limiting. Now we sacrifice
     - Enable write limiting as well as read limiting. Now we sacrifice
@@ -159,6 +182,9 @@ Changes in version 0.1.2.5-alpha - 2007-01-06
       when the last second's write or read exceeds the allotted bandwidth.
       when the last second's write or read exceeds the allotted bandwidth.
     - Report "unrecognized key" rather than an empty string when the
     - Report "unrecognized key" rather than an empty string when the
       controller tries to fetch a networkstatus that doesn't exist.
       controller tries to fetch a networkstatus that doesn't exist.
+    - Flush ERR-level status events just like we currently flush ERR-level
+      log events, so that a Tor shutdown doesn't prevent the controller from
+      learning about current events.
 
 
 
 
 Changes in version 0.1.2.4-alpha - 2006-12-03
 Changes in version 0.1.2.4-alpha - 2006-12-03

+ 67 - 33
doc/control-spec.txt

@@ -962,7 +962,8 @@ $Id$
      Severity = "NOTICE" / "WARN" / "ERR"
      Severity = "NOTICE" / "WARN" / "ERR"
 
 
      Action is a string, and Arguments is a series of keyword=value
      Action is a string, and Arguments is a series of keyword=value
-     pairs on the same line.
+     pairs on the same line.  Values may be space-terminated strings,
+     or quoted strings.
 
 
      These events are always produced with EXTENDED_EVENTS and
      These events are always produced with EXTENDED_EVENTS and
      VERBOSE_NAMES; see the explanations in the USEFEATURE section
      VERBOSE_NAMES; see the explanations in the USEFEATURE section
@@ -971,7 +972,7 @@ $Id$
   Actions for STATUS_GENERAL events can be as follows:
   Actions for STATUS_GENERAL events can be as follows:
 
 
      CLOCK_JUMPED
      CLOCK_JUMPED
-     "time=NUM"
+     "TIME=NUM"
        Tor spent enough time without CPU cycles that it has closed all
        Tor spent enough time without CPU cycles that it has closed all
        its circuits and will establish them anew. This typically
        its circuits and will establish them anew. This typically
        happens when a laptop goes to sleep and then wakes up again. It
        happens when a laptop goes to sleep and then wakes up again. It
@@ -995,20 +996,19 @@ do for each. -RD]
   typically severity WARN events:
   typically severity WARN events:
 
 
      DANGEROUS_VERSION
      DANGEROUS_VERSION
-     "current=version"
+     "CURRENT=version"
-     "reason=new/old/unrecommended"
+     "REASON=NEW/OLD/UNRECOMMENDED"
-     "recommended=\"version, version, ...\""
+     "RECOMMENDED=\"version, version, ...\""
 
 
      TOO_MANY_CONNECTIONS
      TOO_MANY_CONNECTIONS
-     "current=NUM"
+     "CURRENT=NUM"
        Tor has reached its ulimit -n or whatever the native limit is on
        Tor has reached its ulimit -n or whatever the native limit is on
        file descriptors or sockets. The user should really do something
        file descriptors or sockets. The user should really do something
        about this. The "current" argument shows the number of connections
        about this. The "current" argument shows the number of connections
        currently open.
        currently open.
 
 
-   [rest not implemented yet]
      BUG
      BUG
-     "reason=STRING"
+     "REASON=STRING"
        Tor has encountered a situation that its developers never expected,
        Tor has encountered a situation that its developers never expected,
        and the developers would like to learn that it happened. Perhaps
        and the developers would like to learn that it happened. Perhaps
        the controller can explain this to the user and encourage her to
        the controller can explain this to the user and encourage her to
@@ -1018,19 +1018,24 @@ do for each. -RD]
      not DIR_ALL_UNREACHABLE, else as ERRs:]
      not DIR_ALL_UNREACHABLE, else as ERRs:]
 
 
      BAD_DIR_RESPONSE
      BAD_DIR_RESPONSE
+     [unimplemented]
      // unexpected dir response. behind a hotel/airport firewall?
      // unexpected dir response. behind a hotel/airport firewall?
 
 
      CLOCK_SKEWED
      CLOCK_SKEWED
-     // (either from talking to a dir authority, or from perusing a
+       SKEW="+" / "-" SECONDS
-     //  network-status timestamp)
+       SOURCE="DIRSERV:IP:Port" / "NETWORKSTATUS:IP:PORT"
+         If "SKEW" is present, it's an estimate of how far we are from the
+         time declared in the source.  If the source is a DIRSERV, we got
+         the current time from a connection to a dirserver.  If the source is
+         a NETWORKSTATUS, we decided we're skewed because we got a
+         networkstatus from far in the future.
 
 
   Actions for STATUS_GENERAL severity ERR events can be as follows:
   Actions for STATUS_GENERAL severity ERR events can be as follows:
 
 
-[unimplemented]
      BAD_PROXY
      BAD_PROXY
+     [unimplemented]
      // bad http or https proxy?
      // bad http or https proxy?
 
 
-[implemented]
      DIR_ALL_UNREACHABLE
      DIR_ALL_UNREACHABLE
        Tor believes that none of the known directory servers are
        Tor believes that none of the known directory servers are
        reachable -- this is most likely because the local network is
        reachable -- this is most likely because the local network is
@@ -1038,7 +1043,6 @@ do for each. -RD]
        user why Tor appears to be broken.
        user why Tor appears to be broken.
 
 
   Actions for STATUS_CLIENT severity NOTICE events can be as follows:
   Actions for STATUS_CLIENT severity NOTICE events can be as follows:
-  [all implemented]
 
 
      ENOUGH_DIR_INFO
      ENOUGH_DIR_INFO
        Tor now knows enough network-status documents and enough server
        Tor now knows enough network-status documents and enough server
@@ -1063,7 +1067,7 @@ do for each. -RD]
        if it can identify the problem.]
        if it can identify the problem.]
 
 
      CIRCUIT_NOT_ESTABLISHED
      CIRCUIT_NOT_ESTABLISHED
-     "reason=" "EXTERNAL_ADDRESS" / "DIR_ALL_UNREACHABLE" / "CLOCK_JUMPED"
+     "REASON=" "EXTERNAL_ADDRESS" / "DIR_ALL_UNREACHABLE" / "CLOCK_JUMPED"
        We are no longer confident that we can build circuits. The "reason"
        We are no longer confident that we can build circuits. The "reason"
        keyword provides an explanation: which other status event type caused
        keyword provides an explanation: which other status event type caused
        our lack of confidence.
        our lack of confidence.
@@ -1072,19 +1076,23 @@ do for each. -RD]
        [Note: only REASON=CLOCK_JUMPED is implemented currently.]
        [Note: only REASON=CLOCK_JUMPED is implemented currently.]
 
 
   Actions for STATUS_CLIENT severity WARN events can be as follows:
   Actions for STATUS_CLIENT severity WARN events can be as follows:
-  [none implemented yet]
 
 
      DANGEROUS_SOCKS
      DANGEROUS_SOCKS
-     "protocol=socks4/socks4a/socks5"
+     "PROTOCOL=SOCKS4/SOCKS4a/SOCKS5"
-     "address=IP:port"
+     "ADDRESS=IP:port"
+       A connection was made to Tor's SOCKS port that used a raw IP
+       address.  If the client application got this address from
+       gethostbyname(), it's leaking target addresses via DNS.
 
 
      SOCKS_UNKNOWN_PROTOCOL
      SOCKS_UNKNOWN_PROTOCOL
+       "DATA=string"
        A connection was made to Tor's SOCKS port that tried to use it
        A connection was made to Tor's SOCKS port that tried to use it
        for something other than the SOCKS protocol. Perhaps the user is
        for something other than the SOCKS protocol. Perhaps the user is
-       using Tor as an HTTP proxy?
+       using Tor as an HTTP proxy?   The DATA is the first few characters
+       sent to Tor on the SOCKS port.
 
 
      BAD_HOSTNAME
      BAD_HOSTNAME
-
+     [unimplemented]
      // a nickname we asked for is unavailable. no need for this
      // a nickname we asked for is unavailable. no need for this
      // quite yet, since no end-user controllers let you configure that.
      // quite yet, since no end-user controllers let you configure that.
 
 
@@ -1093,47 +1101,73 @@ do for each. -RD]
      [none yet]
      [none yet]
 
 
   Actions for STATUS_SERVER severity NOTICE events can be as follows:
   Actions for STATUS_SERVER severity NOTICE events can be as follows:
-  [none implemented yet]
 
 
      EXTERNAL_ADDRESS
      EXTERNAL_ADDRESS
-     "address=IP"
+     "ADDRESS=IP"
-     "method=guessed/resolved/..."
+     "HOSTNAME=NAME"
+     "METHOD=CONFIGURED/DIRSERV/RESOLVED/INTERFACE/GETHOSTNAME"
+       Our best idea for our externally visible IP has changed to 'IP'.
+       If 'NAME' is present, we got the new IP by resolving 'NAME'.  If the
+       method is 'CONFIGURED', the IP was given verbatim as a configuration
+       option.  If the method is 'RESOLVED', we resolved the Address
+       configuration option to get the IP.  If the method is 'GETHOSTNAME',
+       we resolved our hostname to get the IP.  If the method is 'INTERFACE',
+       we got the address of one of our network interfaces to get the IP.  If
+       the method is 'DIRSERV', a directory server told us a guess for what
+       our IP might be.
 
 
      // hibernating
      // hibernating
 
 
      CHECKING_REACHABILITY
      CHECKING_REACHABILITY
-     "oraddress=IP:port"
+     "ORADDRESS=IP:port"
-     "diraddress=IP:port"
+     "DIRADDRESS=IP:port"
-     "timeout=NUM"
+     "TIMEOUT=NUM"     [timeout unimplemented]
+       We're going to start testing the reachability of our external OR port
+       or directory port.
+
+     REACHABILITY_SUCCEEDED
+     "ORADDRESS=IP:port"
+     "DIRADDRESS=IP:port"
+       We successfully verified the reachability of our external OR port or
+       directory port.
 
 
      GOOD_SERVER_DESCRIPTOR
      GOOD_SERVER_DESCRIPTOR
        We successfully uploaded our server descriptor to each of the
        We successfully uploaded our server descriptor to each of the
        directory authorities, with no complaints.
        directory authorities, with no complaints.
 
 
   Actions for STATUS_SERVER severity WARN events can be as follows:
   Actions for STATUS_SERVER severity WARN events can be as follows:
-  [not implemented yet]
 
 
      // something about failing to parse our address?
      // something about failing to parse our address?
      // from resolve_my_address() in config.c
      // from resolve_my_address() in config.c
+     [unimplemented]
 
 
      // sketchy libevent, sketchy OS, sketchy threading
      // sketchy libevent, sketchy OS, sketchy threading
+     [unimplemented]
 
 
      // too many onions queued. threading problem or slow cpu?
      // too many onions queued. threading problem or slow cpu?
+     [unimplemented]
 
 
      // eventdns statements. like, hijacked dns.
      // eventdns statements. like, hijacked dns.
+     [unimplemented]
 
 
      BAD_SERVER_DESCRIPTOR
      BAD_SERVER_DESCRIPTOR
-     "dirauth=nickname"
+     "DIRAUTH=addr:port"
-     "reason=string"
+     "REASON=string"
-     // dir authorities didn't like my descriptor, e.g. because they
+        A directory authority rejected our descriptor.  Possible reasons
-     // think it's malformed, you're invalid, or wrong key.
+        include malformed descriptors, incorrect keys, highly skewed clocks,
+        and so on.
+
+     ACCEPTED_SERVER_DESCRIPTOR
+     "DIRAUTH=addr:port"
+        A single directory authority accepted our descriptor.
 
 
   Actions for STATUS_SERVER severity ERR events can be as follows:
   Actions for STATUS_SERVER severity ERR events can be as follows:
-  [not implemented yet]
 
 
      REACHABILITY_FAILED
      REACHABILITY_FAILED
-     "oraddress=IP:port"
+     "ORADDRESS=IP:port"
-     "diraddress=IP:port"
+     "DIRADDRESS=IP:port"
+       We failed to connect to our external OR port or directory port
+       successfully.
 
 
   Controllers must tolerate hearing about actions that they don't
   Controllers must tolerate hearing about actions that they don't
   recognize.
   recognize.

+ 13 - 0
src/or/buffers.c

@@ -1022,6 +1022,9 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
                 "TorFAQ#SOCKSAndDNS.%s", req->port,
                 "TorFAQ#SOCKSAndDNS.%s", req->port,
                 safe_socks ? " Rejecting." : "");
                 safe_socks ? " Rejecting." : "");
 //            have_warned_about_unsafe_socks = 1; // (for now, warn every time)
 //            have_warned_about_unsafe_socks = 1; // (for now, warn every time)
+            control_event_client_status(LOG_WARN,
+                          "DANGEROUS_SOCKS PROTOCOL=SOCKS5 ADDRESS=%s:%d",
+                          req->address, req->port);
             if (safe_socks)
             if (safe_socks)
               return -1;
               return -1;
           }
           }
@@ -1125,6 +1128,9 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
                  "TorFAQ#SOCKSAndDNS.%s", req->port,
                  "TorFAQ#SOCKSAndDNS.%s", req->port,
                  safe_socks ? " Rejecting." : "");
                  safe_socks ? " Rejecting." : "");
 //      have_warned_about_unsafe_socks = 1; // (for now, warn every time)
 //      have_warned_about_unsafe_socks = 1; // (for now, warn every time)
+        control_event_client_status(LOG_WARN,
+                        "DANGEROUS_SOCKS PROTOCOL=SOCKS4 ADDRESS=%s:%d",
+                        tmpbuf, req->port);
         if (safe_socks)
         if (safe_socks)
           return -1;
           return -1;
       }
       }
@@ -1200,6 +1206,13 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
       log_warn(LD_APP,
       log_warn(LD_APP,
                "Socks version %d not recognized. (Tor is not an http proxy.)",
                "Socks version %d not recognized. (Tor is not an http proxy.)",
                *(buf->cur));
                *(buf->cur));
+      {
+        char *tmp = tor_strndup(buf->cur, 8);
+        control_event_client_status(LOG_WARN,
+                                    "SOCKS_UNKNOWN_PROTOCOL DATA=\"%s\"",
+                                    escaped(tmp));
+        tor_free(tmp);
+      }
       return -1;
       return -1;
   }
   }
 }
 }

+ 5 - 0
src/or/circuituse.c

@@ -622,12 +622,17 @@ circuit_testing_opened(origin_circuit_t *circ)
 static void
 static void
 circuit_testing_failed(origin_circuit_t *circ, int at_last_hop)
 circuit_testing_failed(origin_circuit_t *circ, int at_last_hop)
 {
 {
+  routerinfo_t *me = router_get_my_routerinfo();
   if (server_mode(get_options()) && check_whether_orport_reachable())
   if (server_mode(get_options()) && check_whether_orport_reachable())
     return;
     return;
+  if (!me)
+    return;
 
 
   log_info(LD_GENERAL,
   log_info(LD_GENERAL,
            "Our testing circuit (to see if your ORPort is reachable) "
            "Our testing circuit (to see if your ORPort is reachable) "
            "has failed. I'll try again later.");
            "has failed. I'll try again later.");
+  control_event_server_status(LOG_WARN, "REACHABILITY_FAILED ORADDRESS=%s:%d",
+                             me->address, me->or_port);
 
 
   /* These aren't used yet. */
   /* These aren't used yet. */
   (void)circ;
   (void)circ;

+ 21 - 0
src/or/config.c

@@ -1801,6 +1801,7 @@ resolve_my_address(int warn_severity, or_options_t *options,
   char hostname[256];
   char hostname[256];
   int explicit_ip=1;
   int explicit_ip=1;
   int explicit_hostname=1;
   int explicit_hostname=1;
+  int from_interface=0;
   char tmpbuf[INET_NTOA_BUF_LEN];
   char tmpbuf[INET_NTOA_BUF_LEN];
   const char *address = options->Address;
   const char *address = options->Address;
   int notice_severity = warn_severity <= LOG_NOTICE ?
   int notice_severity = warn_severity <= LOG_NOTICE ?
@@ -1843,6 +1844,7 @@ resolve_my_address(int warn_severity, or_options_t *options,
                "Could not get local interface IP address. Failing.");
                "Could not get local interface IP address. Failing.");
         return -1;
         return -1;
       }
       }
+      from_interface = 1;
       in.s_addr = htonl(interface_ip);
       in.s_addr = htonl(interface_ip);
       tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf));
       tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf));
       log_fn(notice_severity, LD_CONFIG, "Learned IP address '%s' for "
       log_fn(notice_severity, LD_CONFIG, "Learned IP address '%s' for "
@@ -1872,6 +1874,7 @@ resolve_my_address(int warn_severity, or_options_t *options,
                  "Interface IP address '%s' is a private address too. "
                  "Interface IP address '%s' is a private address too. "
                  "Ignoring.", tmpbuf);
                  "Ignoring.", tmpbuf);
         } else {
         } else {
+          from_interface = 1;
           in.s_addr = htonl(interface_ip);
           in.s_addr = htonl(interface_ip);
           tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf));
           tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf));
           log_fn(notice_severity, LD_CONFIG,
           log_fn(notice_severity, LD_CONFIG,
@@ -1914,6 +1917,24 @@ resolve_my_address(int warn_severity, or_options_t *options,
     log_notice(LD_NET, "Your IP address seems to have changed. Updating.");
     log_notice(LD_NET, "Your IP address seems to have changed. Updating.");
     ip_address_changed(0);
     ip_address_changed(0);
   }
   }
+  if (last_resolved_addr != *addr_out) {
+    const char *method;
+    const char *h = hostname;
+    if (explicit_ip) {
+      method = "CONFIGURED";
+      h = NULL;
+    } else if (explicit_hostname) {
+      method = "RESOLVED";
+    } else if (from_interface) {
+      method = "INTERFACE";
+      h = NULL;
+    } else {
+      method = "GETHOSTNAME";
+    }
+    control_event_server_status(LOG_NOTICE,
+                                "EXTERNAL_ADDRESS ADDRESS=%s METHOD=%s %s%s",
+                                tmpbuf, method, h?"HOSTNAME=":"", h);
+  }
   last_resolved_addr = *addr_out;
   last_resolved_addr = *addr_out;
   if (hostname_out)
   if (hostname_out)
     *hostname_out = tor_strdup(hostname);
     *hostname_out = tor_strdup(hostname);

+ 21 - 3
src/or/control.c

@@ -314,7 +314,8 @@ control_adjust_event_log_severity(void)
       break;
       break;
     }
     }
   }
   }
-  if (EVENT_IS_INTERESTING(EVENT_LOG_OBSOLETE)) {
+  if (EVENT_IS_INTERESTING(EVENT_LOG_OBSOLETE) ||
+      EVENT_IS_INTERESTING(EVENT_STATUS_GENERAL)) {
     if (min_log_event > EVENT_NOTICE_MSG)
     if (min_log_event > EVENT_NOTICE_MSG)
       min_log_event = EVENT_NOTICE_MSG;
       min_log_event = EVENT_NOTICE_MSG;
     if (max_log_event < EVENT_ERR_MSG)
     if (max_log_event < EVENT_ERR_MSG)
@@ -661,8 +662,17 @@ send_control1_event_string(uint16_t event, event_format_t which,
           continue;
           continue;
       }
       }
       if (control_conn->event_mask & (1<<event)) {
       if (control_conn->event_mask & (1<<event)) {
+        int is_err = 0;
         connection_write_to_buf(msg, strlen(msg), TO_CONN(control_conn));
         connection_write_to_buf(msg, strlen(msg), TO_CONN(control_conn));
         if (event == EVENT_ERR_MSG)
         if (event == EVENT_ERR_MSG)
+          is_err = 1;
+        else if (event == EVENT_STATUS_GENERAL)
+          is_err = !strcmpstart(msg, "STATUS_GENERAL ERR ");
+        else if (event == EVENT_STATUS_CLIENT)
+          is_err = !strcmpstart(msg, "STATUS_CLIENT ERR ");
+        else if (event == EVENT_STATUS_SERVER)
+          is_err = !strcmpstart(msg, "STATUS_SERVER ERR ");
+        if (is_err)
           connection_handle_write(TO_CONN(control_conn), 1);
           connection_handle_write(TO_CONN(control_conn), 1);
       }
       }
     }
     }
@@ -3326,14 +3336,22 @@ enable_control_logging(void)
 
 
 /** We got a log message: tell any interested control connections. */
 /** We got a log message: tell any interested control connections. */
 void
 void
-control_event_logmsg(int severity, unsigned int domain, const char *msg)
+control_event_logmsg(int severity, uint32_t domain, const char *msg)
 {
 {
   int oldlog, event;
   int oldlog, event;
-  (void) domain;
 
 
   if (disable_log_messages)
   if (disable_log_messages)
     return;
     return;
 
 
+  if (domain == LD_BUG && EVENT_IS_INTERESTING(EVENT_STATUS_GENERAL) &&
+      severity <= LOG_NOTICE) {
+    char *esc = esc_for_log(msg);
+    ++disable_log_messages;
+    control_event_general_status(severity, "BUG REASON=\"%s\"", esc);
+    --disable_log_messages;
+    tor_free(esc);
+  }
+
   oldlog = EVENT_IS_INTERESTING0(EVENT_LOG_OBSOLETE) &&
   oldlog = EVENT_IS_INTERESTING0(EVENT_LOG_OBSOLETE) &&
     (severity == LOG_NOTICE || severity == LOG_WARN || severity == LOG_ERR);
     (severity == LOG_NOTICE || severity == LOG_WARN || severity == LOG_ERR);
   event = log_severity_to_event(severity);
   event = log_severity_to_event(severity);

+ 62 - 15
src/or/directory.c

@@ -117,6 +117,8 @@ directory_post_to_dirservers(uint8_t purpose, const char *payload,
       if (!post_to_hidserv_only &&
       if (!post_to_hidserv_only &&
           !(ds->is_v1_authority || ds->is_v2_authority))
           !(ds->is_v1_authority || ds->is_v2_authority))
         continue;
         continue;
+      if (purpose == DIR_PURPOSE_UPLOAD_DIR)
+        ds->has_accepted_serverdesc = 0;
       post_via_tor = purpose_is_private(purpose) ||
       post_via_tor = purpose_is_private(purpose) ||
               !fascist_firewall_allows_address_dir(ds->addr, ds->dir_port);
               !fascist_firewall_allows_address_dir(ds->addr, ds->dir_port);
       directory_initiate_command_routerstatus(rs, purpose, post_via_tor,
       directory_initiate_command_routerstatus(rs, purpose, post_via_tor,
@@ -286,6 +288,22 @@ directory_initiate_command_routerstatus(routerstatus_t *status,
                              payload, payload_len);
                              payload, payload_len);
 }
 }
 
 
+/** DOCDOC */
+static int
+directory_conn_is_self_reachability_test(dir_connection_t *conn)
+{
+  if (conn->requested_resource &&
+      !strcmpstart(conn->requested_resource,"authority")) {
+    routerinfo_t *me = router_get_my_routerinfo();
+    if (me &&
+        router_digest_is_me(conn->identity_digest) &&
+        me->addr == conn->_base.addr &&
+        me->dir_port == conn->_base.port)
+      return 1;
+  }
+  return 0;
+}
+
 /** Called when we are unable to complete the client's request to a directory
 /** Called when we are unable to complete the client's request to a directory
  * server due to a network error: Mark the router as down and try again if
  * server due to a network error: Mark the router as down and try again if
  * possible.
  * possible.
@@ -302,6 +320,14 @@ connection_dir_request_failed(dir_connection_t *conn)
              conn->_base.address, conn->_base.port);
              conn->_base.address, conn->_base.port);
     directory_get_from_dirserver(conn->_base.purpose, NULL,
     directory_get_from_dirserver(conn->_base.purpose, NULL,
                                  0 /* don't retry_if_no_servers */);
                                  0 /* don't retry_if_no_servers */);
+
+    if (directory_conn_is_self_reachability_test(conn)) {
+      routerinfo_t *me = router_get_my_routerinfo();
+      if (me)
+        control_event_server_status(LOG_WARN,
+                                    "REACHABILITY_FAILED DIRADDRESS=%s:%d",
+                                    me->address, me->dir_port);
+    }
   } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) {
   } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) {
     log_info(LD_DIR, "Giving up on directory server at '%s'; retrying",
     log_info(LD_DIR, "Giving up on directory server at '%s'; retrying",
              conn->_base.address);
              conn->_base.address);
@@ -920,8 +946,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
     now = time(NULL);
     now = time(NULL);
     delta = now-date_header;
     delta = now-date_header;
     if (abs(delta)>ALLOW_DIRECTORY_TIME_SKEW) {
     if (abs(delta)>ALLOW_DIRECTORY_TIME_SKEW) {
-      log_fn(router_digest_is_trusted_dir(conn->identity_digest) ?
+      int trusted = router_digest_is_trusted_dir(conn->identity_digest);
-                                                        LOG_WARN : LOG_INFO,
+      log_fn(trusted ? LOG_WARN : LOG_INFO,
              LD_HTTP,
              LD_HTTP,
              "Received directory with skewed time (server '%s:%d'): "
              "Received directory with skewed time (server '%s:%d'): "
              "we are %d minutes %s, or the directory is %d minutes %s.",
              "we are %d minutes %s, or the directory is %d minutes %s.",
@@ -929,6 +955,9 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
              abs(delta)/60, delta>0 ? "ahead" : "behind",
              abs(delta)/60, delta>0 ? "ahead" : "behind",
              abs(delta)/60, delta>0 ? "behind" : "ahead");
              abs(delta)/60, delta>0 ? "behind" : "ahead");
       skewed = 1; /* don't check the recommended-versions line */
       skewed = 1; /* don't check the recommended-versions line */
+      control_event_general_status(trusted ? LOG_WARN : LOG_NOTICE,
+                               "CLOCK_SKEW SKEW=%d SOURCE=DIRSERV:%s:%d",
+                               delta, conn->_base.address, conn->_base.port);
     } else {
     } else {
       log_debug(LD_HTTP, "Time on received directory is within tolerance; "
       log_debug(LD_HTTP, "Time on received directory is within tolerance; "
                 "we are %d seconds skewed.  (That's okay.)", delta);
                 "we are %d seconds skewed.  (That's okay.)", delta);
@@ -1173,28 +1202,43 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
       SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
       SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
       smartlist_free(which);
       smartlist_free(which);
     }
     }
-    if (conn->requested_resource &&
+    if (directory_conn_is_self_reachability_test(conn))
-        !strcmpstart(conn->requested_resource,"authority")) {
+      router_dirport_found_reachable();
-      /* this might have been a dirport reachability test. see if it is. */
-      routerinfo_t *me = router_get_my_routerinfo();
-      if (me &&
-          router_digest_is_me(conn->identity_digest) &&
-          me->addr == conn->_base.addr &&
-          me->dir_port == conn->_base.port)
-        router_dirport_found_reachable();
-    }
   }
   }
 
 
   if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_DIR) {
   if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_DIR) {
     switch (status_code) {
     switch (status_code) {
-      case 200:
+      case 200: {
-        log_info(LD_GENERAL,"eof (status 200) after uploading server "
+          int all_done = 1;
-                 "descriptor: finished.");
+          trusted_dir_server_t *ds =
+            router_get_trusteddirserver_by_digest(conn->identity_digest);
+          smartlist_t *servers;
+          log_info(LD_GENERAL,"eof (status 200) after uploading server "
+                   "descriptor: finished.");
+          control_event_server_status(
+                      LOG_NOTICE, "ACCEPTED_SERVER_DESCRIPTOR DIRAUTH=%s:%d",
+                      conn->_base.address, conn->_base.port);
+
+          ds->has_accepted_serverdesc = 1;
+          servers = router_get_trusted_dir_servers();
+          SMARTLIST_FOREACH(servers, trusted_dir_server_t *, d, {
+              if ((d->is_v1_authority || d->is_v2_authority) &&
+                  !d->has_accepted_serverdesc) {
+                all_done = 0;
+                break;
+              }
+            });
+          if (all_done)
+            control_event_server_status(LOG_NOTICE, "GOOD_SERVER_DESCRIPTOR");
+        }
         break;
         break;
       case 400:
       case 400:
         log_warn(LD_GENERAL,"http status 400 (%s) response from "
         log_warn(LD_GENERAL,"http status 400 (%s) response from "
                  "dirserver '%s:%d'. Please correct.",
                  "dirserver '%s:%d'. Please correct.",
                  escaped(reason), conn->_base.address, conn->_base.port);
                  escaped(reason), conn->_base.address, conn->_base.port);
+        control_event_server_status(LOG_WARN,
+                      "BAD_SERVER_DESCRIPTOR DIRAUTH=%s:%d REASON=\"%s\"",
+                      conn->_base.address, conn->_base.port, escaped(reason));
         break;
         break;
       case 403:
       case 403:
         log_warn(LD_GENERAL,
         log_warn(LD_GENERAL,
@@ -1204,6 +1248,9 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
              "private IP address? See http://tor.eff.org/doc/"
              "private IP address? See http://tor.eff.org/doc/"
              "tor-doc-server.html",escaped(reason), conn->_base.address,
              "tor-doc-server.html",escaped(reason), conn->_base.address,
              conn->_base.port);
              conn->_base.port);
+        control_event_server_status(LOG_WARN,
+                      "BAD_SERVER_DESCRIPTOR DIRAUTH=%s:%d REASON=\"%s\"",
+                      conn->_base.address, conn->_base.port, escaped(reason));
         break;
         break;
       default:
       default:
         log_warn(LD_GENERAL,
         log_warn(LD_GENERAL,

+ 3 - 0
src/or/or.h

@@ -2717,6 +2717,9 @@ typedef struct trusted_dir_server_t {
   unsigned int is_v2_authority:1;
   unsigned int is_v2_authority:1;
   /** True iff this server is an authority for hidden services. */
   /** True iff this server is an authority for hidden services. */
   unsigned int is_hidserv_authority:1;
   unsigned int is_hidserv_authority:1;
+  /** True iff this server has accepted the most recent server descriptor
+   * we tried to upload to it. */
+  unsigned int has_accepted_serverdesc:1;
 
 
   int n_networkstatus_failures; /**< How many times have we asked for this
   int n_networkstatus_failures; /**< How many times have we asked for this
                                  * server's network-status unsuccessfully? */
                                  * server's network-status unsuccessfully? */

+ 21 - 0
src/or/router.c

@@ -457,6 +457,9 @@ consider_testing_reachability(int test_or, int test_dir)
              !orport_reachable ? "reachability" : "bandwidth",
              !orport_reachable ? "reachability" : "bandwidth",
              me->address, me->or_port);
              me->address, me->or_port);
     circuit_launch_by_router(CIRCUIT_PURPOSE_TESTING, 0, me, 0, 1, 1);
     circuit_launch_by_router(CIRCUIT_PURPOSE_TESTING, 0, me, 0, 1, 1);
+    control_event_server_status(LOG_NOTICE,
+                                "CHECKING_REACHABILITY ORADDRESS=%s:%d",
+                                me->address, me->or_port);
   }
   }
 
 
   if (test_dir && !check_whether_dirport_reachable() &&
   if (test_dir && !check_whether_dirport_reachable() &&
@@ -466,6 +469,9 @@ consider_testing_reachability(int test_or, int test_dir)
     /* ask myself, via tor, for my server descriptor. */
     /* ask myself, via tor, for my server descriptor. */
     directory_initiate_command_router(me, DIR_PURPOSE_FETCH_SERVERDESC,
     directory_initiate_command_router(me, DIR_PURPOSE_FETCH_SERVERDESC,
                                       1, "authority", NULL, 0);
                                       1, "authority", NULL, 0);
+    control_event_server_status(LOG_NOTICE,
+                                "CHECKING_REACHABILITY DIRADDRESS=%s:%d",
+                                me->address, me->dir_port);
   }
   }
 }
 }
 
 
@@ -474,12 +480,18 @@ void
 router_orport_found_reachable(void)
 router_orport_found_reachable(void)
 {
 {
   if (!can_reach_or_port) {
   if (!can_reach_or_port) {
+    routerinfo_t *me = router_get_my_routerinfo();
     log_notice(LD_OR,"Self-testing indicates your ORPort is reachable from "
     log_notice(LD_OR,"Self-testing indicates your ORPort is reachable from "
                "the outside. Excellent.%s",
                "the outside. Excellent.%s",
                get_options()->PublishServerDescriptor ?
                get_options()->PublishServerDescriptor ?
                  " Publishing server descriptor." : "");
                  " Publishing server descriptor." : "");
     can_reach_or_port = 1;
     can_reach_or_port = 1;
     mark_my_descriptor_dirty();
     mark_my_descriptor_dirty();
+    if (!me)
+      return;
+    control_event_server_status(LOG_NOTICE,
+                                "REACHABILITY_SUCCEEDED ORADDRESS=%s:%d",
+                                me->address, me->dir_port);
   }
   }
 }
 }
 
 
@@ -488,10 +500,16 @@ void
 router_dirport_found_reachable(void)
 router_dirport_found_reachable(void)
 {
 {
   if (!can_reach_dir_port) {
   if (!can_reach_dir_port) {
+    routerinfo_t *me = router_get_my_routerinfo();
     log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable "
     log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable "
                "from the outside. Excellent.");
                "from the outside. Excellent.");
     can_reach_dir_port = 1;
     can_reach_dir_port = 1;
     mark_my_descriptor_dirty();
     mark_my_descriptor_dirty();
+    if (!me)
+      return;
+    control_event_server_status(LOG_NOTICE,
+                                "REACHABILITY_SUCCEEDED DIRADDRESS=%s:%d",
+                                me->address, me->dir_port);
   }
   }
 }
 }
 
 
@@ -1034,6 +1052,9 @@ router_new_address_suggestion(const char *suggestion)
    * us an answer different from what we had the last time we managed to
    * us an answer different from what we had the last time we managed to
    * resolve it. */
    * resolve it. */
   if (last_guessed_ip != addr) {
   if (last_guessed_ip != addr) {
+    control_event_server_status(LOG_NOTICE,
+                                "EXTERNAL_ADDRESS ADDRESS=%s METHOD=DIRSERV",
+                                suggestion);
     log_addr_has_changed(LOG_NOTICE, last_guessed_ip, addr);
     log_addr_has_changed(LOG_NOTICE, last_guessed_ip, addr);
     ip_address_changed(0);
     ip_address_changed(0);
     last_guessed_ip = addr; /* router_rebuild_descriptor() will fetch it */
     last_guessed_ip = addr; /* router_rebuild_descriptor() will fetch it */

+ 3 - 0
src/or/routerlist.c

@@ -2346,6 +2346,9 @@ router_set_networkstatus(const char *s, time_t arrived_at,
              "(%s GMT). Somebody is skewed here: check your clock. "
              "(%s GMT). Somebody is skewed here: check your clock. "
              "Not caching.",
              "Not caching.",
              source_desc, published);
              source_desc, published);
+    control_event_general_status(LOG_WARN,
+                                 "CLOCK_SKEW SOURCE=NETWORKSTATUS:%s:%d",
+                                 ns->source_address, ns->source_dirport);
     skewed = 1;
     skewed = 1;
   }
   }