tor-fw-helper-upnp.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
  2. * Copyright (c) 2010-2011, The Tor Project, Inc. */
  3. /* See LICENSE for licensing information */
  4. /**
  5. * \file tor-fw-helper-upnp.c
  6. * \brief The implementation of our UPnP firewall helper.
  7. **/
  8. #include "orconfig.h"
  9. #ifdef MINIUPNPC
  10. #include <stdint.h>
  11. #include <string.h>
  12. #include <stdio.h>
  13. #include <assert.h>
  14. #include "compat.h"
  15. #include "tor-fw-helper.h"
  16. #include "tor-fw-helper-upnp.h"
  17. /** UPnP timeout value. */
  18. #define UPNP_DISCOVER_TIMEOUT 2000
  19. /** Description of the port mapping in the UPnP table. */
  20. #define UPNP_DESC "Tor relay"
  21. /* XXX TODO: We should print these as a useful user string when we return the
  22. * number to a user */
  23. /** Magic numbers as miniupnpc return codes. */
  24. #define UPNP_ERR_SUCCESS 0
  25. #define UPNP_ERR_NODEVICESFOUND 1
  26. #define UPNP_ERR_NOIGDFOUND 2
  27. #define UPNP_ERR_ADDPORTMAPPING 3
  28. #define UPNP_ERR_GETPORTMAPPING 4
  29. #define UPNP_ERR_DELPORTMAPPING 5
  30. #define UPNP_ERR_GETEXTERNALIP 6
  31. #define UPNP_ERR_INVAL 7
  32. #define UPNP_ERR_OTHER 8
  33. #define UPNP_SUCCESS 1
  34. /** This hooks miniupnpc into our multi-backend API. */
  35. static tor_fw_backend_t tor_miniupnp_backend = {
  36. "miniupnp",
  37. sizeof(struct miniupnpc_state_t),
  38. tor_upnp_init,
  39. tor_upnp_cleanup,
  40. tor_upnp_fetch_public_ip,
  41. tor_upnp_add_tcp_mapping
  42. };
  43. /** Return the backend for miniupnp. */
  44. const tor_fw_backend_t *
  45. tor_fw_get_miniupnp_backend(void)
  46. {
  47. return &tor_miniupnp_backend;
  48. }
  49. /** Initialize the UPnP backend and store the results in
  50. * <b>backend_state</b>.*/
  51. int
  52. tor_upnp_init(tor_fw_options_t *options, void *backend_state)
  53. {
  54. /*
  55. This leaks the user agent from the client to the router - perhaps we don't
  56. want to do that? eg:
  57. User-Agent: Ubuntu/10.04, UPnP/1.0, MiniUPnPc/1.4
  58. */
  59. miniupnpc_state_t *state = (miniupnpc_state_t *) backend_state;
  60. struct UPNPDev *devlist;
  61. int r;
  62. memset(&(state->urls), 0, sizeof(struct UPNPUrls));
  63. memset(&(state->data), 0, sizeof(struct IGDdatas));
  64. state->init = 0;
  65. devlist = upnpDiscover(UPNP_DISCOVER_TIMEOUT, NULL, NULL, 0);
  66. if (NULL == devlist) {
  67. fprintf(stderr, "E: upnpDiscover returned: NULL\n");
  68. return UPNP_ERR_NODEVICESFOUND;
  69. }
  70. assert(options);
  71. r = UPNP_GetValidIGD(devlist, &(state->urls), &(state->data),
  72. state->lanaddr, UPNP_LANADDR_SZ);
  73. fprintf(stdout, "tor-fw-helper: UPnP GetValidIGD returned: %d (%s)\n", r,
  74. r==UPNP_SUCCESS?"SUCCESS":"FAILED");
  75. freeUPNPDevlist(devlist);
  76. if (r != 1 && r != 2)
  77. return UPNP_ERR_NOIGDFOUND;
  78. state->init = 1;
  79. return UPNP_ERR_SUCCESS;
  80. }
  81. /** Tear down the UPnP connection stored in <b>backend_state</b>.*/
  82. int
  83. tor_upnp_cleanup(tor_fw_options_t *options, void *backend_state)
  84. {
  85. miniupnpc_state_t *state = (miniupnpc_state_t *) backend_state;
  86. assert(options);
  87. if (state->init)
  88. FreeUPNPUrls(&(state->urls));
  89. state->init = 0;
  90. return UPNP_ERR_SUCCESS;
  91. }
  92. /** Fetch our likely public IP from our upstream UPnP IGD enabled NAT device.
  93. * Use the connection context stored in <b>backend_state</b>. */
  94. int
  95. tor_upnp_fetch_public_ip(tor_fw_options_t *options, void *backend_state)
  96. {
  97. miniupnpc_state_t *state = (miniupnpc_state_t *) backend_state;
  98. int r;
  99. char externalIPAddress[16];
  100. if (!state->init) {
  101. r = tor_upnp_init(options, state);
  102. if (r != UPNP_ERR_SUCCESS)
  103. return r;
  104. }
  105. r = UPNP_GetExternalIPAddress(state->urls.controlURL,
  106. state->data.first.servicetype,
  107. externalIPAddress);
  108. if (r != UPNPCOMMAND_SUCCESS)
  109. goto err;
  110. if (externalIPAddress[0]) {
  111. fprintf(stdout, "tor-fw-helper: ExternalIPAddress = %s\n",
  112. externalIPAddress); tor_upnp_cleanup(options, state);
  113. options->public_ip_status = 1;
  114. return UPNP_ERR_SUCCESS;
  115. } else {
  116. goto err;
  117. }
  118. err:
  119. tor_upnp_cleanup(options, state);
  120. return UPNP_ERR_GETEXTERNALIP;
  121. }
  122. /** Add a TCP port mapping for a single port stored in <b>tor_fw_options</b>
  123. * and store the results in <b>backend_state</b>. */
  124. int
  125. tor_upnp_add_tcp_mapping(tor_fw_options_t *options, void *backend_state)
  126. {
  127. miniupnpc_state_t *state = (miniupnpc_state_t *) backend_state;
  128. int r;
  129. char internal_port_str[6];
  130. char external_port_str[6];
  131. if (!state->init) {
  132. r = tor_upnp_init(options, state);
  133. if (r != UPNP_ERR_SUCCESS)
  134. return r;
  135. }
  136. if (options->verbose)
  137. fprintf(stdout, "V: internal port: %d, external port: %d\n",
  138. (int)options->internal_port, (int)options->external_port);
  139. tor_snprintf(internal_port_str, sizeof(internal_port_str),
  140. "%d", (int)options->internal_port);
  141. tor_snprintf(external_port_str, sizeof(external_port_str),
  142. "%d", (int)options->external_port);
  143. r = UPNP_AddPortMapping(state->urls.controlURL,
  144. state->data.first.servicetype,
  145. external_port_str, internal_port_str,
  146. state->lanaddr, UPNP_DESC, "TCP", 0);
  147. if (r != UPNPCOMMAND_SUCCESS)
  148. return UPNP_ERR_ADDPORTMAPPING;
  149. options->upnp_status = 1;
  150. return UPNP_ERR_SUCCESS;
  151. }
  152. #endif