Back to index

tor  0.2.3.19-rc
tor-fw-helper.c
Go to the documentation of this file.
00001 /* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
00002  * Copyright (c) 2010-2012, The Tor Project, Inc. */
00003 /* See LICENSE for licensing information */
00004 
00010 /*
00011  * tor-fw-helper is a tool for opening firewalls with NAT-PMP and UPnP; this
00012  * tool is designed to be called by hand or by Tor by way of a exec() at a
00013  * later date.
00014  */
00015 
00016 #include "orconfig.h"
00017 #include <stdio.h>
00018 #include <stdint.h>
00019 #include <stdlib.h>
00020 #include <getopt.h>
00021 #include <time.h>
00022 #include <string.h>
00023 
00024 #ifdef _WIN32
00025 #include <winsock2.h>
00026 #endif
00027 
00028 #include "tor-fw-helper.h"
00029 #ifdef NAT_PMP
00030 #include "tor-fw-helper-natpmp.h"
00031 #endif
00032 #ifdef MINIUPNPC
00033 #include "tor-fw-helper-upnp.h"
00034 #endif
00035 
00039 typedef struct backends_t {
00041   int n_backends;
00043   tor_fw_backend_t backend_ops[MAX_BACKENDS];
00045   void *backend_state[MAX_BACKENDS];
00046 } backends_t;
00047 
00050 static int
00051 init_backends(tor_fw_options_t *options, backends_t *backends)
00052 {
00053   int n_available = 0;
00054   int i, r, n;
00055   tor_fw_backend_t *backend_ops_list[MAX_BACKENDS];
00056   void *data = NULL;
00057   /* First, build a list of the working backends. */
00058   n = 0;
00059 #ifdef MINIUPNPC
00060   backend_ops_list[n++] = (tor_fw_backend_t *) tor_fw_get_miniupnp_backend();
00061 #endif
00062 #ifdef NAT_PMP
00063   backend_ops_list[n++] = (tor_fw_backend_t *) tor_fw_get_natpmp_backend();
00064 #endif
00065   n_available = n;
00066 
00067   /* Now, for each backend that might work, try to initialize it.
00068    * That's how we roll, initialized.
00069    */
00070   n = 0;
00071   for (i=0; i<n_available; ++i) {
00072     data = calloc(1, backend_ops_list[i]->state_len);
00073     if (!data) {
00074       perror("calloc");
00075       exit(1);
00076     }
00077     r = backend_ops_list[i]->init(options, data);
00078     if (r == 0) {
00079       backends->backend_ops[n] = *backend_ops_list[i];
00080       backends->backend_state[n] = data;
00081       n++;
00082     } else {
00083       free(data);
00084     }
00085   }
00086   backends->n_backends = n;
00087 
00088   return n;
00089 }
00090 
00092 static void
00093 usage(void)
00094 {
00095   fprintf(stderr, "tor-fw-helper usage:\n"
00096           " [-h|--help]\n"
00097           " [-T|--Test]\n"
00098           " [-v|--verbose]\n"
00099           " [-g|--fetch-public-ip]\n"
00100           " -i|--internal-or-port [TCP port]\n"
00101           " [-e|--external-or-port [TCP port]]\n"
00102           " [-d|--internal-dir-port [TCP port]\n"
00103           " [-p|--external-dir-port [TCP port]]]\n");
00104 }
00105 
00108 static int
00109 log_commandline_options(int argc, char **argv)
00110 {
00111   int i, retval;
00112   FILE *logfile;
00113   time_t now;
00114 
00115   /* Open the log file */
00116   logfile = fopen("tor-fw-helper.log", "a");
00117   if (NULL == logfile)
00118     return -1;
00119 
00120   /* Send all commandline arguments to the file */
00121   now = time(NULL);
00122   retval = fprintf(logfile, "START: %s\n", ctime(&now));
00123   for (i = 0; i < argc; i++) {
00124     retval = fprintf(logfile, "ARG: %d: %s\n", i, argv[i]);
00125     if (retval < 0)
00126       goto error;
00127 
00128     retval = fprintf(stdout, "ARG: %d: %s\n", i, argv[i]);
00129     if (retval < 0)
00130       goto error;
00131   }
00132   now = time(NULL);
00133   retval = fprintf(logfile, "END: %s\n", ctime(&now));
00134 
00135   /* Close and clean up */
00136   retval = fclose(logfile);
00137   return retval;
00138 
00139   /* If there was an error during writing */
00140  error:
00141   fclose(logfile);
00142   return -1;
00143 }
00144 
00147 static void
00148 tor_fw_fetch_public_ip(tor_fw_options_t *tor_fw_options,
00149                        backends_t *backends)
00150 {
00151   int i;
00152   int r = 0;
00153 
00154   if (tor_fw_options->verbose)
00155     fprintf(stdout, "V: tor_fw_fetch_public_ip\n");
00156 
00157   for (i=0; i<backends->n_backends; ++i) {
00158     if (tor_fw_options->verbose) {
00159         fprintf(stdout, "V: running backend_state now: %i\n", i);
00160         fprintf(stdout, "V: size of backend state: %u\n",
00161                 (int)(backends->backend_ops)[i].state_len);
00162         fprintf(stdout, "V: backend state name: %s\n",
00163                 (char *)(backends->backend_ops)[i].name);
00164       }
00165     r = backends->backend_ops[i].fetch_public_ip(tor_fw_options,
00166                                                  backends->backend_state[i]);
00167     fprintf(stdout, "tor-fw-helper: tor_fw_fetch_public_ip backend %s "
00168             " returned: %i\n", (char *)(backends->backend_ops)[i].name, r);
00169   }
00170 }
00171 
00174 static void
00175 tor_fw_add_or_port(tor_fw_options_t *tor_fw_options,
00176                        backends_t *backends)
00177 {
00178   int i;
00179   int r = 0;
00180 
00181   if (tor_fw_options->verbose)
00182     fprintf(stdout, "V: tor_fw_add_or_port\n");
00183 
00184   for (i=0; i<backends->n_backends; ++i) {
00185     if (tor_fw_options->verbose) {
00186       fprintf(stdout, "V: running backend_state now: %i\n", i);
00187       fprintf(stdout, "V: size of backend state: %u\n",
00188               (int)(backends->backend_ops)[i].state_len);
00189       fprintf(stdout, "V: backend state name: %s\n",
00190               (const char *) backends->backend_ops[i].name);
00191     }
00192     r = backends->backend_ops[i].add_tcp_mapping(tor_fw_options,
00193                                                  backends->backend_state[i]);
00194     fprintf(stdout, "tor-fw-helper: tor_fw_add_or_port backend %s "
00195             "returned: %i\n", (const char *) backends->backend_ops[i].name, r);
00196   }
00197 }
00198 
00201 static void
00202 tor_fw_add_dir_port(tor_fw_options_t *tor_fw_options,
00203                        backends_t *backends)
00204 {
00205   int i;
00206   int r = 0;
00207 
00208   if (tor_fw_options->verbose)
00209     fprintf(stdout, "V: tor_fw_add_dir_port\n");
00210 
00211   for (i=0; i<backends->n_backends; ++i) {
00212     if (tor_fw_options->verbose) {
00213       fprintf(stdout, "V: running backend_state now: %i\n", i);
00214       fprintf(stdout, "V: size of backend state: %u\n",
00215               (int)(backends->backend_ops)[i].state_len);
00216       fprintf(stdout, "V: backend state name: %s\n",
00217               (char *)(backends->backend_ops)[i].name);
00218     }
00219     r = backends->backend_ops[i].add_tcp_mapping(tor_fw_options,
00220                                                  backends->backend_state[i]);
00221     fprintf(stdout, "tor-fw-helper: tor_fw_add_dir_port backend %s "
00222             "returned: %i\n", (const char *)backends->backend_ops[i].name, r);
00223   }
00224 }
00225 
00229 static int
00230 network_init(void)
00231 {
00232 #ifdef _WIN32
00233   /* This silly exercise is necessary before windows will allow
00234    * gethostbyname to work. */
00235   WSADATA WSAData;
00236   int r;
00237   r = WSAStartup(0x101, &WSAData);
00238   if (r) {
00239     fprintf(stderr, "E: Error initializing Windows network layer "
00240             "- code was %d", r);
00241     return -1;
00242   }
00243   /* WSAData.iMaxSockets might show the max sockets we're allowed to use.
00244    * We might use it to complain if we're trying to be a server but have
00245    * too few sockets available. */
00246 #endif
00247   return 0;
00248 }
00249 
00250 int
00251 main(int argc, char **argv)
00252 {
00253   int r = 0;
00254   int c = 0;
00255 
00256   tor_fw_options_t tor_fw_options;
00257   backends_t backend_state;
00258 
00259   memset(&tor_fw_options, 0, sizeof(tor_fw_options));
00260   memset(&backend_state, 0, sizeof(backend_state));
00261 
00262   while (1) {
00263     int option_index = 0;
00264     static struct option long_options[] =
00265       {
00266         {"verbose", 0, 0, 'v'},
00267         {"help", 0, 0, 'h'},
00268         {"internal-or-port", 1, 0, 'i'},
00269         {"external-or-port", 1, 0, 'e'},
00270         {"internal-dir-port", 1, 0, 'd'},
00271         {"external-dir-port", 1, 0, 'p'},
00272         {"fetch-public-ip", 0, 0, 'g'},
00273         {"test-commandline", 0, 0, 'T'},
00274         {0, 0, 0, 0}
00275       };
00276 
00277     c = getopt_long(argc, argv, "vhi:e:d:p:gT",
00278                     long_options, &option_index);
00279     if (c == -1)
00280       break;
00281 
00282     switch (c) {
00283       case 'v': tor_fw_options.verbose = 1; break;
00284       case 'h': tor_fw_options.help = 1; usage(); exit(1); break;
00285       case 'i': sscanf(optarg, "%hu", &tor_fw_options.private_or_port);
00286         break;
00287       case 'e': sscanf(optarg, "%hu", &tor_fw_options.public_or_port);
00288         break;
00289       case 'd': sscanf(optarg, "%hu", &tor_fw_options.private_dir_port);
00290         break;
00291       case 'p': sscanf(optarg, "%hu", &tor_fw_options.public_dir_port);
00292         break;
00293       case 'g': tor_fw_options.fetch_public_ip = 1; break;
00294       case 'T': tor_fw_options.test_commandline = 1; break;
00295       case '?': break;
00296       default : fprintf(stderr, "Unknown option!\n"); usage(); exit(1);
00297     }
00298   }
00299 
00300   if (tor_fw_options.verbose) {
00301     fprintf(stderr, "V: tor-fw-helper version %s\n"
00302             "V: We were called with the following arguments:\n"
00303             "V: verbose = %d, help = %d, pub or port = %u, "
00304             "priv or port = %u\n"
00305             "V: pub dir port =  %u, priv dir port = %u\n"
00306             "V: fetch_public_ip = %u\n",
00307             tor_fw_version, tor_fw_options.verbose, tor_fw_options.help,
00308             tor_fw_options.private_or_port, tor_fw_options.public_or_port,
00309             tor_fw_options.private_dir_port, tor_fw_options.public_dir_port,
00310             tor_fw_options.fetch_public_ip);
00311   }
00312 
00313   if (tor_fw_options.test_commandline) {
00314     return log_commandline_options(argc, argv);
00315   }
00316 
00317   /* At the very least, we require an ORPort;
00318      Given a private ORPort, we can ask for a mapping that matches the port
00319      externally.
00320   */
00321   if (!tor_fw_options.private_or_port && !tor_fw_options.fetch_public_ip) {
00322     fprintf(stderr, "E: We require an ORPort or fetch_public_ip"
00323             " request!\n");
00324     usage();
00325     exit(1);
00326   } else {
00327     /* When we only have one ORPort, internal/external are
00328        set to be the same.*/
00329     if (!tor_fw_options.public_or_port && tor_fw_options.private_or_port) {
00330       if (tor_fw_options.verbose)
00331         fprintf(stdout, "V: We're setting public_or_port = "
00332                 "private_or_port.\n");
00333       tor_fw_options.public_or_port = tor_fw_options.private_or_port;
00334     }
00335   }
00336   if (!tor_fw_options.private_dir_port) {
00337     if (tor_fw_options.verbose)
00338       fprintf(stdout, "V: We have no DirPort; no hole punching for "
00339               "DirPorts\n");
00340 
00341   } else {
00342     /* When we only have one DirPort, internal/external are
00343        set to be the same.*/
00344     if (!tor_fw_options.public_dir_port && tor_fw_options.private_dir_port) {
00345       if (tor_fw_options.verbose)
00346         fprintf(stdout, "V: We're setting public_or_port = "
00347                 "private_or_port.\n");
00348 
00349       tor_fw_options.public_dir_port = tor_fw_options.private_dir_port;
00350     }
00351   }
00352 
00353   if (tor_fw_options.verbose) {
00354     fprintf(stdout, "V: pub or port = %u, priv or port = %u\n"
00355             "V: pub dir port =  %u, priv dir port = %u\n",
00356             tor_fw_options.private_or_port, tor_fw_options.public_or_port,
00357             tor_fw_options.private_dir_port,
00358             tor_fw_options.public_dir_port);
00359   }
00360 
00361   // Initialize networking
00362   if (network_init())
00363     exit(1);
00364 
00365   // Initalize the various fw-helper backend helpers
00366   r = init_backends(&tor_fw_options, &backend_state);
00367   if (r)
00368     printf("tor-fw-helper: %i NAT traversal helper(s) loaded\n", r);
00369 
00370   if (tor_fw_options.fetch_public_ip) {
00371     tor_fw_fetch_public_ip(&tor_fw_options, &backend_state);
00372   }
00373 
00374   if (tor_fw_options.private_or_port) {
00375     tor_fw_options.internal_port = tor_fw_options.private_or_port;
00376     tor_fw_options.external_port = tor_fw_options.private_or_port;
00377     tor_fw_add_or_port(&tor_fw_options, &backend_state);
00378   }
00379 
00380   if (tor_fw_options.private_dir_port) {
00381     tor_fw_options.internal_port = tor_fw_options.private_dir_port;
00382     tor_fw_options.external_port = tor_fw_options.private_dir_port;
00383     tor_fw_add_dir_port(&tor_fw_options, &backend_state);
00384   }
00385 
00386   r = (((tor_fw_options.nat_pmp_status | tor_fw_options.upnp_status)
00387         |tor_fw_options.public_ip_status));
00388   if (r > 0) {
00389     fprintf(stdout, "tor-fw-helper: SUCCESS\n");
00390   } else {
00391     fprintf(stderr, "tor-fw-helper: FAILURE\n");
00392   }
00393 
00394   exit(r);
00395 }
00396