diff --git a/ChangeLog b/ChangeLog index 9c69b24780..736c997860 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,8 @@ Changes in version 0.2.0.8-alpha - 2007-10-12 - Use annotations to record the purpose of each descriptor. - Disable the SETROUTERPURPOSE controller command: it is now obsolete. + - Controllers should now specify cache=no or cache=yes when using + the +POSTDESCRIPTOR command. - Bridge authorities now write bridge descriptors to disk, meaning we can export them to other programs and begin distributing them to blocked users. diff --git a/doc/spec/control-spec.txt b/doc/spec/control-spec.txt index b57de5583c..69f72818b6 100644 --- a/doc/spec/control-spec.txt +++ b/doc/spec/control-spec.txt @@ -635,12 +635,18 @@ $Id$ 3.14. POSTDESCRIPTOR Sent from the client to the server. The syntax is: - "+POSTDESCRIPTOR" [SP "purpose=" Purpose] CRLF Descriptor CRLF "." CRLF + "+POSTDESCRIPTOR" [SP "purpose=" Purpose] [SP "cache=" Cache] + CRLF Descriptor CRLF "." CRLF This message informs the server about a new descriptor. If Purpose is specified, it must be either "general" or "controller", else we return a 552 error. + If Cache is specified, it must be either "no" or "yes", else we + return a 552 error. If Cache is not specified, Tor will decide for + itself whether it wants to cache the descriptor, and controllers + must not rely on its choice. + The descriptor, when parsed, must contain a number of well-specified fields, including fields for its nickname and identity. diff --git a/src/or/control.c b/src/or/control.c index cbe3158a69..873d2f4b36 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -1878,35 +1878,19 @@ handle_control_getinfo(control_connection_t *conn, uint32_t len, return 0; } -/** If *string contains a recognized purpose (for - * circuits if for_circuits is 1, else for routers), - * possibly prefaced with the string "purpose=", then assign it - * and return 0. Otherwise return -1. - * - * If it's prefaced with "purpose=", then set *string to - * the remainder of the string. */ -static int -get_purpose(char **string, int for_circuits, uint8_t *purpose) +/** Given a string, convert it to a circuit purpose. */ +static uint8_t +circuit_purpose_from_string(const char *string) { - if (!strcmpstart(*string, "purpose=")) - *string += strlen("purpose="); + if (!strcmpstart(string, "purpose=")) + string += strlen("purpose="); - if (!for_circuits) { - int r = router_purpose_from_string(*string); - if (r == ROUTER_PURPOSE_UNKNOWN) - return -1; - *purpose = r; - return 0; - } - - if (!strcmp(*string, "general")) - *purpose = CIRCUIT_PURPOSE_C_GENERAL; - else if (!strcmp(*string, "controller")) - *purpose = CIRCUIT_PURPOSE_CONTROLLER; - else { /* not a recognized purpose */ - return -1; - } - return 0; + if (!strcmp(string, "general")) + return CIRCUIT_PURPOSE_C_GENERAL; + else if (!strcmp(string, "controller")) + return CIRCUIT_PURPOSE_CONTROLLER; + else + return CIRCUIT_PURPOSE_UNKNOWN; } /** Return a newly allocated smartlist containing the arguments to the command @@ -1963,7 +1947,8 @@ handle_control_extendcircuit(control_connection_t *conn, uint32_t len, if (zero_circ && smartlist_len(args)>2) { char *purp = smartlist_get(args,2); - if (get_purpose(&purp, 1, &intended_purpose) < 0) { + intended_purpose = circuit_purpose_from_string(purp); + if (intended_purpose == CIRCUIT_PURPOSE_UNKNOWN) { connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n", purp); SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); smartlist_free(args); @@ -2061,7 +2046,8 @@ handle_control_setcircuitpurpose(control_connection_t *conn, { char *purp = smartlist_get(args,1); - if (get_purpose(&purp, 1, &new_purpose) < 0) { + new_purpose = circuit_purpose_from_string(purp); + if (new_purpose == CIRCUIT_PURPOSE_UNKNOWN) { connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n", purp); goto done; } @@ -2178,6 +2164,7 @@ handle_control_postdescriptor(control_connection_t *conn, uint32_t len, char *desc; const char *msg=NULL; uint8_t purpose = ROUTER_PURPOSE_GENERAL; + int cache = 0; /* eventually, we may switch this to 1 */ char *cp = memchr(body, '\n', len); smartlist_t *args = smartlist_create(); @@ -2186,21 +2173,37 @@ handle_control_postdescriptor(control_connection_t *conn, uint32_t len, smartlist_split_string(args, body, " ", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - if (smartlist_len(args)) { - char *purp = smartlist_get(args,0); - if (get_purpose(&purp, 0, &purpose) < 0) { - connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n", - purp); - SMARTLIST_FOREACH(args, char *, arg, tor_free(arg)); - smartlist_free(args); - return 0; + SMARTLIST_FOREACH(args, char *, option, + { + if (!strcasecmpstart(option, "purpose=")) { + option += strlen("purpose="); + purpose = router_purpose_from_string(option); + if (purpose == ROUTER_PURPOSE_UNKNOWN) { + connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n", + option); + goto done; + } + } else if (!strcasecmpstart(option, "cache=")) { + option += strlen("cache="); + if (!strcmp(option, "no")) + cache = 0; + else if (!strcmp(option, "yes")) + cache = 1; + else { + connection_printf_to_buf(conn, "552 Unknown cache request \"%s\"\r\n", + option); + goto done; + } + } else { /* unrecognized argument? */ + connection_printf_to_buf(conn, + "512 Unexpected argument \"%s\" to postdescriptor\r\n", option); + goto done; } - } - SMARTLIST_FOREACH(args, char *, arg, tor_free(arg)); - smartlist_free(args); + }); + read_escaped_data(cp, len-(cp-body), &desc); - switch (router_load_single_router(desc, purpose, &msg)) { + switch (router_load_single_router(desc, purpose, cache, &msg)) { case -1: if (!msg) msg = "Could not parse descriptor"; connection_printf_to_buf(conn, "554 %s\r\n", msg); @@ -2215,6 +2218,9 @@ handle_control_postdescriptor(control_connection_t *conn, uint32_t len, } tor_free(desc); + done: + SMARTLIST_FOREACH(args, char *, arg, tor_free(arg)); + smartlist_free(args); return 0; } diff --git a/src/or/or.h b/src/or/or.h index ed5e6ec37c..fdc9bbc720 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -451,6 +451,9 @@ typedef enum { /** A controller made this circuit and Tor should not use it. */ #define CIRCUIT_PURPOSE_CONTROLLER 18 #define _CIRCUIT_PURPOSE_MAX 18 +/** A catch-all for unrecognized purposes. Currently we don't expect + * to make or see any circuits with this purpose. */ +#define CIRCUIT_PURPOSE_UNKNOWN 255 /** True iff the circuit purpose p is for a circuit that * originated at this node. */ @@ -3600,7 +3603,7 @@ int router_add_to_routerlist(routerinfo_t *router, const char **msg, void router_add_extrainfo_to_routerlist(extrainfo_t *ei, const char **msg, int from_cache, int from_fetch); void routerlist_remove_old_routers(void); -int router_load_single_router(const char *s, uint8_t purpose, +int router_load_single_router(const char *s, uint8_t purpose, int cache, const char **msg); void router_load_routers_from_string(const char *s, const char *eos, saved_location_t saved_location, diff --git a/src/or/router.c b/src/or/router.c index 29d44c33ec..105b1c11a3 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1803,7 +1803,7 @@ router_purpose_to_string(uint8_t p) return NULL; } -/** Given a string, convert it to a router purpose. */ +/** Given a string, convert it to a router purpose. */ uint8_t router_purpose_from_string(const char *s) { diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 501803310a..f7da316ce9 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -2991,7 +2991,8 @@ routerlist_descriptors_added(smartlist_t *sl) * This is used only by the controller. */ int -router_load_single_router(const char *s, uint8_t purpose, const char **msg) +router_load_single_router(const char *s, uint8_t purpose, int cache, + const char **msg) { routerinfo_t *ri; int r; @@ -3017,6 +3018,9 @@ router_load_single_router(const char *s, uint8_t purpose, const char **msg) return 0; } + if (!cache) /* obey the preference of the controller */ + ri->cache_info.do_not_cache = 1; + lst = smartlist_create(); smartlist_add(lst, ri); routers_update_status_from_networkstatus(lst, 0);