summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/feature/control/control_cmd.c154
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),