GNUnet  0.10.x
Data Structures | Macros | Functions | Variables
gnunet-helper-nat-server-windows.c File Reference

Windows tool to help bypass NATs using ICMP method This code will work under W32 only. More...

#include <winsock2.h>
#include <ws2tcpip.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
Include dependency graph for gnunet-helper-nat-server-windows.c:

Go to the source code of this file.

Data Structures

struct  ip_header
 IPv4 header. More...
 
struct  icmp_ttl_exceeded_header
 Format of ICMP packet. More...
 
struct  icmp_echo_header
 
struct  udp_header
 Beginning of UDP packet. More...
 

Macros

#define _GNU_SOURCE
 
#define GNUNET_memcpy(dst, src, n)   do { if (0 != n) { (void)memcpy(dst, src, n); } } while (0)
 
#define FD_SETSIZE   1024
 
#define VERBOSE   0
 Should we print some debug output? More...
 
#define DUMMY_IP   "192.0.2.86"
 Must match IP given in the client. More...
 
#define NAT_TRAV_PORT   22225
 Default Port. More...
 
#define PACKET_ID   256
 Must match packet ID used by gnunet-helper-nat-client.c. More...
 
#define IPDEFTTL   64
 TTL to use for our outgoing messages. More...
 
#define ICMP_ECHO   8
 
#define ICMP_TIME_EXCEEDED   11
 
#define ICMP_SEND_FREQUENCY_MS   500
 How often do we send our ICMP messages to receive replies? More...
 

Functions

static uint16_t calc_checksum (const uint16_t *data, unsigned int bytes)
 CRC-16 for IP/ICMP headers. More...
 
static int inet_pton (int af, const char *cp, struct in_addr *buf)
 Convert IPv4 address from text to binary form. More...
 
static void send_icmp_echo (const struct in_addr *my_ip)
 Send an ICMP message to the dummy IP. More...
 
static void send_udp ()
 Send a UDP message to the dummy IP. More...
 
static void process_icmp_response ()
 We've received an ICMP response. More...
 
static _win_socket make_icmp_socket ()
 Create an ICMP raw socket for reading. More...
 
static _win_socket make_raw_socket ()
 Create an ICMP raw socket for writing. More...
 
static _win_socket make_udp_socket (const struct in_addr *my_ip)
 Create a UDP socket for writing. More...
 
int main (int argc, char *const *argv)
 

Variables

static boolean privilege_testing = FALSE
 Will this binary be run in permissions testing mode? More...
 
static _win_socket icmpsock
 Socket we use to receive "fake" ICMP replies. More...
 
static _win_socket rawsock
 Socket we use to send our ICMP requests. More...
 
static _win_socket udpsock
 Socket we use to send our UDP requests. More...
 
static struct in_addr dummy
 Target "dummy" address. More...
 

Detailed Description

Windows tool to help bypass NATs using ICMP method This code will work under W32 only.

Author
Christian Grothoff

This program will send ONE ICMP message every 500 ms RAW sockets to a DUMMY IP address and also listens for ICMP replies. Since it uses RAW sockets, it must be run as an administrative user. In order to keep the security risk of the resulting binary minimal, the program ONLY opens the two RAW sockets with administrative privileges, then drops them and only then starts to process command line arguments. The code also does not link against any shared libraries (except libc) and is strictly minimal (except for checking for errors). The following list of people have reviewed this code and considered it safe since the last modification (if you reviewed it, please have your name added to the list):

Definition in file gnunet-helper-nat-server-windows.c.

Macro Definition Documentation

◆ _GNU_SOURCE

#define _GNU_SOURCE

Definition at line 43 of file gnunet-helper-nat-server-windows.c.

◆ GNUNET_memcpy

#define GNUNET_memcpy (   dst,
  src,
 
)    do { if (0 != n) { (void)memcpy(dst, src, n); } } while (0)

Definition at line 45 of file gnunet-helper-nat-server-windows.c.

Referenced by process_icmp_response(), and send_icmp_echo().

◆ FD_SETSIZE

#define FD_SETSIZE   1024

Definition at line 47 of file gnunet-helper-nat-server-windows.c.

◆ VERBOSE

#define VERBOSE   0

Should we print some debug output?

Definition at line 63 of file gnunet-helper-nat-server-windows.c.

◆ DUMMY_IP

#define DUMMY_IP   "192.0.2.86"

Must match IP given in the client.

Definition at line 68 of file gnunet-helper-nat-server-windows.c.

Referenced by main().

◆ NAT_TRAV_PORT

#define NAT_TRAV_PORT   22225

Default Port.

Definition at line 73 of file gnunet-helper-nat-server-windows.c.

Referenced by make_udp_socket(), and send_udp().

◆ PACKET_ID

#define PACKET_ID   256

Must match packet ID used by gnunet-helper-nat-client.c.

Definition at line 78 of file gnunet-helper-nat-server-windows.c.

Referenced by send_icmp_echo().

◆ IPDEFTTL

#define IPDEFTTL   64

TTL to use for our outgoing messages.

Definition at line 83 of file gnunet-helper-nat-server-windows.c.

Referenced by send_icmp_echo().

◆ ICMP_ECHO

#define ICMP_ECHO   8

Definition at line 85 of file gnunet-helper-nat-server-windows.c.

Referenced by send_icmp_echo().

◆ ICMP_TIME_EXCEEDED

#define ICMP_TIME_EXCEEDED   11

Definition at line 87 of file gnunet-helper-nat-server-windows.c.

Referenced by process_icmp_response().

◆ ICMP_SEND_FREQUENCY_MS

#define ICMP_SEND_FREQUENCY_MS   500

How often do we send our ICMP messages to receive replies?

Definition at line 92 of file gnunet-helper-nat-server-windows.c.

Referenced by main().

Function Documentation

◆ calc_checksum()

static uint16_t calc_checksum ( const uint16_t *  data,
unsigned int  bytes 
)
static

CRC-16 for IP/ICMP headers.

Parameters
datawhat to calculate the CRC over
bytesnumber of bytes in data (must be multiple of 2)
Returns
the CRC 16.

Definition at line 221 of file gnunet-helper-nat-server-windows.c.

Referenced by send_icmp_echo().

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 }
uint32_t data
The data value.
Here is the caller graph for this function:

◆ inet_pton()

static int inet_pton ( int  af,
const char *  cp,
struct in_addr *  buf 
)
static

Convert IPv4 address from text to binary form.

Parameters
afaddress family
cpthe address to print
bufwhere to write the address result
Returns
1 on success

Definition at line 244 of file gnunet-helper-nat-server-windows.c.

Referenced by main().

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 }
static char buf[2048]
Here is the caller graph for this function:

◆ send_icmp_echo()

static void send_icmp_echo ( const struct in_addr *  my_ip)
static

Send an ICMP message to the dummy IP.

Parameters
my_ipsource address (our ip address)

Definition at line 262 of file gnunet-helper-nat-server-windows.c.

References calc_checksum(), ip_header::checksum, icmp_echo_header::checksum, icmp_echo_header::code, ip_header::dst_ip, dummy, ip_header::flags_frag_offset, GNUNET_memcpy, ICMP_ECHO, ip_header::id, IPDEFTTL, PACKET_ID, ip_header::pkt_len, ip_header::proto, rawsock, icmp_echo_header::reserved, ip_header::src_ip, ip_header::tos, ip_header::ttl, icmp_echo_header::type, and ip_header::vers_ihl.

Referenced by main().

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 }
uint8_t vers_ihl
Version (4 bits) + Internet header length (4 bits)
static struct in_addr dummy
Target "dummy" address.
#define IPDEFTTL
TTL to use for our outgoing messages.
#define PACKET_ID
Must match packet ID used by gnunet-helper-nat-client.c.
static uint16_t calc_checksum(const uint16_t *data, unsigned int bytes)
CRC-16 for IP/ICMP headers.
static _win_socket rawsock
Socket we use to send our ICMP requests.
#define GNUNET_memcpy(dst, src, n)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ send_udp()

static void send_udp ( )
static

Send a UDP message to the dummy IP.

Definition at line 319 of file gnunet-helper-nat-server-windows.c.

References dummy, NAT_TRAV_PORT, and udpsock.

Referenced by main().

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 }
static _win_socket udpsock
Socket we use to send our UDP requests.
static struct in_addr dummy
Target "dummy" address.
#define NAT_TRAV_PORT
Default Port.
Here is the caller graph for this function:

◆ process_icmp_response()

static void process_icmp_response ( )
static

We've received an ICMP response.

Process it.

Definition at line 346 of file gnunet-helper-nat-server-windows.c.

References buf, icmp_ttl_exceeded_header::code, GNUNET_memcpy, ICMP_TIME_EXCEEDED, icmpsock, udp_header::length, port, ip_header::proto, icmp_echo_header::reserved, ip_header::src_ip, and icmp_ttl_exceeded_header::type.

Referenced by main().

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 }
static _win_socket icmpsock
Socket we use to receive "fake" ICMP replies.
static char buf[2048]
static uint16_t port
Port number.
Definition: gnunet-bcd.c:81
#define ICMP_TIME_EXCEEDED
Beginning of UDP packet.
#define GNUNET_memcpy(dst, src, n)
Here is the caller graph for this function:

◆ make_icmp_socket()

static _win_socket make_icmp_socket ( )
static

Create an ICMP raw socket for reading.

Returns
INVALID_SOCKET on error

Definition at line 442 of file gnunet-helper-nat-server-windows.c.

References INVALID_SOCKET, and ret.

Referenced by main().

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 }
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define INVALID_SOCKET
Definition: network.c:39
Here is the caller graph for this function:

◆ make_raw_socket()

static _win_socket make_raw_socket ( )
static

Create an ICMP raw socket for writing.

Returns
INVALID_SOCKET on error

Definition at line 462 of file gnunet-helper-nat-server-windows.c.

References INVALID_SOCKET, and rawsock.

Referenced by main().

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 }
#define INVALID_SOCKET
Definition: network.c:39
static _win_socket rawsock
Socket we use to send our ICMP requests.
Here is the caller graph for this function:

◆ make_udp_socket()

static _win_socket make_udp_socket ( const struct in_addr *  my_ip)
static

Create a UDP socket for writing.

Parameters
my_ipsource address (our ip address)
Returns
INVALID_SOCKET on error

Definition at line 501 of file gnunet-helper-nat-server-windows.c.

References INVALID_SOCKET, NAT_TRAV_PORT, and ret.

Referenced by main().

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 }
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define INVALID_SOCKET
Definition: network.c:39
#define NAT_TRAV_PORT
Default Port.
Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char *const *  argv 
)

Definition at line 527 of file gnunet-helper-nat-server-windows.c.

References dummy, DUMMY_IP, ICMP_SEND_FREQUENCY_MS, icmpsock, inet_pton(), INVALID_SOCKET, make_icmp_socket(), make_raw_socket(), make_udp_socket(), privilege_testing, process_icmp_response(), rawsock, send_icmp_echo(), send_udp(), and udpsock.

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 }
static _win_socket udpsock
Socket we use to send our UDP requests.
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?
static void process_icmp_response()
We&#39;ve received an ICMP response.
static _win_socket make_raw_socket()
Create an ICMP raw socket for writing.
static _win_socket icmpsock
Socket we use to receive "fake" ICMP replies.
#define INVALID_SOCKET
Definition: network.c:39
static struct in_addr dummy
Target "dummy" address.
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 _win_socket rawsock
Socket we use to send our ICMP requests.
#define DUMMY_IP
Must match IP given in the client.
static _win_socket make_udp_socket(const struct in_addr *my_ip)
Create a UDP socket for writing.
#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.
Here is the call graph for this function:

Variable Documentation

◆ privilege_testing

boolean privilege_testing = FALSE
static

Will this binary be run in permissions testing mode?

Definition at line 190 of file gnunet-helper-nat-server-windows.c.

Referenced by main().

◆ icmpsock

_win_socket icmpsock
static

Socket we use to receive "fake" ICMP replies.

Definition at line 195 of file gnunet-helper-nat-server-windows.c.

Referenced by main(), and process_icmp_response().

◆ rawsock

_win_socket rawsock
static

Socket we use to send our ICMP requests.

Definition at line 200 of file gnunet-helper-nat-server-windows.c.

Referenced by main(), make_raw_socket(), and send_icmp_echo().

◆ udpsock

_win_socket udpsock
static

Socket we use to send our UDP requests.

Definition at line 205 of file gnunet-helper-nat-server-windows.c.

Referenced by main(), and send_udp().

◆ dummy

struct in_addr dummy
static

Target "dummy" address.

Definition at line 210 of file gnunet-helper-nat-server-windows.c.

Referenced by main(), send_icmp_echo(), and send_udp().