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

Tool to help bypass NATs using ICMP method; must run as administrator on W32 This code is forx W32. 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-client-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 ICMP_ECHO   8
 
#define IPDEFTTL   64
 
#define ICMP_TIME_EXCEEDED   11
 
#define DUMMY_IP   "192.0.2.86"
 Must match IP given in the server. More...
 
#define NAT_TRAV_PORT   22225
 

Functions

static int inet_pton (int af, const char *cp, struct in_addr *buf)
 Convert IPv4 address from text to binary form. More...
 
static uint16_t calc_checksum (const uint16_t *data, unsigned int bytes)
 CRC-16 for IP/ICMP headers. More...
 
static void send_icmp_udp (const struct in_addr *my_ip, const struct in_addr *other)
 Send an ICMP message to the target. More...
 
static void send_icmp (const struct in_addr *my_ip, const struct in_addr *other)
 Send an ICMP message to the target. More...
 
static SOCKET make_raw_socket ()
 Create an ICMP raw socket. 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 SOCKET rawsock
 Socket we use to send our ICMP packets. More...
 
static struct in_addr dummy
 Target "dummy" address. More...
 
static uint16_t port
 Port we are listening on (communicated to the server). More...
 

Detailed Description

Tool to help bypass NATs using ICMP method; must run as administrator on W32 This code is forx W32.

Author
Nathan Evans

This program will send ONE ICMP message using RAW sockets to the IP address specified as the second argument. Since it uses RAW sockets, it must be installed SUID or run as 'root'. In order to keep the security risk of the resulting SUID binary minimal, the program ONLY opens the RAW socket with root 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-client-windows.c.

Macro Definition Documentation

◆ _GNU_SOURCE

#define _GNU_SOURCE

Definition at line 44 of file gnunet-helper-nat-client-windows.c.

◆ GNUNET_memcpy

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

Definition at line 46 of file gnunet-helper-nat-client-windows.c.

Referenced by send_icmp(), and send_icmp_udp().

◆ FD_SETSIZE

#define FD_SETSIZE   1024

Definition at line 48 of file gnunet-helper-nat-client-windows.c.

◆ ICMP_ECHO

#define ICMP_ECHO   8

Definition at line 62 of file gnunet-helper-nat-client-windows.c.

Referenced by send_icmp(), and send_icmp_echo().

◆ IPDEFTTL

#define IPDEFTTL   64

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

Referenced by send_icmp(), and send_icmp_echo().

◆ ICMP_TIME_EXCEEDED

#define ICMP_TIME_EXCEEDED   11

Definition at line 64 of file gnunet-helper-nat-client-windows.c.

Referenced by send_icmp(), and send_icmp_udp().

◆ DUMMY_IP

#define DUMMY_IP   "192.0.2.86"

Must match IP given in the server.

Definition at line 69 of file gnunet-helper-nat-client-windows.c.

Referenced by main().

◆ NAT_TRAV_PORT

#define NAT_TRAV_PORT   22225

Definition at line 71 of file gnunet-helper-nat-client-windows.c.

Referenced by send_icmp_udp().

Function Documentation

◆ 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 203 of file gnunet-helper-nat-client-windows.c.

Referenced by add_services(), allocate_v4_address(), allocate_v6_address(), check_config(), dns_string_to_value(), EnumNICs3(), extract_hosts(), gns_resolve_name(), GNUNET_DNSSTUB_add_dns_ip(), GNUNET_HOSTLIST_server_start(), GNUNET_RESOLVER_ip_get(), GNUNET_SOCKS_set_handshake_destination(), GNUNET_STRINGS_parse_ipv6_policy(), GNUNET_STRINGS_to_address_ipv6(), iface_proc(), libgnunet_plugin_transport_udp_init(), lookup_hole_external(), main(), match_ipv4(), match_ipv6(), modify_record(), nat_server_read(), numeric_resolution(), process_map_output(), process_refresh_output(), read_external_ipv4(), recursive_gns2dns_resolution(), run(), server_configure_plugin(), set_address4(), set_address6(), setup_broadcast(), setup_exit_helper_args(), start_resolver_lookup(), tcp_address_to_sockaddr(), try_ifconfig(), try_ip(), and udp_address_to_sockaddr().

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

◆ 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 223 of file gnunet-helper-nat-client-windows.c.

Referenced by send_icmp(), and send_icmp_udp().

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

◆ send_icmp_udp()

static void send_icmp_udp ( const struct in_addr *  my_ip,
const struct in_addr *  other 
)
static

Send an ICMP message to the target.

Parameters
my_ipsource address
othertarget address

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

References calc_checksum(), ip_header::checksum, icmp_ttl_exceeded_header::checksum, icmp_ttl_exceeded_header::code, udp_header::crc, ip_header::dst_ip, udp_header::dst_port, dummy, ip_header::flags_frag_offset, GNUNET_memcpy, ICMP_TIME_EXCEEDED, ip_header::id, udp_header::length, NAT_TRAV_PORT, ip_header::pkt_len, port, ip_header::proto, rawsock, ip_header::src_ip, udp_header::src_port, ip_header::tos, ip_header::ttl, icmp_ttl_exceeded_header::type, icmp_ttl_exceeded_header::unused, and ip_header::vers_ihl.

Referenced by main().

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 }
static struct in_addr dummy
Target "dummy" address.
static SOCKET rawsock
Socket we use to send our ICMP packets.
#define GNUNET_memcpy(dst, src, n)
static uint16_t calc_checksum(const uint16_t *data, unsigned int bytes)
CRC-16 for IP/ICMP headers.
static uint16_t port
Port we are listening on (communicated to the server).
Beginning of UDP packet.
#define ICMP_TIME_EXCEEDED
Here is the call graph for this function:
Here is the caller graph for this function:

◆ send_icmp()

static void send_icmp ( const struct in_addr *  my_ip,
const struct in_addr *  other 
)
static

Send an ICMP message to the target.

Parameters
my_ipsource address
othertarget address

Definition at line 338 of file gnunet-helper-nat-client-windows.c.

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

Referenced by main().

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 }
static struct in_addr dummy
Target "dummy" address.
static SOCKET rawsock
Socket we use to send our ICMP packets.
#define GNUNET_memcpy(dst, src, n)
static uint16_t calc_checksum(const uint16_t *data, unsigned int bytes)
CRC-16 for IP/ICMP headers.
static uint16_t port
Port we are listening on (communicated to the server).
#define ICMP_TIME_EXCEEDED
Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_raw_socket()

static SOCKET make_raw_socket ( )
static

Create an ICMP raw socket.

Returns
INVALID_SOCKET on error

Definition at line 435 of file gnunet-helper-nat-client-windows.c.

References INVALID_SOCKET, rawsock, ret, and SOCKET.

Referenced by main().

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 }
static SOCKET rawsock
Socket we use to send our ICMP packets.
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define INVALID_SOCKET
Definition: network.c:39
#define SOCKET(a, t, p)
Definition: plibc.h:711
Here is the caller graph for this function:

◆ main()

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

Definition at line 467 of file gnunet-helper-nat-client-windows.c.

References dummy, DUMMY_IP, inet_pton(), make_raw_socket(), p, port, privilege_testing, rawsock, send_icmp(), and send_icmp_udp().

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 }
static struct in_addr dummy
Target "dummy" address.
static SOCKET rawsock
Socket we use to send our ICMP packets.
#define DUMMY_IP
Must match IP given in the server.
static void send_icmp(const struct in_addr *my_ip, const struct in_addr *other)
Send an ICMP message to the target.
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-qr.c:59
static SOCKET make_raw_socket()
Create an ICMP raw socket.
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.
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 175 of file gnunet-helper-nat-client-windows.c.

Referenced by main().

◆ rawsock

SOCKET rawsock
static

Socket we use to send our ICMP packets.

Definition at line 180 of file gnunet-helper-nat-client-windows.c.

Referenced by main(), make_raw_socket(), send_icmp(), and send_icmp_udp().

◆ dummy

struct in_addr dummy
static

◆ port

uint16_t port
static

Port we are listening on (communicated to the server).

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

Referenced by main(), send_icmp(), and send_icmp_udp().