use LOG macro in nat.c
[oweals/gnunet.git] / src / nat / gnunet-helper-nat-server-windows.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010 Christian Grothoff (and other contributing authors)
4
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
7      by the Free Software Foundation; either version 3, or (at your
8      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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file src/nat/gnunet-helper-nat-server-windows.c
23  * @brief Windows tool to help bypass NATs using ICMP method
24  *        This code will work under W32 only
25  * @author Christian Grothoff
26  *
27  * This program will send ONE ICMP message every 500 ms RAW sockets
28  * to a DUMMY IP address and also listens for ICMP replies.  Since
29  * it uses RAW sockets, it must be run as an administrative user.
30  * In order to keep the security risk of the resulting binary
31  * minimal, the program ONLY opens the two RAW sockets with administrative
32  * privileges, then drops them and only then starts to process
33  * command line arguments.  The code also does not link against
34  * any shared libraries (except libc) and is strictly minimal
35  * (except for checking for errors).  The following list of people
36  * have reviewed this code and considered it safe since the last
37  * modification (if you reviewed it, please have your name added
38  * to the list):
39  *
40  * - Nathan Evans
41  * - Christian Grothoff
42  */
43 #define _GNU_SOURCE
44
45
46 #include <winsock2.h>
47 #include <ws2tcpip.h>
48 #include <sys/time.h>
49 #include <sys/types.h>
50 #include <unistd.h>
51 #include <stdio.h>
52 #include <string.h>
53 #include <errno.h>
54 #include <stdlib.h>
55 #include <stdint.h>
56 #include <time.h>
57
58 /**
59  * Should we print some debug output?
60  */
61 #define VERBOSE 0
62
63 /**
64  * Must match IP given in the client.
65  */
66 #define DUMMY_IP "192.0.2.86"
67
68 /**
69  * Default Port
70  */
71 #define NAT_TRAV_PORT 22225
72
73 /**
74  * TTL to use for our outgoing messages.
75  */
76 #define IPDEFTTL 64
77
78 #define ICMP_ECHO 8
79
80 #define ICMP_TIME_EXCEEDED 11
81
82 /**
83  * How often do we send our ICMP messages to receive replies?
84  */
85 #define ICMP_SEND_FREQUENCY_MS 500
86
87 /**
88  * IPv4 header.
89  */
90 struct ip_header
91 {
92
93   /**
94    * Version (4 bits) + Internet header length (4 bits)
95    */
96   uint8_t vers_ihl;
97
98   /**
99    * Type of service
100    */
101   uint8_t tos;
102
103   /**
104    * Total length
105    */
106   uint16_t pkt_len;
107
108   /**
109    * Identification
110    */
111   uint16_t id;
112
113   /**
114    * Flags (3 bits) + Fragment offset (13 bits)
115    */
116   uint16_t flags_frag_offset;
117
118   /**
119    * Time to live
120    */
121   uint8_t ttl;
122
123   /**
124    * Protocol
125    */
126   uint8_t proto;
127
128   /**
129    * Header checksum
130    */
131   uint16_t checksum;
132
133   /**
134    * Source address
135    */
136   uint32_t src_ip;
137
138   /**
139    * Destination address
140    */
141   uint32_t dst_ip;
142 };
143
144 /**
145  * Format of ICMP packet.
146  */
147 struct icmp_ttl_exceeded_header
148 {
149   uint8_t type;
150
151   uint8_t code;
152
153   uint16_t checksum;
154
155   uint32_t unused;
156
157   /* followed by original payload */
158 };
159
160 struct icmp_echo_header
161 {
162   uint8_t type;
163
164   uint8_t code;
165
166   uint16_t checksum;
167
168   uint32_t reserved;
169 };
170
171 /**
172  * Beginning of UDP packet.
173  */
174 struct udp_header
175 {
176   uint16_t src_port;
177
178   uint16_t dst_port;
179
180   uint16_t length;
181
182   uint16_t crc;
183 };
184
185 /**
186  * Socket we use to receive "fake" ICMP replies.
187  */
188 static SOCKET icmpsock;
189
190 /**
191  * Socket we use to send our ICMP requests.
192  */
193 static SOCKET rawsock;
194
195 /**
196  * Socket we use to send our UDP requests.
197  */
198 static SOCKET udpsock;
199
200 /**
201  * Target "dummy" address.
202  */
203 static struct in_addr dummy;
204
205
206 /**
207  * CRC-16 for IP/ICMP headers.
208  *
209  * @param data what to calculate the CRC over
210  * @param bytes number of bytes in data (must be multiple of 2)
211  * @return the CRC 16.
212  */
213 static uint16_t
214 calc_checksum (const uint16_t * data, unsigned int bytes)
215 {
216   uint32_t sum;
217   unsigned int i;
218
219   sum = 0;
220   for (i = 0; i < bytes / 2; i++)
221     sum += data[i];
222   sum = (sum & 0xffff) + (sum >> 16);
223   sum = htons (0xffff - sum);
224   return sum;
225 }
226
227
228 /**
229  * Convert IPv4 address from text to binary form.
230  *
231  * @param af address family
232  * @param cp the address to print
233  * @param buf where to write the address result
234  * @return 1 on success
235  */
236 static int
237 inet_pton (int af, const char *cp, struct in_addr *buf)
238 {
239   buf->s_addr = inet_addr (cp);
240   if (buf->s_addr == INADDR_NONE)
241   {
242     fprintf (stderr, "Error %d handling address %s", WSAGetLastError (), cp);
243     return 0;
244   }
245   return 1;
246 }
247
248
249 /**
250  * Send an ICMP message to the dummy IP.
251  *
252  * @param my_ip source address (our ip address)
253  */
254 static void
255 send_icmp_echo (const struct in_addr *my_ip)
256 {
257   char packet[sizeof (struct ip_header) + sizeof (struct icmp_echo_header)];
258   struct icmp_echo_header icmp_echo;
259   struct ip_header ip_pkt;
260   struct sockaddr_in dst;
261   size_t off;
262   int err;
263
264   off = 0;
265   ip_pkt.vers_ihl = 0x45;
266   ip_pkt.tos = 0;
267   ip_pkt.pkt_len = htons (sizeof (packet));
268   ip_pkt.id = htons (256);
269   ip_pkt.flags_frag_offset = 0;
270   ip_pkt.ttl = IPDEFTTL;
271   ip_pkt.proto = IPPROTO_ICMP;
272   ip_pkt.checksum = 0;
273   ip_pkt.src_ip = my_ip->s_addr;
274   ip_pkt.dst_ip = dummy.s_addr;
275   ip_pkt.checksum =
276       htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header)));
277   memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header));
278   off += sizeof (struct ip_header);
279
280   icmp_echo.type = ICMP_ECHO;
281   icmp_echo.code = 0;
282   icmp_echo.reserved = 0;
283   icmp_echo.checksum = 0;
284   icmp_echo.checksum =
285       htons (calc_checksum
286              ((uint16_t *) & icmp_echo, sizeof (struct icmp_echo_header)));
287   memcpy (&packet[off], &icmp_echo, sizeof (struct icmp_echo_header));
288   off += sizeof (struct icmp_echo_header);
289
290   memset (&dst, 0, sizeof (dst));
291   dst.sin_family = AF_INET;
292   dst.sin_addr = dummy;
293   err =
294       sendto (rawsock, packet, off, 0, (struct sockaddr *) &dst, sizeof (dst));
295   if (err < 0)
296   {
297 #if VERBOSE
298     fprintf (stderr, "sendto failed: %s\n", strerror (errno));
299 #endif
300   }
301   else if (err != off)
302   {
303     fprintf (stderr, "Error: partial send of ICMP message\n");
304   }
305 }
306
307
308 /**
309  * Send a UDP message to the dummy IP.
310  */
311 static void
312 send_udp ()
313 {
314   struct sockaddr_in dst;
315   ssize_t err;
316
317   memset (&dst, 0, sizeof (dst));
318   dst.sin_family = AF_INET;
319   dst.sin_addr = dummy;
320   dst.sin_port = htons (NAT_TRAV_PORT);
321   err = sendto (udpsock, NULL, 0, 0, (struct sockaddr *) &dst, sizeof (dst));
322   if (err < 0)
323   {
324 #if VERBOSE
325     fprintf (stderr, "sendto failed: %s\n", strerror (errno));
326 #endif
327   }
328   else if (0 != err)
329   {
330     fprintf (stderr, "Error: partial send of ICMP message\n");
331   }
332 }
333
334
335 /**
336  * We've received an ICMP response.  Process it.
337  */
338 static void
339 process_icmp_response ()
340 {
341   char buf[65536];
342   ssize_t have;
343   struct in_addr source_ip;
344   struct ip_header ip_pkt;
345   struct icmp_ttl_exceeded_header icmp_ttl;
346   struct icmp_echo_header icmp_echo;
347   struct udp_header udp_pkt;
348   size_t off;
349   uint16_t port;
350   DWORD ssize;
351
352   have = read (icmpsock, buf, sizeof (buf));
353   if (have == -1)
354   {
355     fprintf (stderr, "Error reading raw socket: %s\n", strerror (errno));
356     return;
357   }
358 #if VERBOSE
359   fprintf (stderr, "Received message of %u bytes\n", (unsigned int) have);
360 #endif
361   if (have <
362       (ssize_t) (sizeof (struct ip_header) +
363                  sizeof (struct icmp_ttl_exceeded_header) +
364                  sizeof (struct ip_header)))
365   {
366     /* malformed */
367     return;
368   }
369   off = 0;
370   memcpy (&ip_pkt, &buf[off], sizeof (struct ip_header));
371   off += sizeof (struct ip_header);
372   memcpy (&source_ip, &ip_pkt.src_ip, sizeof (source_ip));
373   memcpy (&icmp_ttl, &buf[off], sizeof (struct icmp_ttl_exceeded_header));
374   off += sizeof (struct icmp_ttl_exceeded_header);
375   if ((ICMP_TIME_EXCEEDED != icmp_ttl.type) || (0 != icmp_ttl.code))
376   {
377     /* different type than what we want */
378     return;
379   }
380   /* skip 2nd IP header */
381   memcpy (&ip_pkt, &buf[off], sizeof (struct ip_header));
382   off += sizeof (struct ip_header);
383
384   switch (ip_pkt.proto)
385   {
386   case IPPROTO_ICMP:
387     if (have !=
388         (sizeof (struct ip_header) * 2 +
389          sizeof (struct icmp_ttl_exceeded_header) +
390          sizeof (struct icmp_echo_header)))
391     {
392       /* malformed */
393       return;
394     }
395     /* grab ICMP ECHO content */
396     memcpy (&icmp_echo, &buf[off], sizeof (struct icmp_echo_header));
397     port = (uint16_t) ntohl (icmp_echo.reserved);
398     break;
399   case IPPROTO_UDP:
400     if (have !=
401         (sizeof (struct ip_header) * 2 +
402          sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct udp_header)))
403     {
404       /* malformed */
405       return;
406     }
407     /* grab UDP content */
408     memcpy (&udp_pkt, &buf[off], sizeof (struct udp_header));
409     port = ntohs (udp_pkt.length);
410     break;
411   default:
412     /* different type than what we want */
413     return;
414   }
415
416   ssize = sizeof (buf);
417   WSAAddressToString ((LPSOCKADDR) & source_ip, sizeof (source_ip), NULL, buf,
418                       &ssize);
419   if (port == 0)
420     fprintf (stdout, "%s\n", buf);
421   else
422     fprintf (stdout, "%s:%u\n", buf, (unsigned int) port);
423   fflush (stdout);
424 }
425
426
427 /**
428  * Create an ICMP raw socket for reading.
429  *
430  * @return INVALID_SOCKET on error
431  */
432 static SOCKET
433 make_icmp_socket ()
434 {
435   SOCKET ret;
436
437   ret = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
438   if (INVALID_SOCKET == ret)
439   {
440     fprintf (stderr, "Error opening RAW socket: %s\n", strerror (errno));
441     return INVALID_SOCKET;
442   }
443   return ret;
444 }
445
446
447 /**
448  * Create an ICMP raw socket for writing.
449  *
450  * @return INVALID_SOCKET on error
451  */
452 static SOCKET
453 make_raw_socket ()
454 {
455   DWORD bOptVal = TRUE;
456   int bOptLen = sizeof (bOptVal);
457
458   rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
459   if (INVALID_SOCKET == rawsock)
460   {
461     fprintf (stderr, "Error opening RAW socket: %s\n", strerror (errno));
462     return INVALID_SOCKET;
463   }
464
465   if (0 !=
466       setsockopt (rawsock, SOL_SOCKET, SO_BROADCAST, (char *) &bOptVal,
467                   bOptLen))
468   {
469     fprintf (stderr, "Error setting SO_BROADCAST to ON: %s\n",
470              strerror (errno));
471     closesocket (rawsock);
472     return INVALID_SOCKET;
473   }
474   if (0 !=
475       setsockopt (rawsock, IPPROTO_IP, IP_HDRINCL, (char *) &bOptVal, bOptLen))
476   {
477     fprintf (stderr, "Error setting IP_HDRINCL to ON: %s\n", strerror (errno));
478     closesocket (rawsock);
479     return INVALID_SOCKET;
480   }
481   return rawsock;
482 }
483
484
485 /**
486  * Create a UDP socket for writing.
487  *
488  * @param my_ip source address (our ip address)
489  * @return INVALID_SOCKET on error
490  */
491 static SOCKET
492 make_udp_socket (const struct in_addr *my_ip)
493 {
494   SOCKET ret;
495   struct sockaddr_in addr;
496
497   ret = socket (AF_INET, SOCK_DGRAM, 0);
498   if (INVALID_SOCKET == ret)
499   {
500     fprintf (stderr, "Error opening UDP socket: %s\n", strerror (errno));
501     return INVALID_SOCKET;
502   }
503   memset (&addr, 0, sizeof (addr));
504   addr.sin_family = AF_INET;
505   addr.sin_addr = *my_ip;
506   addr.sin_port = htons (NAT_TRAV_PORT);
507   if (0 != bind (ret, (struct sockaddr *) &addr, sizeof (addr)))
508   {
509     fprintf (stderr, "Error binding UDP socket to port %u: %s\n", NAT_TRAV_PORT,
510              strerror (errno));
511     /* likely problematic, but not certain, try to continue */
512   }
513   return ret;
514 }
515
516
517 int
518 main (int argc, char *const *argv)
519 {
520   struct in_addr external;
521   fd_set rs;
522   struct timeval tv;
523   WSADATA wsaData;
524   unsigned int alt;
525
526   alt = 0;
527   if (2 != argc)
528   {
529     fprintf (stderr,
530              "This program must be started with our (internal NAT) IP as the only argument.\n");
531     return 1;
532   }
533   if (1 != inet_pton (AF_INET, argv[1], &external))
534   {
535     fprintf (stderr, "Error parsing IPv4 address: %s, error %s\n", argv[1],
536              strerror (errno));
537     return 1;
538   }
539   if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy))
540   {
541     fprintf (stderr, "Internal error converting dummy IP to binary.\n");
542     return 2;
543   }
544   if (WSAStartup (MAKEWORD (2, 1), &wsaData) != 0)
545   {
546     fprintf (stderr, "Failed to find Winsock 2.1 or better.\n");
547     return 2;
548   }
549   if (INVALID_SOCKET == (icmpsock = make_icmp_socket ()))
550   {
551     return 3;
552   }
553   if (INVALID_SOCKET == (make_raw_socket ()))
554   {
555     closesocket (icmpsock);
556     return 3;
557   }
558   if (INVALID_SOCKET == (udpsock = make_udp_socket (&external)))
559   {
560     closesocket (icmpsock);
561     closesocket (rawsock);
562     return 3;
563   }
564   while (1)
565   {
566     FD_ZERO (&rs);
567     FD_SET (icmpsock, &rs);
568     tv.tv_sec = 0;
569     tv.tv_usec = ICMP_SEND_FREQUENCY_MS * 1000;
570     if (-1 == select (icmpsock + 1, &rs, NULL, NULL, &tv))
571     {
572       if (errno == EINTR)
573         continue;
574       fprintf (stderr, "select failed: %s\n", strerror (errno));
575       break;
576     }
577     if (FD_ISSET (icmpsock, &rs))
578       process_icmp_response ();
579     if (0 == (++alt % 2))
580       send_icmp_echo (&external);
581     else
582       send_udp ();
583   }
584   /* select failed (internal error or OS out of resources) */
585   closesocket (icmpsock);
586   closesocket (rawsock);
587   closesocket (udpsock);
588   WSACleanup ();
589   return 4;
590 }
591
592
593 /* end of gnunet-helper-nat-server-windows.c */