1 /* Copyright (c) 2001-2004, Roger Dingledine.
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2015, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
9 #define STATEFILE_PRIVATE
10 #define CONTROL_PRIVATE
13 #include "confparse.h"
15 #include "transports.h"
16 #include "circuitbuild.h"
18 #include "statefile.h"
22 reset_mp(managed_proxy_t
*mp
)
24 mp
->conf_state
= PT_PROTO_LAUNCHED
;
25 SMARTLIST_FOREACH(mp
->transports
, transport_t
*, t
, transport_free(t
));
26 smartlist_clear(mp
->transports
);
30 test_pt_parsing(void *arg
)
33 transport_t
*transport
= NULL
;
36 managed_proxy_t
*mp
= tor_malloc_zero(sizeof(managed_proxy_t
));
38 mp
->conf_state
= PT_PROTO_INFANT
;
39 mp
->transports
= smartlist_new();
41 /* incomplete cmethod */
42 strlcpy(line
,"CMETHOD trebuchet",sizeof(line
));
43 tt_assert(parse_cmethod_line(line
, mp
) < 0);
47 /* wrong proxy type */
48 strlcpy(line
,"CMETHOD trebuchet dog 127.0.0.1:1999",sizeof(line
));
49 tt_assert(parse_cmethod_line(line
, mp
) < 0);
54 strlcpy(line
,"CMETHOD trebuchet socks4 abcd",sizeof(line
));
55 tt_assert(parse_cmethod_line(line
, mp
) < 0);
60 strlcpy(line
,"CMETHOD trebuchet socks5 127.0.0.1:1999",sizeof(line
));
61 tt_assert(parse_cmethod_line(line
, mp
) == 0);
62 tt_assert(smartlist_len(mp
->transports
) == 1);
63 transport
= smartlist_get(mp
->transports
, 0);
64 /* test registered address of transport */
65 tor_addr_parse(&test_addr
, "127.0.0.1");
66 tt_assert(tor_addr_eq(&test_addr
, &transport
->addr
));
67 /* test registered port of transport */
68 tt_assert(transport
->port
== 1999);
69 /* test registered SOCKS version of transport */
70 tt_assert(transport
->socks_version
== PROXY_SOCKS5
);
71 /* test registered name of transport */
72 tt_str_op(transport
->name
,OP_EQ
, "trebuchet");
76 /* incomplete smethod */
77 strlcpy(line
,"SMETHOD trebuchet",sizeof(line
));
78 tt_assert(parse_smethod_line(line
, mp
) < 0);
83 strlcpy(line
,"SMETHOD trebuchet abcd",sizeof(line
));
84 tt_assert(parse_smethod_line(line
, mp
) < 0);
89 strlcpy(line
,"SMETHOD trebuchy 127.0.0.2:2999",sizeof(line
));
90 tt_assert(parse_smethod_line(line
, mp
) == 0);
91 tt_assert(smartlist_len(mp
->transports
) == 1);
92 transport
= smartlist_get(mp
->transports
, 0);
93 /* test registered address of transport */
94 tor_addr_parse(&test_addr
, "127.0.0.2");
95 tt_assert(tor_addr_eq(&test_addr
, &transport
->addr
));
96 /* test registered port of transport */
97 tt_assert(transport
->port
== 2999);
98 /* test registered name of transport */
99 tt_str_op(transport
->name
,OP_EQ
, "trebuchy");
103 /* Include some arguments. Good ones. */
104 strlcpy(line
,"SMETHOD trebuchet 127.0.0.1:9999 "
105 "ARGS:counterweight=3,sling=snappy",
107 tt_assert(parse_smethod_line(line
, mp
) == 0);
108 tt_int_op(1, OP_EQ
, smartlist_len(mp
->transports
));
110 const transport_t
*transport
= smartlist_get(mp
->transports
, 0);
111 tt_assert(transport
);
112 tt_str_op(transport
->name
, OP_EQ
, "trebuchet");
113 tt_int_op(transport
->port
, OP_EQ
, 9999);
114 tt_str_op(fmt_addr(&transport
->addr
), OP_EQ
, "127.0.0.1");
115 tt_str_op(transport
->extra_info_args
, OP_EQ
,
116 "counterweight=3,sling=snappy");
120 /* unsupported version */
121 strlcpy(line
,"VERSION 666",sizeof(line
));
122 tt_assert(parse_version(line
, mp
) < 0);
124 /* incomplete VERSION */
125 strlcpy(line
,"VERSION ",sizeof(line
));
126 tt_assert(parse_version(line
, mp
) < 0);
128 /* correct VERSION */
129 strlcpy(line
,"VERSION 1",sizeof(line
));
130 tt_assert(parse_version(line
, mp
) == 0);
134 smartlist_free(mp
->transports
);
139 test_pt_get_transport_options(void *arg
)
142 smartlist_t
*transport_list
= smartlist_new();
144 or_options_t
*options
= get_options_mutable();
145 char *opt_str
= NULL
;
146 config_line_t
*cl
= NULL
;
149 execve_args
= tor_malloc(sizeof(char*)*2);
150 execve_args
[0] = tor_strdup("cheeseshop");
151 execve_args
[1] = NULL
;
153 mp
= managed_proxy_create(transport_list
, execve_args
, 1);
154 tt_ptr_op(mp
, OP_NE
, NULL
);
155 opt_str
= get_transport_options_for_server_proxy(mp
);
156 tt_ptr_op(opt_str
, OP_EQ
, NULL
);
158 smartlist_add(mp
->transports_to_launch
, tor_strdup("gruyere"));
159 smartlist_add(mp
->transports_to_launch
, tor_strdup("roquefort"));
160 smartlist_add(mp
->transports_to_launch
, tor_strdup("stnectaire"));
164 cl
= tor_malloc_zero(sizeof(config_line_t
));
165 cl
->value
= tor_strdup("gruyere melty=10 hardness=se;ven");
166 options
->ServerTransportOptions
= cl
;
168 cl
= tor_malloc_zero(sizeof(config_line_t
));
169 cl
->value
= tor_strdup("stnectaire melty=4 hardness=three");
170 cl
->next
= options
->ServerTransportOptions
;
171 options
->ServerTransportOptions
= cl
;
173 cl
= tor_malloc_zero(sizeof(config_line_t
));
174 cl
->value
= tor_strdup("pepperjack melty=12 hardness=five");
175 cl
->next
= options
->ServerTransportOptions
;
176 options
->ServerTransportOptions
= cl
;
178 opt_str
= get_transport_options_for_server_proxy(mp
);
179 tt_str_op(opt_str
, OP_EQ
,
180 "gruyere:melty=10;gruyere:hardness=se\\;ven;"
181 "stnectaire:melty=4;stnectaire:hardness=three");
185 config_free_lines(cl
);
186 managed_proxy_destroy(mp
, 0);
187 smartlist_free(transport_list
);
191 test_pt_protocol(void *arg
)
195 managed_proxy_t
*mp
= tor_malloc_zero(sizeof(managed_proxy_t
));
197 mp
->conf_state
= PT_PROTO_LAUNCHED
;
198 mp
->transports
= smartlist_new();
199 mp
->argv
= tor_calloc(2, sizeof(char *));
200 mp
->argv
[0] = tor_strdup("<testcase>");
202 /* various wrong protocol runs: */
204 strlcpy(line
,"VERSION 1",sizeof(line
));
205 handle_proxy_line(line
, mp
);
206 tt_assert(mp
->conf_state
== PT_PROTO_ACCEPTING_METHODS
);
208 strlcpy(line
,"VERSION 1",sizeof(line
));
209 handle_proxy_line(line
, mp
);
210 tt_assert(mp
->conf_state
== PT_PROTO_BROKEN
);
214 strlcpy(line
,"CMETHOD trebuchet socks5 127.0.0.1:1999",sizeof(line
));
215 handle_proxy_line(line
, mp
);
216 tt_assert(mp
->conf_state
== PT_PROTO_BROKEN
);
220 /* correct protocol run: */
221 strlcpy(line
,"VERSION 1",sizeof(line
));
222 handle_proxy_line(line
, mp
);
223 tt_assert(mp
->conf_state
== PT_PROTO_ACCEPTING_METHODS
);
225 strlcpy(line
,"CMETHOD trebuchet socks5 127.0.0.1:1999",sizeof(line
));
226 handle_proxy_line(line
, mp
);
227 tt_assert(mp
->conf_state
== PT_PROTO_ACCEPTING_METHODS
);
229 strlcpy(line
,"CMETHODS DONE",sizeof(line
));
230 handle_proxy_line(line
, mp
);
231 tt_assert(mp
->conf_state
== PT_PROTO_CONFIGURED
);
235 smartlist_free(mp
->transports
);
236 tor_free(mp
->argv
[0]);
242 test_pt_get_extrainfo_string(void *arg
)
244 managed_proxy_t
*mp1
= NULL
, *mp2
= NULL
;
245 char **argv1
, **argv2
;
246 smartlist_t
*t1
= smartlist_new(), *t2
= smartlist_new();
251 argv1
= tor_malloc_zero(sizeof(char*)*3);
252 argv1
[0] = tor_strdup("ewige");
253 argv1
[1] = tor_strdup("Blumenkraft");
255 argv2
= tor_malloc_zero(sizeof(char*)*4);
256 argv2
[0] = tor_strdup("und");
257 argv2
[1] = tor_strdup("ewige");
258 argv2
[2] = tor_strdup("Schlangenkraft");
261 mp1
= managed_proxy_create(t1
, argv1
, 1);
262 mp2
= managed_proxy_create(t2
, argv2
, 1);
264 r
= parse_smethod_line("SMETHOD hagbard 127.0.0.1:5555", mp1
);
265 tt_int_op(r
, OP_EQ
, 0);
266 r
= parse_smethod_line("SMETHOD celine 127.0.0.1:1723 ARGS:card=no-enemy",
268 tt_int_op(r
, OP_EQ
, 0);
270 /* Force these proxies to look "completed" or they won't generate output. */
271 mp1
->conf_state
= mp2
->conf_state
= PT_PROTO_COMPLETED
;
273 s
= pt_get_extra_info_descriptor_string();
276 "transport hagbard 127.0.0.1:5555\n"
277 "transport celine 127.0.0.1:1723 card=no-enemy\n");
280 /* XXXX clean up better */
287 #define STDIN_HANDLE HANDLE
289 #define STDIN_HANDLE FILE
293 tor_get_lines_from_handle_replacement(STDIN_HANDLE
*handle
,
294 enum stream_status
*stream_status_out
)
296 static int times_called
= 0;
297 smartlist_t
*retval_sl
= smartlist_new();
300 (void) stream_status_out
;
302 /* Generate some dummy CMETHOD lines the first 5 times. The 6th
303 time, send 'CMETHODS DONE' to finish configuring the proxy. */
304 if (times_called
++ != 5) {
305 smartlist_add_asprintf(retval_sl
, "SMETHOD mock%d 127.0.0.1:555%d",
306 times_called
, times_called
);
308 smartlist_add(retval_sl
, tor_strdup("SMETHODS DONE"));
316 tor_process_handle_destroy_replacement(process_handle_t
*process_handle
,
317 int also_terminate_process
)
319 (void) process_handle
;
320 (void) also_terminate_process
;
323 static or_state_t
*dummy_state
= NULL
;
326 get_or_state_replacement(void)
331 static int controlevent_n
= 0;
332 static uint16_t controlevent_event
= 0;
333 static smartlist_t
*controlevent_msgs
= NULL
;
336 queue_control_event_string_replacement(uint16_t event
, char *msg
)
339 controlevent_event
= event
;
340 if (!controlevent_msgs
)
341 controlevent_msgs
= smartlist_new();
342 smartlist_add(controlevent_msgs
, msg
);
345 /* Test the configure_proxy() function. */
347 test_pt_configure_proxy(void *arg
)
350 managed_proxy_t
*mp
= NULL
;
353 dummy_state
= tor_malloc_zero(sizeof(or_state_t
));
355 MOCK(tor_get_lines_from_handle
,
356 tor_get_lines_from_handle_replacement
);
357 MOCK(tor_process_handle_destroy
,
358 tor_process_handle_destroy_replacement
);
360 get_or_state_replacement
);
361 MOCK(queue_control_event_string
,
362 queue_control_event_string_replacement
);
364 control_testing_set_global_event_mask(EVENT_TRANSPORT_LAUNCHED
);
366 mp
= tor_malloc_zero(sizeof(managed_proxy_t
));
367 mp
->conf_state
= PT_PROTO_ACCEPTING_METHODS
;
368 mp
->transports
= smartlist_new();
369 mp
->transports_to_launch
= smartlist_new();
370 mp
->process_handle
= tor_malloc_zero(sizeof(process_handle_t
));
371 mp
->argv
= tor_malloc_zero(sizeof(char*)*2);
372 mp
->argv
[0] = tor_strdup("<testcase>");
375 /* Test the return value of configure_proxy() by calling it some
376 times while it is uninitialized and then finally finalizing its
378 for (i
= 0 ; i
< 5 ; i
++) {
379 retval
= configure_proxy(mp
);
380 /* retval should be zero because proxy hasn't finished configuring yet */
381 tt_int_op(retval
, OP_EQ
, 0);
382 /* check the number of registered transports */
383 tt_assert(smartlist_len(mp
->transports
) == i
+1);
384 /* check that the mp is still waiting for transports */
385 tt_assert(mp
->conf_state
== PT_PROTO_ACCEPTING_METHODS
);
388 /* this last configure_proxy() should finalize the proxy configuration. */
389 retval
= configure_proxy(mp
);
390 /* retval should be 1 since the proxy finished configuring */
391 tt_int_op(retval
, OP_EQ
, 1);
392 /* check the mp state */
393 tt_assert(mp
->conf_state
== PT_PROTO_COMPLETED
);
395 tt_int_op(controlevent_n
, OP_EQ
, 5);
396 tt_int_op(controlevent_event
, OP_EQ
, EVENT_TRANSPORT_LAUNCHED
);
397 tt_int_op(smartlist_len(controlevent_msgs
), OP_EQ
, 5);
398 smartlist_sort_strings(controlevent_msgs
);
399 tt_str_op(smartlist_get(controlevent_msgs
, 0), OP_EQ
,
400 "650 TRANSPORT_LAUNCHED server mock1 127.0.0.1 5551\r\n");
401 tt_str_op(smartlist_get(controlevent_msgs
, 1), OP_EQ
,
402 "650 TRANSPORT_LAUNCHED server mock2 127.0.0.1 5552\r\n");
403 tt_str_op(smartlist_get(controlevent_msgs
, 2), OP_EQ
,
404 "650 TRANSPORT_LAUNCHED server mock3 127.0.0.1 5553\r\n");
405 tt_str_op(smartlist_get(controlevent_msgs
, 3), OP_EQ
,
406 "650 TRANSPORT_LAUNCHED server mock4 127.0.0.1 5554\r\n");
407 tt_str_op(smartlist_get(controlevent_msgs
, 4), OP_EQ
,
408 "650 TRANSPORT_LAUNCHED server mock5 127.0.0.1 5555\r\n");
410 { /* check that the transport info were saved properly in the tor state */
411 config_line_t
*transport_in_state
= NULL
;
412 smartlist_t
*transport_info_sl
= smartlist_new();
413 char *name_of_transport
= NULL
;
414 char *bindaddr
= NULL
;
416 /* Get the bindaddr for "mock1" and check it against the bindaddr
417 that the mocked tor_get_lines_from_handle() generated. */
418 transport_in_state
= get_transport_in_state_by_name("mock1");
419 tt_assert(transport_in_state
);
420 smartlist_split_string(transport_info_sl
, transport_in_state
->value
,
422 name_of_transport
= smartlist_get(transport_info_sl
, 0);
423 bindaddr
= smartlist_get(transport_info_sl
, 1);
424 tt_str_op(name_of_transport
, OP_EQ
, "mock1");
425 tt_str_op(bindaddr
, OP_EQ
, "127.0.0.1:5551");
427 SMARTLIST_FOREACH(transport_info_sl
, char *, cp
, tor_free(cp
));
428 smartlist_free(transport_info_sl
);
432 or_state_free(dummy_state
);
433 UNMOCK(tor_get_lines_from_handle
);
434 UNMOCK(tor_process_handle_destroy
);
435 UNMOCK(get_or_state
);
436 UNMOCK(queue_control_event_string
);
437 if (controlevent_msgs
) {
438 SMARTLIST_FOREACH(controlevent_msgs
, char *, cp
, tor_free(cp
));
439 smartlist_free(controlevent_msgs
);
440 controlevent_msgs
= NULL
;
442 if (mp
->transports
) {
443 SMARTLIST_FOREACH(mp
->transports
, transport_t
*, t
, transport_free(t
));
444 smartlist_free(mp
->transports
);
446 smartlist_free(mp
->transports_to_launch
);
447 tor_free(mp
->process_handle
);
448 tor_free(mp
->argv
[0]);
453 /* Test the get_pt_proxy_uri() function. */
455 test_get_pt_proxy_uri(void *arg
)
457 or_options_t
*options
= get_options_mutable();
462 /* Test with no proxy. */
463 uri
= get_pt_proxy_uri();
464 tt_assert(uri
== NULL
);
466 /* Test with a SOCKS4 proxy. */
467 options
->Socks4Proxy
= tor_strdup("192.0.2.1:1080");
468 ret
= tor_addr_port_lookup(options
->Socks4Proxy
,
469 &options
->Socks4ProxyAddr
,
470 &options
->Socks4ProxyPort
);
471 tt_int_op(ret
, OP_EQ
, 0);
472 uri
= get_pt_proxy_uri();
473 tt_str_op(uri
, OP_EQ
, "socks4a://192.0.2.1:1080");
475 tor_free(options
->Socks4Proxy
);
477 /* Test with a SOCKS5 proxy, no username/password. */
478 options
->Socks5Proxy
= tor_strdup("192.0.2.1:1080");
479 ret
= tor_addr_port_lookup(options
->Socks5Proxy
,
480 &options
->Socks5ProxyAddr
,
481 &options
->Socks5ProxyPort
);
482 tt_int_op(ret
, OP_EQ
, 0);
483 uri
= get_pt_proxy_uri();
484 tt_str_op(uri
, OP_EQ
, "socks5://192.0.2.1:1080");
487 /* Test with a SOCKS5 proxy, with username/password. */
488 options
->Socks5ProxyUsername
= tor_strdup("hwest");
489 options
->Socks5ProxyPassword
= tor_strdup("r34n1m470r");
490 uri
= get_pt_proxy_uri();
491 tt_str_op(uri
, OP_EQ
, "socks5://hwest:r34n1m470r@192.0.2.1:1080");
493 tor_free(options
->Socks5Proxy
);
494 tor_free(options
->Socks5ProxyUsername
);
495 tor_free(options
->Socks5ProxyPassword
);
497 /* Test with a HTTPS proxy, no authenticator. */
498 options
->HTTPSProxy
= tor_strdup("192.0.2.1:80");
499 ret
= tor_addr_port_lookup(options
->HTTPSProxy
,
500 &options
->HTTPSProxyAddr
,
501 &options
->HTTPSProxyPort
);
502 tt_int_op(ret
, OP_EQ
, 0);
503 uri
= get_pt_proxy_uri();
504 tt_str_op(uri
, OP_EQ
, "http://192.0.2.1:80");
507 /* Test with a HTTPS proxy, with authenticator. */
508 options
->HTTPSProxyAuthenticator
= tor_strdup("hwest:r34n1m470r");
509 uri
= get_pt_proxy_uri();
510 tt_str_op(uri
, OP_EQ
, "http://hwest:r34n1m470r@192.0.2.1:80");
512 tor_free(options
->HTTPSProxy
);
513 tor_free(options
->HTTPSProxyAuthenticator
);
515 /* Token nod to the fact that IPv6 exists. */
516 options
->Socks4Proxy
= tor_strdup("[2001:db8::1]:1080");
517 ret
= tor_addr_port_lookup(options
->Socks4Proxy
,
518 &options
->Socks4ProxyAddr
,
519 &options
->Socks4ProxyPort
);
520 tt_int_op(ret
, OP_EQ
, 0);
521 uri
= get_pt_proxy_uri();
522 tt_str_op(uri
, OP_EQ
, "socks4a://[2001:db8::1]:1080");
524 tor_free(options
->Socks4Proxy
);
531 #define PT_LEGACY(name) \
532 { #name, test_pt_ ## name , 0, NULL, NULL }
534 struct testcase_t pt_tests
[] = {
537 { "get_transport_options", test_pt_get_transport_options
, TT_FORK
,
539 { "get_extrainfo_string", test_pt_get_extrainfo_string
, TT_FORK
,
541 { "configure_proxy",test_pt_configure_proxy
, TT_FORK
,
543 { "get_pt_proxy_uri", test_get_pt_proxy_uri
, TT_FORK
,