/** Return a string containing the address:port that a proxy transport * should bind on. The string is stored on the heap and must be freed * by the caller of this function. */ char * get_stored_bindaddr_for_server_transport(const char *transport) { char *default_addrport = NULL; const char *stored_bindaddr = NULL; config_line_t *line = get_transport_in_state_by_name(transport); if (!line) /* Found no references in state for this transport. */ goto no_bindaddr_found; stored_bindaddr = get_transport_bindaddr(line->value, transport); if (stored_bindaddr) /* found stored bindaddr in state file. */ return tor_strdup(stored_bindaddr); no_bindaddr_found: /** If we didn't find references for this pluggable transport in the state file, we should instruct the pluggable transport proxy to listen on INADDR_ANY on a random ephemeral port. */ tor_asprintf(&default_addrport, "%s:%s", fmt_addr32(INADDR_ANY), "0"); return default_addrport; }
/** Save <b>transport</b> listening on <b>addr</b>:<b>port</b> to state */ void save_transport_to_state(const char *transport, const tor_addr_t *addr, uint16_t port) { or_state_t *state = get_or_state(); char *transport_addrport=NULL; /** find where to write on the state */ config_line_t **next, *line; /* see if this transport is already stored in state */ config_line_t *transport_line = get_transport_in_state_by_name(transport); if (transport_line) { /* if transport already exists in state... */ const char *prev_bindaddr = /* get its addrport... */ get_transport_bindaddr(transport_line->value, transport); tor_asprintf(&transport_addrport, "%s:%d", fmt_addr(addr), (int)port); /* if transport in state has the same address as this one, life is good */ if (!strcmp(prev_bindaddr, transport_addrport)) { log_info(LD_CONFIG, "Transport seems to have spawned on its usual " "address:port."); goto done; } else { /* if addrport in state is different than the one we got */ log_info(LD_CONFIG, "Transport seems to have spawned on different " "address:port. Let's update the state file with the new " "address:port"); tor_free(transport_line->value); /* free the old line */ tor_asprintf(&transport_line->value, "%s %s:%d", transport, fmt_addr(addr), (int) port); /* replace old addrport line with new line */ } } else { /* never seen this one before; save it in state for next time */ log_info(LD_CONFIG, "It's the first time we see this transport. " "Let's save its address:port"); next = &state->TransportProxies; /* find the last TransportProxy line in the state and point 'next' right after it */ line = state->TransportProxies; while (line) { next = &(line->next); line = line->next; } /* allocate space for the new line and fill it in */ *next = line = tor_malloc_zero(sizeof(config_line_t)); line->key = tor_strdup("TransportProxy"); tor_asprintf(&line->value, "%s %s:%d", transport, fmt_addr(addr), (int) port); next = &(line->next); } if (!get_options()->AvoidDiskWrites) or_state_mark_dirty(state, 0); done: tor_free(transport_addrport); }
/* Test the configure_proxy() function. */ static void test_pt_configure_proxy(void *arg) { int i, retval; managed_proxy_t *mp = NULL; (void) arg; dummy_state = tor_malloc_zero(sizeof(or_state_t)); MOCK(process_read_stdout, process_read_stdout_replacement); MOCK(get_or_state, get_or_state_replacement); MOCK(queue_control_event_string, queue_control_event_string_replacement); control_testing_set_global_event_mask(EVENT_TRANSPORT_LAUNCHED); mp = tor_malloc_zero(sizeof(managed_proxy_t)); mp->conf_state = PT_PROTO_ACCEPTING_METHODS; mp->transports = smartlist_new(); mp->transports_to_launch = smartlist_new(); mp->argv = tor_malloc_zero(sizeof(char*)*2); mp->argv[0] = tor_strdup("<testcase>"); mp->is_server = 1; /* Configure the process. */ mp->process = process_new(""); process_set_stdout_read_callback(mp->process, managed_proxy_stdout_callback); process_set_data(mp->process, mp); /* Test the return value of configure_proxy() by calling it some times while it is uninitialized and then finally finalizing its configuration. */ for (i = 0 ; i < 5 ; i++) { /* force a read from our mocked stdout reader. */ process_notify_event_stdout(mp->process); /* try to configure our proxy. */ retval = configure_proxy(mp); /* retval should be zero because proxy hasn't finished configuring yet */ tt_int_op(retval, OP_EQ, 0); /* check the number of registered transports */ tt_int_op(smartlist_len(mp->transports), OP_EQ, i+1); /* check that the mp is still waiting for transports */ tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); } /* Get the SMETHOD DONE written to the process. */ process_notify_event_stdout(mp->process); /* this last configure_proxy() should finalize the proxy configuration. */ retval = configure_proxy(mp); /* retval should be 1 since the proxy finished configuring */ tt_int_op(retval, OP_EQ, 1); /* check the mp state */ tt_assert(mp->conf_state == PT_PROTO_COMPLETED); tt_int_op(controlevent_n, OP_EQ, 5); tt_int_op(controlevent_event, OP_EQ, EVENT_TRANSPORT_LAUNCHED); tt_int_op(smartlist_len(controlevent_msgs), OP_EQ, 5); smartlist_sort_strings(controlevent_msgs); tt_str_op(smartlist_get(controlevent_msgs, 0), OP_EQ, "650 TRANSPORT_LAUNCHED server mock1 127.0.0.1 5551\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 1), OP_EQ, "650 TRANSPORT_LAUNCHED server mock2 127.0.0.1 5552\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 2), OP_EQ, "650 TRANSPORT_LAUNCHED server mock3 127.0.0.1 5553\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 3), OP_EQ, "650 TRANSPORT_LAUNCHED server mock4 127.0.0.1 5554\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 4), OP_EQ, "650 TRANSPORT_LAUNCHED server mock5 127.0.0.1 5555\r\n"); /* Get the log message out. */ process_notify_event_stdout(mp->process); tt_int_op(controlevent_n, OP_EQ, 10); tt_int_op(controlevent_event, OP_EQ, EVENT_PT_LOG); tt_int_op(smartlist_len(controlevent_msgs), OP_EQ, 10); tt_str_op(smartlist_get(controlevent_msgs, 5), OP_EQ, "650 PT_LOG PT=<testcase> SEVERITY=error " "MESSAGE=\"Oh noes, " "something bad happened. What do we do!?\"\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 6), OP_EQ, "650 PT_LOG PT=<testcase> SEVERITY=warning " "MESSAGE=\"warning msg\"\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 7), OP_EQ, "650 PT_LOG PT=<testcase> SEVERITY=notice " "MESSAGE=\"notice msg\"\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 8), OP_EQ, "650 PT_LOG PT=<testcase> SEVERITY=info " "MESSAGE=\"info msg\"\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 9), OP_EQ, "650 PT_LOG PT=<testcase> 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=<testcase> TRANSPORT=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=<testcase> TRANSPORT=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=<testcase> TRANSPORT=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(); char *name_of_transport = NULL; char *bindaddr = NULL; /* Get the bindaddr for "mock1" and check it against the bindaddr that the mocked tor_get_lines_from_handle() generated. */ transport_in_state = get_transport_in_state_by_name("mock1"); tt_assert(transport_in_state); smartlist_split_string(transport_info_sl, transport_in_state->value, NULL, 0, 0); name_of_transport = smartlist_get(transport_info_sl, 0); bindaddr = smartlist_get(transport_info_sl, 1); tt_str_op(name_of_transport, OP_EQ, "mock1"); tt_str_op(bindaddr, OP_EQ, "127.0.0.1:5551"); SMARTLIST_FOREACH(transport_info_sl, char *, cp, tor_free(cp)); smartlist_free(transport_info_sl); } done: or_state_free(dummy_state); UNMOCK(process_read_stdout); UNMOCK(get_or_state); UNMOCK(queue_control_event_string); if (controlevent_msgs) { SMARTLIST_FOREACH(controlevent_msgs, char *, cp, tor_free(cp)); smartlist_free(controlevent_msgs); controlevent_msgs = NULL; } if (mp->transports) { SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t)); smartlist_free(mp->transports); }
/* Test the configure_proxy() function. */ static void test_pt_configure_proxy(void *arg) { int i, retval; managed_proxy_t *mp = NULL; (void) arg; dummy_state = tor_malloc_zero(sizeof(or_state_t)); MOCK(tor_get_lines_from_handle, tor_get_lines_from_handle_replacement); MOCK(tor_process_handle_destroy, tor_process_handle_destroy_replacement); MOCK(get_or_state, get_or_state_replacement); MOCK(queue_control_event_string, queue_control_event_string_replacement); control_testing_set_global_event_mask(EVENT_TRANSPORT_LAUNCHED); mp = tor_malloc_zero(sizeof(managed_proxy_t)); mp->conf_state = PT_PROTO_ACCEPTING_METHODS; mp->transports = smartlist_new(); mp->transports_to_launch = smartlist_new(); mp->process_handle = tor_malloc_zero(sizeof(process_handle_t)); mp->argv = tor_malloc_zero(sizeof(char*)*2); mp->argv[0] = tor_strdup("<testcase>"); mp->is_server = 1; /* Test the return value of configure_proxy() by calling it some times while it is uninitialized and then finally finalizing its configuration. */ for (i = 0 ; i < 5 ; i++) { retval = configure_proxy(mp); /* retval should be zero because proxy hasn't finished configuring yet */ tt_int_op(retval, OP_EQ, 0); /* check the number of registered transports */ tt_assert(smartlist_len(mp->transports) == i+1); /* check that the mp is still waiting for transports */ tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); } /* this last configure_proxy() should finalize the proxy configuration. */ retval = configure_proxy(mp); /* retval should be 1 since the proxy finished configuring */ tt_int_op(retval, OP_EQ, 1); /* check the mp state */ tt_assert(mp->conf_state == PT_PROTO_COMPLETED); tt_int_op(controlevent_n, OP_EQ, 5); tt_int_op(controlevent_event, OP_EQ, EVENT_TRANSPORT_LAUNCHED); tt_int_op(smartlist_len(controlevent_msgs), OP_EQ, 5); smartlist_sort_strings(controlevent_msgs); tt_str_op(smartlist_get(controlevent_msgs, 0), OP_EQ, "650 TRANSPORT_LAUNCHED server mock1 127.0.0.1 5551\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 1), OP_EQ, "650 TRANSPORT_LAUNCHED server mock2 127.0.0.1 5552\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 2), OP_EQ, "650 TRANSPORT_LAUNCHED server mock3 127.0.0.1 5553\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 3), OP_EQ, "650 TRANSPORT_LAUNCHED server mock4 127.0.0.1 5554\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 4), OP_EQ, "650 TRANSPORT_LAUNCHED server mock5 127.0.0.1 5555\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(); char *name_of_transport = NULL; char *bindaddr = NULL; /* Get the bindaddr for "mock1" and check it against the bindaddr that the mocked tor_get_lines_from_handle() generated. */ transport_in_state = get_transport_in_state_by_name("mock1"); tt_assert(transport_in_state); smartlist_split_string(transport_info_sl, transport_in_state->value, NULL, 0, 0); name_of_transport = smartlist_get(transport_info_sl, 0); bindaddr = smartlist_get(transport_info_sl, 1); tt_str_op(name_of_transport, OP_EQ, "mock1"); tt_str_op(bindaddr, OP_EQ, "127.0.0.1:5551"); SMARTLIST_FOREACH(transport_info_sl, char *, cp, tor_free(cp)); smartlist_free(transport_info_sl); } done: or_state_free(dummy_state); UNMOCK(tor_get_lines_from_handle); UNMOCK(tor_process_handle_destroy); UNMOCK(get_or_state); UNMOCK(queue_control_event_string); if (controlevent_msgs) { SMARTLIST_FOREACH(controlevent_msgs, char *, cp, tor_free(cp)); smartlist_free(controlevent_msgs); controlevent_msgs = NULL; } if (mp->transports) { SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t)); smartlist_free(mp->transports); }