Merge remote-tracking branch 'asn2/bug3656'

Conflicts:
	src/common/util.c
	src/common/util.h
	src/or/config.h
	src/or/main.c
	src/test/test_util.c
This commit is contained in:
Nick Mathewson 2011-10-07 16:05:13 -04:00
commit ed39621a9d
16 changed files with 2158 additions and 164 deletions

View file

@ -31,6 +31,7 @@
#include <direct.h>
#include <process.h>
#include <tchar.h>
#include <Winbase.h>
#else
#include <dirent.h>
#include <pwd.h>
@ -46,6 +47,7 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
@ -769,6 +771,34 @@ find_str_at_start_of_line(const char *haystack, const char *needle)
return NULL;
}
/** Returns true if <b>string</b> could be a C identifier.
A C identifier must begin with a letter or an underscore and the
rest of its characters can be letters, numbers or underscores. No
length limit is imposed. */
int
string_is_C_identifier(const char *string)
{
size_t iter;
size_t length = strlen(string);
if (!length)
return 0;
for (iter = 0; iter < length ; iter++) {
if (iter == 0) {
if (!(TOR_ISALPHA(string[iter]) ||
string[iter] == '_'))
return 0;
} else {
if (!(TOR_ISALPHA(string[iter]) ||
TOR_ISDIGIT(string[iter]) ||
string[iter] == '_'))
return 0;
}
}
return 1;
}
/** Return true iff the 'len' bytes at 'mem' are all zero. */
int
tor_mem_is_zero(const char *mem, size_t len)
@ -3129,6 +3159,28 @@ format_helper_exit_status(unsigned char child_state, int saved_errno,
/* Maximum number of file descriptors, if we cannot get it via sysconf() */
#define DEFAULT_MAX_FD 256
/** Terminate process running at PID <b>pid</b>.
* Code borrowed from Python's os.kill. */
int
tor_terminate_process(pid_t pid)
{
#ifdef MS_WINDOWS
HANDLE handle;
/* If the signal is outside of what GenerateConsoleCtrlEvent can use,
attempt to open and terminate the process. */
handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!handle)
return -1;
if (!TerminateProcess(handle, 0))
return -1;
else
return 0;
#else /* Unix */
return kill(pid, SIGTERM);
#endif
}
#define CHILD_STATE_INIT 0
#define CHILD_STATE_PIPE 1
#define CHILD_STATE_MAXFD 2
@ -3140,8 +3192,6 @@ format_helper_exit_status(unsigned char child_state, int saved_errno,
#define CHILD_STATE_EXEC 8
#define CHILD_STATE_FAILEXEC 9
#define SPAWN_ERROR_MESSAGE "ERR: Failed to spawn background process - code "
/** Start a program in the background. If <b>filename</b> contains a '/', then
* it will be treated as an absolute or relative path. Otherwise, on
* non-Windows systems, the system path will be searched for <b>filename</b>.
@ -3161,9 +3211,9 @@ format_helper_exit_status(unsigned char child_state, int saved_errno,
* Python, and example code from
* http://msdn.microsoft.com/en-us/library/ms682499%28v=vs.85%29.aspx.
*/
int
tor_spawn_background(const char *const filename, const char **argv,
const char **envp,
process_handle_t *process_handle)
{
#ifdef MS_WINDOWS
@ -3372,6 +3422,9 @@ tor_spawn_background(const char *const filename, const char **argv,
/* Call the requested program. We need the cast because
execvp doesn't define argv as const, even though it
does not modify the arguments */
if (envp)
execve(filename, (char *const *) argv, (char*const*)envp);
else
execvp(filename, (char *const *) argv);
/* If we got here, the exec or open(/dev/null) failed */
@ -3763,6 +3816,7 @@ log_from_handle(HANDLE *pipe, int severity)
}
#else
/** Read from stream, and send lines to log at the specified log level.
* Returns 1 if stream is closed normally, -1 if there is a error reading, and
* 0 otherwise. Handles lines from tor-fw-helper and
@ -3773,42 +3827,22 @@ log_from_pipe(FILE *stream, int severity, const char *executable,
int *child_status)
{
char buf[256];
enum stream_status r;
for (;;) {
char *retval;
retval = fgets(buf, sizeof(buf), stream);
r = get_string_from_pipe(stream, buf, sizeof(buf) - 1);
if (NULL == retval) {
if (feof(stream)) {
/* Program has closed stream (probably it exited) */
/* TODO: check error */
if (r == IO_STREAM_CLOSED) {
fclose(stream);
return 1;
} else {
if (EAGAIN == errno) {
/* Nothing more to read, try again next time */
} else if (r == IO_STREAM_EAGAIN) {
return 0;
} else {
/* There was a problem, abandon this child process */
} else if (r == IO_STREAM_TERM) {
fclose(stream);
return -1;
}
}
} else {
/* We have some data, log it and keep asking for more */
size_t len;
len = strlen(buf);
if (buf[len - 1] == '\n') {
/* Remove the trailing newline */
buf[len - 1] = '\0';
} else {
/* No newline; check whether we overflowed the buffer */
if (!feof(stream))
log_warn(LD_GENERAL,
"Line from port forwarding helper was truncated: %s", buf);
/* TODO: What to do with this error? */
}
tor_assert(r == IO_STREAM_OKAY);
/* Check if buf starts with SPAWN_ERROR_MESSAGE */
if (strcmpstart(buf, SPAWN_ERROR_MESSAGE) == 0) {
@ -3833,13 +3867,71 @@ log_from_pipe(FILE *stream, int severity, const char *executable,
log_fn(severity, LD_GENERAL, "Port forwarding helper says: %s", buf);
}
}
}
/* We should never get here */
return -1;
}
#endif
/** Reads from <b>stream</b> and stores input in <b>buf_out</b> making
* sure it's below <b>count</b> bytes.
* If the string has a trailing newline, we strip it off.
*
* This function is specifically created to handle input from managed
* proxies, according to the pluggable transports spec. Make sure it
* fits your needs before using it.
*
* Returns:
* IO_STREAM_CLOSED: If the stream is closed.
* IO_STREAM_EAGAIN: If there is nothing to read and we should check back
* later.
* IO_STREAM_TERM: If something is wrong with the stream.
* IO_STREAM_OKAY: If everything went okay and we got a string
* in <b>buf_out</b>. */
enum stream_status
get_string_from_pipe(FILE *stream, char *buf_out, size_t count)
{
char *retval;
size_t len;
retval = fgets(buf_out, count, stream);
if (!retval) {
if (feof(stream)) {
/* Program has closed stream (probably it exited) */
/* TODO: check error */
return IO_STREAM_CLOSED;
} else {
if (EAGAIN == errno) {
/* Nothing more to read, try again next time */
return IO_STREAM_EAGAIN;
} else {
/* There was a problem, abandon this child process */
return IO_STREAM_TERM;
}
}
} else {
len = strlen(buf_out);
tor_assert(len>0);
if (buf_out[len - 1] == '\n') {
/* Remove the trailing newline */
buf_out[len - 1] = '\0';
} else {
/* No newline; check whether we overflowed the buffer */
if (!feof(stream))
log_info(LD_GENERAL,
"Line from stream was truncated: %s", buf_out);
/* TODO: What to do with this error? */
}
return IO_STREAM_OKAY;
}
/* We should never get here */
return IO_STREAM_TERM;
}
void
tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
time_t now)
@ -3885,9 +3977,9 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
#ifdef MS_WINDOWS
/* Passing NULL as lpApplicationName makes Windows search for the .exe */
tor_spawn_background(NULL, argv, &child_handle);
tor_spawn_background(NULL, argv, NULL &child_handle);
#else
tor_spawn_background(filename, argv, &child_handle);
tor_spawn_background(filename, argv, NULL, &child_handle);
#endif
if (PROCESS_STATUS_ERROR == child_handle.status) {
log_warn(LD_GENERAL, "Failed to start port forwarding helper %s",

View file

@ -205,6 +205,8 @@ const char *find_whitespace(const char *s) ATTR_PURE;
const char *find_whitespace_eos(const char *s, const char *eos) ATTR_PURE;
const char *find_str_at_start_of_line(const char *haystack, const char *needle)
ATTR_PURE;
int string_is_C_identifier(const char *string);
int tor_mem_is_zero(const char *mem, size_t len) ATTR_PURE;
int tor_digest_is_zero(const char *digest) ATTR_PURE;
int tor_digest256_is_zero(const char *digest) ATTR_PURE;
@ -286,6 +288,16 @@ char *rate_limit_log(ratelim_t *lim, time_t now);
ssize_t write_all(tor_socket_t fd, const char *buf, size_t count,int isSocket);
ssize_t read_all(tor_socket_t fd, char *buf, size_t count, int isSocket);
/** Status of an I/O stream. */
enum stream_status {
IO_STREAM_OKAY,
IO_STREAM_EAGAIN,
IO_STREAM_TERM,
IO_STREAM_CLOSED
};
enum stream_status get_string_from_pipe(FILE *stream, char *buf, size_t count);
/** Return values from file_status(); see that function's documentation
* for details. */
typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR } file_status_t;
@ -348,6 +360,13 @@ void write_pidfile(char *filename);
void tor_check_port_forwarding(const char *filename,
int dir_port, int or_port, time_t now);
int tor_terminate_process(pid_t pid);
typedef struct process_handle_s process_handle_t;
int tor_spawn_background(const char *const filename, const char **argv,
const char **envp, process_handle_t *process_handle);
#define SPAWN_ERROR_MESSAGE "ERR: Failed to spawn background process - code "
#ifdef MS_WINDOWS
HANDLE load_windows_system_library(const TCHAR *library_name);
#endif
@ -361,7 +380,7 @@ HANDLE load_windows_system_library(const TCHAR *library_name);
#define PROCESS_STATUS_NOTRUNNING 0
#define PROCESS_STATUS_RUNNING 1
#define PROCESS_STATUS_ERROR -1
typedef struct process_handle_s {
struct process_handle_s {
int status;
#ifdef MS_WINDOWS
HANDLE stdout_pipe;
@ -374,10 +393,7 @@ typedef struct process_handle_s {
FILE *stderr_handle;
pid_t pid;
#endif // MS_WINDOWS
} process_handle_t;
int tor_spawn_background(const char *const filename, const char **argv,
process_handle_t *process_handle);
};
/* Return values of tor_get_exit_code() */
#define PROCESS_EXIT_RUNNING 1
@ -399,6 +415,7 @@ ssize_t tor_read_all_from_process_stdout(
ssize_t tor_read_all_from_process_stderr(
const process_handle_t *process_handle, char *buf, size_t count);
char *tor_join_win_cmdline(const char *argv[]);
void format_helper_exit_status(unsigned char child_state,
int saved_errno, char *hex_errno);

View file

@ -39,6 +39,7 @@ libtor_a_SOURCES = \
networkstatus.c \
nodelist.c \
onion.c \
transports.c \
policies.c \
reasons.c \
relay.c \
@ -104,6 +105,7 @@ noinst_HEADERS = \
ntmain.h \
onion.h \
or.h \
transports.h \
policies.h \
reasons.h \
relay.h \

View file

@ -26,6 +26,7 @@
#include "nodelist.h"
#include "onion.h"
#include "policies.h"
#include "transports.h"
#include "relay.h"
#include "rephist.h"
#include "router.h"
@ -123,8 +124,6 @@ static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
static void entry_guards_changed(void);
static const transport_t *transport_get_by_name(const char *name);
static void transport_free(transport_t *transport);
static void bridge_free(bridge_info_t *bridge);
/**
@ -4595,6 +4594,32 @@ bridge_free(bridge_info_t *bridge)
/** A list of pluggable transports found in torrc. */
static smartlist_t *transport_list = NULL;
/** Mark every entry of the transport list to be removed on our next call to
* sweep_transport_list unless it has first been un-marked. */
void
mark_transport_list(void)
{
if (!transport_list)
transport_list = smartlist_create();
SMARTLIST_FOREACH(transport_list, transport_t *, t,
t->marked_for_removal = 1);
}
/** Remove every entry of the transport list that was marked with
* mark_transport_list if it has not subsequently been un-marked. */
void
sweep_transport_list(void)
{
if (!transport_list)
transport_list = smartlist_create();
SMARTLIST_FOREACH_BEGIN(transport_list, transport_t *, t) {
if (t->marked_for_removal) {
SMARTLIST_DEL_CURRENT(transport_list, t);
transport_free(t);
}
} SMARTLIST_FOREACH_END(t);
}
/** Initialize the pluggable transports list to empty, creating it if
* needed. */
void
@ -4607,7 +4632,7 @@ clear_transport_list(void)
}
/** Free the pluggable transport struct <b>transport</b>. */
static void
void
transport_free(transport_t *transport)
{
if (!transport)
@ -4619,7 +4644,7 @@ transport_free(transport_t *transport)
/** Returns the transport in our transport list that has the name <b>name</b>.
* Else returns NULL. */
static const transport_t *
transport_t *
transport_get_by_name(const char *name)
{
tor_assert(name);
@ -4627,7 +4652,7 @@ transport_get_by_name(const char *name)
if (!transport_list)
return NULL;
SMARTLIST_FOREACH_BEGIN(transport_list, const transport_t *, transport) {
SMARTLIST_FOREACH_BEGIN(transport_list, transport_t *, transport) {
if (!strcmp(transport->name, name))
return transport;
} SMARTLIST_FOREACH_END(transport);
@ -4635,41 +4660,139 @@ transport_get_by_name(const char *name)
return NULL;
}
/** Remember a new pluggable transport proxy at <b>addr</b>:<b>port</b>.
* <b>name</b> is set to the name of the protocol this proxy uses.
* <b>socks_ver</b> is set to the SOCKS version of the proxy.
*
* Returns 0 on success, -1 on fail. */
int
transport_add_from_config(const tor_addr_t *addr, uint16_t port,
/** Returns a transport_t struct for a transport proxy supporting the
protocol <b>name</b> listening at <b>addr</b>:<b>port</b> using
SOCKS version <b>socks_ver</b>. */
transport_t *
transport_create(const tor_addr_t *addr, uint16_t port,
const char *name, int socks_ver)
{
transport_t *t;
transport_t *t = tor_malloc_zero(sizeof(transport_t));
if (transport_get_by_name(name)) { /* check for duplicate names */
log_warn(LD_CONFIG, "More than one transport has '%s' as "
"its name.", name);
return -1;
}
t = tor_malloc_zero(sizeof(transport_t));
tor_addr_copy(&t->addr, addr);
t->port = port;
t->name = tor_strdup(name);
t->socks_version = socks_ver;
if (!transport_list)
transport_list = smartlist_create();
return t;
}
/** Resolve any conflicts that the insertion of transport <b>t</b>
* might cause.
* Return 0 if <b>t</b> is OK and should be registered, 1 if there is
* a transport identical to <b>t</b> already registered and -1 if
* <b>t</b> cannot be added due to conflicts. */
static int
transport_resolve_conflicts(transport_t *t)
{
/* This is how we resolve transport conflicts:
If there is already a transport with the same name and addrport,
we either have duplicate torrc lines OR we are here post-HUP and
this transport was here pre-HUP as well. In any case, mark the
old transport so that it doesn't get removed and ignore the new
one. Our caller has to free the new transport so we return '1' to
signify this.
If there is already a transport with the same name but different
addrport:
* if it's marked for removal, it means that it either has a lower
priority than 't' in torrc (otherwise the mark would have been
cleared by the paragraph above), or it doesn't exist at all in
the post-HUP torrc. We destroy the old transport and register 't'.
* if it's *not* marked for removal, it means that it was newly
added in the post-HUP torrc or that it's of higher priority, in
this case we ignore 't'. */
transport_t *t_tmp = transport_get_by_name(t->name);
if (t_tmp) { /* same name */
if (tor_addr_eq(&t->addr, &t_tmp->addr) && (t->port == t_tmp->port)) {
/* same name *and* addrport */
t_tmp->marked_for_removal = 0;
return 1;
} else { /* same name but different addrport */
if (t_tmp->marked_for_removal) { /* marked for removal */
log_notice(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' "
"but there was already a transport marked for deletion at "
"'%s:%u'. We deleted the old transport and registered the "
"new one.", t->name, fmt_addr(&t->addr), t->port,
fmt_addr(&t_tmp->addr), t_tmp->port);
smartlist_remove(transport_list, t_tmp);
transport_free(t_tmp);
} else { /* *not* marked for removal */
log_notice(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' "
"but the same transport already exists at '%s:%u'. "
"Skipping.", t->name, fmt_addr(&t->addr), t->port,
fmt_addr(&t_tmp->addr), t_tmp->port);
return -1;
}
}
}
smartlist_add(transport_list, t);
return 0;
}
/** Warns the user of possible pluggable transport misconfiguration. */
void
/** Add transport <b>t</b> to the internal list of pluggable
* transports.
* Returns 0 if the transport was added correctly, 1 if the same
* transport was already registered (in this case the caller must
* free the transport) and -1 if there was an error. */
int
transport_add(transport_t *t)
{
int r;
tor_assert(t);
r = transport_resolve_conflicts(t);
switch (r) {
case 0: /* should register transport */
if (!transport_list)
transport_list = smartlist_create();
smartlist_add(transport_list, t);
return 0;
default: /* let our caller know the return code */
return r;
}
}
/** Remember a new pluggable transport proxy at <b>addr</b>:<b>port</b>.
* <b>name</b> is set to the name of the protocol this proxy uses.
* <b>socks_ver</b> is set to the SOCKS version of the proxy. */
int
transport_add_from_config(const tor_addr_t *addr, uint16_t port,
const char *name, int socks_ver)
{
transport_t *t = transport_create(addr, port, name, socks_ver);
int r = transport_add(t);
switch (r) {
case -1:
default:
log_notice(LD_GENERAL, "Could not add transport %s at %s:%u. Skipping.",
t->name, fmt_addr(&t->addr), t->port);
transport_free(t);
return -1;
case 1:
log_info(LD_GENERAL, "Succesfully registered transport %s at %s:%u.",
t->name, fmt_addr(&t->addr), t->port);
transport_free(t); /* falling */
return 0;
case 0:
log_info(LD_GENERAL, "Succesfully registered transport %s at %s:%u.",
t->name, fmt_addr(&t->addr), t->port);
return 0;
}
}
/** Warn the user of possible pluggable transport misconfiguration.
* Return 0 if the validation happened, -1 if we should postpone the
* validation. */
int
validate_pluggable_transports_config(void)
{
if (bridge_list) {
/* Don't validate if managed proxies are not yet fully configured. */
if (bridge_list && !pt_proxies_configuration_pending()) {
SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) {
/* Skip bridges without transports. */
if (!b->transport_name)
@ -4683,6 +4806,10 @@ validate_pluggable_transports_config(void)
"corresponding ClientTransportPlugin line.",
b->transport_name);
} SMARTLIST_FOREACH_END(b);
return 0;
} else {
return -1;
}
}
@ -4913,6 +5040,11 @@ fetch_bridge_descriptors(const or_options_t *options, time_t now)
if (!bridge_list)
return;
/* If we still have unconfigured managed proxies, don't go and
connect to a bridge. */
if (pt_proxies_configuration_pending())
return;
SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge)
{
if (!download_status_is_ready(&bridge->fetch_status, now,

View file

@ -22,6 +22,9 @@ typedef struct {
tor_addr_t addr;
/** Port of proxy */
uint16_t port;
/** Boolean: We are re-parsing our transport list, and we are going to remove
* this one if we don't find it in the list of configured transports. */
unsigned marked_for_removal : 1;
} transport_t;
char *circuit_list_path(origin_circuit_t *circ, int verbose);
@ -77,6 +80,9 @@ int getinfo_helper_entry_guards(control_connection_t *conn,
void mark_bridge_list(void);
void sweep_bridge_list(void);
void mark_transport_list(void);
void sweep_transport_list(void);
int routerinfo_is_a_configured_bridge(const routerinfo_t *ri);
int node_is_a_configured_bridge(const node_t *node);
void learned_router_identity(const tor_addr_t *addr, uint16_t port,
@ -142,9 +148,16 @@ int circuit_build_times_get_bw_scale(networkstatus_t *ns);
void clear_transport_list(void);
int transport_add_from_config(const tor_addr_t *addr, uint16_t port,
const char *name, int socks_ver);
int transport_add(transport_t *t);
void transport_free(transport_t *transport);
transport_t *transport_create(const tor_addr_t *addr, uint16_t port,
const char *name, int socks_ver);
int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
const transport_t **transport);
void validate_pluggable_transports_config(void);
transport_t *transport_get_by_name(const char *name);
int validate_pluggable_transports_config(void);
#endif

View file

@ -33,7 +33,9 @@
#include "rendservice.h"
#include "rephist.h"
#include "router.h"
#include "util.h"
#include "routerlist.h"
#include "transports.h"
#ifdef MS_WINDOWS
#include <shlobj.h>
#endif
@ -301,6 +303,7 @@ static config_var_t _option_vars[] = {
V(HTTPProxyAuthenticator, STRING, NULL),
V(HTTPSProxy, STRING, NULL),
V(HTTPSProxyAuthenticator, STRING, NULL),
VAR("ServerTransportPlugin", LINELIST, ServerTransportPlugin, NULL),
V(Socks4Proxy, STRING, NULL),
V(Socks5Proxy, STRING, NULL),
V(Socks5ProxyUsername, STRING, NULL),
@ -477,6 +480,9 @@ static config_var_t _state_vars[] = {
VAR("EntryGuardAddedBy", LINELIST_S, EntryGuards, NULL),
V(EntryGuards, LINELIST_V, NULL),
VAR("TransportProxy", LINELIST_S, TransportProxies, NULL),
V(TransportProxies, LINELIST_V, NULL),
V(BWHistoryReadEnds, ISOTIME, NULL),
V(BWHistoryReadInterval, UINT, "900"),
V(BWHistoryReadValues, CSV, ""),
@ -503,7 +509,6 @@ static config_var_t _state_vars[] = {
V(CircuitBuildAbandonedCount, UINT, "0"),
VAR("CircuitBuildTimeBin", LINELIST_S, BuildtimeHistogram, NULL),
VAR("BuildtimeHistogram", LINELIST_V, BuildtimeHistogram, NULL),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
};
@ -581,6 +586,8 @@ static int check_nickname_list(const char *lst, const char *name, char **msg);
static int parse_bridge_line(const char *line, int validate_only);
static int parse_client_transport_line(const char *line, int validate_only);
static int parse_server_transport_line(const char *line, int validate_only);
static int parse_dir_server_line(const char *line,
dirinfo_type_t required_type,
int validate_only);
@ -1276,18 +1283,6 @@ options_act(const or_options_t *old_options)
if (consider_adding_dir_authorities(options, old_options) < 0)
return -1;
clear_transport_list();
if (options->ClientTransportPlugin) {
for (cl = options->ClientTransportPlugin; cl; cl = cl->next) {
if (parse_client_transport_line(cl->value, 0)<0) {
log_warn(LD_BUG,
"Previously validated ClientTransportPlugin line "
"could not be added!");
return -1;
}
}
}
if (options->Bridges) {
mark_bridge_list();
for (cl = options->Bridges; cl; cl = cl->next) {
@ -1300,11 +1295,6 @@ options_act(const or_options_t *old_options)
sweep_bridge_list();
}
/* If we have pluggable transport related options enabled, see if we
should warn the user about potential configuration problems. */
if (options->Bridges || options->ClientTransportPlugin)
validate_pluggable_transports_config();
if (running_tor && rend_config_services(options, 0)<0) {
log_warn(LD_BUG,
"Previously validated hidden services line could not be added!");
@ -1324,6 +1314,32 @@ options_act(const or_options_t *old_options)
rep_hist_load_mtbf_data(time(NULL));
}
mark_transport_list();
pt_prepare_proxy_list_for_config_read();
if (options->ClientTransportPlugin) {
for (cl = options->ClientTransportPlugin; cl; cl = cl->next) {
if (parse_client_transport_line(cl->value, 0)<0) {
log_warn(LD_BUG,
"Previously validated ClientTransportPlugin line "
"could not be added!");
return -1;
}
}
}
if (options->ServerTransportPlugin) {
for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
if (parse_server_transport_line(cl->value, 0)<0) {
log_warn(LD_BUG,
"Previously validated ServerTransportPlugin line "
"could not be added!");
return -1;
}
}
}
sweep_transport_list();
sweep_proxy_list();
/* Bail out at this point if we're not going to be a client or server:
* we want to not fork, and to log stuff to stderr. */
if (!running_tor)
@ -3727,14 +3743,19 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->UseBridges && !options->TunnelDirConns)
REJECT("If you set UseBridges, you must set TunnelDirConns.");
for (cl = options->Bridges; cl; cl = cl->next) {
if (parse_bridge_line(cl->value, 1)<0)
REJECT("Bridge line did not parse. See logs for details.");
}
for (cl = options->ClientTransportPlugin; cl; cl = cl->next) {
if (parse_client_transport_line(cl->value, 1)<0)
REJECT("Transport line did not parse. See logs for details.");
}
for (cl = options->Bridges; cl; cl = cl->next) {
if (parse_bridge_line(cl->value, 1)<0)
REJECT("Bridge line did not parse. See logs for details.");
for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
if (parse_server_transport_line(cl->value, 1)<0)
REJECT("Server transport line did not parse. See logs for details.");
}
if (options->ConstrainedSockets) {
@ -4702,49 +4723,102 @@ parse_bridge_line(const char *line, int validate_only)
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
smartlist_free(items);
tor_free(addrport);
tor_free(fingerprint);
tor_free(transport_name);
tor_free(fingerprint);
return r;
}
/** Read the contents of a ClientTransportPlugin line from
* <b>line</b>. Return 0 if the line is well-formed, and -1 if it
* isn't. If <b>validate_only</b> is 0, and the line is well-formed,
* then add the transport described in the line to our internal
* transport list.
*/
* isn't.
*
* If <b>validate_only</b> is 0, and the line is well-formed:
* - If it's an external proxy line, add the transport described in the line to
* our internal transport list.
* - If it's a managed proxy line, launch the managed proxy. */
static int
parse_client_transport_line(const char *line, int validate_only)
{
smartlist_t *items = NULL;
int r;
char *socks_ver_str=NULL;
char *name=NULL;
char *field2=NULL;
const char *transports=NULL;
smartlist_t *transport_list=NULL;
char *addrport=NULL;
int socks_ver;
tor_addr_t addr;
uint16_t port = 0;
int socks_ver=PROXY_NONE;
/* managed proxy options */
int is_managed=0;
char **proxy_argv=NULL;
char **tmp=NULL;
int proxy_argc,i;
int line_length;
items = smartlist_create();
smartlist_split_string(items, line, NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
if (smartlist_len(items) < 3) {
line_length = smartlist_len(items);
if (line_length < 3) {
log_warn(LD_CONFIG, "Too few arguments on ClientTransportPlugin line.");
goto err;
}
name = smartlist_get(items, 0);
/* Get the first line element, split it to commas into
transport_list (in case it's multiple transports) and validate
the transport names. */
transports = smartlist_get(items, 0);
transport_list = smartlist_create();
smartlist_split_string(transport_list, transports, ",",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
SMARTLIST_FOREACH_BEGIN(transport_list, const char *, transport_name) {
if (!string_is_C_identifier(transport_name)) {
log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).",
transport_name);
goto err;
}
} SMARTLIST_FOREACH_END(transport_name);
socks_ver_str = smartlist_get(items, 1);
/* field2 is either a SOCKS version or "exec" */
field2 = smartlist_get(items, 1);
if (!strcmp(socks_ver_str,"socks4"))
if (!strcmp(field2,"socks4")) {
socks_ver = PROXY_SOCKS4;
else if (!strcmp(socks_ver_str,"socks5"))
} else if (!strcmp(field2,"socks5")) {
socks_ver = PROXY_SOCKS5;
else {
log_warn(LD_CONFIG, "Strange ClientTransportPlugin proxy type '%s'.",
socks_ver_str);
} else if (!strcmp(field2,"exec")) {
is_managed=1;
} else {
log_warn(LD_CONFIG, "Strange ClientTransportPlugin field '%s'.",
field2);
goto err;
}
if (is_managed) { /* managed */
if (!validate_only) { /* if we are not just validating, use the
rest of the line as the argv of the proxy
to be launched */
proxy_argc = line_length-2;
tor_assert(proxy_argc > 0);
proxy_argv = tor_malloc_zero(sizeof(char*)*(proxy_argc+1));
tmp = proxy_argv;
for (i=0;i<proxy_argc;i++) { /* store arguments */
*tmp++ = smartlist_get(items, 2);
smartlist_del_keeporder(items, 2);
}
*tmp = NULL; /*terminated with NUL pointer, just like execve() likes it*/
/* kickstart the thing */
pt_kickstart_client_proxy(transport_list, proxy_argv);
}
} else { /* external */
if (smartlist_len(transport_list) != 1) {
log_warn(LD_CONFIG, "You can't have an external proxy with "
"more than one transports.");
goto err;
}
@ -4755,7 +4829,6 @@ parse_client_transport_line(const char *line, int validate_only)
"address '%s'", addrport);
goto err;
}
if (!port) {
log_warn(LD_CONFIG,
"Transport address '%s' has no port.", addrport);
@ -4763,11 +4836,12 @@ parse_client_transport_line(const char *line, int validate_only)
}
if (!validate_only) {
log_debug(LD_DIR, "Transport %s found at %s:%d", name,
fmt_addr(&addr), (int)port);
transport_add_from_config(&addr, port, smartlist_get(transport_list, 0),
socks_ver);
if (transport_add_from_config(&addr, port, name, socks_ver) < 0)
goto err;
log_info(LD_DIR, "Transport '%s' found at %s:%d",
transports, fmt_addr(&addr), (int)port);
}
}
r = 0;
@ -4779,6 +4853,127 @@ parse_client_transport_line(const char *line, int validate_only)
done:
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
smartlist_free(items);
SMARTLIST_FOREACH(transport_list, char*, s, tor_free(s));
smartlist_free(transport_list);
return r;
}
/** Read the contents of a ServerTransportPlugin line from
* <b>line</b>. Return 0 if the line is well-formed, and -1 if it
* isn't.
* If <b>validate_only</b> is 0, the line is well-formed, and it's a
* managed proxy line, launch the managed proxy. */
static int
parse_server_transport_line(const char *line, int validate_only)
{
smartlist_t *items = NULL;
int r;
const char *transports=NULL;
smartlist_t *transport_list=NULL;
char *type=NULL;
char *addrport=NULL;
tor_addr_t addr;
uint16_t port = 0;
/* managed proxy options */
int is_managed=0;
char **proxy_argv=NULL;
char **tmp=NULL;
int proxy_argc,i;
int line_length;
items = smartlist_create();
smartlist_split_string(items, line, NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
line_length = smartlist_len(items);
if (line_length < 3) {
log_warn(LD_CONFIG, "Too few arguments on ServerTransportPlugin line.");
goto err;
}
/* Get the first line element, split it to commas into
transport_list (in case it's multiple transports) and validate
the transport names. */
transports = smartlist_get(items, 0);
transport_list = smartlist_create();
smartlist_split_string(transport_list, transports, ",",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
SMARTLIST_FOREACH_BEGIN(transport_list, const char *, transport_name) {
if (!string_is_C_identifier(transport_name)) {
log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).",
transport_name);
goto err;
}
} SMARTLIST_FOREACH_END(transport_name);
type = smartlist_get(items, 1);
if (!strcmp(type, "exec")) {
is_managed=1;
} else if (!strcmp(type, "proxy")) {
is_managed=0;
} else {
log_warn(LD_CONFIG, "Strange ServerTransportPlugin type '%s'", type);
goto err;
}
if (is_managed) { /* managed */
if (!validate_only) {
proxy_argc = line_length-2;
tor_assert(proxy_argc > 0);
proxy_argv = tor_malloc_zero(sizeof(char*)*(proxy_argc+1));
tmp = proxy_argv;
for (i=0;i<proxy_argc;i++) { /* store arguments */
*tmp++ = smartlist_get(items, 2);
smartlist_del_keeporder(items, 2);
}
*tmp = NULL; /*terminated with NUL pointer, just like execve() likes it*/
/* kickstart the thing */
pt_kickstart_server_proxy(transport_list, proxy_argv);
}
} else { /* external */
if (smartlist_len(transport_list) != 1) {
log_warn(LD_CONFIG, "You can't have an external proxy with "
"more than one transports.");
goto err;
}
addrport = smartlist_get(items, 2);
if (tor_addr_port_parse(addrport, &addr, &port)<0) {
log_warn(LD_CONFIG, "Error parsing transport "
"address '%s'", addrport);
goto err;
}
if (!port) {
log_warn(LD_CONFIG,
"Transport address '%s' has no port.", addrport);
goto err;
}
if (!validate_only) {
log_info(LD_DIR, "Server transport '%s' at %s:%d.",
transports, fmt_addr(&addr), (int)port);
}
}
r = 0;
goto done;
err:
r = -1;
done:
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
smartlist_free(items);
SMARTLIST_FOREACH(transport_list, char*, s, tor_free(s));
smartlist_free(transport_list);
return r;
}
@ -5721,6 +5916,69 @@ options_get_datadir_fname2_suffix(const or_options_t *options,
return fname;
}
/** Return true if <b>line</b> is a valid state TransportProxy line.
* Return false otherwise. */
static int
state_transport_line_is_valid(const char *line)
{
smartlist_t *items = NULL;
char *addrport=NULL;
tor_addr_t addr;
uint16_t port = 0;
int r;
items = smartlist_create();
smartlist_split_string(items, line, NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
if (smartlist_len(items) != 2) {
log_warn(LD_CONFIG, "state: Not enough arguments in TransportProxy line.");
goto err;
}
addrport = smartlist_get(items, 1);
if (tor_addr_port_parse(addrport, &addr, &port) < 0) {
log_warn(LD_CONFIG, "state: Could not parse addrport.");
goto err;
}
if (!port) {
log_warn(LD_CONFIG, "state: Transport line did not contain port.");
goto err;
}
r = 1;
goto done;
err:
r = 0;
done:
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
smartlist_free(items);
return r;
}
/** Return 0 if all TransportProxy lines in <b>state</b> are well
* formed. Otherwise, return -1. */
static int
validate_transports_in_state(or_state_t *state)
{
int broken = 0;
config_line_t *line;
for (line = state->TransportProxies ; line ; line = line->next) {
tor_assert(!strcmp(line->key, "TransportProxy"));
if (!state_transport_line_is_valid(line->value)<0)
broken = 1;
}
if (broken)
log_warn(LD_CONFIG, "state: State file seems to be broken.");
return 0;
}
/** Return 0 if every setting in <b>state</b> is reasonable, and a
* permissible transition from <b>old_state</b>. Else warn and return -1.
* Should have no side effects, except for normalizing the contents of
@ -5739,6 +5997,9 @@ or_state_validate(or_state_t *old_state, or_state_t *state,
if (entry_guards_parse_state(state, 0, msg)<0)
return -1;
if (validate_transports_in_state(state)<0)
return -1;
return 0;
}
@ -5971,6 +6232,150 @@ or_state_save(time_t now)
return 0;
}
/** Return the config line for transport <b>transport</b> in the current state.
* Return NULL if there is no config line for <b>transport</b>. */
static config_line_t *
get_transport_in_state_by_name(const char *transport)
{
or_state_t *or_state = get_or_state();
config_line_t *line;
config_line_t *ret = NULL;
smartlist_t *items = NULL;
for (line = or_state->TransportProxies ; line ; line = line->next) {
tor_assert(!strcmp(line->key, "TransportProxy"));
items = smartlist_create();
smartlist_split_string(items, line->value, NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
if (smartlist_len(items) != 2) /* broken state */
goto done;
if (!strcmp(smartlist_get(items, 0), transport)) {
ret = line;
goto done;
}
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
smartlist_free(items);
items = NULL;
}
done:
if (items) {
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
smartlist_free(items);
}
return ret;
}
/** Return string containing the address:port part of the
* TransportProxy <b>line</b> for transport <b>transport</b>.
* If the line is corrupted, return NULL. */
static const char *
get_transport_bindaddr(const char *line, const char *transport)
{
char *line_tmp = NULL;
if (strlen(line) < strlen(transport) + 2) {
goto broken_state;
} else {
/* line should start with the name of the transport and a space.
(for example, "obfs2 127.0.0.1:47245") */
tor_asprintf(&line_tmp, "%s ", transport);
if (strcmpstart(line, line_tmp))
goto broken_state;
tor_free(line_tmp);
return (line+strlen(transport)+1);
}
broken_state:
tor_free(line_tmp);
return NULL;
}
/** Return a static string containing the address:port a proxy
* transport should bind on. */
const char *
get_bindaddr_for_transport(const char *transport)
{
static const char default_addrport[] = "127.0.0.1:0";
const char *bindaddr = NULL;
config_line_t *line = get_transport_in_state_by_name(transport);
if (!line)
return default_addrport;
bindaddr = get_transport_bindaddr(line->value, transport);
return bindaddr ? bindaddr : 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);
}
/** Given a file name check to see whether the file exists but has not been
* modified for a very long time. If so, remove it. */
void

View file

@ -68,6 +68,11 @@ const smartlist_t *get_configured_client_ports(void);
int options_need_geoip_info(const or_options_t *options,
const char **reason_out);
void save_transport_to_state(const char *transport_name,
const tor_addr_t *addr, uint16_t port);
const char *get_bindaddr_for_transport(const char *transport);
int getinfo_helper_config(control_connection_t *conn,
const char *question, char **answer,
const char **errmsg);

View file

@ -2020,9 +2020,12 @@ retry_all_listeners(smartlist_t *replaced_conns,
return retval;
}
/** Return 1 if we should apply rate limiting to <b>conn</b>,
* and 0 otherwise. Right now this just checks if it's an internal
* IP address or an internal connection. */
/** Return 1 if we should apply rate limiting to <b>conn</b>, and 0
* otherwise.
* Right now this just checks if it's an internal IP address or an
* internal connection. We also check if the connection uses pluggable
* transports, since we should then limit it even if it comes from an
* internal IP address. */
static int
connection_is_rate_limited(connection_t *conn)
{

View file

@ -37,6 +37,7 @@
#include "ntmain.h"
#include "onion.h"
#include "policies.h"
#include "transports.h"
#include "relay.h"
#include "rendclient.h"
#include "rendcommon.h"
@ -1086,7 +1087,9 @@ run_scheduled_events(time_t now)
static int should_init_bridge_stats = 1;
static time_t time_to_retry_dns_init = 0;
static time_t time_to_next_heartbeat = 0;
static int has_validated_pt = 0;
const or_options_t *options = get_options();
int is_server = server_mode(options);
int i;
int have_dir_info;
@ -1463,7 +1466,7 @@ run_scheduled_events(time_t now)
}
}
/** 10b. write bridge networkstatus file to disk */
/** 10. write bridge networkstatus file to disk */
if (options->BridgeAuthoritativeDir &&
time_to_write_bridge_status_file < now) {
networkstatus_dump_bridge_status_to_file(now);
@ -1471,6 +1474,7 @@ run_scheduled_events(time_t now)
time_to_write_bridge_status_file = now+BRIDGE_STATUSFILE_INTERVAL;
}
/** 11. check the port forwarding app */
if (time_to_check_port_forwarding < now &&
options->PortForwarding &&
is_server) {
@ -1482,7 +1486,19 @@ run_scheduled_events(time_t now)
time_to_check_port_forwarding = now+PORT_FORWARDING_CHECK_INTERVAL;
}
/** 11. write the heartbeat message */
/** 11b. check pending unconfigured managed proxies */
if (pt_proxies_configuration_pending())
pt_configure_remaining_proxies();
/** 11c. validate pluggable transports configuration if we need to */
if (!has_validated_pt &&
(options->Bridges || options->ClientTransportPlugin)) {
if (validate_pluggable_transports_config() == 0) {
has_validated_pt = 1;
}
}
/** 12. write the heartbeat message */
if (options->HeartbeatPeriod &&
time_to_next_heartbeat < now) {
log_heartbeat(now);
@ -2341,6 +2357,7 @@ tor_free_all(int postfork)
clear_pending_onions();
circuit_free_all();
entry_guards_free_all();
pt_free_all();
connection_free_all();
buf_shrink_freelists(1);
memarea_clear_freelist();

View file

@ -2879,6 +2879,9 @@ typedef struct {
config_line_t *ClientTransportPlugin; /**< List of client
transport plugins. */
config_line_t *ServerTransportPlugin; /**< List of client
transport plugins. */
int BridgeRelay; /**< Boolean: are we acting as a bridge relay? We make
* this explicit so we can change how we behave in the
* future. */
@ -3350,6 +3353,8 @@ typedef struct {
/** A list of Entry Guard-related configuration lines. */
config_line_t *EntryGuards;
config_line_t *TransportProxies;
/** These fields hold information on the history of bandwidth usage for
* servers. The "Ends" fields hold the time when we last updated the
* bandwidth usage. The "Interval" fields hold the granularity, in seconds,

1048
src/or/transports.c Normal file

File diff suppressed because it is too large Load diff

105
src/or/transports.h Normal file
View file

@ -0,0 +1,105 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2011, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file transports.h
* \brief Headers for transports.c
**/
#ifndef TOR_TRANSPORTS_H
#define TOR_TRANSPORTS_H
void pt_kickstart_proxy(const smartlist_t *transport_list, char **proxy_argv,
int is_server);
#define pt_kickstart_client_proxy(tl, pa) \
pt_kickstart_proxy(tl, pa, 0)
#define pt_kickstart_server_proxy(tl, pa) \
pt_kickstart_proxy(tl, pa, 1)
void pt_configure_remaining_proxies(void);
int pt_proxies_configuration_pending(void);
void pt_free_all(void);
void pt_prepare_proxy_list_for_config_read(void);
void sweep_proxy_list(void);
#ifdef PT_PRIVATE
/** State of the managed proxy configuration protocol. */
enum pt_proto_state {
PT_PROTO_INFANT, /* was just born */
PT_PROTO_LAUNCHED, /* was just launched */
PT_PROTO_ACCEPTING_METHODS, /* accepting methods */
PT_PROTO_CONFIGURED, /* configured successfully */
PT_PROTO_COMPLETED, /* configure and registered its transports */
PT_PROTO_BROKEN
};
/** Structure containing information of a managed proxy. */
typedef struct {
enum pt_proto_state conf_state; /* the current configuration state */
char **argv; /* the cli arguments of this proxy */
int conf_protocol; /* the configuration protocol version used */
int is_server; /* is it a server proxy? */
FILE *_stdout; /* a stream to its stdout
(closed in managed_proxy_destroy()) */
int pid; /* The Process ID this managed proxy is using. */
/** Boolean: We are re-parsing our config, and we are going to
* remove this managed proxy if we don't find it any transport
* plugins that use it. */
unsigned int marked_for_removal : 1;
/** Boolean: We got a SIGHUP while this proxy was running. We use
* this flag to signify that this proxy might need to be restarted
* so that it can listen for other transports according to the new
* torrc. */
unsigned int got_hup : 1;
/* transports to-be-launched by this proxy */
smartlist_t *transports_to_launch;
/* The 'transports' list contains all the transports this proxy has
launched.
Before a managed_proxy_t reaches the PT_PROTO_COMPLETED phase,
this smartlist contains a 'transport_t' for every transport it
has launched.
When the managed_proxy_t reaches the PT_PROTO_COMPLETED phase, it
registers all its transports to the circuitbuild.c subsystem. At
that point the 'transport_t's are owned by the circuitbuild.c
subsystem.
To avoid carrying dangling 'transport_t's in this smartlist,
right before the managed_proxy_t reaches the PT_PROTO_COMPLETED
phase we replace all 'transport_t's with strings of their
transport names.
So, tl;dr:
When (conf_state != PT_PROTO_COMPLETED) this list carries
(transport_t *).
When (conf_state == PT_PROTO_COMPLETED) this list carries
(char *).
*/
smartlist_t *transports;
} managed_proxy_t;
int parse_cmethod_line(const char *line, managed_proxy_t *mp);
int parse_smethod_line(const char *line, managed_proxy_t *mp);
int parse_version(const char *line, managed_proxy_t *mp);
void parse_env_error(const char *line);
void handle_proxy_line(const char *line, managed_proxy_t *mp);
#endif
#endif

View file

@ -19,6 +19,7 @@ test_SOURCES = \
test_data.c \
test_dir.c \
test_microdesc.c \
test_pt.c \
test_util.c \
tinytest.c

View file

@ -1941,6 +1941,7 @@ extern struct testcase_t container_tests[];
extern struct testcase_t util_tests[];
extern struct testcase_t dir_tests[];
extern struct testcase_t microdesc_tests[];
extern struct testcase_t pt_tests[];
static struct testgroup_t testgroups[] = {
{ "", test_array },
@ -1951,6 +1952,7 @@ static struct testgroup_t testgroups[] = {
{ "util/", util_tests },
{ "dir/", dir_tests },
{ "dir/md/", microdesc_tests },
{ "pt/", pt_tests },
END_OF_GROUPS
};

147
src/test/test_pt.c Normal file
View file

@ -0,0 +1,147 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2011, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#define PT_PRIVATE
#include "or.h"
#include "transports.h"
#include "circuitbuild.h"
#include "test.h"
static void
reset_mp(managed_proxy_t *mp)
{
mp->conf_state = PT_PROTO_LAUNCHED;
SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
smartlist_clear(mp->transports);
}
static void
test_pt_parsing(void)
{
char line[200];
managed_proxy_t *mp = tor_malloc(sizeof(managed_proxy_t));
mp->conf_state = PT_PROTO_INFANT;
mp->transports = smartlist_create();
/* incomplete cmethod */
strcpy(line,"CMETHOD trebuchet");
test_assert(parse_cmethod_line(line, mp) < 0);
reset_mp(mp);
/* wrong proxy type */
strcpy(line,"CMETHOD trebuchet dog 127.0.0.1:1999");
test_assert(parse_cmethod_line(line, mp) < 0);
reset_mp(mp);
/* wrong addrport */
strcpy(line,"CMETHOD trebuchet socks4 abcd");
test_assert(parse_cmethod_line(line, mp) < 0);
reset_mp(mp);
/* correct line */
strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999");
test_assert(parse_cmethod_line(line, mp) == 0);
test_assert(smartlist_len(mp->transports));
reset_mp(mp);
/* incomplete smethod */
strcpy(line,"SMETHOD trebuchet");
test_assert(parse_smethod_line(line, mp) < 0);
reset_mp(mp);
/* wrong addr type */
strcpy(line,"SMETHOD trebuchet abcd");
test_assert(parse_smethod_line(line, mp) < 0);
reset_mp(mp);
/* cowwect */
strcpy(line,"SMETHOD trebuchy 127.0.0.1:1999");
test_assert(parse_smethod_line(line, mp) == 0);
reset_mp(mp);
/* unsupported version */
strcpy(line,"VERSION 666");
test_assert(parse_version(line, mp) < 0);
/* incomplete VERSION */
strcpy(line,"VERSION ");
test_assert(parse_version(line, mp) < 0);
/* correct VERSION */
strcpy(line,"VERSION 1");
test_assert(parse_version(line, mp) == 0);
done:
tor_free(mp);
}
static void
test_pt_protocol(void)
{
char line[200];
managed_proxy_t *mp = tor_malloc(sizeof(managed_proxy_t));
mp->conf_state = PT_PROTO_LAUNCHED;
mp->transports = smartlist_create();
/* various wrong protocol runs: */
strcpy(line, "TEST TEST");
handle_proxy_line(line, mp);
test_assert(mp->conf_state == PT_PROTO_BROKEN);
reset_mp(mp);
strcpy(line,"VERSION 1");
handle_proxy_line(line, mp);
test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
strcpy(line,"VERSION 1");
handle_proxy_line(line, mp);
test_assert(mp->conf_state == PT_PROTO_BROKEN);
reset_mp(mp);
strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999");
handle_proxy_line(line, mp);
test_assert(mp->conf_state == PT_PROTO_BROKEN);
reset_mp(mp);
/* correct protocol run: */
strcpy(line,"VERSION 1");
handle_proxy_line(line, mp);
test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999");
handle_proxy_line(line, mp);
test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
strcpy(line,"CMETHODS DONE");
handle_proxy_line(line, mp);
test_assert(mp->conf_state == PT_PROTO_CONFIGURED);
done:
tor_free(mp);
}
#define PT_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_pt_ ## name }
struct testcase_t pt_tests[] = {
PT_LEGACY(parsing),
PT_LEGACY(protocol),
END_OF_TESTCASES
};

View file

@ -1389,9 +1389,9 @@ run_util_spawn_background(const char *argv[], const char *expected_out,
/* Start the program */
#ifdef MS_WINDOWS
tor_spawn_background(NULL, argv, &process_handle);
tor_spawn_background(NULL, argv, NULL, &process_handle);
#else
tor_spawn_background(argv[0], argv, &process_handle);
tor_spawn_background(argv[0], argv, NULL, &process_handle);
#endif
tt_int_op(process_handle.status, ==, expected_status);
@ -1506,9 +1506,9 @@ test_util_spawn_background_partial_read(void *ptr)
/* Start the program */
#ifdef MS_WINDOWS
tor_spawn_background(NULL, argv, &process_handle);
tor_spawn_background(NULL, argv, NULL, &process_handle);
#else
tor_spawn_background(argv[0], argv, &process_handle);
tor_spawn_background(argv[0], argv, NULL, &process_handle);
#endif
tt_int_op(process_handle.status, ==, expected_status);