Back to index

tor  0.2.3.18-rc
tor-fw-helper-natpmp.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 #include "orconfig.h"
00011 #ifdef NAT_PMP
00012 #ifdef _WIN32
00013 #define STATICLIB
00014 #endif
00015 #include <stdint.h>
00016 #include <stdio.h>
00017 #include <string.h>
00018 #include <errno.h>
00019 #ifndef _WIN32
00020 #include <arpa/inet.h>
00021 #endif
00022 
00023 // debugging stuff
00024 #include <assert.h>
00025 
00026 #include "compat.h"
00027 
00028 #include "tor-fw-helper.h"
00029 #include "tor-fw-helper-natpmp.h"
00030 
00032 static tor_fw_backend_t tor_natpmp_backend = {
00033   "natpmp",
00034   sizeof(struct natpmp_state_t),
00035   tor_natpmp_init,
00036   tor_natpmp_cleanup,
00037   tor_natpmp_fetch_public_ip,
00038   tor_natpmp_add_tcp_mapping
00039 };
00040 
00042 const tor_fw_backend_t *
00043 tor_fw_get_natpmp_backend(void)
00044 {
00045   return &tor_natpmp_backend;
00046 }
00047 
00050 int
00051 tor_natpmp_init(tor_fw_options_t *tor_fw_options, void *backend_state)
00052 {
00053   natpmp_state_t *state = (natpmp_state_t *) backend_state;
00054   int r = 0;
00055 
00056   memset(&(state->natpmp), 0, sizeof(natpmp_t));
00057   memset(&(state->response), 0, sizeof(natpmpresp_t));
00058   state->init = 0;
00059   state->protocol = NATPMP_PROTOCOL_TCP;
00060   state->lease = NATPMP_DEFAULT_LEASE;
00061 
00062   if (tor_fw_options->verbose)
00063     fprintf(stdout, "V: natpmp init...\n");
00064 
00065   r = initnatpmp(&(state->natpmp), 0, 0);
00066   if (r == 0) {
00067     state->init = 1;
00068     fprintf(stdout, "tor-fw-helper: natpmp initialized...\n");
00069     return r;
00070   } else {
00071     fprintf(stderr, "tor-fw-helper: natpmp failed to initialize...\n");
00072     return r;
00073   }
00074 }
00075 
00077 int
00078 tor_natpmp_cleanup(tor_fw_options_t *tor_fw_options, void *backend_state)
00079 {
00080   natpmp_state_t *state = (natpmp_state_t *) backend_state;
00081   int r = 0;
00082   if (tor_fw_options->verbose)
00083     fprintf(stdout, "V: natpmp cleanup...\n");
00084   r = closenatpmp(&(state->natpmp));
00085   if (tor_fw_options->verbose)
00086     fprintf(stdout, "V: closing natpmp socket: %d\n", r);
00087   return r;
00088 }
00089 
00091 static int
00092 wait_until_fd_readable(tor_socket_t fd, struct timeval *timeout)
00093 {
00094   int r;
00095   fd_set fds;
00096   if (fd >= FD_SETSIZE) {
00097     fprintf(stderr, "E: NAT-PMP FD_SETSIZE error %d\n", fd);
00098     return -1;
00099   }
00100   FD_ZERO(&fds);
00101   FD_SET(fd, &fds);
00102   r = select(fd+1, &fds, NULL, NULL, timeout);
00103   if (r == -1) {
00104     fprintf(stdout, "V: select failed in wait_until_fd_readable: %s\n",
00105             strerror(errno));
00106     return -1;
00107   }
00108   /* XXXX we should really check to see whether fd was readable, or we timed
00109      out. */
00110   return 0;
00111 }
00112 
00115 int
00116 tor_natpmp_add_tcp_mapping(tor_fw_options_t *tor_fw_options,
00117                            void *backend_state)
00118 {
00119   natpmp_state_t *state = (natpmp_state_t *) backend_state;
00120   int r = 0;
00121   int x = 0;
00122   int sav_errno;
00123 
00124   struct timeval timeout;
00125 
00126   if (tor_fw_options->verbose)
00127     fprintf(stdout, "V: sending natpmp portmapping request...\n");
00128   r = sendnewportmappingrequest(&(state->natpmp), state->protocol,
00129                                 tor_fw_options->internal_port,
00130                                 tor_fw_options->external_port,
00131                                 state->lease);
00132   if (tor_fw_options->verbose)
00133     fprintf(stdout, "tor-fw-helper: NAT-PMP sendnewportmappingrequest "
00134             "returned %d (%s)\n", r, r==12?"SUCCESS":"FAILED");
00135 
00136   do {
00137     getnatpmprequesttimeout(&(state->natpmp), &timeout);
00138     x = wait_until_fd_readable(state->natpmp.s, &timeout);
00139     if (x == -1)
00140       return -1;
00141 
00142     if (tor_fw_options->verbose)
00143       fprintf(stdout, "V: attempting to readnatpmpreponseorretry...\n");
00144     r = readnatpmpresponseorretry(&(state->natpmp), &(state->response));
00145     sav_errno = errno;
00146 
00147     if (r<0 && r!=NATPMP_TRYAGAIN) {
00148       fprintf(stderr, "E: readnatpmpresponseorretry failed %d\n", r);
00149       fprintf(stderr, "E: errno=%d '%s'\n", sav_errno,
00150               strerror(sav_errno));
00151     }
00152 
00153   } while (r == NATPMP_TRYAGAIN);
00154 
00155   if (r != 0) {
00156     /* XXX TODO: NATPMP_* should be formatted into useful error strings */
00157     fprintf(stderr, "E: NAT-PMP It appears that something went wrong:"
00158             " %d\n", r);
00159     if (r == -51)
00160       fprintf(stderr, "E: NAT-PMP It appears that the request was "
00161               "unauthorized\n");
00162     return r;
00163   }
00164 
00165   if (r == NATPMP_SUCCESS) {
00166     fprintf(stdout, "tor-fw-helper: NAT-PMP mapped public port %hu to"
00167             " localport %hu liftime %u\n",
00168             (state->response).pnu.newportmapping.mappedpublicport,
00169             (state->response).pnu.newportmapping.privateport,
00170             (state->response).pnu.newportmapping.lifetime);
00171   }
00172 
00173   tor_fw_options->nat_pmp_status = 1;
00174 
00175   return r;
00176 }
00177 
00180 int
00181 tor_natpmp_fetch_public_ip(tor_fw_options_t *tor_fw_options,
00182                            void *backend_state)
00183 {
00184   int r = 0;
00185   int x = 0;
00186   int sav_errno;
00187   natpmp_state_t *state = (natpmp_state_t *) backend_state;
00188 
00189   struct timeval timeout;
00190 
00191   r = sendpublicaddressrequest(&(state->natpmp));
00192   fprintf(stdout, "tor-fw-helper: NAT-PMP sendpublicaddressrequest returned"
00193           " %d (%s)\n", r, r==2?"SUCCESS":"FAILED");
00194 
00195   do {
00196     getnatpmprequesttimeout(&(state->natpmp), &timeout);
00197 
00198     x = wait_until_fd_readable(state->natpmp.s, &timeout);
00199     if (x == -1)
00200       return -1;
00201 
00202     if (tor_fw_options->verbose)
00203       fprintf(stdout, "V: NAT-PMP attempting to read reponse...\n");
00204     r = readnatpmpresponseorretry(&(state->natpmp), &(state->response));
00205     sav_errno = errno;
00206 
00207     if (tor_fw_options->verbose)
00208       fprintf(stdout, "V: NAT-PMP readnatpmpresponseorretry returned"
00209               " %d\n", r);
00210 
00211     if ( r < 0 && r != NATPMP_TRYAGAIN) {
00212       fprintf(stderr, "E: NAT-PMP readnatpmpresponseorretry failed %d\n",
00213               r);
00214       fprintf(stderr, "E: NAT-PMP errno=%d '%s'\n", sav_errno,
00215               strerror(sav_errno));
00216     }
00217 
00218   } while (r == NATPMP_TRYAGAIN );
00219 
00220   if (r != 0) {
00221     fprintf(stderr, "E: NAT-PMP It appears that something went wrong:"
00222             " %d\n", r);
00223     return r;
00224   }
00225 
00226   fprintf(stdout, "tor-fw-helper: ExternalIPAddress = %s\n",
00227           inet_ntoa((state->response).pnu.publicaddress.addr));
00228   tor_fw_options->public_ip_status = 1;
00229 
00230   if (tor_fw_options->verbose) {
00231     fprintf(stdout, "V: result = %u\n", r);
00232     fprintf(stdout, "V: type = %u\n", (state->response).type);
00233     fprintf(stdout, "V: resultcode = %u\n", (state->response).resultcode);
00234     fprintf(stdout, "V: epoch = %u\n", (state->response).epoch);
00235   }
00236 
00237   return r;
00238 }
00239 #endif
00240