aboutsummaryrefslogtreecommitdiff
path: root/src/nat-auto/nat_auto_api.c
blob: a5b41ac491e2c86343abc35a2ec529cdc5f29439 (plain) (blame)
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
/*
     This file is part of GNUnet.
     Copyright (C) 2007-2017 GNUnet e.V.

     GNUnet is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published
     by the Free Software Foundation; either version 3, or (at your
     option) any later version.

     GNUnet is distributed in the hope that it will be useful, but
     WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     General Public License for more details.

     You should have received a copy of the GNU General Public License
     along with GNUnet; see the file COPYING.  If not, write to the
     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     Boston, MA 02110-1301, USA.
*/

/**
 * @author Christian Grothoff
 * @author Milan Bouchet-Valat
 *
 * @file nat-auto/nat_auto_api.c
 * Routines for NAT auto configuration.
 */
#include "platform.h"
#include "gnunet_nat_service.h"
#include "gnunet_nat_auto_service.h"
#include "nat-auto.h"



/**
 * Handle to auto-configuration in progress.
 */
struct GNUNET_NAT_AUTO_AutoHandle
{

  /**
   * Configuration we use.
   */
  const struct GNUNET_CONFIGURATION_Handle *cfg;
  
  /**
   * Message queue for communicating with the NAT service.
   */
  struct GNUNET_MQ_Handle *mq;

  /**
   * Function called with the result from the autoconfiguration.
   */
  GNUNET_NAT_AUTO_AutoResultCallback arc;

  /**
   * Closure for @e arc.
   */
  void *arc_cls;

};


/**
 * Converts `enum GNUNET_NAT_StatusCode` to string
 *
 * @param err error code to resolve to a string
 * @return point to a static string containing the error code
 */
const char *
GNUNET_NAT_AUTO_status2string (enum GNUNET_NAT_StatusCode err)
{
  switch (err)
  {
  case GNUNET_NAT_ERROR_SUCCESS:
    return _ ("Operation Successful");
  case GNUNET_NAT_ERROR_IPC_FAILURE:
    return _ ("IPC failure");
  case GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR:
    return _ ("Failure in network subsystem, check permissions.");
  case GNUNET_NAT_ERROR_TIMEOUT:
    return _ ("Encountered timeout while performing operation");
  case GNUNET_NAT_ERROR_NOT_ONLINE:
    return _ ("detected that we are offline");
  case GNUNET_NAT_ERROR_UPNPC_NOT_FOUND:
    return _ ("`upnpc` command not found");
  case GNUNET_NAT_ERROR_UPNPC_FAILED:
    return _ ("Failed to run `upnpc` command");
  case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
    return _ ("`upnpc' command took too long, process killed");
  case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
    return _ ("`upnpc' command failed to establish port mapping");
  case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
    return _ ("`external-ip' command not found");
  case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
    return _ ("Failed to run `external-ip` command");
  case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
    return _ ("`external-ip' command output invalid");
  case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
    return _ ("no valid address was returned by `external-ip'");
  case GNUNET_NAT_ERROR_NO_VALID_IF_IP_COMBO:
    return _ ("Could not determine interface with internal/local network address");
  case GNUNET_NAT_ERROR_HELPER_NAT_SERVER_NOT_FOUND:
    return _ ("No functioning gnunet-helper-nat-server installation found");
  case GNUNET_NAT_ERROR_NAT_TEST_START_FAILED:
    return _ ("NAT test could not be initialized");
  case GNUNET_NAT_ERROR_NAT_TEST_TIMEOUT:
    return _ ("NAT test timeout reached");
  case GNUNET_NAT_ERROR_NAT_REGISTER_FAILED:
    return _ ("could not register NAT");
  case GNUNET_NAT_ERROR_HELPER_NAT_CLIENT_NOT_FOUND:
    return _ ("No working gnunet-helper-nat-client installation found");
  default:
    return "unknown status code";
  }
}


/**
 * Check result from autoconfiguration attempt.
 *
 * @param cls the `struct GNUNET_NAT_AUTO_AutoHandle`
 * @param res the result
 * @return #GNUNET_OK if @a res is well-formed (always for now)
 */
static int
check_auto_result (void *cls,
		   const struct GNUNET_NAT_AUTO_AutoconfigResultMessage *res)
{
  return GNUNET_OK;
}


/**
 * Handle result from autoconfiguration attempt.
 *
 * @param cls the `struct GNUNET_NAT_AUTO_AutoHandle`
 * @param res the result
 */
static void
handle_auto_result (void *cls,
		    const struct GNUNET_NAT_AUTO_AutoconfigResultMessage *res)
{
  struct GNUNET_NAT_AUTO_AutoHandle *ah = cls;
  size_t left;
  struct GNUNET_CONFIGURATION_Handle *cfg;
  enum GNUNET_NAT_Type type
    = (enum GNUNET_NAT_Type) ntohl (res->type);
  enum GNUNET_NAT_StatusCode status
    = (enum GNUNET_NAT_StatusCode) ntohl (res->status_code);

  left = ntohs (res->header.size) - sizeof (*res);
  cfg = GNUNET_CONFIGURATION_create ();
  if (GNUNET_OK !=
      GNUNET_CONFIGURATION_deserialize (cfg,
					(const char *) &res[1],
					left,
					GNUNET_NO))
  {
    GNUNET_break (0);
    ah->arc (ah->arc_cls,
	     NULL,
	     GNUNET_NAT_ERROR_IPC_FAILURE,
	     type);
  }
  else
  {
    ah->arc (ah->arc_cls,
	     cfg,
	     status,
	     type);
  }
  GNUNET_CONFIGURATION_destroy (cfg);
  GNUNET_NAT_AUTO_autoconfig_cancel (ah);
}


/**
 * Handle queue errors by reporting autoconfiguration failure.
 *
 * @param cls the `struct GNUNET_NAT_AUTO_AutoHandle *`
 * @param error details about the error
 */
static void
ah_error_handler (void *cls,
		  enum GNUNET_MQ_Error error)
{
  struct GNUNET_NAT_AUTO_AutoHandle *ah = cls;

  ah->arc (ah->arc_cls,
	   NULL,
	   GNUNET_NAT_ERROR_IPC_FAILURE,
	   GNUNET_NAT_TYPE_UNKNOWN);
  GNUNET_NAT_AUTO_autoconfig_cancel (ah);
}


/**
 * Start auto-configuration routine.  The transport adapters should
 * be stopped while this function is called.
 *
 * @param cfg initial configuration
 * @param cb function to call with autoconfiguration result
 * @param cb_cls closure for @a cb
 * @return handle to cancel operation
 */
struct GNUNET_NAT_AUTO_AutoHandle *
GNUNET_NAT_AUTO_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
			     GNUNET_NAT_AUTO_AutoResultCallback cb,
			     void *cb_cls)
{
  struct GNUNET_NAT_AUTO_AutoHandle *ah = GNUNET_new (struct GNUNET_NAT_AUTO_AutoHandle);
  struct GNUNET_MQ_MessageHandler handlers[] = {
    GNUNET_MQ_hd_var_size (auto_result,
			   GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT,
			   struct GNUNET_NAT_AUTO_AutoconfigResultMessage,
			   ah),
    GNUNET_MQ_handler_end ()
  };
  struct GNUNET_MQ_Envelope *env;
  struct GNUNET_NAT_AUTO_AutoconfigRequestMessage *req;
  char *buf;
  size_t size;

  buf = GNUNET_CONFIGURATION_serialize (cfg,
					&size);
  if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*req))
  {
    GNUNET_break (0);
    GNUNET_free (buf);
    GNUNET_free (ah);
    return NULL;
  }
  ah->arc = cb;
  ah->arc_cls = cb_cls;
  ah->mq = GNUNET_CLIENT_connect (cfg,
				  "nat",
				  handlers,
				  &ah_error_handler,
				  ah);
  if (NULL == ah->mq)
  {
    GNUNET_break (0);
    GNUNET_free (buf);
    GNUNET_free (ah);
    return NULL;
  }
  env = GNUNET_MQ_msg_extra (req,
			     size,
			     GNUNET_MESSAGE_TYPE_NAT_AUTO_REQUEST_CFG);
  GNUNET_memcpy (&req[1],
		 buf,
		 size);
  GNUNET_free (buf);
  GNUNET_MQ_send (ah->mq,
		  env);
  return ah;
}


/**
 * Abort autoconfiguration.
 *
 * @param ah handle for operation to abort
 */
void
GNUNET_NAT_AUTO_autoconfig_cancel (struct GNUNET_NAT_AUTO_AutoHandle *ah)
{
  GNUNET_MQ_destroy (ah->mq);
  GNUNET_free (ah);
}

/* end of nat_api_auto.c */