From 4efe4cc2f918ce45075b010d2cdc09ec7791ac6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20F=C3=A6r=C3=B8y?= Date: Thu, 20 Dec 2018 03:55:02 +0100 Subject: [PATCH] Add support for STATUS messages from Pluggable Transports. This patch adds support for the new STATUS message that PT's can emit from their standard out. The STATUS message uses the `config_line_t` K/V format that was recently added in Tor. See: https://bugs.torproject.org/28846 --- src/feature/client/transports.c | 60 +++++++++++++++++++++++++++++++-- src/feature/client/transports.h | 1 + src/feature/control/control.c | 10 ++++++ src/feature/control/control.h | 4 ++- src/test/test_pt.c | 21 ++++++++++++ 5 files changed, 92 insertions(+), 4 deletions(-) diff --git a/src/feature/client/transports.c b/src/feature/client/transports.c index 6a3479a470..45dbd0c888 100644 --- a/src/feature/client/transports.c +++ b/src/feature/client/transports.c @@ -130,6 +130,7 @@ static void parse_method_error(const char *line, int is_server_method); #define PROTO_PROXY_DONE "PROXY DONE" #define PROTO_PROXY_ERROR "PROXY-ERROR" #define PROTO_LOG "LOG" +#define PROTO_STATUS "STATUS" /** The first and only supported - at the moment - configuration protocol version. */ @@ -912,12 +913,16 @@ handle_proxy_line(const char *line, managed_proxy_t *mp) parse_proxy_error(line); goto err; - /* We check for the additional " " after the PROTO_LOG string to make sure - * we can later extend this big if/else-if table with something that begins - * with "LOG" without having to get the order right. */ + /* We check for the additional " " after the PROTO_LOG * PROTO_STATUS + * string to make sure we can later extend this big if/else-if table with + * something that begins with "LOG" without having to get the order right. + * */ } else if (!strcmpstart(line, PROTO_LOG " ")) { parse_log_line(line, mp); return; + } else if (!strcmpstart(line, PROTO_STATUS " ")) { + parse_status_line(line, mp); + return; } log_notice(LD_GENERAL, "Unknown line received by managed proxy (%s).", line); @@ -1205,6 +1210,55 @@ parse_log_line(const char *line, managed_proxy_t *mp) tor_free(log_message); } +/** Parses a STATUS line and emit control events accordingly. */ +STATIC void +parse_status_line(const char *line, managed_proxy_t *mp) +{ + tor_assert(line); + tor_assert(mp); + + config_line_t *values = NULL; + char *status_message = NULL; + + if (strlen(line) < (strlen(PROTO_STATUS) + 1)) { + log_warn(LD_PT, "Managed proxy sent us a %s line " + "with missing argument.", PROTO_STATUS); + goto done; + } + + const char *data = line + strlen(PROTO_STATUS) + 1; + + values = kvline_parse(data, KV_QUOTED); + + if (! values) { + log_warn(LD_PT, "Managed proxy \"%s\" wrote an invalid " + "STATUS message: %s", mp->argv[0], data); + goto done; + } + + /* We check if we received the TYPE parameter, which is the only *required* + * value. */ + const config_line_t *type = config_line_find(values, "TYPE"); + + if (! type) { + log_warn(LD_PT, "Managed proxy \"%s\" wrote a STATUS line without " + "TYPE: %s", mp->argv[0], data); + goto done; + } + + /* Prepend the PT name. */ + config_line_prepend(&values, "PT", mp->argv[0]); + status_message = kvline_encode(values, KV_QUOTED); + + /* We have checked that TYPE is there, we can now emit the STATUS event via + * the control port. */ + control_event_pt_status(status_message); + + done: + config_free_lines(values); + tor_free(status_message); +} + /** Return a newly allocated string that tor should place in * TOR_PT_SERVER_TRANSPORT_OPTIONS while configuring the server * manged proxy in mp. Return NULL if no such options are found. */ diff --git a/src/feature/client/transports.h b/src/feature/client/transports.h index b8d1bb0081..1a910ae82c 100644 --- a/src/feature/client/transports.h +++ b/src/feature/client/transports.h @@ -129,6 +129,7 @@ STATIC void parse_env_error(const char *line); STATIC void parse_proxy_error(const char *line); STATIC void handle_proxy_line(const char *line, managed_proxy_t *mp); STATIC void parse_log_line(const char *line, managed_proxy_t *mp); +STATIC void parse_status_line(const char *line, managed_proxy_t *mp); STATIC char *get_transport_options_for_server_proxy(const managed_proxy_t *mp); STATIC void managed_proxy_destroy(managed_proxy_t *mp, diff --git a/src/feature/control/control.c b/src/feature/control/control.c index 849f11707e..4ef550c919 100644 --- a/src/feature/control/control.c +++ b/src/feature/control/control.c @@ -7043,6 +7043,16 @@ control_event_pt_log(const char *log) log); } +/** A pluggable transport has emitted a STATUS message found in + * status. */ +void +control_event_pt_status(const char *status) +{ + send_control_event(EVENT_PT_STATUS, + "650 PT_STATUS %s\r\n", + status); +} + /** Convert rendezvous auth type to string for HS_DESC control events */ const char * diff --git a/src/feature/control/control.h b/src/feature/control/control.h index b3a2707672..d78ce4d87c 100644 --- a/src/feature/control/control.h +++ b/src/feature/control/control.h @@ -208,6 +208,7 @@ void control_event_transport_launched(const char *mode, const char *transport_name, tor_addr_t *addr, uint16_t port); void control_event_pt_log(const char *log); +void control_event_pt_status(const char *status); const char *rend_auth_type_to_string(rend_auth_type_t auth_type); MOCK_DECL(const char *, node_describe_longname_by_id,(const char *id_digest)); void control_event_hs_descriptor_requested(const char *onion_address, @@ -297,7 +298,8 @@ void control_free_all(void); #define EVENT_HS_DESC_CONTENT 0x0022 #define EVENT_NETWORK_LIVENESS 0x0023 #define EVENT_PT_LOG 0x0024 -#define EVENT_MAX_ 0x0024 +#define EVENT_PT_STATUS 0x0025 +#define EVENT_MAX_ 0x0025 /* sizeof(control_connection_t.event_mask) in bits, currently a uint64_t */ #define EVENT_CAPACITY_ 0x0040 diff --git a/src/test/test_pt.c b/src/test/test_pt.c index 271d74f26a..8de687c866 100644 --- a/src/test/test_pt.c +++ b/src/test/test_pt.c @@ -316,6 +316,10 @@ process_read_stdout_replacement(process_t *process, buf_t *buffer) buf_add_string(buffer, "LOG SEVERITY=notice MESSAGE=\"notice msg\"\n"); buf_add_string(buffer, "LOG SEVERITY=info MESSAGE=\"info msg\"\n"); buf_add_string(buffer, "LOG SEVERITY=debug MESSAGE=\"debug msg\"\n"); + } else if (times_called <= 8) { + buf_add_string(buffer, "STATUS TYPE=a K_1=a K_2=b K_3=\"foo bar\"\n"); + buf_add_string(buffer, "STATUS TYPE=b K_1=a K_2=b K_3=\"foo bar\"\n"); + buf_add_string(buffer, "STATUS TYPE=c K_1=a K_2=b K_3=\"foo bar\"\n"); } return (int)buf_datalen(buffer); @@ -440,6 +444,23 @@ test_pt_configure_proxy(void *arg) "650 PT_LOG PT= SEVERITY=debug " "MESSAGE=\"debug msg\"\r\n"); + /* Get the STATUS messages out. */ + process_notify_event_stdout(mp->process); + + tt_int_op(controlevent_n, OP_EQ, 13); + tt_int_op(controlevent_event, OP_EQ, EVENT_PT_STATUS); + tt_int_op(smartlist_len(controlevent_msgs), OP_EQ, 13); + + tt_str_op(smartlist_get(controlevent_msgs, 10), OP_EQ, + "650 PT_STATUS " + "PT= TYPE=a K_1=a K_2=b K_3=\"foo bar\"\r\n"); + tt_str_op(smartlist_get(controlevent_msgs, 11), OP_EQ, + "650 PT_STATUS " + "PT= TYPE=b K_1=a K_2=b K_3=\"foo bar\"\r\n"); + tt_str_op(smartlist_get(controlevent_msgs, 12), OP_EQ, + "650 PT_STATUS " + "PT= TYPE=c K_1=a K_2=b K_3=\"foo bar\"\r\n"); + { /* check that the transport info were saved properly in the tor state */ config_line_t *transport_in_state = NULL; smartlist_t *transport_info_sl = smartlist_new();