aboutsummaryrefslogtreecommitdiff
path: root/src/cli/nat-auto/gnunet-nat-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cli/nat-auto/gnunet-nat-server.c')
-rw-r--r--src/cli/nat-auto/gnunet-nat-server.c403
1 files changed, 403 insertions, 0 deletions
diff --git a/src/cli/nat-auto/gnunet-nat-server.c b/src/cli/nat-auto/gnunet-nat-server.c
new file mode 100644
index 000000000..baa610e8f
--- /dev/null
+++ b/src/cli/nat-auto/gnunet-nat-server.c
@@ -0,0 +1,403 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011, 2017 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file src/nat/gnunet-nat-server.c
23 * @brief Daemon to run on 'gnunet.org' to help test NAT traversal code
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_nat_service.h"
29#include "gnunet_protocols.h"
30// FIXME can we build this without this header?
31#include "../../service/nat-auto/nat-auto.h"
32
33
34/**
35 * Information we track per client.
36 */
37struct ClientData
38{
39 /**
40 * Timeout task.
41 */
42 struct GNUNET_SCHEDULER_Task *tt;
43
44 /**
45 * Client handle.
46 */
47 struct GNUNET_SERVICE_Client *client;
48};
49
50
51/**
52 * Our configuration.
53 */
54static const struct GNUNET_CONFIGURATION_Handle *cfg;
55
56
57/**
58 * Try contacting the peer using autonomous NAT traversal method.
59 *
60 * @param dst_ipv4 IPv4 address to send the fake ICMP message
61 * @param dport destination port to include in ICMP message
62 * @param is_tcp mark for TCP (#GNUNET_YES) or UDP (#GNUNET_NO)
63 */
64static void
65try_anat (uint32_t dst_ipv4,
66 uint16_t dport,
67 int is_tcp)
68{
69 struct GNUNET_NAT_Handle *h;
70 struct sockaddr_in lsa;
71 struct sockaddr_in rsa;
72 const struct sockaddr *sa;
73 socklen_t sa_len;
74
75 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
76 "Asking for connection reversal with %x and code %u\n",
77 (unsigned int) dst_ipv4,
78 (unsigned int) dport);
79 memset (&lsa, 0, sizeof(lsa));
80 lsa.sin_family = AF_INET;
81#if HAVE_SOCKADDR_IN_SIN_LEN
82 lsa.sin_len = sizeof(sa);
83#endif
84 lsa.sin_addr.s_addr = 0;
85 lsa.sin_port = htons (dport);
86 memset (&rsa, 0, sizeof(rsa));
87 rsa.sin_family = AF_INET;
88#if HAVE_SOCKADDR_IN_SIN_LEN
89 rsa.sin_len = sizeof(sa);
90#endif
91 rsa.sin_addr.s_addr = dst_ipv4;
92 rsa.sin_port = htons (dport);
93 sa_len = sizeof(lsa);
94 sa = (const struct sockaddr *) &lsa;
95 h = GNUNET_NAT_register (cfg,
96 "none",
97 is_tcp ? IPPROTO_TCP : IPPROTO_UDP,
98 1,
99 &sa,
100 &sa_len,
101 NULL, NULL, NULL);
102 GNUNET_NAT_request_reversal (h,
103 &lsa,
104 &rsa);
105 GNUNET_NAT_unregister (h);
106}
107
108
109/**
110 * Closure for #tcp_send.
111 */
112struct TcpContext
113{
114 /**
115 * TCP socket.
116 */
117 struct GNUNET_NETWORK_Handle *s;
118
119 /**
120 * Data to transmit.
121 */
122 uint16_t data;
123};
124
125
126/**
127 * Task called by the scheduler once we can do the TCP send
128 * (or once we failed to connect...).
129 *
130 * @param cls the `struct TcpContext`
131 */
132static void
133tcp_send (void *cls)
134{
135 struct TcpContext *ctx = cls;
136 const struct GNUNET_SCHEDULER_TaskContext *tc;
137
138 tc = GNUNET_SCHEDULER_get_task_context ();
139 if ((NULL != tc->write_ready) &&
140 (GNUNET_NETWORK_fdset_isset (tc->write_ready, ctx->s)))
141 {
142 if (-1 ==
143 GNUNET_NETWORK_socket_send (ctx->s, &ctx->data, sizeof(ctx->data)))
144 {
145 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send");
146 }
147 GNUNET_NETWORK_socket_shutdown (ctx->s, SHUT_RDWR);
148 }
149 GNUNET_NETWORK_socket_close (ctx->s);
150 GNUNET_free (ctx);
151}
152
153
154/**
155 * Try to send @a data to the
156 * IP @a dst_ipv4' at port @a dport via TCP.
157 *
158 * @param dst_ipv4 target IP
159 * @param dport target port
160 * @param data data to send
161 */
162static void
163try_send_tcp (uint32_t dst_ipv4,
164 uint16_t dport,
165 uint16_t data)
166{
167 struct GNUNET_NETWORK_Handle *s;
168 struct sockaddr_in sa;
169 struct TcpContext *ctx;
170
171 s = GNUNET_NETWORK_socket_create (AF_INET,
172 SOCK_STREAM,
173 0);
174 if (NULL == s)
175 {
176 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
177 "socket");
178 return;
179 }
180 memset (&sa, 0, sizeof(sa));
181 sa.sin_family = AF_INET;
182#if HAVE_SOCKADDR_IN_SIN_LEN
183 sa.sin_len = sizeof(sa);
184#endif
185 sa.sin_addr.s_addr = dst_ipv4;
186 sa.sin_port = htons (dport);
187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
188 "Sending TCP message to `%s'\n",
189 GNUNET_a2s ((struct sockaddr *) &sa,
190 sizeof(sa)));
191 if ((GNUNET_OK !=
192 GNUNET_NETWORK_socket_connect (s,
193 (const struct sockaddr *) &sa,
194 sizeof(sa))) &&
195 (errno != EINPROGRESS))
196 {
197 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
198 "connect");
199 GNUNET_NETWORK_socket_close (s);
200 return;
201 }
202 ctx = GNUNET_new (struct TcpContext);
203 ctx->s = s;
204 ctx->data = data;
205 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_SECONDS,
206 s,
207 &tcp_send,
208 ctx);
209}
210
211
212/**
213 * Try to send @a data to the
214 * IP @a dst_ipv4 at port @a dport via UDP.
215 *
216 * @param dst_ipv4 target IP
217 * @param dport target port
218 * @param data data to send
219 */
220static void
221try_send_udp (uint32_t dst_ipv4,
222 uint16_t dport,
223 uint16_t data)
224{
225 struct GNUNET_NETWORK_Handle *s;
226 struct sockaddr_in sa;
227
228 s = GNUNET_NETWORK_socket_create (AF_INET,
229 SOCK_DGRAM,
230 0);
231 if (NULL == s)
232 {
233 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
234 "socket");
235 return;
236 }
237 memset (&sa, 0, sizeof(sa));
238 sa.sin_family = AF_INET;
239#if HAVE_SOCKADDR_IN_SIN_LEN
240 sa.sin_len = sizeof(sa);
241#endif
242 sa.sin_addr.s_addr = dst_ipv4;
243 sa.sin_port = htons (dport);
244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
245 "Sending UDP packet to `%s'\n",
246 GNUNET_a2s ((struct sockaddr *) &sa,
247 sizeof(sa)));
248 if (-1 ==
249 GNUNET_NETWORK_socket_sendto (s,
250 &data,
251 sizeof(data),
252 (const struct sockaddr *) &sa,
253 sizeof(sa)))
254 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
255 "sendto");
256 GNUNET_NETWORK_socket_close (s);
257}
258
259
260/**
261 * We've received a request to probe a NAT
262 * traversal. Do it.
263 *
264 * @param cls handle to client (we always close)
265 * @param tm message with details about what to test
266 */
267static void
268handle_test (void *cls,
269 const struct GNUNET_NAT_AUTO_TestMessage *tm)
270{
271 struct ClientData *cd = cls;
272 uint16_t dport;
273
274 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
275 "Received test request\n");
276 dport = ntohs (tm->dport);
277 if (0 == dport)
278 try_anat (tm->dst_ipv4,
279 ntohs (tm->data),
280 (int) ntohl (tm->is_tcp));
281 else if (GNUNET_YES == ntohl (tm->is_tcp))
282 try_send_tcp (tm->dst_ipv4,
283 dport,
284 tm->data);
285 else
286 try_send_udp (tm->dst_ipv4,
287 dport,
288 tm->data);
289 GNUNET_SERVICE_client_drop (cd->client);
290}
291
292
293/**
294 * Main function that will be run.
295 *
296 * @param cls closure
297 * @param c configuration
298 * @param srv service handle
299 */
300static void
301run (void *cls,
302 const struct GNUNET_CONFIGURATION_Handle *c,
303 struct GNUNET_SERVICE_Handle *srv)
304{
305 cfg = c;
306}
307
308
309/**
310 * Forcefully drops client after 1s.
311 *
312 * @param cls our `struct ClientData` of a client to drop
313 */
314static void
315force_timeout (void *cls)
316{
317 struct ClientData *cd = cls;
318
319 cd->tt = NULL;
320 GNUNET_SERVICE_client_drop (cd->client);
321}
322
323
324/**
325 * Callback called when a client connects to the service.
326 *
327 * @param cls closure for the service
328 * @param c the new client that connected to the service
329 * @param mq the message queue used to send messages to the client
330 * @return our `struct ClientData`
331 */
332static void *
333client_connect_cb (void *cls,
334 struct GNUNET_SERVICE_Client *c,
335 struct GNUNET_MQ_Handle *mq)
336{
337 struct ClientData *cd;
338
339 cd = GNUNET_new (struct ClientData);
340 cd->client = c;
341 cd->tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
342 &force_timeout,
343 cd);
344 return cd;
345}
346
347
348/**
349 * Callback called when a client disconnected from the service
350 *
351 * @param cls closure for the service
352 * @param c the client that disconnected
353 * @param internal_cls our `struct ClientData`
354 */
355static void
356client_disconnect_cb (void *cls,
357 struct GNUNET_SERVICE_Client *c,
358 void *internal_cls)
359{
360 struct ClientData *cd = internal_cls;
361
362 if (NULL != cd->tt)
363 GNUNET_SCHEDULER_cancel (cd->tt);
364 GNUNET_free (cd);
365}
366
367
368/**
369 * Define "main" method using service macro.
370 */
371GNUNET_SERVICE_MAIN
372 ("nat-server",
373 GNUNET_SERVICE_OPTION_NONE,
374 &run,
375 &client_connect_cb,
376 &client_disconnect_cb,
377 NULL,
378 GNUNET_MQ_hd_fixed_size (test,
379 GNUNET_MESSAGE_TYPE_NAT_TEST,
380 struct GNUNET_NAT_AUTO_TestMessage,
381 NULL),
382 GNUNET_MQ_handler_end ());
383
384
385#if defined(__linux__) && defined(__GLIBC__)
386#include <malloc.h>
387
388/**
389 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
390 */
391void __attribute__ ((constructor))
392GNUNET_ARM_memory_init ()
393{
394 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
395 mallopt (M_TOP_PAD, 1 * 1024);
396 malloc_trim (0);
397}
398
399
400#endif
401
402
403/* end of gnunet-nat-server.c */