GNUnet  0.10.x
gnunet-helper-nat-client-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 
44 #define _GNU_SOURCE
45 /* Instead of including gnunet_common.h */
46 #define GNUNET_memcpy(dst,src,n) do { if (0 != n) { (void) memcpy (dst,src,n); } } while (0)
47 
48 #define FD_SETSIZE 1024
49 #include <winsock2.h>
50 #include <ws2tcpip.h>
51 #include <sys/time.h>
52 #include <sys/types.h>
53 #include <unistd.h>
54 #include <stdio.h>
55 #include <string.h>
56 #include <errno.h>
57 #include <stdlib.h>
58 #include <stdint.h>
59 #include <time.h>
60 
61 
62 #define ICMP_ECHO 8
63 #define IPDEFTTL 64
64 #define ICMP_TIME_EXCEEDED 11
65 
69 #define DUMMY_IP "192.0.2.86"
70 
71 #define NAT_TRAV_PORT 22225
72 
76 struct ip_header
77 {
78 
82  uint8_t vers_ihl;
83 
87  uint8_t tos;
88 
92  uint16_t pkt_len;
93 
97  uint16_t id;
98 
103 
107  uint8_t ttl;
108 
112  uint8_t proto;
113 
117  uint16_t checksum;
118 
122  uint32_t src_ip;
123 
127  uint32_t dst_ip;
128 };
129 
130 
135 {
136  uint8_t type;
137 
138  uint8_t code;
139 
140  uint16_t checksum;
141 
142  uint32_t unused;
143 
144  /* followed by original payload */
145 };
146 
148 {
149  uint8_t type;
150 
151  uint8_t code;
152 
153  uint16_t checksum;
154 
155  uint32_t reserved;
156 };
157 
162 {
163  uint16_t src_port;
164 
165  uint16_t dst_port;
166 
167  uint16_t length;
168 
169  uint16_t crc;
170 };
171 
175 static boolean privilege_testing = FALSE;
176 
181 
185 static struct in_addr dummy;
186 
190 static uint16_t port;
191 
192 
193 
202 static int
203 inet_pton (int af, const char *cp, struct in_addr *buf)
204 {
205  buf->s_addr = inet_addr (cp);
206  if (buf->s_addr == INADDR_NONE)
207  {
208  fprintf (stderr, "Error %d handling address %s", WSAGetLastError (), cp);
209  return 0;
210  }
211  return 1;
212 }
213 
214 
222 static uint16_t
223 calc_checksum (const uint16_t * data, unsigned int bytes)
224 {
225  uint32_t sum;
226  unsigned int i;
227 
228  sum = 0;
229  for (i = 0; i < bytes / 2; i++)
230  sum += data[i];
231  sum = (sum & 0xffff) + (sum >> 16);
232  sum = htons (0xffff - sum);
233  return sum;
234 }
235 
236 
243 static void
244 send_icmp_udp (const struct in_addr *my_ip, const struct in_addr *other)
245 {
246  char packet[sizeof (struct ip_header) * 2 +
247  sizeof (struct icmp_ttl_exceeded_header) +
248  sizeof (struct udp_header)];
249  struct ip_header ip_pkt;
250  struct icmp_ttl_exceeded_header icmp_pkt;
251  struct udp_header udp_pkt;
252  struct sockaddr_in dst;
253  size_t off;
254  int err;
255 
256  /* ip header: send to (known) ip address */
257  off = 0;
258  ip_pkt.vers_ihl = 0x45;
259  ip_pkt.tos = 0;
260  ip_pkt.pkt_len = htons (sizeof (packet));
261  ip_pkt.id = htons (256);
262  ip_pkt.flags_frag_offset = 0;
263  ip_pkt.ttl = 128;
264  ip_pkt.proto = IPPROTO_ICMP;
265  ip_pkt.checksum = 0;
266  ip_pkt.src_ip = my_ip->s_addr;
267  ip_pkt.dst_ip = other->s_addr;
268  ip_pkt.checksum =
269  htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header)));
270  GNUNET_memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header));
271  off += sizeof (struct ip_header);
272 
273  icmp_pkt.type = ICMP_TIME_EXCEEDED;
274  icmp_pkt.code = 0;
275  icmp_pkt.checksum = 0;
276  icmp_pkt.unused = 0;
277  GNUNET_memcpy (&packet[off], &icmp_pkt, sizeof (struct icmp_ttl_exceeded_header));
278  off += sizeof (struct icmp_ttl_exceeded_header);
279 
280  /* ip header of the presumably 'lost' udp packet */
281  ip_pkt.vers_ihl = 0x45;
282  ip_pkt.tos = 0;
283  ip_pkt.pkt_len =
284  htons (sizeof (struct ip_header) + sizeof (struct udp_header));
285  ip_pkt.id = htons (0);
286  ip_pkt.flags_frag_offset = 0;
287  ip_pkt.ttl = 128;
288  ip_pkt.proto = IPPROTO_UDP;
289  ip_pkt.checksum = 0;
290  ip_pkt.src_ip = other->s_addr;
291  ip_pkt.dst_ip = dummy.s_addr;
292  ip_pkt.checksum =
293  htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header)));
294  GNUNET_memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header));
295  off += sizeof (struct ip_header);
296 
297  /* build UDP header */
298  udp_pkt.src_port = htons (NAT_TRAV_PORT);
299  udp_pkt.dst_port = htons (NAT_TRAV_PORT);
300  udp_pkt.length = htons (port);
301  udp_pkt.crc = 0;
302  GNUNET_memcpy (&packet[off], &udp_pkt, sizeof (struct udp_header));
303  off += sizeof (struct udp_header);
304 
305  /* no go back to calculate ICMP packet checksum */
306  icmp_pkt.checksum =
307  htons (calc_checksum
308  ((uint16_t *) & packet[off],
309  sizeof (struct icmp_ttl_exceeded_header) +
310  sizeof (struct ip_header) + sizeof (struct udp_header)));
311  GNUNET_memcpy (&packet[sizeof (struct ip_header)], &icmp_pkt,
312  sizeof (struct icmp_ttl_exceeded_header));
313 
314  memset (&dst, 0, sizeof (dst));
315  dst.sin_family = AF_INET;
316  dst.sin_addr = *other;
317  err =
318  sendto (rawsock, packet, sizeof (packet), 0, (struct sockaddr *) &dst,
319  sizeof (dst));
320  if (err < 0)
321  {
322  fprintf (stderr, "sendto failed: %s\n", strerror (errno));
323  }
324  else if (sizeof (packet) != (size_t) err)
325  {
326  fprintf (stderr, "Error: partial send of ICMP message\n");
327  }
328 }
329 
330 
337 static void
338 send_icmp (const struct in_addr *my_ip, const struct in_addr *other)
339 {
340  struct ip_header ip_pkt;
341  struct icmp_ttl_exceeded_header icmp_ttl;
342  struct icmp_echo_header icmp_echo;
343  struct sockaddr_in dst;
344  char packet[sizeof (struct ip_header) * 2 +
345  sizeof (struct icmp_ttl_exceeded_header) +
346  sizeof (struct icmp_echo_header)];
347  size_t off;
348  int err;
349 
350  /* ip header: send to (known) ip address */
351  off = 0;
352  ip_pkt.vers_ihl = 0x45;
353  ip_pkt.tos = 0;
354  ip_pkt.pkt_len = htons (sizeof (packet));
355  ip_pkt.id = htons (256);
356  ip_pkt.flags_frag_offset = 0;
357  ip_pkt.ttl = IPDEFTTL;
358  ip_pkt.proto = IPPROTO_ICMP;
359  ip_pkt.checksum = 0;
360  ip_pkt.src_ip = my_ip->s_addr;
361  ip_pkt.dst_ip = other->s_addr;
362  ip_pkt.checksum =
363  htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header)));
364  GNUNET_memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header));
365  off += sizeof (ip_pkt);
366 
367  /* icmp reply: time exceeded */
368  icmp_ttl.type = ICMP_TIME_EXCEEDED;
369  icmp_ttl.code = 0;
370  icmp_ttl.checksum = 0;
371  icmp_ttl.unused = 0;
372  GNUNET_memcpy (&packet[off], &icmp_ttl, sizeof (struct icmp_ttl_exceeded_header));
373  off += sizeof (struct icmp_ttl_exceeded_header);
374 
375  /* ip header of the presumably 'lost' udp packet */
376  ip_pkt.vers_ihl = 0x45;
377  ip_pkt.tos = 0;
378  ip_pkt.pkt_len =
379  htons (sizeof (struct ip_header) + sizeof (struct icmp_echo_header));
380  ip_pkt.id = htons (256);
381  ip_pkt.flags_frag_offset = 0;
382  ip_pkt.ttl = 1; /* real TTL would be 1 on a time exceeded packet */
383  ip_pkt.proto = IPPROTO_ICMP;
384  ip_pkt.src_ip = other->s_addr;
385  ip_pkt.dst_ip = dummy.s_addr;
386  ip_pkt.checksum = 0;
387  ip_pkt.checksum =
388  htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header)));
389  GNUNET_memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header));
390  off += sizeof (struct ip_header);
391 
392  icmp_echo.type = ICMP_ECHO;
393  icmp_echo.code = 0;
394  icmp_echo.reserved = htonl (port);
395  icmp_echo.checksum = 0;
396  icmp_echo.checksum =
397  htons (calc_checksum
398  ((uint16_t *) & icmp_echo, sizeof (struct icmp_echo_header)));
399  GNUNET_memcpy (&packet[off], &icmp_echo, sizeof (struct icmp_echo_header));
400 
401  /* no go back to calculate ICMP packet checksum */
402  off = sizeof (struct ip_header);
403  icmp_ttl.checksum =
404  htons (calc_checksum
405  ((uint16_t *) & packet[off],
406  sizeof (struct icmp_ttl_exceeded_header) +
407  sizeof (struct ip_header) + sizeof (struct icmp_echo_header)));
408  GNUNET_memcpy (&packet[off], &icmp_ttl, sizeof (struct icmp_ttl_exceeded_header));
409 
410  memset (&dst, 0, sizeof (dst));
411  dst.sin_family = AF_INET;
412  dst.sin_addr = *other;
413 
414  err =
415  sendto (rawsock, packet, sizeof (packet), 0, (struct sockaddr *) &dst,
416  sizeof (dst));
417 
418  if (err < 0)
419  {
420  fprintf (stderr, "sendto failed: %s\n", strerror (errno));
421  }
422  else if (sizeof (packet) != (size_t) err)
423  {
424  fprintf (stderr, "Error: partial send of ICMP message\n");
425  }
426 }
427 
428 
434 static SOCKET
436 {
437  DWORD bOptVal = TRUE;
438  int bOptLen = sizeof (bOptVal);
439  SOCKET ret;
440 
441  ret = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);
442  if (INVALID_SOCKET == ret)
443  {
444  fprintf (stderr, "Error opening RAW socket: %s\n", strerror (errno));
445  return INVALID_SOCKET;
446  }
447  if (0 !=
448  setsockopt (ret, SOL_SOCKET, SO_BROADCAST, (char *) &bOptVal, bOptLen))
449  {
450  fprintf (stderr, "Error setting SO_BROADCAST to ON: %s\n",
451  strerror (errno));
452  closesocket (rawsock);
453  return INVALID_SOCKET;
454  }
455 
456  if (0 != setsockopt (ret, IPPROTO_IP, IP_HDRINCL, (char *) &bOptVal, bOptLen))
457  {
458  fprintf (stderr, "Error setting IP_HDRINCL to ON: %s\n", strerror (errno));
459  closesocket (rawsock);
460  return INVALID_SOCKET;
461  }
462  return ret;
463 }
464 
465 
466 int
467 main (int argc, char *const *argv)
468 {
469  struct in_addr external;
470  struct in_addr target;
471  WSADATA wsaData;
472  unsigned int p;
473 
474  if (argc > 1 && 0 != strcmp (argv[1], "-d")){
475  privilege_testing = TRUE;
476  fprintf (stderr,
477  "%s",
478  "DEBUG: Running binary in privilege testing mode.");
479  argv++;
480  argc--;
481  }
482 
483  if (argc != 4)
484  {
485  fprintf (stderr,
486  "%s",
487  "This program must be started with our IP, the targets external IP, and our port as arguments.\n");
488  return 1;
489  }
490  if ((1 != inet_pton (AF_INET, argv[1], &external)) ||
491  (1 != inet_pton (AF_INET, argv[2], &target)))
492  {
493  fprintf (stderr,
494  "Error parsing IPv4 address: %s\n",
495  strerror (errno));
496  return 1;
497  }
498  if ((1 != sscanf (argv[3], "%u", &p)) || (0 == p) || (0xFFFF < p))
499  {
500  fprintf (stderr,
501  "Error parsing port value `%s'\n",
502  argv[3]);
503  return 1;
504  }
505  port = (uint16_t) p;
506 
507  if (0 != WSAStartup (MAKEWORD (2, 1), &wsaData))
508  {
509  fprintf (stderr,
510  "%s",
511  "Failed to find Winsock 2.1 or better.\n");
512  return 2;
513  }
514  if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy))
515  {
516  fprintf (stderr,
517  "%s",
518  "Internal error converting dummy IP to binary.\n");
519  return 2;
520  }
521  if (-1 == (rawsock = make_raw_socket ()))
522  return 3;
523  if (!privilege_testing){
524  send_icmp (&external, &target);
525  send_icmp_udp (&external, &target);
526  }
527  closesocket (rawsock);
528  WSACleanup ();
529  return 0;
530 }
531 
532 /* end of gnunet-helper-nat-client-windows.c */
static struct in_addr dummy
Target "dummy" address.
uint32_t src_ip
Source address.
static SOCKET rawsock
Socket we use to send our ICMP packets.
uint16_t checksum
Header checksum.
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.
#define DUMMY_IP
Must match IP given in the server.
static int ret
Final status code.
Definition: gnunet-arm.c:89
static void send_icmp(const struct in_addr *my_ip, const struct in_addr *other)
Send an ICMP message to the target.
uint16_t pkt_len
Total length.
#define GNUNET_memcpy(dst, src, n)
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-qr.c:59
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 SOCKET make_raw_socket()
Create an ICMP raw socket.
static char buf[2048]
static uint16_t calc_checksum(const uint16_t *data, unsigned int bytes)
CRC-16 for IP/ICMP headers.
uint8_t ttl
Time to live.
static boolean privilege_testing
Will this binary be run in permissions testing mode?
static uint16_t port
Port we are listening on (communicated to the server).
static void send_icmp_udp(const struct in_addr *my_ip, const struct in_addr *other)
Send an ICMP message to the target.
static int inet_pton(int af, const char *cp, struct in_addr *buf)
Convert IPv4 address from text to binary form.
Beginning of UDP packet.
#define ICMP_TIME_EXCEEDED
uint32_t data
The data value.
int main(int argc, char *const *argv)