Back to index

tor  0.2.3.19-rc
transports.c
Go to the documentation of this file.
00001 /* Copyright (c) 2011-2012, The Tor Project, Inc. */
00002 /* See LICENSE for licensing information */
00003 
00086 #define PT_PRIVATE
00087 #include "or.h"
00088 #include "config.h"
00089 #include "circuitbuild.h"
00090 #include "transports.h"
00091 #include "util.h"
00092 #include "router.h"
00093 
00094 static process_environment_t *
00095 create_managed_proxy_environment(const managed_proxy_t *mp);
00096 
00097 static INLINE int proxy_configuration_finished(const managed_proxy_t *mp);
00098 
00099 static void managed_proxy_destroy(managed_proxy_t *mp,
00100                                   int also_terminate_process);
00101 
00102 static void handle_finished_proxy(managed_proxy_t *mp);
00103 static void configure_proxy(managed_proxy_t *mp);
00104 
00105 static void parse_method_error(const char *line, int is_server_method);
00106 #define parse_server_method_error(l) parse_method_error(l, 1)
00107 #define parse_client_method_error(l) parse_method_error(l, 0)
00108 
00109 static INLINE void free_execve_args(char **arg);
00110 
00112 #define PROTO_ENV_ERROR "ENV-ERROR"
00113 #define PROTO_NEG_SUCCESS "VERSION"
00114 #define PROTO_NEG_FAIL "VERSION-ERROR no-version"
00115 #define PROTO_CMETHOD "CMETHOD"
00116 #define PROTO_SMETHOD "SMETHOD"
00117 #define PROTO_CMETHOD_ERROR "CMETHOD-ERROR"
00118 #define PROTO_SMETHOD_ERROR "SMETHOD-ERROR"
00119 #define PROTO_CMETHODS_DONE "CMETHODS DONE"
00120 #define PROTO_SMETHODS_DONE "SMETHODS DONE"
00121 
00123 #define ENVIRON_SIZE_CLIENT 3
00124 #define ENVIRON_SIZE_SERVER 7 /* XXX known to be too high, but that's ok */
00125 
00128 #define PROTO_VERSION_ONE 1
00129 
00131 static smartlist_t *managed_proxy_list = NULL;
00133 static int unconfigured_proxies_n = 0;
00135 static int check_if_restarts_needed = 0;
00136 
00139 int
00140 pt_proxies_configuration_pending(void)
00141 {
00142   return unconfigured_proxies_n || check_if_restarts_needed;
00143 }
00144 
00147 static void
00148 assert_unconfigured_count_ok(void)
00149 {
00150   int n_completed = 0;
00151   if (!managed_proxy_list) {
00152     tor_assert(unconfigured_proxies_n == 0);
00153     return;
00154   }
00155 
00156   SMARTLIST_FOREACH(managed_proxy_list, managed_proxy_t *, mp, {
00157       if (mp->conf_state == PT_PROTO_COMPLETED)
00158         ++n_completed;
00159   });
00160 
00161   tor_assert(n_completed + unconfigured_proxies_n ==
00162              smartlist_len(managed_proxy_list));
00163 }
00164 
00166 static int
00167 managed_proxy_has_argv(const managed_proxy_t *mp, char **proxy_argv)
00168 {
00169   char **tmp1=proxy_argv;
00170   char **tmp2=mp->argv;
00171 
00172   tor_assert(tmp1);
00173   tor_assert(tmp2);
00174 
00175   while (*tmp1 && *tmp2) {
00176     if (strcmp(*tmp1++, *tmp2++))
00177       return 0;
00178   }
00179 
00180   if (!*tmp1 && !*tmp2)
00181     return 1;
00182 
00183   return 0;
00184 }
00185 
00188 static managed_proxy_t *
00189 get_managed_proxy_by_argv_and_type(char **proxy_argv, int is_server)
00190 {
00191   if (!managed_proxy_list)
00192     return NULL;
00193 
00194   SMARTLIST_FOREACH_BEGIN(managed_proxy_list,  managed_proxy_t *, mp) {
00195     if (managed_proxy_has_argv(mp, proxy_argv) &&
00196         mp->is_server == is_server)
00197       return mp;
00198   } SMARTLIST_FOREACH_END(mp);
00199 
00200   return NULL;
00201 }
00202 
00204 static void
00205 add_transport_to_proxy(const char *transport, managed_proxy_t *mp)
00206 {
00207   tor_assert(mp->transports_to_launch);
00208   if (!smartlist_string_isin(mp->transports_to_launch, transport))
00209     smartlist_add(mp->transports_to_launch, tor_strdup(transport));
00210 }
00211 
00215 static int
00216 proxy_needs_restart(const managed_proxy_t *mp)
00217 {
00218   /* mp->transport_to_launch is populated with the names of the
00219      transports that must be launched *after* the SIGHUP.
00220      mp->transports is populated with the names of the transports that
00221      were launched *before* the SIGHUP.
00222 
00223      If the two lists contain the same strings, we don't need to
00224      restart the proxy, since it already does what we want. */
00225 
00226   tor_assert(smartlist_len(mp->transports_to_launch) > 0);
00227   tor_assert(mp->conf_state == PT_PROTO_COMPLETED);
00228 
00229   if (smartlist_len(mp->transports_to_launch) != smartlist_len(mp->transports))
00230     goto needs_restart;
00231 
00232   SMARTLIST_FOREACH_BEGIN(mp->transports_to_launch, char *, t_t_l) {
00233     if (!smartlist_string_isin(mp->transports, t_t_l))
00234       goto needs_restart;
00235 
00236   } SMARTLIST_FOREACH_END(t_t_l);
00237 
00238   return 0;
00239 
00240  needs_restart:
00241   return 1;
00242 }
00243 
00247 static void
00248 proxy_prepare_for_restart(managed_proxy_t *mp)
00249 {
00250   transport_t *t_tmp = NULL;
00251 
00252   tor_assert(mp->conf_state == PT_PROTO_COMPLETED);
00253 
00254   /* destroy the process handle and terminate the process. */
00255   tor_process_handle_destroy(mp->process_handle, 1);
00256   mp->process_handle = NULL;
00257 
00258   /* destroy all its old transports. we no longer use them. */
00259   SMARTLIST_FOREACH_BEGIN(mp->transports, const char *, t_name) {
00260     t_tmp = transport_get_by_name(t_name);
00261     if (t_tmp)
00262       t_tmp->marked_for_removal = 1;
00263   } SMARTLIST_FOREACH_END(t_name);
00264   sweep_transport_list();
00265 
00266   /* free the transport names in mp->transports */
00267   SMARTLIST_FOREACH(mp->transports, char *, t_name, tor_free(t_name));
00268   smartlist_clear(mp->transports);
00269 
00270   /* flag it as an infant proxy so that it gets launched on next tick */
00271   mp->conf_state = PT_PROTO_INFANT;
00272   unconfigured_proxies_n++;
00273 }
00274 
00276 static int
00277 launch_managed_proxy(managed_proxy_t *mp)
00278 {
00279   int retval;
00280 
00281   process_environment_t *env = create_managed_proxy_environment(mp);
00282 
00283 #ifdef _WIN32
00284   /* Passing NULL as lpApplicationName makes Windows search for the .exe */
00285   retval = tor_spawn_background(NULL,
00286                                 (const char **)mp->argv,
00287                                 env,
00288                                 &mp->process_handle);
00289 #else
00290   retval = tor_spawn_background(mp->argv[0],
00291                                 (const char **)mp->argv,
00292                                 env,
00293                                 &mp->process_handle);
00294 #endif
00295 
00296   process_environment_free(env);
00297 
00298   if (retval == PROCESS_STATUS_ERROR) {
00299     log_warn(LD_GENERAL, "Managed proxy at '%s' failed at launch.",
00300              mp->argv[0]);
00301     return -1;
00302   }
00303 
00304   log_info(LD_CONFIG, "Managed proxy at '%s' has spawned with PID '%d'.",
00305            mp->argv[0], tor_process_get_pid(mp->process_handle));
00306 
00307   mp->conf_state = PT_PROTO_LAUNCHED;
00308 
00309   return 0;
00310 }
00311 
00315 void
00316 pt_configure_remaining_proxies(void)
00317 {
00318   smartlist_t *tmp = smartlist_new();
00319 
00320   log_debug(LD_CONFIG, "Configuring remaining managed proxies (%d)!",
00321             unconfigured_proxies_n);
00322 
00323   /* Iterate over tmp, not managed_proxy_list, since configure_proxy can
00324    * remove elements from managed_proxy_list. */
00325   smartlist_add_all(tmp, managed_proxy_list);
00326 
00327   assert_unconfigured_count_ok();
00328 
00329   SMARTLIST_FOREACH_BEGIN(tmp,  managed_proxy_t *, mp) {
00330     tor_assert(mp->conf_state != PT_PROTO_BROKEN ||
00331                mp->conf_state != PT_PROTO_FAILED_LAUNCH);
00332 
00333     if (mp->got_hup) {
00334       mp->got_hup = 0;
00335 
00336       /* This proxy is marked by a SIGHUP. Check whether we need to
00337          restart it. */
00338       if (proxy_needs_restart(mp)) {
00339         log_info(LD_GENERAL, "Preparing managed proxy '%s' for restart.",
00340                  mp->argv[0]);
00341         proxy_prepare_for_restart(mp);
00342       } else { /* it doesn't need to be restarted. */
00343         log_info(LD_GENERAL, "Nothing changed for managed proxy '%s' after "
00344                  "HUP: not restarting.", mp->argv[0]);
00345       }
00346 
00347       continue;
00348     }
00349 
00350     /* If the proxy is not fully configured, try to configure it
00351        futher. */
00352     if (!proxy_configuration_finished(mp))
00353       configure_proxy(mp);
00354 
00355   } SMARTLIST_FOREACH_END(mp);
00356 
00357   smartlist_free(tmp);
00358   check_if_restarts_needed = 0;
00359   assert_unconfigured_count_ok();
00360 }
00361 
00362 #ifdef _WIN32
00363 
00365 static void
00366 configure_proxy(managed_proxy_t *mp)
00367 {
00368   int pos;
00369   char stdout_buf[200];
00370   smartlist_t *lines = NULL;
00371 
00372   /* if we haven't launched the proxy yet, do it now */
00373   if (mp->conf_state == PT_PROTO_INFANT) {
00374     if (launch_managed_proxy(mp) < 0) { /* launch fail */
00375       mp->conf_state = PT_PROTO_FAILED_LAUNCH;
00376       handle_finished_proxy(mp);
00377     }
00378     return;
00379   }
00380 
00381   tor_assert(mp->conf_state != PT_PROTO_INFANT);
00382   tor_assert(mp->process_handle);
00383 
00384   pos = tor_read_all_handle(tor_process_get_stdout_pipe(mp->process_handle),
00385                             stdout_buf, sizeof(stdout_buf) - 1, NULL);
00386   if (pos < 0) {
00387     log_notice(LD_GENERAL, "Failed to read data from managed proxy '%s'.",
00388                mp->argv[0]);
00389     mp->conf_state = PT_PROTO_BROKEN;
00390     goto done;
00391   }
00392 
00393   if (pos == 0) /* proxy has nothing interesting to say. */
00394     return;
00395 
00396   /* End with a null even if there isn't a \r\n at the end */
00397   /* TODO: What if this is a partial line? */
00398   stdout_buf[pos] = '\0';
00399 
00400   /* Split up the buffer */
00401   lines = smartlist_new();
00402   tor_split_lines(lines, stdout_buf, pos);
00403 
00404   /* Handle lines. */
00405   SMARTLIST_FOREACH_BEGIN(lines, const char *, line) {
00406     handle_proxy_line(line, mp);
00407     if (proxy_configuration_finished(mp))
00408       goto done;
00409   } SMARTLIST_FOREACH_END(line);
00410 
00411  done:
00412   /* if the proxy finished configuring, exit the loop. */
00413   if (proxy_configuration_finished(mp))
00414     handle_finished_proxy(mp);
00415 
00416   if (lines)
00417     smartlist_free(lines);
00418 }
00419 
00420 #else /* _WIN32 */
00421 
00423 static void
00424 configure_proxy(managed_proxy_t *mp)
00425 {
00426   enum stream_status r;
00427   char stdout_buf[200];
00428 
00429   /* if we haven't launched the proxy yet, do it now */
00430   if (mp->conf_state == PT_PROTO_INFANT) {
00431     if (launch_managed_proxy(mp) < 0) { /* launch fail */
00432       mp->conf_state = PT_PROTO_FAILED_LAUNCH;
00433       handle_finished_proxy(mp);
00434     }
00435     return;
00436   }
00437 
00438   tor_assert(mp->conf_state != PT_PROTO_INFANT);
00439   tor_assert(mp->process_handle);
00440 
00441   while (1) {
00442     r = get_string_from_pipe(tor_process_get_stdout_pipe(mp->process_handle),
00443                              stdout_buf, sizeof(stdout_buf) - 1);
00444 
00445     if (r  == IO_STREAM_OKAY) { /* got a line; handle it! */
00446       handle_proxy_line((const char *)stdout_buf, mp);
00447     } else if (r == IO_STREAM_EAGAIN) { /* check back later */
00448       return;
00449     } else if (r == IO_STREAM_CLOSED || r == IO_STREAM_TERM) { /* snap! */
00450       log_warn(LD_GENERAL, "Our communication channel with the managed proxy "
00451                "'%s' closed. Most probably application stopped running.",
00452                mp->argv[0]);
00453       mp->conf_state = PT_PROTO_BROKEN;
00454     } else { /* unknown stream status */
00455       log_warn(LD_BUG, "Unknown stream status '%d' while configuring managed "
00456                "proxy '%s'.", (int)r, mp->argv[0]);
00457     }
00458 
00459     /* if the proxy finished configuring, exit the loop. */
00460     if (proxy_configuration_finished(mp)) {
00461       handle_finished_proxy(mp);
00462       return;
00463     }
00464   }
00465 }
00466 
00467 #endif /* _WIN32 */
00468 
00470 static void
00471 register_server_proxy(managed_proxy_t *mp)
00472 {
00473   /* After we register this proxy's transports, we switch its
00474      mp->transports to a list containing strings of its transport
00475      names. (See transports.h) */
00476   smartlist_t *sm_tmp = smartlist_new();
00477 
00478   tor_assert(mp->conf_state != PT_PROTO_COMPLETED);
00479   SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) {
00480     save_transport_to_state(t->name, &t->addr, t->port);
00481     log_notice(LD_GENERAL, "Registered server transport '%s' at '%s:%d'",
00482                t->name, fmt_addr(&t->addr), (int)t->port);
00483     smartlist_add(sm_tmp, tor_strdup(t->name));
00484   } SMARTLIST_FOREACH_END(t);
00485 
00486   /* Since server proxies don't register their transports in the
00487      circuitbuild.c subsystem, it's our duty to free them when we
00488      switch mp->transports to strings. */
00489   SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
00490   smartlist_free(mp->transports);
00491 
00492   mp->transports = sm_tmp;
00493 }
00494 
00497 static void
00498 register_client_proxy(managed_proxy_t *mp)
00499 {
00500   int r;
00501   /* After we register this proxy's transports, we switch its
00502      mp->transports to a list containing strings of its transport
00503      names. (See transports.h) */
00504   smartlist_t *sm_tmp = smartlist_new();
00505 
00506   tor_assert(mp->conf_state != PT_PROTO_COMPLETED);
00507   SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) {
00508     r = transport_add(t);
00509     switch (r) {
00510     case -1:
00511       log_notice(LD_GENERAL, "Could not add transport %s. Skipping.", t->name);
00512       transport_free(t);
00513       break;
00514     case 0:
00515       log_info(LD_GENERAL, "Succesfully registered transport %s", t->name);
00516       smartlist_add(sm_tmp, tor_strdup(t->name));
00517       break;
00518     case 1:
00519       log_info(LD_GENERAL, "Succesfully registered transport %s", t->name);
00520       smartlist_add(sm_tmp, tor_strdup(t->name));
00521       transport_free(t);
00522       break;
00523     }
00524   } SMARTLIST_FOREACH_END(t);
00525 
00526   smartlist_free(mp->transports);
00527   mp->transports = sm_tmp;
00528 }
00529 
00531 static INLINE void
00532 register_proxy(managed_proxy_t *mp)
00533 {
00534   if (mp->is_server)
00535     register_server_proxy(mp);
00536   else
00537     register_client_proxy(mp);
00538 }
00539 
00541 static void
00542 managed_proxy_destroy(managed_proxy_t *mp,
00543                       int also_terminate_process)
00544 {
00545   if (mp->conf_state != PT_PROTO_COMPLETED)
00546     SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
00547   else
00548     SMARTLIST_FOREACH(mp->transports, char *, t_name, tor_free(t_name));
00549 
00550   /* free the transports smartlist */
00551   smartlist_free(mp->transports);
00552 
00553   /* free the transports_to_launch smartlist */
00554   SMARTLIST_FOREACH(mp->transports_to_launch, char *, t, tor_free(t));
00555   smartlist_free(mp->transports_to_launch);
00556 
00557   /* remove it from the list of managed proxies */
00558   smartlist_remove(managed_proxy_list, mp);
00559 
00560   /* free the argv */
00561   free_execve_args(mp->argv);
00562 
00563   tor_process_handle_destroy(mp->process_handle, also_terminate_process);
00564   mp->process_handle = NULL;
00565 
00566   tor_free(mp);
00567 }
00568 
00570 static void
00571 handle_finished_proxy(managed_proxy_t *mp)
00572 {
00573   switch (mp->conf_state) {
00574   case PT_PROTO_BROKEN: /* if broken: */
00575     managed_proxy_destroy(mp, 1); /* annihilate it. */
00576     break;
00577   case PT_PROTO_FAILED_LAUNCH: /* if it failed before launching: */
00578     managed_proxy_destroy(mp, 0); /* destroy it but don't terminate */
00579     break;
00580   case PT_PROTO_CONFIGURED: /* if configured correctly: */
00581     register_proxy(mp); /* register its transports */
00582     mp->conf_state = PT_PROTO_COMPLETED; /* and mark it as completed. */
00583     break;
00584   case PT_PROTO_INFANT:
00585   case PT_PROTO_LAUNCHED:
00586   case PT_PROTO_ACCEPTING_METHODS:
00587   case PT_PROTO_COMPLETED:
00588   default:
00589     log_warn(LD_CONFIG, "Unexpected state '%d' of managed proxy '%s'.",
00590              (int)mp->conf_state, mp->argv[0]);
00591     tor_assert(0);
00592   }
00593 
00594   unconfigured_proxies_n--;
00595   tor_assert(unconfigured_proxies_n >= 0);
00596 }
00597 
00600 static INLINE int
00601 proxy_configuration_finished(const managed_proxy_t *mp)
00602 {
00603   return (mp->conf_state == PT_PROTO_CONFIGURED ||
00604           mp->conf_state == PT_PROTO_BROKEN ||
00605           mp->conf_state == PT_PROTO_FAILED_LAUNCH);
00606 }
00607 
00609 static void
00610 handle_methods_done(const managed_proxy_t *mp)
00611 {
00612   tor_assert(mp->transports);
00613 
00614   if (smartlist_len(mp->transports) == 0)
00615     log_notice(LD_GENERAL, "Managed proxy '%s' was spawned successfully, "
00616                "but it didn't launch any pluggable transport listeners!",
00617                mp->argv[0]);
00618 
00619   log_info(LD_CONFIG, "%s managed proxy '%s' configuration completed!",
00620            mp->is_server ? "Server" : "Client",
00621            mp->argv[0]);
00622 }
00623 
00626 void
00627 handle_proxy_line(const char *line, managed_proxy_t *mp)
00628 {
00629   log_info(LD_GENERAL, "Got a line from managed proxy '%s': (%s)",
00630            mp->argv[0], line);
00631 
00632   if (!strcmpstart(line, PROTO_ENV_ERROR)) {
00633     if (mp->conf_state != PT_PROTO_LAUNCHED)
00634       goto err;
00635 
00636     parse_env_error(line);
00637     goto err;
00638   } else if (!strcmpstart(line, PROTO_NEG_FAIL)) {
00639     if (mp->conf_state != PT_PROTO_LAUNCHED)
00640       goto err;
00641 
00642     log_warn(LD_CONFIG, "Managed proxy could not pick a "
00643              "configuration protocol version.");
00644     goto err;
00645   } else if (!strcmpstart(line, PROTO_NEG_SUCCESS)) {
00646     if (mp->conf_state != PT_PROTO_LAUNCHED)
00647       goto err;
00648 
00649     if (parse_version(line,mp) < 0)
00650       goto err;
00651 
00652     tor_assert(mp->conf_protocol != 0);
00653     mp->conf_state = PT_PROTO_ACCEPTING_METHODS;
00654     return;
00655   } else if (!strcmpstart(line, PROTO_CMETHODS_DONE)) {
00656     if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS)
00657       goto err;
00658 
00659     handle_methods_done(mp);
00660 
00661     mp->conf_state = PT_PROTO_CONFIGURED;
00662     return;
00663   } else if (!strcmpstart(line, PROTO_SMETHODS_DONE)) {
00664     if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS)
00665       goto err;
00666 
00667     handle_methods_done(mp);
00668 
00669     mp->conf_state = PT_PROTO_CONFIGURED;
00670     return;
00671   } else if (!strcmpstart(line, PROTO_CMETHOD_ERROR)) {
00672     if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS)
00673       goto err;
00674 
00675     parse_client_method_error(line);
00676     goto err;
00677   } else if (!strcmpstart(line, PROTO_SMETHOD_ERROR)) {
00678     if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS)
00679       goto err;
00680 
00681     parse_server_method_error(line);
00682     goto err;
00683   } else if (!strcmpstart(line, PROTO_CMETHOD)) {
00684     if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS)
00685       goto err;
00686 
00687     if (parse_cmethod_line(line, mp) < 0)
00688       goto err;
00689 
00690     return;
00691   } else if (!strcmpstart(line, PROTO_SMETHOD)) {
00692     if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS)
00693       goto err;
00694 
00695     if (parse_smethod_line(line, mp) < 0)
00696       goto err;
00697 
00698     return;
00699   } else if (!strcmpstart(line, SPAWN_ERROR_MESSAGE)) {
00700     /* managed proxy launch failed: parse error message to learn why. */
00701     int retval, child_state, saved_errno;
00702     retval = tor_sscanf(line, SPAWN_ERROR_MESSAGE "%x/%x",
00703                         &child_state, &saved_errno);
00704     if (retval == 2) {
00705       log_warn(LD_GENERAL,
00706                "Could not launch managed proxy executable at '%s' ('%s').",
00707                mp->argv[0], strerror(saved_errno));
00708     } else { /* failed to parse error message */
00709       log_warn(LD_GENERAL,"Could not launch managed proxy executable at '%s'.",
00710                mp->argv[0]);
00711     }
00712 
00713     mp->conf_state = PT_PROTO_FAILED_LAUNCH;
00714     return;
00715   }
00716 
00717   log_notice(LD_GENERAL, "Unknown line received by managed proxy (%s).", line);
00718   return;
00719 
00720  err:
00721   mp->conf_state = PT_PROTO_BROKEN;
00722   log_warn(LD_CONFIG, "Managed proxy at '%s' failed the configuration protocol"
00723            " and will be destroyed.", mp->argv[0]);
00724 }
00725 
00727 void
00728 parse_env_error(const char *line)
00729 {
00730   /* (Length of the protocol string) plus (a space) and (the first char of
00731      the error message) */
00732   if (strlen(line) < (strlen(PROTO_ENV_ERROR) + 2))
00733     log_notice(LD_CONFIG, "Managed proxy sent us an %s without an error "
00734                "message.", PROTO_ENV_ERROR);
00735 
00736   log_warn(LD_CONFIG, "Managed proxy couldn't understand the "
00737            "pluggable transport environment variables. (%s)",
00738            line+strlen(PROTO_ENV_ERROR)+1);
00739 }
00740 
00743 int
00744 parse_version(const char *line, managed_proxy_t *mp)
00745 {
00746   if (strlen(line) < (strlen(PROTO_NEG_SUCCESS) + 2)) {
00747     log_warn(LD_CONFIG, "Managed proxy sent us malformed %s line.",
00748              PROTO_NEG_SUCCESS);
00749     return -1;
00750   }
00751 
00752   if (strcmp("1", line+strlen(PROTO_NEG_SUCCESS)+1)) { /* hardcoded temp */
00753     log_warn(LD_CONFIG, "Managed proxy tried to negotiate on version '%s'. "
00754              "We only support version '1'", line+strlen(PROTO_NEG_SUCCESS)+1);
00755     return -1;
00756   }
00757 
00758   mp->conf_protocol = PROTO_VERSION_ONE; /* temp. till more versions appear */
00759   return 0;
00760 }
00761 
00765 static void
00766 parse_method_error(const char *line, int is_server)
00767 {
00768   const char* error = is_server ?
00769     PROTO_SMETHOD_ERROR : PROTO_CMETHOD_ERROR;
00770 
00771   /* (Length of the protocol string) plus (a space) and (the first char of
00772      the error message) */
00773   if (strlen(line) < (strlen(error) + 2))
00774     log_warn(LD_CONFIG, "Managed proxy sent us an %s without an error "
00775              "message.", error);
00776 
00777   log_warn(LD_CONFIG, "%s managed proxy encountered a method error. (%s)",
00778            is_server ? "Server" : "Client",
00779            line+strlen(error)+1);
00780 }
00781 
00784 int
00785 parse_smethod_line(const char *line, managed_proxy_t *mp)
00786 {
00787   int r;
00788   smartlist_t *items = NULL;
00789 
00790   char *method_name=NULL;
00791 
00792   char *addrport=NULL;
00793   tor_addr_t tor_addr;
00794   char *address=NULL;
00795   uint16_t port = 0;
00796 
00797   transport_t *transport=NULL;
00798 
00799   items = smartlist_new();
00800   smartlist_split_string(items, line, NULL,
00801                          SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
00802   if (smartlist_len(items) < 3) {
00803     log_warn(LD_CONFIG, "Server managed proxy sent us a SMETHOD line "
00804              "with too few arguments.");
00805     goto err;
00806   }
00807 
00808   tor_assert(!strcmp(smartlist_get(items,0),PROTO_SMETHOD));
00809 
00810   method_name = smartlist_get(items,1);
00811   if (!string_is_C_identifier(method_name)) {
00812     log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).",
00813              method_name);
00814     goto err;
00815   }
00816 
00817   addrport = smartlist_get(items, 2);
00818   if (tor_addr_port_split(LOG_PROTOCOL_WARN, addrport, &address, &port)<0) {
00819     log_warn(LD_CONFIG, "Error parsing transport "
00820              "address '%s'", addrport);
00821     goto err;
00822   }
00823 
00824   if (!port) {
00825     log_warn(LD_CONFIG,
00826              "Transport address '%s' has no port.", addrport);
00827     goto err;
00828   }
00829 
00830   if (tor_addr_parse(&tor_addr, address) < 0) {
00831     log_warn(LD_CONFIG, "Error parsing transport address '%s'", address);
00832     goto err;
00833   }
00834 
00835   transport = transport_new(&tor_addr, port, method_name, PROXY_NONE);
00836   if (!transport)
00837     goto err;
00838 
00839   smartlist_add(mp->transports, transport);
00840 
00841   /* For now, notify the user so that he knows where the server
00842      transport is listening. */
00843   log_info(LD_CONFIG, "Server transport %s at %s:%d.",
00844            method_name, address, (int)port);
00845 
00846   r=0;
00847   goto done;
00848 
00849  err:
00850   r = -1;
00851 
00852  done:
00853   SMARTLIST_FOREACH(items, char*, s, tor_free(s));
00854   smartlist_free(items);
00855   tor_free(address);
00856   return r;
00857 }
00858 
00861 int
00862 parse_cmethod_line(const char *line, managed_proxy_t *mp)
00863 {
00864   int r;
00865   smartlist_t *items = NULL;
00866 
00867   char *method_name=NULL;
00868 
00869   char *socks_ver_str=NULL;
00870   int socks_ver=PROXY_NONE;
00871 
00872   char *addrport=NULL;
00873   tor_addr_t tor_addr;
00874   char *address=NULL;
00875   uint16_t port = 0;
00876 
00877   transport_t *transport=NULL;
00878 
00879   items = smartlist_new();
00880   smartlist_split_string(items, line, NULL,
00881                          SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
00882   if (smartlist_len(items) < 4) {
00883     log_warn(LD_CONFIG, "Client managed proxy sent us a CMETHOD line "
00884              "with too few arguments.");
00885     goto err;
00886   }
00887 
00888   tor_assert(!strcmp(smartlist_get(items,0),PROTO_CMETHOD));
00889 
00890   method_name = smartlist_get(items,1);
00891   if (!string_is_C_identifier(method_name)) {
00892     log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).",
00893              method_name);
00894     goto err;
00895   }
00896 
00897   socks_ver_str = smartlist_get(items,2);
00898 
00899   if (!strcmp(socks_ver_str,"socks4")) {
00900     socks_ver = PROXY_SOCKS4;
00901   } else if (!strcmp(socks_ver_str,"socks5")) {
00902     socks_ver = PROXY_SOCKS5;
00903   } else {
00904     log_warn(LD_CONFIG, "Client managed proxy sent us a proxy protocol "
00905              "we don't recognize. (%s)", socks_ver_str);
00906     goto err;
00907   }
00908 
00909   addrport = smartlist_get(items, 3);
00910   if (tor_addr_port_split(LOG_PROTOCOL_WARN, addrport, &address, &port)<0) {
00911     log_warn(LD_CONFIG, "Error parsing transport "
00912              "address '%s'", addrport);
00913     goto err;
00914   }
00915 
00916   if (!port) {
00917     log_warn(LD_CONFIG,
00918              "Transport address '%s' has no port.", addrport);
00919     goto err;
00920   }
00921 
00922   if (tor_addr_parse(&tor_addr, address) < 0) {
00923     log_warn(LD_CONFIG, "Error parsing transport address '%s'", address);
00924     goto err;
00925   }
00926 
00927   transport = transport_new(&tor_addr, port, method_name, socks_ver);
00928   if (!transport)
00929     goto err;
00930 
00931   smartlist_add(mp->transports, transport);
00932 
00933   log_info(LD_CONFIG, "Transport %s at %s:%d with SOCKS %d. "
00934            "Attached to managed proxy.",
00935            method_name, address, (int)port, socks_ver);
00936 
00937   r=0;
00938   goto done;
00939 
00940  err:
00941   r = -1;
00942 
00943  done:
00944   SMARTLIST_FOREACH(items, char*, s, tor_free(s));
00945   smartlist_free(items);
00946   tor_free(address);
00947   return r;
00948 }
00949 
00954 static char *
00955 get_bindaddr_for_server_proxy(const managed_proxy_t *mp)
00956 {
00957   char *bindaddr_result = NULL;
00958   char *bindaddr_tmp = NULL;
00959   smartlist_t *string_tmp = smartlist_new();
00960 
00961   tor_assert(mp->is_server);
00962 
00963   SMARTLIST_FOREACH_BEGIN(mp->transports_to_launch, char *, t) {
00964     bindaddr_tmp = get_stored_bindaddr_for_server_transport(t);
00965 
00966     smartlist_add_asprintf(string_tmp, "%s-%s", t, bindaddr_tmp);
00967 
00968     tor_free(bindaddr_tmp);
00969   } SMARTLIST_FOREACH_END(t);
00970 
00971   bindaddr_result = smartlist_join_strings(string_tmp, ",", 0, NULL);
00972 
00973   SMARTLIST_FOREACH(string_tmp, char *, t, tor_free(t));
00974   smartlist_free(string_tmp);
00975 
00976   return bindaddr_result;
00977 }
00978 
00981 static process_environment_t *
00982 create_managed_proxy_environment(const managed_proxy_t *mp)
00983 {
00984   /* Environment variables to be added to or set in mp's environment. */
00985   smartlist_t *envs = smartlist_new();
00986   /* XXXX The next time someone touches this code, shorten the name of
00987    * set_environment_variable_in_smartlist, add a
00988    * set_env_var_in_smartlist_asprintf function, and get rid of the
00989    * silly extra envs smartlist. */
00990 
00991   /* The final environment to be passed to mp. */
00992   smartlist_t *merged_env_vars = get_current_process_environment_variables();
00993 
00994   process_environment_t *env;
00995 
00996   {
00997     char *state_tmp = get_datadir_fname("pt_state/"); /* XXX temp */
00998     smartlist_add_asprintf(envs, "TOR_PT_STATE_LOCATION=%s", state_tmp);
00999     tor_free(state_tmp);
01000   }
01001 
01002   smartlist_add(envs, tor_strdup("TOR_PT_MANAGED_TRANSPORT_VER=1"));
01003 
01004   {
01005     char *transports_to_launch =
01006       smartlist_join_strings(mp->transports_to_launch, ",", 0, NULL);
01007 
01008     smartlist_add_asprintf(envs,
01009                            mp->is_server ?
01010                            "TOR_PT_SERVER_TRANSPORTS=%s" :
01011                            "TOR_PT_CLIENT_TRANSPORTS=%s",
01012                            transports_to_launch);
01013 
01014     tor_free(transports_to_launch);
01015   }
01016 
01017   if (mp->is_server) {
01018     {
01019       char *orport_tmp =
01020         get_first_listener_addrport_string(CONN_TYPE_OR_LISTENER);
01021       smartlist_add_asprintf(envs, "TOR_PT_ORPORT=%s", orport_tmp);
01022       tor_free(orport_tmp);
01023     }
01024 
01025     {
01026       char *bindaddr_tmp = get_bindaddr_for_server_proxy(mp);
01027       smartlist_add_asprintf(envs, "TOR_PT_SERVER_BINDADDR=%s", bindaddr_tmp);
01028       tor_free(bindaddr_tmp);
01029     }
01030 
01031     /* XXX024 Remove the '=' here once versions of obfsproxy which
01032      * assert that this env var exists are sufficiently dead.
01033      *
01034      * (If we remove this line entirely, some joker will stick this
01035      * variable in Tor's environment and crash PTs that try to parse
01036      * it even when not run in server mode.) */
01037     smartlist_add(envs, tor_strdup("TOR_PT_EXTENDED_SERVER_PORT="));
01038   }
01039 
01040   SMARTLIST_FOREACH_BEGIN(envs, const char *, env_var) {
01041     set_environment_variable_in_smartlist(merged_env_vars, env_var,
01042                                           _tor_free, 1);
01043   } SMARTLIST_FOREACH_END(env_var);
01044 
01045   env = process_environment_make(merged_env_vars);
01046 
01047   smartlist_free(envs);
01048 
01049   SMARTLIST_FOREACH(merged_env_vars, void *, x, tor_free(x));
01050   smartlist_free(merged_env_vars);
01051 
01052   return env;
01053 }
01054 
01061 static managed_proxy_t *
01062 managed_proxy_create(const smartlist_t *transport_list,
01063                      char **proxy_argv, int is_server)
01064 {
01065   managed_proxy_t *mp = tor_malloc_zero(sizeof(managed_proxy_t));
01066   mp->conf_state = PT_PROTO_INFANT;
01067   mp->is_server = is_server;
01068   mp->argv = proxy_argv;
01069   mp->transports = smartlist_new();
01070 
01071   mp->transports_to_launch = smartlist_new();
01072   SMARTLIST_FOREACH(transport_list, const char *, transport,
01073                     add_transport_to_proxy(transport, mp));
01074 
01075   /* register the managed proxy */
01076   if (!managed_proxy_list)
01077     managed_proxy_list = smartlist_new();
01078   smartlist_add(managed_proxy_list, mp);
01079   unconfigured_proxies_n++;
01080 
01081   assert_unconfigured_count_ok();
01082 
01083   return mp;
01084 }
01085 
01095 void
01096 pt_kickstart_proxy(const smartlist_t *transport_list,
01097                    char **proxy_argv, int is_server)
01098 {
01099   managed_proxy_t *mp=NULL;
01100   transport_t *old_transport = NULL;
01101 
01102   if (!proxy_argv || !proxy_argv[0]) {
01103     return;
01104   }
01105 
01106   mp = get_managed_proxy_by_argv_and_type(proxy_argv, is_server);
01107 
01108   if (!mp) { /* we haven't seen this proxy before */
01109     managed_proxy_create(transport_list, proxy_argv, is_server);
01110 
01111   } else { /* known proxy. add its transport to its transport list */
01112     if (mp->got_hup) {
01113       /* If the managed proxy we found is marked by a SIGHUP, it means
01114          that it's not useless and should be kept. If it's marked for
01115          removal, unmark it and increase the unconfigured proxies so
01116          that we try to restart it if we need to. Afterwards, check if
01117          a transport_t for 'transport' used to exist before the SIGHUP
01118          and make sure it doesn't get deleted because we might reuse
01119          it. */
01120       if (mp->marked_for_removal) {
01121         mp->marked_for_removal = 0;
01122         check_if_restarts_needed = 1;
01123       }
01124 
01125       SMARTLIST_FOREACH_BEGIN(transport_list, const char *, transport) {
01126         old_transport = transport_get_by_name(transport);
01127         if (old_transport)
01128           old_transport->marked_for_removal = 0;
01129       } SMARTLIST_FOREACH_END(transport);
01130     }
01131 
01132     SMARTLIST_FOREACH(transport_list, const char *, transport,
01133                       add_transport_to_proxy(transport, mp));
01134     free_execve_args(proxy_argv);
01135   }
01136 }
01137 
01140 static INLINE void
01141 free_execve_args(char **arg)
01142 {
01143   char **tmp = arg;
01144   while (*tmp) /* use the fact that the last element of the array is a
01145                   NULL pointer to know when to stop freeing */
01146     _tor_free(*tmp++);
01147 
01148   tor_free(arg);
01149 }
01150 
01155 void
01156 pt_prepare_proxy_list_for_config_read(void)
01157 {
01158   if (!managed_proxy_list)
01159     return;
01160 
01161   assert_unconfigured_count_ok();
01162   SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) {
01163     /* Destroy unconfigured proxies. */
01164     if (mp->conf_state != PT_PROTO_COMPLETED) {
01165       SMARTLIST_DEL_CURRENT(managed_proxy_list, mp);
01166       managed_proxy_destroy(mp, 1);
01167       unconfigured_proxies_n--;
01168       continue;
01169     }
01170 
01171     tor_assert(mp->conf_state == PT_PROTO_COMPLETED);
01172 
01173     mp->marked_for_removal = 1;
01174     mp->got_hup = 1;
01175     SMARTLIST_FOREACH(mp->transports_to_launch, char *, t, tor_free(t));
01176     smartlist_clear(mp->transports_to_launch);
01177   } SMARTLIST_FOREACH_END(mp);
01178 
01179   assert_unconfigured_count_ok();
01180 
01181   tor_assert(unconfigured_proxies_n == 0);
01182 }
01183 
01188 void
01189 sweep_proxy_list(void)
01190 {
01191   if (!managed_proxy_list)
01192     return;
01193   assert_unconfigured_count_ok();
01194   SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) {
01195     if (mp->marked_for_removal) {
01196       SMARTLIST_DEL_CURRENT(managed_proxy_list, mp);
01197       managed_proxy_destroy(mp, 1);
01198     }
01199   } SMARTLIST_FOREACH_END(mp);
01200   assert_unconfigured_count_ok();
01201 }
01202 
01204 void
01205 pt_free_all(void)
01206 {
01207   if (managed_proxy_list) {
01208     /* If the proxy is in PT_PROTO_COMPLETED, it has registered its
01209        transports and it's the duty of the circuitbuild.c subsystem to
01210        free them. Otherwise, it hasn't registered its transports yet
01211        and we should free them here. */
01212     SMARTLIST_FOREACH(managed_proxy_list, managed_proxy_t *, mp, {
01213         SMARTLIST_DEL_CURRENT(managed_proxy_list, mp);
01214         managed_proxy_destroy(mp, 1);
01215     });
01216 
01217     smartlist_free(managed_proxy_list);
01218     managed_proxy_list=NULL;
01219   }
01220 }
01221