tor-fw-helper-upnp.c 5.1 KB

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