GNUnet  0.10.x
gnunet-helper-nat-server-windows.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2010 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 
43 #define _GNU_SOURCE
44 /* Instead of including gnunet_common.h */
45 #define GNUNET_memcpy(dst,src,n) do { if (0 != n) { (void) memcpy (dst,src,n); } } while (0)
46 
47 #define FD_SETSIZE 1024
48 #include <winsock2.h>
49 #include <ws2tcpip.h>
50 #include <sys/time.h>
51 #include <sys/types.h>
52 #include <unistd.h>
53 #include <stdio.h>
54 #include <string.h>
55 #include <errno.h>
56 #include <stdlib.h>
57 #include <stdint.h>
58 #include <time.h>
59 
63 #define VERBOSE 0
64 
68 #define DUMMY_IP "192.0.2.86"
69 
73 #define NAT_TRAV_PORT 22225
74 
78 #define PACKET_ID 256
79 
83 #define IPDEFTTL 64
84 
85 #define ICMP_ECHO 8
86 
87 #define ICMP_TIME_EXCEEDED 11
88 
92 #define ICMP_SEND_FREQUENCY_MS 500
93 
97 struct ip_header
98 {
99 
103  uint8_t vers_ihl;
104 
108  uint8_t tos;
109 
113  uint16_t pkt_len;
114 
118  uint16_t id;
119 
123  uint16_t flags_frag_offset;
124 
128  uint8_t ttl;
129 
133  uint8_t proto;
134 
138  uint16_t checksum;
139 
143  uint32_t src_ip;
144 
148  uint32_t dst_ip;
149 };
150 
155 {
156  uint8_t type;
157 
158  uint8_t code;
159 
160  uint16_t checksum;
161 
162  uint32_t unused;
163 
164  /* followed by original payload */
165 };
166 
167 struct icmp_echo_header
168 {
169  uint8_t type;
170 
171  uint8_t code;
172 
173  uint16_t checksum;
174 
175  uint32_t reserved;
176 };
177 
181 struct udp_header
182 {
183  uint16_t src_port;
184 
185  uint16_t dst_port;
186 
187  uint16_t length;
188 
189  uint16_t crc;
190 };
191 
195 static boolean privilege_testing = FALSE;
196 
201 
206 
211 
215 static struct in_addr dummy;
216 
217 
225 static uint16_t
226 calc_checksum (const uint16_t * data, unsigned int bytes)
227 {
228  uint32_t sum;
229  unsigned int i;
230 
231  sum = 0;
232  for (i = 0; i < bytes / 2; i++)
233  sum += data[i];
234  sum = (sum & 0xffff) + (sum >> 16);
235  sum = htons (0xffff - sum);
236  return sum;
237 }
238 
239 
248 static int
249 inet_pton (int af, const char *cp, struct in_addr *buf)
250 {
251  buf->s_addr = inet_addr (cp);
252  if (buf->s_addr == INADDR_NONE)
253  {
254  fprintf (stderr, "Error %d handling address %s", WSAGetLastError (), cp);
255  return 0;
256  }
257  return 1;
258 }
259 
260 
266 static void
267 send_icmp_echo (const struct in_addr *my_ip)
268 {
269  char packet[sizeof (struct ip_header) + sizeof (struct icmp_echo_header)];
270  struct icmp_echo_header icmp_echo;
271  struct ip_header ip_pkt;
272  struct sockaddr_in dst;
273  size_t off;
274  int err;
275 
276  off = 0;
277  ip_pkt.vers_ihl = 0x45;
278  ip_pkt.tos = 0;
279  ip_pkt.pkt_len = htons (sizeof (packet));
280  ip_pkt.id = htons (PACKET_ID);
281  ip_pkt.flags_frag_offset = 0;
282  ip_pkt.ttl = IPDEFTTL;
283  ip_pkt.proto = IPPROTO_ICMP;
284  ip_pkt.checksum = 0;
285  ip_pkt.src_ip = my_ip->s_addr;
286  ip_pkt.dst_ip = dummy.s_addr;
287  ip_pkt.checksum =
288  htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header)));
289  GNUNET_memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header));
290  off += sizeof (struct ip_header);
291 
292  icmp_echo.type = ICMP_ECHO;
293  icmp_echo.code = 0;
294  icmp_echo.reserved = 0;
295  icmp_echo.checksum = 0;
296  icmp_echo.checksum =
297  htons (calc_checksum
298  ((uint16_t *) & icmp_echo, sizeof (struct icmp_echo_header)));
299  GNUNET_memcpy (&packet[off], &icmp_echo, sizeof (struct icmp_echo_header));
300  off += sizeof (struct icmp_echo_header);
301 
302  memset (&dst, 0, sizeof (dst));
303  dst.sin_family = AF_INET;
304  dst.sin_addr = dummy;
305  err =
306  sendto (rawsock, packet, off, 0, (struct sockaddr *) &dst, sizeof (dst));
307  if (err < 0)
308  {
309 #if VERBOSE
310  fprintf (stderr, "sendto failed: %s\n", strerror (errno));
311 #endif
312  }
313  else if (err != off)
314  {
315  fprintf (stderr, "Error: partial send of ICMP message\n");
316  }
317 }
318 
319 
323 static void
325 {
326  struct sockaddr_in dst;
327  ssize_t err;
328 
329  memset (&dst, 0, sizeof (dst));
330  dst.sin_family = AF_INET;
331  dst.sin_addr = dummy;
332  dst.sin_port = htons (NAT_TRAV_PORT);
333  err = sendto (udpsock, NULL, 0, 0, (struct sockaddr *) &dst, sizeof (dst));
334  if (err < 0)
335  {
336 #if VERBOSE
337  fprintf (stderr, "sendto failed: %s\n", strerror (errno));
338 #endif
339  }
340  else if (0 != err)
341  {
342  fprintf (stderr, "Error: partial send of ICMP message\n");
343  }
344 }
345 
346 
350 static void
352 {
353  char buf[65536];
354  ssize_t have;
355  struct in_addr source_ip;
356  struct ip_header ip_pkt;
357  struct icmp_ttl_exceeded_header icmp_ttl;
358  struct icmp_echo_header icmp_echo;
359  struct udp_header udp_pkt;
360  size_t off;
361  uint16_t port;
362  DWORD ssize;
363 
364  have = read (icmpsock, buf, sizeof (buf));
365  if (have == -1)
366  {
367  fprintf (stderr, "Error reading raw socket: %s\n", strerror (errno));
368  return;
369  }
370 #if VERBOSE
371  fprintf (stderr, "Received message of %u bytes\n", (unsigned int) have);
372 #endif
373  if (have <
374  (ssize_t) (sizeof (struct ip_header) +
375  sizeof (struct icmp_ttl_exceeded_header) +
376  sizeof (struct ip_header)))
377  {
378  /* malformed */
379  return;
380  }
381  off = 0;
382  GNUNET_memcpy (&ip_pkt, &buf[off], sizeof (struct ip_header));
383  off += sizeof (struct ip_header);
384  GNUNET_memcpy (&source_ip, &ip_pkt.src_ip, sizeof (source_ip));
385  GNUNET_memcpy (&icmp_ttl, &buf[off], sizeof (struct icmp_ttl_exceeded_header));
386  off += sizeof (struct icmp_ttl_exceeded_header);
387  if ((ICMP_TIME_EXCEEDED != icmp_ttl.type) || (0 != icmp_ttl.code))
388  {
389  /* different type than what we want */
390  return;
391  }
392  /* skip 2nd IP header */
393  GNUNET_memcpy (&ip_pkt, &buf[off], sizeof (struct ip_header));
394  off += sizeof (struct ip_header);
395 
396  switch (ip_pkt.proto)
397  {
398  case IPPROTO_ICMP:
399  if (have !=
400  (sizeof (struct ip_header) * 2 +
401  sizeof (struct icmp_ttl_exceeded_header) +
402  sizeof (struct icmp_echo_header)))
403  {
404  /* malformed */
405  return;
406  }
407  /* grab ICMP ECHO content */
408  GNUNET_memcpy (&icmp_echo, &buf[off], sizeof (struct icmp_echo_header));
409  port = (uint16_t) ntohl (icmp_echo.reserved);
410  break;
411  case IPPROTO_UDP:
412  if (have !=
413  (sizeof (struct ip_header) * 2 +
414  sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct udp_header)))
415  {
416  /* malformed */
417  return;
418  }
419  /* grab UDP content */
420  GNUNET_memcpy (&udp_pkt, &buf[off], sizeof (struct udp_header));
421  port = ntohs (udp_pkt.length);
422  break;
423  default:
424  /* different type than what we want */
425  return;
426  }
427 
428  ssize = sizeof (buf);
429  WSAAddressToString ((LPSOCKADDR) & source_ip, sizeof (source_ip), NULL, buf,
430  &ssize);
431  if (port == 0)
432  fprintf (stdout, "%s\n", buf);
433  else
434  fprintf (stdout, "%s:%u\n", buf, (unsigned int) port);
435  fflush (stdout);
436 }
437 
438 
444 static SOCKET
446 {
447  SOCKET ret;
448 
449  ret = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
450  if (INVALID_SOCKET == ret)
451  {
452  fprintf (stderr, "Error opening RAW socket: %s\n", strerror (errno));
453  return INVALID_SOCKET;
454  }
455  return ret;
456 }
457 
458 
464 static SOCKET
466 {
467  DWORD bOptVal = TRUE;
468  int bOptLen = sizeof (bOptVal);
469 
470  rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
471  if (INVALID_SOCKET == rawsock)
472  {
473  fprintf (stderr, "Error opening RAW socket: %s\n", strerror (errno));
474  return INVALID_SOCKET;
475  }
476 
477  if (0 !=
478  setsockopt (rawsock, SOL_SOCKET, SO_BROADCAST, (char *) &bOptVal,
479  bOptLen))
480  {
481  fprintf (stderr, "Error setting SO_BROADCAST to ON: %s\n",
482  strerror (errno));
483  closesocket (rawsock);
484  return INVALID_SOCKET;
485  }
486  if (0 !=
487  setsockopt (rawsock, IPPROTO_IP, IP_HDRINCL, (char *) &bOptVal, bOptLen))
488  {
489  fprintf (stderr, "Error setting IP_HDRINCL to ON: %s\n", strerror (errno));
490  closesocket (rawsock);
491  return INVALID_SOCKET;
492  }
493  return rawsock;
494 }
495 
496 
503 static SOCKET
504 make_udp_socket (const struct in_addr *my_ip)
505 {
506  SOCKET ret;
507  struct sockaddr_in addr;
508 
509  ret = socket (AF_INET, SOCK_DGRAM, 0);
510  if (INVALID_SOCKET == ret)
511  {
512  fprintf (stderr, "Error opening UDP socket: %s\n", strerror (errno));
513  return INVALID_SOCKET;
514  }
515  memset (&addr, 0, sizeof (addr));
516  addr.sin_family = AF_INET;
517  addr.sin_addr = *my_ip;
518  addr.sin_port = htons (NAT_TRAV_PORT);
519  if (0 != bind (ret, (struct sockaddr *) &addr, sizeof (addr)))
520  {
521  fprintf (stderr, "Error binding UDP socket to port %u: %s\n", NAT_TRAV_PORT,
522  strerror (errno));
523  /* likely problematic, but not certain, try to continue */
524  }
525  return ret;
526 }
527 
528 
529 int
530 main (int argc, char *const *argv)
531 {
532  struct in_addr external;
533  fd_set rs;
534  struct timeval tv;
535  WSADATA wsaData;
536  unsigned int alt = 0;
537 
538  if ( (argc > 1) && (0 != strcmp (argv[1], "-d")))
539  {
540  privilege_testing = TRUE;
541  fprintf (stderr,
542  "%s",
543  "DEBUG: Running binary in privilege testing mode.");
544  argv++;
545  argc--;
546  }
547 
548  if (2 != argc)
549  {
550  fprintf (stderr,
551  "This program must be started with our (internal NAT) IP as the only argument.\n");
552  return 1;
553  }
554  if (1 != inet_pton (AF_INET, argv[1], &external))
555  {
556  fprintf (stderr, "Error parsing IPv4 address: %s, error %s\n", argv[1],
557  strerror (errno));
558  return 1;
559  }
560  if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy))
561  {
562  fprintf (stderr, "Internal error converting dummy IP to binary.\n");
563  return 2;
564  }
565  if (WSAStartup (MAKEWORD (2, 1), &wsaData) != 0)
566  {
567  fprintf (stderr, "Failed to find Winsock 2.1 or better.\n");
568  return 2;
569  }
571  {
572  return 3;
573  }
574  if (INVALID_SOCKET == (make_raw_socket ()))
575  {
576  closesocket (icmpsock);
577  return 3;
578  }
579  if (INVALID_SOCKET == (udpsock = make_udp_socket (&external)))
580  {
581  closesocket (icmpsock);
582  closesocket (rawsock);
583  return 3;
584  }
585 
586  while ( ! privilege_testing)
587  {
588  FD_ZERO (&rs);
589  FD_SET (icmpsock, &rs);
590  tv.tv_sec = 0;
591  tv.tv_usec = ICMP_SEND_FREQUENCY_MS * 1000;
592  if (-1 == select (icmpsock + 1, &rs, NULL, NULL, &tv))
593  {
594  if (errno == EINTR)
595  continue;
596  fprintf (stderr, "select failed: %s\n", strerror (errno));
597  break;
598  }
599  if (FD_ISSET (icmpsock, &rs))
601  if (0 == (++alt % 2))
602  send_icmp_echo (&external);
603  else
604  send_udp ();
605  }
606  /* select failed (internal error or OS out of resources) */
607  closesocket (icmpsock);
608  closesocket (rawsock);
609  closesocket (udpsock);
610  WSACleanup ();
611  if (privilege_testing)
612  return 0;
613  return 4;
614 }
615 
616 
617 /* end of gnunet-helper-nat-server-windows.c */
static SOCKET make_raw_socket()
Create an ICMP raw socket for writing.
uint32_t src_ip
Source address.
static int inet_pton(int af, const char *cp, struct in_addr *buf)
Convert IPv4 address from text to binary form.
static boolean privilege_testing
Will this binary be run in permissions testing mode?
uint16_t checksum
Header checksum.
static void process_icmp_response()
We&#39;ve received an ICMP response.
uint16_t id
Identification.
uint32_t dst_ip
Destination address.
uint8_t vers_ihl
Version (4 bits) + Internet header length (4 bits)
uint8_t tos
Type of service.
static int ret
Final status code.
Definition: gnunet-arm.c:89
static SOCKET udpsock
Socket we use to send our UDP requests.
uint16_t pkt_len
Total length.
int main(int argc, char *const *argv)
uint16_t flags_frag_offset
Flags (3 bits) + Fragment offset (13 bits)
#define INVALID_SOCKET
Definition: network.c:39
#define SOCKET(a, t, p)
Definition: plibc.h:711
static char buf[2048]
static SOCKET make_udp_socket(const struct in_addr *my_ip)
Create a UDP socket for writing.
static struct in_addr dummy
Target "dummy" address.
static SOCKET icmpsock
Socket we use to receive "fake" ICMP replies.
uint8_t ttl
Time to live.
#define IPDEFTTL
TTL to use for our outgoing messages.
#define PACKET_ID
Must match packet ID used by gnunet-helper-nat-client.c.
static void send_udp()
Send a UDP message to the dummy IP.
static void send_icmp_echo(const struct in_addr *my_ip)
Send an ICMP message to the dummy IP.
static SOCKET make_icmp_socket()
Create an ICMP raw socket for reading.
static uint16_t calc_checksum(const uint16_t *data, unsigned int bytes)
CRC-16 for IP/ICMP headers.
static uint16_t port
Port number.
Definition: gnunet-bcd.c:79
#define DUMMY_IP
Must match IP given in the client.
#define ICMP_TIME_EXCEEDED
enum GNUNET_TESTBED_UnderlayLinkModelType type
the type of this model
static SOCKET rawsock
Socket we use to send our ICMP requests.
static unsigned long long reserved
How much space have we currently reserved?
Beginning of UDP packet.
#define ICMP_SEND_FREQUENCY_MS
How often do we send our ICMP messages to receive replies?
uint32_t data
The data value.
#define NAT_TRAV_PORT
Default Port.
#define GNUNET_memcpy(dst, src, n)