aboutsummaryrefslogtreecommitdiff
path: root/src/nat/gnunet-nat-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nat/gnunet-nat-server.c')
-rw-r--r--src/nat/gnunet-nat-server.c275
1 files changed, 270 insertions, 5 deletions
diff --git a/src/nat/gnunet-nat-server.c b/src/nat/gnunet-nat-server.c
index c1f1be668..ae831db08 100644
--- a/src/nat/gnunet-nat-server.c
+++ b/src/nat/gnunet-nat-server.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2010 Christian Grothoff (and other contributing authors) 3 (C) 2011 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -26,11 +26,220 @@
26 */ 26 */
27#include "platform.h" 27#include "platform.h"
28#include "gnunet_util_lib.h" 28#include "gnunet_util_lib.h"
29#include "gnunet_nat_lib.h"
30#include "gnunet_protocols.h"
31#include "nat.h"
29 32
30/** 33/**
31 * Should we print some debug output? 34 * Our server.
32 */ 35 */
33#define VERBOSE 0 36static struct GNUNET_SERVER_Handle *server;
37
38/**
39 * Our configuration.
40 */
41static const struct GNUNET_CONFIGURATION_Handle *cfg;
42
43/**
44 * Try contacting the peer using autonomous
45 * NAT traveral method.
46 *
47 * @param dst_ipv4 IPv4 address to send the fake ICMP message
48 * @param dport destination port to include in ICMP message
49 * @param is_tcp mark for TCP (GNUNET_YES) or UDP (GNUNET_NO)
50 */
51static void
52try_anat (uint32_t dst_ipv4,
53 uint16_t dport,
54 int is_tcp)
55{
56 struct GNUNET_NAT_Handle *h;
57 struct sockaddr_in sa;
58
59 h = GNUNET_NAT_register (cfg,
60 is_tcp,
61 dport,
62 0, NULL, NULL,
63 NULL, NULL, NULL);
64 memset (&sa, 0, sizeof (sa));
65#if HAVE_SOCKADDR_IN_SIN_LEN
66 sa.sin_len = sizeof (sa);
67#endif
68 sa.sin_addr.s_addr = dst_ipv4;
69 GNUNET_NAT_run_client (h, &sa);
70 GNUNET_NAT_unregister (h);
71}
72
73
74/**
75 * Closure for 'tcp_send'.
76 */
77struct TcpContext
78{
79 /**
80 * TCP socket.
81 */
82 struct GNUNET_NETWORK_Handle *s;
83
84 /**
85 * Data to transmit.
86 */
87 uint16_t data;
88};
89
90
91/**
92 * Task called by the scheduler once we can do the TCP send
93 * (or once we failed to connect...).
94 *
95 * @param ctx the 'struct TcpContext'
96 * @param tc scheduler context
97 */
98static void
99tcp_send (void *cls,
100 const struct GNUNET_SCHEDULER_TaskContext *tc)
101{
102 struct TcpContext *ctx = cls;
103
104 if ( (NULL != tc->write_ready) &&
105 (GNUNET_NETWORK_fdset_isset (tc->write_ready,
106 ctx->s)) )
107 {
108 if (-1 == GNUNET_NETWORK_socket_send (ctx->s, &ctx->data, sizeof (ctx->data)))
109 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
110 GNUNET_NETWORK_socket_shutdown (ctx->s, SHUT_RDWR);
111 }
112 GNUNET_NETWORK_socket_close (ctx->s);
113 GNUNET_free (ctx);
114}
115
116
117/**
118 * Try to send 'data' to the
119 * IP 'dst_ipv4' at port 'dport' via TCP.
120 *
121 * @param dst_ivp4 target IP
122 * @param dport target port
123 * @param data data to send
124 */
125static void
126try_send_tcp (uint32_t dst_ipv4,
127 uint16_t dport,
128 uint16_t data)
129{
130 struct GNUNET_NETWORK_Handle *s;
131 struct sockaddr_in sa;
132 struct TcpContext *ctx;
133
134 s = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
135 if (NULL == s)
136 {
137 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket");
138 return;
139 }
140 memset (&sa, 0, sizeof (sa));
141#if HAVE_SOCKADDR_IN_SIN_LEN
142 sa.sin_len = sizeof (sa);
143#endif
144 sa.sin_addr.s_addr = dst_ipv4;
145 sa.sin_port = htons (dport);
146 if ( (GNUNET_OK !=
147 GNUNET_NETWORK_socket_connect (s,
148 (const struct sockaddr*) &sa, sizeof (sa))) &&
149 (errno != EINPROGRESS) )
150 {
151 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect");
152 GNUNET_NETWORK_socket_close (s);
153 return;
154 }
155 ctx = GNUNET_malloc (sizeof (struct TcpContext));
156 ctx->s = s;
157 ctx->data = data;
158 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_SECONDS,
159 s,
160 &tcp_send, ctx);
161}
162
163
164/**
165 * Try to send 'data' to the
166 * IP 'dst_ipv4' at port 'dport' via UDP.
167 *
168 * @param dst_ivp4 target IP
169 * @param dport target port
170 * @param data data to send
171 */
172static void
173try_send_udp (uint32_t dst_ipv4,
174 uint16_t dport,
175 uint16_t data)
176{
177 struct GNUNET_NETWORK_Handle *s;
178 struct sockaddr_in sa;
179
180 s = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_DGRAM, 0);
181 if (NULL == s)
182 {
183 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket");
184 return;
185 }
186 memset (&sa, 0, sizeof (sa));
187#if HAVE_SOCKADDR_IN_SIN_LEN
188 sa.sin_len = sizeof (sa);
189#endif
190 sa.sin_addr.s_addr = dst_ipv4;
191 sa.sin_port = htons (dport);
192 if (-1 == GNUNET_NETWORK_socket_sendto (s, &data, sizeof(data), (const struct sockaddr*) &sa, sizeof (sa)))
193 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "sendto");
194 GNUNET_NETWORK_socket_close (s);
195}
196
197
198/**
199 * We've received a request to probe a NAT
200 * traversal. Do it.
201 *
202 * @param cls unused
203 * @param client handle to client (we always close)
204 * @param msg message with details about what to test
205 */
206static void
207test (void *cls,
208 struct GNUNET_SERVER_Client *client,
209 const struct GNUNET_MessageHeader *msg)
210{
211 const struct GNUNET_NAT_TestMessage *tm;
212 uint16_t dport;
213
214 tm = (const struct GNUNET_NAT_TestMessage*) msg;
215 dport = ntohs (tm->dport);
216 if (0 == dport)
217 try_anat (tm->dst_ipv4,
218 ntohs (tm->data),
219 (int) ntohl (tm->is_tcp));
220 else if (GNUNET_YES == ntohl (tm->is_tcp))
221 try_send_tcp (tm->dst_ipv4, dport, tm->data);
222 else
223 try_send_udp (tm->dst_ipv4, dport, tm->data);
224 GNUNET_SERVER_receive_done (client,
225 GNUNET_NO);
226}
227
228
229/**
230 * Task run during shutdown.
231 *
232 * @param ctx unused
233 * @param tc scheduler context
234 */
235static void
236shutdown_task (void *cls,
237 const struct GNUNET_SCHEDULER_TaskContext *tc)
238{
239 GNUNET_SERVER_destroy (server);
240 server = NULL;
241}
242
34 243
35/** 244/**
36 * Main function that will be run. 245 * Main function that will be run.
@@ -44,11 +253,67 @@ static void
44run (void *cls, 253run (void *cls,
45 char *const *args, 254 char *const *args,
46 const char *cfgfile, 255 const char *cfgfile,
47 const struct GNUNET_CONFIGURATION_Handle * c) 256 const struct GNUNET_CONFIGURATION_Handle *c)
48{ 257{
258 static const struct GNUNET_SERVER_MessageHandler handlers[] =
259 {
260 { &test, NULL, GNUNET_MESSAGE_TYPE_NAT_TEST, sizeof (struct GNUNET_NAT_TestMessage) },
261 { NULL, NULL, 0, 0 }
262 };
263 unsigned int port;
264 struct sockaddr_in in4;
265 struct sockaddr_in6 in6;
266 socklen_t slen[] =
267 {
268 sizeof (in4),
269 sizeof (in6),
270 0
271 };
272 struct sockaddr *sa[] =
273 {
274 (struct sockaddr*) &in4,
275 (struct sockaddr*) &in6,
276 NULL
277 };
278
279 cfg = c;
280 if ( (args[0] == NULL) ||
281 (1 != SSCANF (args[0], "%u", &port)) ||
282 (0 == port) ||
283 (65536 >= port) )
284 {
285 fprintf (stderr,
286 _("Please pass valid port number as the first argument!\n"));
287 return;
288 }
289 memset (&in4, 0, sizeof (in4));
290 memset (&in6, 0, sizeof (in6));
291 in4.sin_port = htons ((uint16_t) port);
292 in6.sin6_port = htons ((uint16_t) port);
293#if HAVE_SOCKADDR_IN_SIN_LEN
294 in4.sin_len = sizeof (in);
295 in6.sin6_len = sizeof (in6);
296#endif
297 server = GNUNET_SERVER_create (NULL, NULL,
298 (struct sockaddr*const*) sa,
299 slen,
300 GNUNET_TIME_UNIT_SECONDS,
301 GNUNET_YES);
302 GNUNET_SERVER_add_handlers (server,
303 handlers);
304 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
305 &shutdown_task,
306 NULL);
49} 307}
50 308
51 309
310/**
311 * Main function of gnunet-nat-server.
312 *
313 * @param argc number of command-line arguments
314 * @param argv command line
315 * @return 0 on success, -1 on error
316 */
52int 317int
53main (int argc, char *const argv[]) 318main (int argc, char *const argv[])
54{ 319{
@@ -58,7 +323,7 @@ main (int argc, char *const argv[])
58 323
59 if (GNUNET_OK != 324 if (GNUNET_OK !=
60 GNUNET_PROGRAM_run (argc, argv, 325 GNUNET_PROGRAM_run (argc, argv,
61 "gnunet-nat-server", 326 "gnunet-nat-server [options] PORT",
62 _("GNUnet NAT traversal test helper daemon"), 327 _("GNUnet NAT traversal test helper daemon"),
63 options, 328 options,
64 &run, NULL)) 329 &run, NULL))