summaryrefslogtreecommitdiff
path: root/src/tools/tor-fw-helper/tor-fw-helper-upnp.c
blob: b471a6cd6f1924cf5d726ec4ac271beba899aa4a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
 * Copyright (c) 2010, The Tor Project, Inc. */
/* See LICENSE for licensing information */

#include <stdint.h>
#include <string.h>
#include <stdio.h>

#include "tor-fw-helper.h"
#include "tor-fw-helper-upnp.h"

#define UPNP_DISCOVER_TIMEOUT 2000
/* Description of the port mapping in the UPnP table */
#define UPNP_DESC "Tor relay"

#define UPNP_ERR_SUCCESS 0
#define UPNP_ERR_NODEVICESFOUND 1
#define UPNP_ERR_NOIGDFOUND 2
#define UPNP_ERR_ADDPORTMAPPING 3
#define UPNP_ERR_GETPORTMAPPING 4
#define UPNP_ERR_DELPORTMAPPING 5
#define UPNP_ERR_GETEXTERNALIP 6
#define UPNP_ERR_INVAL 7
#define UPNP_ERR_OTHER 8
#define UPNP_SUCCESS 1

int
tor_upnp_init(miniupnpc_state_t *state)
{
  struct UPNPDev *devlist;
  int r;

  memset(&(state->urls), 0, sizeof(struct UPNPUrls));
  memset(&(state->data), 0, sizeof(struct IGDdatas));

  devlist = upnpDiscover(UPNP_DISCOVER_TIMEOUT, NULL, NULL, 0);
  if (NULL == devlist) {
    fprintf(stderr, "E: upnpDiscover returned: NULL\n");
    return UPNP_ERR_NODEVICESFOUND;
  }

  r = UPNP_GetValidIGD(devlist, &(state->urls), &(state->data),
                       state->lanaddr, UPNP_LANADDR_SZ);
  fprintf(stdout, "tor-fw-helper: UPnP GetValidIGD returned: %d (%s)\n", r,
          r==UPNP_SUCCESS?"SUCCESS":"FAILED");

  freeUPNPDevlist(devlist);

  if (r != 1 && r != 2)
    return UPNP_ERR_NOIGDFOUND;

  state->init = 1;
  return UPNP_ERR_SUCCESS;
}

int
tor_upnp_cleanup(miniupnpc_state_t *state)
{
  if (state->init)
    FreeUPNPUrls(&(state->urls));
  state->init = 0;

  return UPNP_ERR_SUCCESS;
}

int
tor_upnp_fetch_public_ip(miniupnpc_state_t *state)
{
  int r;
  char externalIPAddress[16];

  if (!state->init) {
    r = tor_upnp_init(state);
    if (r != UPNP_ERR_SUCCESS)
      return r;
  }

  r = UPNP_GetExternalIPAddress(state->urls.controlURL,
                                state->data.first.servicetype,
                                externalIPAddress);

  if (r != UPNPCOMMAND_SUCCESS)
    goto err;

  if (externalIPAddress[0]) {
    fprintf(stdout, "tor-fw-helper: ExternalIPAddress = %s\n",
            externalIPAddress); tor_upnp_cleanup(state);
    return UPNP_ERR_SUCCESS;
  } else
    goto err;

  err:
    tor_upnp_cleanup(state);
    return UPNP_ERR_GETEXTERNALIP;
}

int
tor_upnp_add_tcp_mapping(miniupnpc_state_t *state,
    uint16_t internal_port, uint16_t external_port)
{
  int r;
  char internal_port_str[6];
  char external_port_str[6];

  if (!state->init) {
    r = tor_upnp_init(state);
    if (r != UPNP_ERR_SUCCESS)
      return r;
  }

  snprintf(internal_port_str, sizeof(internal_port_str),
           "%d", internal_port);
  snprintf(external_port_str, sizeof(external_port_str),
           "%d", external_port);

  r = UPNP_AddPortMapping(state->urls.controlURL,
                          state->data.first.servicetype,
                          external_port_str, internal_port_str,
                          state->lanaddr, UPNP_DESC, "TCP", 0);
  if (r != UPNPCOMMAND_SUCCESS)
    return UPNP_ERR_ADDPORTMAPPING;

  return UPNP_ERR_SUCCESS;
}