Back to index

tor  0.2.3.19-rc
tor-fw-helper-upnp.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 MINIUPNPC
00012 #ifdef _WIN32
00013 #define STATICLIB
00014 #endif
00015 #include <stdint.h>
00016 #include <string.h>
00017 #include <stdio.h>
00018 
00019 #include <assert.h>
00020 
00021 #include "compat.h"
00022 #include "tor-fw-helper.h"
00023 #include "tor-fw-helper-upnp.h"
00024 
00026 #define UPNP_DISCOVER_TIMEOUT 2000
00027 
00028 #define UPNP_DESC "Tor relay"
00029 
00030 /* XXX TODO: We should print these as a useful user string when we return the
00031  * number to a user */
00033 #define UPNP_ERR_SUCCESS 0
00034 #define UPNP_ERR_NODEVICESFOUND 1
00035 #define UPNP_ERR_NOIGDFOUND 2
00036 #define UPNP_ERR_ADDPORTMAPPING 3
00037 #define UPNP_ERR_GETPORTMAPPING 4
00038 #define UPNP_ERR_DELPORTMAPPING 5
00039 #define UPNP_ERR_GETEXTERNALIP 6
00040 #define UPNP_ERR_INVAL 7
00041 #define UPNP_ERR_OTHER 8
00042 #define UPNP_SUCCESS 1
00043 
00045 static tor_fw_backend_t tor_miniupnp_backend = {
00046   "miniupnp",
00047   sizeof(struct miniupnpc_state_t),
00048   tor_upnp_init,
00049   tor_upnp_cleanup,
00050   tor_upnp_fetch_public_ip,
00051   tor_upnp_add_tcp_mapping
00052 };
00053 
00055 const tor_fw_backend_t *
00056 tor_fw_get_miniupnp_backend(void)
00057 {
00058   return &tor_miniupnp_backend;
00059 }
00060 
00063 int
00064 tor_upnp_init(tor_fw_options_t *options, void *backend_state)
00065 {
00066   /*
00067     This leaks the user agent from the client to the router - perhaps we don't
00068     want to do that? eg:
00069 
00070     User-Agent: Ubuntu/10.04, UPnP/1.0, MiniUPnPc/1.4
00071 
00072   */
00073   miniupnpc_state_t *state = (miniupnpc_state_t *) backend_state;
00074   struct UPNPDev *devlist;
00075   int r;
00076 
00077   memset(&(state->urls), 0, sizeof(struct UPNPUrls));
00078   memset(&(state->data), 0, sizeof(struct IGDdatas));
00079   state->init = 0;
00080 
00081 #ifdef MINIUPNPC15
00082   devlist = upnpDiscover(UPNP_DISCOVER_TIMEOUT, NULL, NULL, 0);
00083 #else
00084   devlist = upnpDiscover(UPNP_DISCOVER_TIMEOUT, NULL, NULL, 0, 0, NULL);
00085 #endif
00086   if (NULL == devlist) {
00087     fprintf(stderr, "E: upnpDiscover returned: NULL\n");
00088     return UPNP_ERR_NODEVICESFOUND;
00089   }
00090 
00091   assert(options);
00092   r = UPNP_GetValidIGD(devlist, &(state->urls), &(state->data),
00093                        state->lanaddr, UPNP_LANADDR_SZ);
00094   fprintf(stdout, "tor-fw-helper: UPnP GetValidIGD returned: %d (%s)\n", r,
00095           r==UPNP_SUCCESS?"SUCCESS":"FAILED");
00096 
00097   freeUPNPDevlist(devlist);
00098 
00099   if (r != 1 && r != 2)
00100     return UPNP_ERR_NOIGDFOUND;
00101 
00102   state->init = 1;
00103   return UPNP_ERR_SUCCESS;
00104 }
00105 
00107 int
00108 tor_upnp_cleanup(tor_fw_options_t *options, void *backend_state)
00109 {
00110 
00111   miniupnpc_state_t *state = (miniupnpc_state_t *) backend_state;
00112   assert(options);
00113 
00114   if (state->init)
00115     FreeUPNPUrls(&(state->urls));
00116   state->init = 0;
00117 
00118   return UPNP_ERR_SUCCESS;
00119 }
00120 
00123 int
00124 tor_upnp_fetch_public_ip(tor_fw_options_t *options, void *backend_state)
00125 {
00126   miniupnpc_state_t *state = (miniupnpc_state_t *) backend_state;
00127   int r;
00128   char externalIPAddress[16];
00129 
00130   if (!state->init) {
00131     r = tor_upnp_init(options, state);
00132     if (r != UPNP_ERR_SUCCESS)
00133       return r;
00134   }
00135 
00136   r = UPNP_GetExternalIPAddress(state->urls.controlURL,
00137                                 state->data.first.servicetype,
00138                                 externalIPAddress);
00139 
00140   if (r != UPNPCOMMAND_SUCCESS)
00141     goto err;
00142 
00143   if (externalIPAddress[0]) {
00144     fprintf(stdout, "tor-fw-helper: ExternalIPAddress = %s\n",
00145             externalIPAddress); tor_upnp_cleanup(options, state);
00146     options->public_ip_status = 1;
00147     return UPNP_ERR_SUCCESS;
00148   } else {
00149     goto err;
00150   }
00151 
00152  err:
00153   tor_upnp_cleanup(options, state);
00154   return UPNP_ERR_GETEXTERNALIP;
00155 }
00156 
00159 int
00160 tor_upnp_add_tcp_mapping(tor_fw_options_t *options, void *backend_state)
00161 {
00162   miniupnpc_state_t *state = (miniupnpc_state_t *) backend_state;
00163   int r;
00164   char internal_port_str[6];
00165   char external_port_str[6];
00166 
00167   if (!state->init) {
00168     r = tor_upnp_init(options, state);
00169     if (r != UPNP_ERR_SUCCESS)
00170       return r;
00171   }
00172 
00173   if (options->verbose)
00174     fprintf(stdout, "V: internal port: %d, external port: %d\n",
00175             (int)options->internal_port, (int)options->external_port);
00176 
00177   tor_snprintf(internal_port_str, sizeof(internal_port_str),
00178                "%d", (int)options->internal_port);
00179   tor_snprintf(external_port_str, sizeof(external_port_str),
00180                "%d", (int)options->external_port);
00181 
00182   r = UPNP_AddPortMapping(state->urls.controlURL,
00183                           state->data.first.servicetype,
00184                           external_port_str, internal_port_str,
00185 #ifdef MINIUPNPC15
00186                           state->lanaddr, UPNP_DESC, "TCP", 0);
00187 #else
00188                           state->lanaddr, UPNP_DESC, "TCP", 0, 0);
00189 #endif
00190   if (r != UPNPCOMMAND_SUCCESS)
00191     return UPNP_ERR_ADDPORTMAPPING;
00192 
00193   options->upnp_status = 1;
00194   return UPNP_ERR_SUCCESS;
00195 }
00196 #endif
00197