2 This file is part of GNUnet.
3 Copyright (C) 2011, 2017 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU 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.
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.
17 * @file src/nat/gnunet-nat-server.c
18 * @brief Daemon to run on 'gnunet.org' to help test NAT traversal code
19 * @author Christian Grothoff
22 #include "gnunet_util_lib.h"
23 #include "gnunet_nat_service.h"
24 #include "gnunet_protocols.h"
29 * Information we track per client.
36 struct GNUNET_SCHEDULER_Task *tt;
41 struct GNUNET_SERVICE_Client *client;
48 static const struct GNUNET_CONFIGURATION_Handle *cfg;
52 * Try contacting the peer using autonomous NAT traveral method.
54 * @param dst_ipv4 IPv4 address to send the fake ICMP message
55 * @param dport destination port to include in ICMP message
56 * @param is_tcp mark for TCP (#GNUNET_YES) or UDP (#GNUNET_NO)
59 try_anat (uint32_t dst_ipv4,
63 struct GNUNET_NAT_Handle *h;
64 struct sockaddr_in lsa;
65 struct sockaddr_in rsa;
66 const struct sockaddr *sa;
69 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
70 "Asking for connection reversal with %x and code %u\n",
71 (unsigned int) dst_ipv4,
72 (unsigned int) dport);
73 memset (&lsa, 0, sizeof (lsa));
74 lsa.sin_family = AF_INET;
75 #if HAVE_SOCKADDR_IN_SIN_LEN
76 lsa.sin_len = sizeof (sa);
78 lsa.sin_addr.s_addr = 0;
79 lsa.sin_port = htons (dport);
80 memset (&rsa, 0, sizeof (rsa));
81 rsa.sin_family = AF_INET;
82 #if HAVE_SOCKADDR_IN_SIN_LEN
83 rsa.sin_len = sizeof (sa);
85 rsa.sin_addr.s_addr = dst_ipv4;
86 rsa.sin_port = htons (dport);
87 sa_len = sizeof (lsa);
88 sa = (const struct sockaddr *) &lsa;
89 h = GNUNET_NAT_register (cfg,
91 is_tcp ? IPPROTO_TCP : IPPROTO_UDP,
96 GNUNET_NAT_request_reversal (h,
99 GNUNET_NAT_unregister (h);
104 * Closure for #tcp_send.
111 struct GNUNET_NETWORK_Handle *s;
121 * Task called by the scheduler once we can do the TCP send
122 * (or once we failed to connect...).
124 * @param cls the `struct TcpContext`
129 struct TcpContext *ctx = cls;
130 const struct GNUNET_SCHEDULER_TaskContext *tc;
132 tc = GNUNET_SCHEDULER_get_task_context ();
133 if ((NULL != tc->write_ready) &&
134 (GNUNET_NETWORK_fdset_isset (tc->write_ready, ctx->s)))
137 GNUNET_NETWORK_socket_send (ctx->s, &ctx->data, sizeof (ctx->data)))
139 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send");
141 GNUNET_NETWORK_socket_shutdown (ctx->s, SHUT_RDWR);
143 GNUNET_NETWORK_socket_close (ctx->s);
149 * Try to send @a data to the
150 * IP @a dst_ipv4' at port @a dport via TCP.
152 * @param dst_ipv4 target IP
153 * @param dport target port
154 * @param data data to send
157 try_send_tcp (uint32_t dst_ipv4,
161 struct GNUNET_NETWORK_Handle *s;
162 struct sockaddr_in sa;
163 struct TcpContext *ctx;
165 s = GNUNET_NETWORK_socket_create (AF_INET,
170 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
174 memset (&sa, 0, sizeof (sa));
175 sa.sin_family = AF_INET;
176 #if HAVE_SOCKADDR_IN_SIN_LEN
177 sa.sin_len = sizeof (sa);
179 sa.sin_addr.s_addr = dst_ipv4;
180 sa.sin_port = htons (dport);
181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
182 "Sending TCP message to `%s'\n",
183 GNUNET_a2s ((struct sockaddr *) &sa,
186 GNUNET_NETWORK_socket_connect (s,
187 (const struct sockaddr *) &sa,
189 (errno != EINPROGRESS) )
191 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
193 GNUNET_NETWORK_socket_close (s);
196 ctx = GNUNET_new (struct TcpContext);
199 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_SECONDS,
207 * Try to send @a data to the
208 * IP @a dst_ipv4 at port @a dport via UDP.
210 * @param dst_ipv4 target IP
211 * @param dport target port
212 * @param data data to send
215 try_send_udp (uint32_t dst_ipv4,
219 struct GNUNET_NETWORK_Handle *s;
220 struct sockaddr_in sa;
222 s = GNUNET_NETWORK_socket_create (AF_INET,
227 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
231 memset (&sa, 0, sizeof (sa));
232 sa.sin_family = AF_INET;
233 #if HAVE_SOCKADDR_IN_SIN_LEN
234 sa.sin_len = sizeof (sa);
236 sa.sin_addr.s_addr = dst_ipv4;
237 sa.sin_port = htons (dport);
238 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
239 "Sending UDP packet to `%s'\n",
240 GNUNET_a2s ((struct sockaddr *) &sa,
243 GNUNET_NETWORK_socket_sendto (s,
246 (const struct sockaddr *) &sa,
248 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
250 GNUNET_NETWORK_socket_close (s);
255 * We've received a request to probe a NAT
258 * @param cls handle to client (we always close)
259 * @param msg message with details about what to test
262 handle_test (void *cls,
263 const struct GNUNET_NAT_AUTO_TestMessage *tm)
265 struct ClientData *cd = cls;
268 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
269 "Received test request\n");
270 dport = ntohs (tm->dport);
272 try_anat (tm->dst_ipv4,
274 (int) ntohl (tm->is_tcp));
275 else if (GNUNET_YES == ntohl (tm->is_tcp))
276 try_send_tcp (tm->dst_ipv4,
280 try_send_udp (tm->dst_ipv4,
283 GNUNET_SERVICE_client_drop (cd->client);
288 * Main function that will be run.
291 * @param c configuration
292 * @param srv service handle
296 const struct GNUNET_CONFIGURATION_Handle *c,
297 struct GNUNET_SERVICE_Handle *srv)
304 * Forcefully drops client after 1s.
306 * @param cls our `struct ClientData` of a client to drop
309 force_timeout (void *cls)
311 struct ClientData *cd = cls;
314 GNUNET_SERVICE_client_drop (cd->client);
320 * Callback called when a client connects to the service.
322 * @param cls closure for the service
323 * @param c the new client that connected to the service
324 * @param mq the message queue used to send messages to the client
325 * @return our `struct ClientData`
328 client_connect_cb (void *cls,
329 struct GNUNET_SERVICE_Client *c,
330 struct GNUNET_MQ_Handle *mq)
332 struct ClientData *cd;
334 cd = GNUNET_new (struct ClientData);
336 cd->tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
344 * Callback called when a client disconnected from the service
346 * @param cls closure for the service
347 * @param c the client that disconnected
348 * @param internal_cls our `struct ClientData`
351 client_disconnect_cb (void *cls,
352 struct GNUNET_SERVICE_Client *c,
355 struct ClientData *cd = internal_cls;
358 GNUNET_SCHEDULER_cancel (cd->tt);
364 * Define "main" method using service macro.
368 GNUNET_SERVICE_OPTION_NONE,
371 &client_disconnect_cb,
373 GNUNET_MQ_hd_fixed_size (test,
374 GNUNET_MESSAGE_TYPE_NAT_TEST,
375 struct GNUNET_NAT_AUTO_TestMessage,
377 GNUNET_MQ_handler_end ());
380 #if defined(LINUX) && defined(__GLIBC__)
384 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
386 void __attribute__ ((constructor))
387 GNUNET_ARM_memory_init ()
389 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
390 mallopt (M_TOP_PAD, 1 * 1024);
398 /* end of gnunet-nat-server.c */