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 for 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 _win_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 _win_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 for 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 198 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().

199 {
200  buf->s_addr = inet_addr(cp);
201  if (buf->s_addr == INADDR_NONE)
202  {
203  fprintf(stderr, "Error %d handling address %s", WSAGetLastError(), cp);
204  return 0;
205  }
206  return 1;
207 }
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 218 of file gnunet-helper-nat-client-windows.c.

Referenced by send_icmp(), and send_icmp_udp().

219 {
220  uint32_t sum;
221  unsigned int i;
222 
223  sum = 0;
224  for (i = 0; i < bytes / 2; i++)
225  sum += data[i];
226  sum = (sum & 0xffff) + (sum >> 16);
227  sum = htons(0xffff - sum);
228  return sum;
229 }
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 239 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().

240 {
241  char packet[sizeof(struct ip_header) * 2 +
242  sizeof(struct icmp_ttl_exceeded_header) +
243  sizeof(struct udp_header)];
244  struct ip_header ip_pkt;
245  struct icmp_ttl_exceeded_header icmp_pkt;
246  struct udp_header udp_pkt;
247  struct sockaddr_in dst;
248  size_t off;
249  int err;
250 
251  /* ip header: send to (known) ip address */
252  off = 0;
253  ip_pkt.vers_ihl = 0x45;
254  ip_pkt.tos = 0;
255  ip_pkt.pkt_len = htons(sizeof(packet));
256  ip_pkt.id = htons(256);
257  ip_pkt.flags_frag_offset = 0;
258  ip_pkt.ttl = 128;
259  ip_pkt.proto = IPPROTO_ICMP;
260  ip_pkt.checksum = 0;
261  ip_pkt.src_ip = my_ip->s_addr;
262  ip_pkt.dst_ip = other->s_addr;
263  ip_pkt.checksum =
264  htons(calc_checksum((uint16_t *)&ip_pkt, sizeof(struct ip_header)));
265  GNUNET_memcpy(&packet[off], &ip_pkt, sizeof(struct ip_header));
266  off += sizeof(struct ip_header);
267 
268  icmp_pkt.type = ICMP_TIME_EXCEEDED;
269  icmp_pkt.code = 0;
270  icmp_pkt.checksum = 0;
271  icmp_pkt.unused = 0;
272  GNUNET_memcpy(&packet[off], &icmp_pkt, sizeof(struct icmp_ttl_exceeded_header));
273  off += sizeof(struct icmp_ttl_exceeded_header);
274 
275  /* ip header of the presumably 'lost' udp packet */
276  ip_pkt.vers_ihl = 0x45;
277  ip_pkt.tos = 0;
278  ip_pkt.pkt_len =
279  htons(sizeof(struct ip_header) + sizeof(struct udp_header));
280  ip_pkt.id = htons(0);
281  ip_pkt.flags_frag_offset = 0;
282  ip_pkt.ttl = 128;
283  ip_pkt.proto = IPPROTO_UDP;
284  ip_pkt.checksum = 0;
285  ip_pkt.src_ip = other->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  /* build UDP header */
293  udp_pkt.src_port = htons(NAT_TRAV_PORT);
294  udp_pkt.dst_port = htons(NAT_TRAV_PORT);
295  udp_pkt.length = htons(port);
296  udp_pkt.crc = 0;
297  GNUNET_memcpy(&packet[off], &udp_pkt, sizeof(struct udp_header));
298  off += sizeof(struct udp_header);
299 
300  /* no go back to calculate ICMP packet checksum */
301  icmp_pkt.checksum =
302  htons(calc_checksum
303  ((uint16_t *)&packet[off],
304  sizeof(struct icmp_ttl_exceeded_header) +
305  sizeof(struct ip_header) + sizeof(struct udp_header)));
306  GNUNET_memcpy(&packet[sizeof(struct ip_header)], &icmp_pkt,
307  sizeof(struct icmp_ttl_exceeded_header));
308 
309  memset(&dst, 0, sizeof(dst));
310  dst.sin_family = AF_INET;
311  dst.sin_addr = *other;
312  err =
313  sendto(rawsock, packet, sizeof(packet), 0, (struct sockaddr *)&dst,
314  sizeof(dst));
315  if (err < 0)
316  {
317  fprintf(stderr, "sendto failed: %s\n", strerror(errno));
318  }
319  else if (sizeof(packet) != (size_t)err)
320  {
321  fprintf(stderr, "Error: partial send of ICMP message\n");
322  }
323 }
static struct in_addr dummy
Target "dummy" address.
#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).
static _win_socket rawsock
Socket we use to send our ICMP packets.
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 333 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, 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().

334 {
335  struct ip_header ip_pkt;
336  struct icmp_ttl_exceeded_header icmp_ttl;
337  struct icmp_echo_header icmp_echo;
338  struct sockaddr_in dst;
339  char packet[sizeof(struct ip_header) * 2 +
340  sizeof(struct icmp_ttl_exceeded_header) +
341  sizeof(struct icmp_echo_header)];
342  size_t off;
343  int err;
344 
345  /* ip header: send to (known) ip address */
346  off = 0;
347  ip_pkt.vers_ihl = 0x45;
348  ip_pkt.tos = 0;
349  ip_pkt.pkt_len = htons(sizeof(packet));
350  ip_pkt.id = htons(256);
351  ip_pkt.flags_frag_offset = 0;
352  ip_pkt.ttl = IPDEFTTL;
353  ip_pkt.proto = IPPROTO_ICMP;
354  ip_pkt.checksum = 0;
355  ip_pkt.src_ip = my_ip->s_addr;
356  ip_pkt.dst_ip = other->s_addr;
357  ip_pkt.checksum =
358  htons(calc_checksum((uint16_t *)&ip_pkt, sizeof(struct ip_header)));
359  GNUNET_memcpy(&packet[off], &ip_pkt, sizeof(struct ip_header));
360  off += sizeof(ip_pkt);
361 
362  /* icmp reply: time exceeded */
363  icmp_ttl.type = ICMP_TIME_EXCEEDED;
364  icmp_ttl.code = 0;
365  icmp_ttl.checksum = 0;
366  icmp_ttl.unused = 0;
367  GNUNET_memcpy(&packet[off], &icmp_ttl, sizeof(struct icmp_ttl_exceeded_header));
368  off += sizeof(struct icmp_ttl_exceeded_header);
369 
370  /* ip header of the presumably 'lost' udp packet */
371  ip_pkt.vers_ihl = 0x45;
372  ip_pkt.tos = 0;
373  ip_pkt.pkt_len =
374  htons(sizeof(struct ip_header) + sizeof(struct icmp_echo_header));
375  ip_pkt.id = htons(256);
376  ip_pkt.flags_frag_offset = 0;
377  ip_pkt.ttl = 1; /* real TTL would be 1 on a time exceeded packet */
378  ip_pkt.proto = IPPROTO_ICMP;
379  ip_pkt.src_ip = other->s_addr;
380  ip_pkt.dst_ip = dummy.s_addr;
381  ip_pkt.checksum = 0;
382  ip_pkt.checksum =
383  htons(calc_checksum((uint16_t *)&ip_pkt, sizeof(struct ip_header)));
384  GNUNET_memcpy(&packet[off], &ip_pkt, sizeof(struct ip_header));
385  off += sizeof(struct ip_header);
386 
387  icmp_echo.type = ICMP_ECHO;
388  icmp_echo.code = 0;
389  icmp_echo.reserved = htonl(port);
390  icmp_echo.checksum = 0;
391  icmp_echo.checksum =
392  htons(calc_checksum
393  ((uint16_t *)&icmp_echo, sizeof(struct icmp_echo_header)));
394  GNUNET_memcpy(&packet[off], &icmp_echo, sizeof(struct icmp_echo_header));
395 
396  /* no go back to calculate ICMP packet checksum */
397  off = sizeof(struct ip_header);
398  icmp_ttl.checksum =
399  htons(calc_checksum
400  ((uint16_t *)&packet[off],
401  sizeof(struct icmp_ttl_exceeded_header) +
402  sizeof(struct ip_header) + sizeof(struct icmp_echo_header)));
403  GNUNET_memcpy(&packet[off], &icmp_ttl, sizeof(struct icmp_ttl_exceeded_header));
404 
405  memset(&dst, 0, sizeof(dst));
406  dst.sin_family = AF_INET;
407  dst.sin_addr = *other;
408 
409  err =
410  sendto(rawsock, packet, sizeof(packet), 0, (struct sockaddr *)&dst,
411  sizeof(dst));
412 
413  if (err < 0)
414  {
415  fprintf(stderr, "sendto failed: %s\n", strerror(errno));
416  }
417  else if (sizeof(packet) != (size_t)err)
418  {
419  fprintf(stderr, "Error: partial send of ICMP message\n");
420  }
421 }
static struct in_addr dummy
Target "dummy" address.
#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).
static _win_socket rawsock
Socket we use to send our ICMP packets.
#define ICMP_TIME_EXCEEDED
Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_raw_socket()

static _win_socket make_raw_socket ( )
static

Create an ICMP raw socket.

Returns
INVALID_SOCKET on error

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

References INVALID_SOCKET, rawsock, and ret.

Referenced by main().

431 {
432  DWORD bOptVal = TRUE;
433  int bOptLen = sizeof(bOptVal);
434  _win_socket ret;
435 
436  ret = _win_socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
437  if (INVALID_SOCKET == ret)
438  {
439  fprintf(stderr, "Error opening RAW socket: %s\n", strerror(errno));
440  return INVALID_SOCKET;
441  }
442  if (0 !=
443  _win_setsockopt(ret, SOL_SOCKET, SO_BROADCAST, (char *)&bOptVal, bOptLen))
444  {
445  fprintf(stderr, "Error setting SO_BROADCAST to ON: %s\n",
446  strerror(errno));
447  closesocket(rawsock);
448  return INVALID_SOCKET;
449  }
450 
451  if (0 != _win_setsockopt(ret, IPPROTO_IP, IP_HDRINCL, (char *)&bOptVal, bOptLen))
452  {
453  fprintf(stderr, "Error setting IP_HDRINCL to ON: %s\n", strerror(errno));
454  closesocket(rawsock);
455  return INVALID_SOCKET;
456  }
457  return ret;
458 }
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define INVALID_SOCKET
Definition: network.c:39
static _win_socket rawsock
Socket we use to send our ICMP packets.
Here is the caller graph for this function:

◆ main()

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

Definition at line 462 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().

463 {
464  struct in_addr external;
465  struct in_addr target;
466  WSADATA wsaData;
467  unsigned int p;
468 
469  if (argc > 1 && 0 != strcmp(argv[1], "-d"))
470  {
471  privilege_testing = TRUE;
472  fprintf(stderr,
473  "%s",
474  "DEBUG: Running binary in privilege testing mode.");
475  argv++;
476  argc--;
477  }
478 
479  if (argc != 4)
480  {
481  fprintf(stderr,
482  "%s",
483  "This program must be started with our IP, the targets external IP, and our port as arguments.\n");
484  return 1;
485  }
486  if ((1 != inet_pton(AF_INET, argv[1], &external)) ||
487  (1 != inet_pton(AF_INET, argv[2], &target)))
488  {
489  fprintf(stderr,
490  "Error parsing IPv4 address: %s\n",
491  strerror(errno));
492  return 1;
493  }
494  if ((1 != sscanf(argv[3], "%u", &p)) || (0 == p) || (0xFFFF < p))
495  {
496  fprintf(stderr,
497  "Error parsing port value `%s'\n",
498  argv[3]);
499  return 1;
500  }
501  port = (uint16_t)p;
502 
503  if (0 != WSAStartup(MAKEWORD(2, 1), &wsaData))
504  {
505  fprintf(stderr,
506  "%s",
507  "Failed to find Winsock 2.1 or better.\n");
508  return 2;
509  }
510  if (1 != inet_pton(AF_INET, DUMMY_IP, &dummy))
511  {
512  fprintf(stderr,
513  "%s",
514  "Internal error converting dummy IP to binary.\n");
515  return 2;
516  }
517  if (-1 == (rawsock = make_raw_socket()))
518  return 3;
519  if (!privilege_testing)
520  {
521  send_icmp(&external, &target);
522  send_icmp_udp(&external, &target);
523  }
524  closesocket(rawsock);
525  WSACleanup();
526  return 0;
527 }
static struct in_addr dummy
Target "dummy" address.
#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 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 _win_socket rawsock
Socket we use to send our ICMP packets.
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.
static _win_socket make_raw_socket()
Create an ICMP raw socket.
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 170 of file gnunet-helper-nat-client-windows.c.

Referenced by main().

◆ rawsock

_win_socket rawsock
static

Socket we use to send our ICMP packets.

Definition at line 175 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 185 of file gnunet-helper-nat-client-windows.c.

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