diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/feature/control/control_cmd.c | 154 |
1 files changed, 55 insertions, 99 deletions
diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c index cfd35e8096..0b4f3555ff 100644 --- a/src/feature/control/control_cmd.c +++ b/src/feature/control/control_cmd.c @@ -594,7 +594,7 @@ address_is_invalid_mapaddress_target(const char *addr) } static const control_cmd_syntax_t mapaddress_syntax = { - .max_args=0, + .max_args=1, .accept_keywords=true, }; @@ -683,94 +683,61 @@ circuit_purpose_from_string(const char *string) return CIRCUIT_PURPOSE_UNKNOWN; } -/** Return a newly allocated smartlist containing the arguments to the command - * waiting in <b>body</b>. If there are fewer than <b>min_args</b> arguments, - * or if <b>max_args</b> is nonnegative and there are more than - * <b>max_args</b> arguments, send a 512 error to the controller, using - * <b>command</b> as the command name in the error message. */ -static smartlist_t * -getargs_helper(const char *command, control_connection_t *conn, - const char *body, int min_args, int max_args) -{ - smartlist_t *args = smartlist_new(); - smartlist_split_string(args, body, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - if (smartlist_len(args) < min_args) { - connection_printf_to_buf(conn, "512 Missing argument to %s\r\n",command); - goto err; - } else if (max_args >= 0 && smartlist_len(args) > max_args) { - connection_printf_to_buf(conn, "512 Too many arguments to %s\r\n",command); - goto err; - } - return args; - err: - SMARTLIST_FOREACH(args, char *, s, tor_free(s)); - smartlist_free(args); - return NULL; -} - -/** Helper. Return the first element of <b>sl</b> at index <b>start_at</b> or - * higher that starts with <b>prefix</b>, case-insensitive. Return NULL if no - * such element exists. */ -static const char * -find_element_starting_with(smartlist_t *sl, int start_at, const char *prefix) -{ - int i; - for (i = start_at; i < smartlist_len(sl); ++i) { - const char *elt = smartlist_get(sl, i); - if (!strcasecmpstart(elt, prefix)) - return elt; - } - return NULL; -} - -/** Helper. Return true iff s is an argument that we should treat as a - * key-value pair. */ -static int -is_keyval_pair(const char *s) -{ - /* An argument is a key-value pair if it has an =, and it isn't of the form - * $fingeprint=name */ - return strchr(s, '=') && s[0] != '$'; -} +static const control_cmd_syntax_t extendcircuit_syntax = { + .min_args=1, + .max_args=1, // see note in function + .accept_keywords=true, + .kvline_flags=KV_OMIT_VALS +}; /** Called when we get an EXTENDCIRCUIT message. Try to extend the listed * circuit, and report success or failure. */ static int -handle_control_extendcircuit(control_connection_t *conn, uint32_t len, - const char *body) +handle_control_extendcircuit(control_connection_t *conn, + const control_cmd_args_t *args) { - smartlist_t *router_nicknames=NULL, *nodes=NULL; + smartlist_t *router_nicknames=smartlist_new(), *nodes=NULL; origin_circuit_t *circ = NULL; - int zero_circ; uint8_t intended_purpose = CIRCUIT_PURPOSE_C_GENERAL; - smartlist_t *args; - (void) len; - - router_nicknames = smartlist_new(); - - args = getargs_helper("EXTENDCIRCUIT", conn, body, 1, -1); - if (!args) - goto done; + const config_line_t *kwargs = args->kwargs; + const char *circ_id = smartlist_get(args->args, 0); + const char *path_str = NULL; + char *path_str_alloc = NULL; + + /* The syntax for this command is unfortunate. The second argument is + optional, and is a comma-separated list long-format fingerprints, which + can (historically!) contain an equals sign. + + Here we check the second argument to see if it's a path, and if so we + remove it from the kwargs list and put it in path_str. + */ + if (kwargs) { + const config_line_t *arg1 = kwargs; + if (!strcmp(arg1->value, "")) { + path_str = arg1->key; + kwargs = kwargs->next; + } else if (arg1->key[0] == '$') { + tor_asprintf(&path_str_alloc, "%s=%s", arg1->key, arg1->value); + path_str = path_str_alloc; + kwargs = kwargs->next; + } + } - zero_circ = !strcmp("0", (char*)smartlist_get(args,0)); + const config_line_t *purpose_line = config_line_find_case(kwargs, "PURPOSE"); + bool zero_circ = !strcmp("0", circ_id); - if (zero_circ) { - const char *purp = find_element_starting_with(args, 1, "PURPOSE="); - - if (purp) { - 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); - goto done; - } + if (purpose_line) { + intended_purpose = circuit_purpose_from_string(purpose_line->value); + if (intended_purpose == CIRCUIT_PURPOSE_UNKNOWN) { + connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n", + purpose_line->value); + goto done; } + } - if ((smartlist_len(args) == 1) || - (smartlist_len(args) >= 2 && is_keyval_pair(smartlist_get(args, 1)))) { - // "EXTENDCIRCUIT 0" || EXTENDCIRCUIT 0 foo=bar" + if (zero_circ) { + if (!path_str) { + // "EXTENDCIRCUIT 0" with no path. circ = circuit_launch(intended_purpose, CIRCLAUNCH_NEED_CAPACITY); if (!circ) { connection_write_str_to_buf("551 Couldn't start circuit\r\n", conn); @@ -778,37 +745,24 @@ handle_control_extendcircuit(control_connection_t *conn, uint32_t len, connection_printf_to_buf(conn, "250 EXTENDED %lu\r\n", (unsigned long)circ->global_identifier); } - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); goto done; } - // "EXTENDCIRCUIT 0 router1,router2" || - // "EXTENDCIRCUIT 0 router1,router2 PURPOSE=foo" } - if (!zero_circ && !(circ = get_circ(smartlist_get(args,0)))) { - connection_printf_to_buf(conn, "552 Unknown circuit \"%s\"\r\n", - (char*)smartlist_get(args, 0)); - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); + if (!zero_circ && !(circ = get_circ(circ_id))) { + connection_printf_to_buf(conn, "552 Unknown circuit \"%s\"\r\n", circ_id); goto done; } - if (smartlist_len(args) < 2) { - connection_printf_to_buf(conn, - "512 syntax error: not enough arguments.\r\n"); - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); + if (!path_str) { + connection_printf_to_buf(conn, "512 syntax error: path required.\r\n"); goto done; } - smartlist_split_string(router_nicknames, smartlist_get(args,1), ",", 0, 0); - - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); + smartlist_split_string(router_nicknames, path_str, ",", 0, 0); nodes = smartlist_new(); - int first_node = zero_circ; + bool first_node = zero_circ; SMARTLIST_FOREACH_BEGIN(router_nicknames, const char *, n) { const node_t *node = node_get_by_nickname(n, 0); if (!node) { @@ -820,8 +774,9 @@ handle_control_extendcircuit(control_connection_t *conn, uint32_t len, goto done; } smartlist_add(nodes, (void*)node); - first_node = 0; + first_node = false; } SMARTLIST_FOREACH_END(n); + if (!smartlist_len(nodes)) { connection_write_str_to_buf("512 No router names provided\r\n", conn); goto done; @@ -887,6 +842,7 @@ handle_control_extendcircuit(control_connection_t *conn, uint32_t len, SMARTLIST_FOREACH(router_nicknames, char *, n, tor_free(n)); smartlist_free(router_nicknames); smartlist_free(nodes); + tor_free(path_str_alloc); return 0; } @@ -2360,7 +2316,7 @@ static const control_cmd_def_t CONTROL_COMMANDS[] = ONE_LINE_PARSED(dropownership, 0), ONE_LINE_PARSED(mapaddress, 0), ONE_LINE_PARSED(getinfo, 0), - ONE_LINE(extendcircuit, legacy, 0), + ONE_LINE_PARSED(extendcircuit, 0), ONE_LINE_PARSED(setcircuitpurpose, 0), OBSOLETE(setrouterpurpose), ONE_LINE_PARSED(attachstream, 0), |