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 {
101  uint8_t vers_ihl;
102 
106  uint8_t tos;
107 
111  uint16_t pkt_len;
112 
116  uint16_t id;
117 
121  uint16_t flags_frag_offset;
122 
126  uint8_t ttl;
127 
131  uint8_t proto;
132 
136  uint16_t checksum;
137 
141  uint32_t src_ip;
142 
146  uint32_t dst_ip;
147 };
148 
153  uint8_t type;
154 
155  uint8_t code;
156 
157  uint16_t checksum;
158 
159  uint32_t unused;
160 
161  /* followed by original payload */
162 };
163 
164 struct icmp_echo_header {
165  uint8_t type;
166 
167  uint8_t code;
168 
169  uint16_t checksum;
170 
171  uint32_t reserved;
172 };
173 
177 struct udp_header {
178  uint16_t src_port;
179 
180  uint16_t dst_port;
181 
182  uint16_t length;
183 
184  uint16_t crc;
185 };
186 
190 static boolean privilege_testing = FALSE;
191 
195 static _win_socket icmpsock;
196 
200 static _win_socket rawsock;
201 
205 static _win_socket udpsock;
206 
210 static struct in_addr dummy;
211 
212 
220 static uint16_t
221 calc_checksum(const uint16_t * data, unsigned int bytes)
222 {
223  uint32_t sum;
224  unsigned int i;
225 
226  sum = 0;
227  for (i = 0; i < bytes / 2; i++)
228  sum += data[i];
229  sum = (sum & 0xffff) + (sum >> 16);
230  sum = htons(0xffff - sum);
231  return sum;
232 }
233 
234 
243 static int
244 inet_pton(int af, const char *cp, struct in_addr *buf)
245 {
246  buf->s_addr = inet_addr(cp);
247  if (buf->s_addr == INADDR_NONE)
248  {
249  fprintf(stderr, "Error %d handling address %s", WSAGetLastError(), cp);
250  return 0;
251  }
252  return 1;
253 }
254 
255 
261 static void
262 send_icmp_echo(const struct in_addr *my_ip)
263 {
264  char packet[sizeof(struct ip_header) + sizeof(struct icmp_echo_header)];
265  struct icmp_echo_header icmp_echo;
266  struct ip_header ip_pkt;
267  struct sockaddr_in dst;
268  size_t off;
269  int err;
270 
271  off = 0;
272  ip_pkt.vers_ihl = 0x45;
273  ip_pkt.tos = 0;
274  ip_pkt.pkt_len = htons(sizeof(packet));
275  ip_pkt.id = htons(PACKET_ID);
276  ip_pkt.flags_frag_offset = 0;
277  ip_pkt.ttl = IPDEFTTL;
278  ip_pkt.proto = IPPROTO_ICMP;
279  ip_pkt.checksum = 0;
280  ip_pkt.src_ip = my_ip->s_addr;
281  ip_pkt.dst_ip = dummy.s_addr;
282  ip_pkt.checksum =
283  htons(calc_checksum((uint16_t *)&ip_pkt, sizeof(struct ip_header)));
284  GNUNET_memcpy(&packet[off], &ip_pkt, sizeof(struct ip_header));
285  off += sizeof(struct ip_header);
286 
287  icmp_echo.type = ICMP_ECHO;
288  icmp_echo.code = 0;
289  icmp_echo.reserved = 0;
290  icmp_echo.checksum = 0;
291  icmp_echo.checksum =
292  htons(calc_checksum
293  ((uint16_t *)&icmp_echo, sizeof(struct icmp_echo_header)));
294  GNUNET_memcpy(&packet[off], &icmp_echo, sizeof(struct icmp_echo_header));
295  off += sizeof(struct icmp_echo_header);
296 
297  memset(&dst, 0, sizeof(dst));
298  dst.sin_family = AF_INET;
299  dst.sin_addr = dummy;
300  err =
301  sendto(rawsock, packet, off, 0, (struct sockaddr *)&dst, sizeof(dst));
302  if (err < 0)
303  {
304 #if VERBOSE
305  fprintf(stderr, "sendto failed: %s\n", strerror(errno));
306 #endif
307  }
308  else if (err != off)
309  {
310  fprintf(stderr, "Error: partial send of ICMP message\n");
311  }
312 }
313 
314 
318 static void
320 {
321  struct sockaddr_in dst;
322  ssize_t err;
323 
324  memset(&dst, 0, sizeof(dst));
325  dst.sin_family = AF_INET;
326  dst.sin_addr = dummy;
327  dst.sin_port = htons(NAT_TRAV_PORT);
328  err = sendto(udpsock, NULL, 0, 0, (struct sockaddr *)&dst, sizeof(dst));
329  if (err < 0)
330  {
331 #if VERBOSE
332  fprintf(stderr, "sendto failed: %s\n", strerror(errno));
333 #endif
334  }
335  else if (0 != err)
336  {
337  fprintf(stderr, "Error: partial send of ICMP message\n");
338  }
339 }
340 
341 
345 static void
347 {
348  char buf[65536];
349  ssize_t have;
350  struct in_addr source_ip;
351  struct ip_header ip_pkt;
352  struct icmp_ttl_exceeded_header icmp_ttl;
353  struct icmp_echo_header icmp_echo;
354  struct udp_header udp_pkt;
355  size_t off;
356  uint16_t port;
357  DWORD ssize;
358 
359  have = read(icmpsock, buf, sizeof(buf));
360  if (have == -1)
361  {
362  fprintf(stderr, "Error reading raw socket: %s\n", strerror(errno));
363  return;
364  }
365 #if VERBOSE
366  fprintf(stderr, "Received message of %u bytes\n", (unsigned int)have);
367 #endif
368  if (have <
369  (ssize_t)(sizeof(struct ip_header) +
370  sizeof(struct icmp_ttl_exceeded_header) +
371  sizeof(struct ip_header)))
372  {
373  /* malformed */
374  return;
375  }
376  off = 0;
377  GNUNET_memcpy(&ip_pkt, &buf[off], sizeof(struct ip_header));
378  off += sizeof(struct ip_header);
379  GNUNET_memcpy(&source_ip, &ip_pkt.src_ip, sizeof(source_ip));
380  GNUNET_memcpy(&icmp_ttl, &buf[off], sizeof(struct icmp_ttl_exceeded_header));
381  off += sizeof(struct icmp_ttl_exceeded_header);
382  if ((ICMP_TIME_EXCEEDED != icmp_ttl.type) || (0 != icmp_ttl.code))
383  {
384  /* different type than what we want */
385  return;
386  }
387  /* skip 2nd IP header */
388  GNUNET_memcpy(&ip_pkt, &buf[off], sizeof(struct ip_header));
389  off += sizeof(struct ip_header);
390 
391  switch (ip_pkt.proto)
392  {
393  case IPPROTO_ICMP:
394  if (have !=
395  (sizeof(struct ip_header) * 2 +
396  sizeof(struct icmp_ttl_exceeded_header) +
397  sizeof(struct icmp_echo_header)))
398  {
399  /* malformed */
400  return;
401  }
402  /* grab ICMP ECHO content */
403  GNUNET_memcpy(&icmp_echo, &buf[off], sizeof(struct icmp_echo_header));
404  port = (uint16_t)ntohl(icmp_echo.reserved);
405  break;
406 
407  case IPPROTO_UDP:
408  if (have !=
409  (sizeof(struct ip_header) * 2 +
410  sizeof(struct icmp_ttl_exceeded_header) + sizeof(struct udp_header)))
411  {
412  /* malformed */
413  return;
414  }
415  /* grab UDP content */
416  GNUNET_memcpy(&udp_pkt, &buf[off], sizeof(struct udp_header));
417  port = ntohs(udp_pkt.length);
418  break;
419 
420  default:
421  /* different type than what we want */
422  return;
423  }
424 
425  ssize = sizeof(buf);
426  WSAAddressToString((LPSOCKADDR)&source_ip, sizeof(source_ip), NULL, buf,
427  &ssize);
428  if (port == 0)
429  fprintf(stdout, "%s\n", buf);
430  else
431  fprintf(stdout, "%s:%u\n", buf, (unsigned int)port);
432  fflush(stdout);
433 }
434 
435 
441 static _win_socket
443 {
444  _win_socket ret;
445 
446  ret = _win_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
447  if (INVALID_SOCKET == ret)
448  {
449  fprintf(stderr, "Error opening RAW socket: %s\n", strerror(errno));
450  return INVALID_SOCKET;
451  }
452  return ret;
453 }
454 
455 
461 static _win_socket
463 {
464  DWORD bOptVal = TRUE;
465  int bOptLen = sizeof(bOptVal);
466 
467  rawsock = _win_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
468  if (INVALID_SOCKET == rawsock)
469  {
470  fprintf(stderr, "Error opening RAW socket: %s\n", strerror(errno));
471  return INVALID_SOCKET;
472  }
473 
474  if (0 !=
475  _win_setsockopt(rawsock, SOL_SOCKET, SO_BROADCAST, (char *)&bOptVal,
476  bOptLen))
477  {
478  fprintf(stderr, "Error setting SO_BROADCAST to ON: %s\n",
479  strerror(errno));
480  closesocket(rawsock);
481  return INVALID_SOCKET;
482  }
483  if (0 !=
484  _win_setsockopt(rawsock, IPPROTO_IP, IP_HDRINCL, (char *)&bOptVal, bOptLen))
485  {
486  fprintf(stderr, "Error setting IP_HDRINCL to ON: %s\n", strerror(errno));
487  closesocket(rawsock);
488  return INVALID_SOCKET;
489  }
490  return rawsock;
491 }
492 
493 
500 static _win_socket
501 make_udp_socket(const struct in_addr *my_ip)
502 {
503  _win_socket ret;
504  struct sockaddr_in addr;
505 
506  ret = _win_socket(AF_INET, SOCK_DGRAM, 0);
507  if (INVALID_SOCKET == ret)
508  {
509  fprintf(stderr, "Error opening UDP socket: %s\n", strerror(errno));
510  return INVALID_SOCKET;
511  }
512  memset(&addr, 0, sizeof(addr));
513  addr.sin_family = AF_INET;
514  addr.sin_addr = *my_ip;
515  addr.sin_port = htons(NAT_TRAV_PORT);
516  if (0 != bind(ret, (struct sockaddr *)&addr, sizeof(addr)))
517  {
518  fprintf(stderr, "Error binding UDP socket to port %u: %s\n", NAT_TRAV_PORT,
519  strerror(errno));
520  /* likely problematic, but not certain, try to continue */
521  }
522  return ret;
523 }
524 
525 
526 int
527 main(int argc, char *const *argv)
528 {
529  struct in_addr external;
530  fd_set rs;
531  struct timeval tv;
532  WSADATA wsaData;
533  unsigned int alt = 0;
534 
535  if ((argc > 1) && (0 != strcmp(argv[1], "-d")))
536  {
537  privilege_testing = TRUE;
538  fprintf(stderr,
539  "%s",
540  "DEBUG: Running binary in privilege testing mode.");
541  argv++;
542  argc--;
543  }
544 
545  if (2 != argc)
546  {
547  fprintf(stderr,
548  "This program must be started with our (internal NAT) IP as the only argument.\n");
549  return 1;
550  }
551  if (1 != inet_pton(AF_INET, argv[1], &external))
552  {
553  fprintf(stderr, "Error parsing IPv4 address: %s, error %s\n", argv[1],
554  strerror(errno));
555  return 1;
556  }
557  if (1 != inet_pton(AF_INET, DUMMY_IP, &dummy))
558  {
559  fprintf(stderr, "Internal error converting dummy IP to binary.\n");
560  return 2;
561  }
562  if (WSAStartup(MAKEWORD(2, 1), &wsaData) != 0)
563  {
564  fprintf(stderr, "Failed to find Winsock 2.1 or better.\n");
565  return 2;
566  }
568  {
569  return 3;
570  }
571  if (INVALID_SOCKET == (make_raw_socket()))
572  {
573  closesocket(icmpsock);
574  return 3;
575  }
576  if (INVALID_SOCKET == (udpsock = make_udp_socket(&external)))
577  {
578  closesocket(icmpsock);
579  closesocket(rawsock);
580  return 3;
581  }
582 
583  while (!privilege_testing)
584  {
585  FD_ZERO(&rs);
586  FD_SET(icmpsock, &rs);
587  tv.tv_sec = 0;
588  tv.tv_usec = ICMP_SEND_FREQUENCY_MS * 1000;
589  if (-1 == select(icmpsock + 1, &rs, NULL, NULL, &tv))
590  {
591  if (errno == EINTR)
592  continue;
593  fprintf(stderr, "select failed: %s\n", strerror(errno));
594  break;
595  }
596  if (FD_ISSET(icmpsock, &rs))
598  if (0 == (++alt % 2))
599  send_icmp_echo(&external);
600  else
601  send_udp();
602  }
603  /* select failed (internal error or OS out of resources) */
604  closesocket(icmpsock);
605  closesocket(rawsock);
606  closesocket(udpsock);
607  WSACleanup();
608  if (privilege_testing)
609  return 0;
610  return 4;
611 }
612 
613 
614 /* end of gnunet-helper-nat-server-windows.c */
static _win_socket udpsock
Socket we use to send our UDP requests.
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 _win_socket make_raw_socket()
Create an ICMP raw socket for writing.
static int ret
Final status code.
Definition: gnunet-arm.c:89
static _win_socket icmpsock
Socket we use to receive "fake" ICMP replies.
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
static char buf[2048]
static struct in_addr dummy
Target "dummy" address.
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 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:81
static _win_socket rawsock
Socket we use to send our ICMP requests.
#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 _win_socket make_udp_socket(const struct in_addr *my_ip)
Create a UDP socket for writing.
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?
static _win_socket make_icmp_socket()
Create an ICMP raw socket for reading.
uint32_t data
The data value.
#define NAT_TRAV_PORT
Default Port.
#define GNUNET_memcpy(dst, src, n)