GNUnet  0.10.x
Data Structures | Macros | Typedefs | Enumerations | Functions | Variables
gnunet-helper-exit-windows.c File Reference

the helper for the EXIT service in win32 builds. More...

#include <stdio.h>
#include <Winsock2.h>
#include <windows.h>
#include <setupapi.h>
#include <ddk/cfgmgr32.h>
#include <ddk/newdev.h>
#include <time.h>
#include "platform.h"
#include "tap-windows.h"
#include "gnunet_crypto_lib.h"
#include "gnunet_common.h"
#include "gnunet_protocols.h"
Include dependency graph for gnunet-helper-exit-windows.c:

Go to the source code of this file.

Data Structures

struct  io_facility
 A IO Object + read/writebuffer + buffer-size for windows asynchronous IO handling. More...
 

Macros

#define DEBUG   GNUNET_NO
 Need 'struct GNUNET_HashCode' and 'struct GNUNET_PeerIdentity'. More...
 
#define LOG_DEBUG(msg)   do {} while (0)
 
#define MAX_SIZE   65536
 Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE) More...
 
#define INF_FILE   "share/gnunet/openvpn-tap32/tapw32/OemWin2k.inf"
 Name or Path+Name of our win32 driver. More...
 
#define INF_FILE64   "share/gnunet/openvpn-tap32/tapw64/OemWin2k.inf"
 Name or Path+Name of our win64 driver. More...
 
#define HARDWARE_ID   "tap0901"
 Hardware ID used in the inf-file. More...
 
#define TAP_WIN_MIN_MAJOR   9
 Minimum major-id of the driver version we can work with. More...
 
#define TAP_WIN_MIN_MINOR   9
 Minimum minor-id of the driver version we can work with. More...
 
#define TAP32_POSTUP_WAITTIME   4
 Time in seconds to wait for our virtual device to go up after telling it to do so. More...
 
#define INTERFACE_REGISTRY_LOCATION   "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
 Location of the network interface list resides in registry. More...
 

Typedefs

typedef BOOL(WINAPI * LPFN_ISWOW64PROCESS) (HANDLE, PBOOL)
 IsWow64Process definition for our is_win64, as this is a kernel function. More...
 

Enumerations

enum  IO_State {
  IOSTATE_READY = 0, IOSTATE_QUEUED, IOSTATE_WAITING, IOSTATE_RESUME,
  IOSTATE_FAILED, IOSTATE_READY = 0, IOSTATE_QUEUED, IOSTATE_WAITING,
  IOSTATE_RESUME, IOSTATE_FAILED
}
 Possible states of an IO facility. More...
 

Functions

WINBASEAPI HANDLE WINAPI ReOpenFile (HANDLE, DWORD, DWORD, DWORD)
 ReOpenFile is only available as of XP SP2 and 2003 SP1. More...
 
size_t GNUNET_strlcpy (char *dst, const char *src, size_t n)
 Like strlcpy but portable. More...
 
BOOL is_win64 ()
 Determines if the host OS is win32 or win64. More...
 
static int execute_shellcommand (const char *command)
 Wrapper for executing a shellcommand in windows. More...
 
static int set_address6 (const char *address, unsigned long prefix_len)
 Sets the IPv6-Address given in address on the interface dev. More...
 
static void remove_address6 (const char *address)
 Removes the IPv6-Address given in address from the interface dev. More...
 
static int set_address4 (const char *address, const char *mask)
 Sets the IPv4-Address given in address on the interface dev. More...
 
static void remove_address4 (const char *address)
 Removes the IPv4-Address given in address from the interface dev. More...
 
static BOOL setup_interface ()
 Setup a new virtual interface to use for tunneling. More...
 
static BOOL remove_interface ()
 Remove our new virtual interface to use for tunneling. More...
 
static BOOL resolve_interface_name ()
 Do all the lookup necessary to retrieve the inteface's actual name off the registry. More...
 
static BOOL check_tapw32_version (HANDLE handle)
 Determines the version of the installed TAP32 driver and checks if it's sufficiently new for GNUNET. More...
 
static HANDLE init_tun ()
 Creates a tun-interface called dev;. More...
 
static BOOL tun_up (HANDLE handle)
 Brings a TAP device up and sets it to connected state. More...
 
static BOOL attempt_read_tap (struct io_facility *input_facility, struct io_facility *output_facility)
 Attempts to read off an input facility (tap or named pipe) in overlapped mode. More...
 
static BOOL attempt_read_stdin (struct io_facility *input_facility, struct io_facility *output_facility)
 Attempts to read off an input facility (tap or named pipe) in overlapped mode. More...
 
static BOOL attempt_write (struct io_facility *output_facility, struct io_facility *input_facility)
 Attempts to write to an output facility (tap or named pipe) in overlapped mode. More...
 
static BOOL initialize_io_facility (struct io_facility *elem, int initial_state, BOOL signaled)
 Initialize a overlapped structure. More...
 
static void run (HANDLE tap_handle)
 Start forwarding to and from the tunnel. More...
 
int main (int argc, char **argv)
 Open VPN tunnel interface. More...
 

Variables

static boolean privilege_testing = FALSE
 Will this binary be run in permissions testing mode? More...
 
static char secondary_hwid [LINE_LEN/2]
 Our local process' PID. More...
 
static char device_visible_name [256]
 Device's visible Name, used to identify a network device in netsh. More...
 
static HDEVINFO DeviceInfo = INVALID_HANDLE_VALUE
 This is our own local instance of a virtual network interface It is (somewhat) equivalent to using tun/tap in unixoid systems. More...
 
static SP_DEVINFO_DATA DeviceNode
 Registry Key we hand over to windows to spawn a new virtual interface. More...
 
static char device_guid [256]
 GUID of our virtual device in the form of {12345678-1234-1234-1234-123456789abc} - in hex. More...
 

Detailed Description

the helper for the EXIT service in win32 builds.

Opens a virtual network-interface, sends data received on the if to stdout, sends data received on stdin to the interface

Author
Christian M. Fuchs

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-exit-windows.c.

Macro Definition Documentation

◆ DEBUG

#define DEBUG   GNUNET_NO

Need 'struct GNUNET_HashCode' and 'struct GNUNET_PeerIdentity'.

Need 'struct GNUNET_MessageHeader'. Need VPN message types. Should we print (interesting|debug) messages that can happen during normal operation?

Definition at line 65 of file gnunet-helper-exit-windows.c.

◆ LOG_DEBUG

#define LOG_DEBUG (   msg)    do {} while (0)

◆ MAX_SIZE

#define MAX_SIZE   65536

Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)

Definition at line 82 of file gnunet-helper-exit-windows.c.

◆ INF_FILE

#define INF_FILE   "share/gnunet/openvpn-tap32/tapw32/OemWin2k.inf"

Name or Path+Name of our win32 driver.

The .sys and .cat files HAVE to be in the same location as this file!

Definition at line 88 of file gnunet-helper-exit-windows.c.

Referenced by setup_interface().

◆ INF_FILE64

#define INF_FILE64   "share/gnunet/openvpn-tap32/tapw64/OemWin2k.inf"

Name or Path+Name of our win64 driver.

The .sys and .cat files HAVE to be in the same location as this file!

Definition at line 94 of file gnunet-helper-exit-windows.c.

Referenced by setup_interface().

◆ HARDWARE_ID

#define HARDWARE_ID   "tap0901"

Hardware ID used in the inf-file.

This might change over time, as openvpn advances their driver

Definition at line 100 of file gnunet-helper-exit-windows.c.

Referenced by setup_interface().

◆ TAP_WIN_MIN_MAJOR

#define TAP_WIN_MIN_MAJOR   9

Minimum major-id of the driver version we can work with.

Definition at line 105 of file gnunet-helper-exit-windows.c.

Referenced by check_tapw32_version().

◆ TAP_WIN_MIN_MINOR

#define TAP_WIN_MIN_MINOR   9

Minimum minor-id of the driver version we can work with.

v <= 7 has buggy IPv6. v == 8 is broken for small IPv4 Packets

Definition at line 112 of file gnunet-helper-exit-windows.c.

Referenced by check_tapw32_version().

◆ TAP32_POSTUP_WAITTIME

#define TAP32_POSTUP_WAITTIME   4

Time in seconds to wait for our virtual device to go up after telling it to do so.

openvpn doesn't specify a value, 4 seems sane for testing, even for openwrt (in fact, 4 was chosen by a fair dice roll...)

Definition at line 120 of file gnunet-helper-exit-windows.c.

Referenced by tun_up().

◆ INTERFACE_REGISTRY_LOCATION

#define INTERFACE_REGISTRY_LOCATION   "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"

Location of the network interface list resides in registry.

Definition at line 125 of file gnunet-helper-exit-windows.c.

Referenced by resolve_interface_name().

Typedef Documentation

◆ LPFN_ISWOW64PROCESS

typedef BOOL(WINAPI * LPFN_ISWOW64PROCESS) (HANDLE, PBOOL)

IsWow64Process definition for our is_win64, as this is a kernel function.

Definition at line 251 of file gnunet-helper-exit-windows.c.

Enumeration Type Documentation

◆ IO_State

enum IO_State

Possible states of an IO facility.

Enumerator
IOSTATE_READY 

overlapped I/O is ready for work

IOSTATE_QUEUED 

overlapped I/O has been queued

IOSTATE_WAITING 

overlapped I/O has finished, but is waiting for it's write-partner

IOSTATE_RESUME 

there is a full buffer waiting

IOSTATE_FAILED 

Operlapped IO states for facility objects overlapped I/O has failed, stop processing.

IOSTATE_READY 

overlapped I/O is ready for work

IOSTATE_QUEUED 

overlapped I/O has been queued

IOSTATE_WAITING 

overlapped I/O has finished, but is waiting for it's write-partner

IOSTATE_RESUME 

there is a full buffer waiting

IOSTATE_FAILED 

Operlapped IO states for facility objects overlapped I/O has failed, stop processing.

Definition at line 165 of file gnunet-helper-exit-windows.c.

166 {
167 
171  IOSTATE_READY = 0,
172 
177 
182 
187 
193 
194 };
overlapped I/O has been queued
Operlapped IO states for facility objects overlapped I/O has failed, stop processing.
there is a full buffer waiting
overlapped I/O is ready for work
overlapped I/O has finished, but is waiting for it&#39;s write-partner

Function Documentation

◆ ReOpenFile()

WINBASEAPI HANDLE WINAPI ReOpenFile ( HANDLE  ,
DWORD  ,
DWORD  ,
DWORD   
)

ReOpenFile is only available as of XP SP2 and 2003 SP1.

Referenced by run().

Here is the caller graph for this function:

◆ is_win64()

BOOL is_win64 ( )

Determines if the host OS is win32 or win64.

Returns
true if

Definition at line 286 of file gnunet-helper-exit-windows.c.

Referenced by setup_interface().

287 {
288 #if defined(_WIN64)
289  //this is a win64 binary,
290  return TRUE;
291 #elif defined(_WIN32)
292  //this is a 32bit binary, and we need to check if we are running in WOW64
293  BOOL success = FALSE;
294  BOOL on_wow64 = FALSE;
295  LPFN_ISWOW64PROCESS IsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress (GetModuleHandle ("kernel32"), "IsWow64Process");
296 
297  if (NULL != IsWow64Process)
298  success = IsWow64Process (GetCurrentProcess (), &on_wow64);
299 
300  return success && on_wow64;
301 #endif
302 }
BOOL(WINAPI * LPFN_ISWOW64PROCESS)(HANDLE, PBOOL)
IsWow64Process definition for our is_win64, as this is a kernel function.
Here is the caller graph for this function:

◆ execute_shellcommand()

static int execute_shellcommand ( const char *  command)
static

Wrapper for executing a shellcommand in windows.

Parameters
command- the command + parameters to execute
Returns
* exitcode of the program executed,
  • EINVAL (cmd/file not found)
  • EPIPE (could not read STDOUT)

Definition at line 312 of file gnunet-helper-exit-windows.c.

Referenced by main(), remove_address4(), remove_address6(), set_address4(), and set_address6().

313 {
314  FILE *pipe;
315 
316  if ( (NULL == command) ||
317  (NULL == (pipe = _popen (command, "rt"))) )
318  return EINVAL;
319 
320 #if DEBUG
321  fprintf (stderr, "DEBUG: Command output: \n");
322  char output[LINE_LEN];
323  while (NULL != fgets (output, sizeof (output), pipe))
324  fprintf (stderr, "%s", output);
325 #endif
326 
327  return _pclose (pipe);
328 }
Here is the caller graph for this function:

◆ set_address6()

static int set_address6 ( const char *  address,
unsigned long  prefix_len 
)
static

Sets the IPv6-Address given in address on the interface dev.

Parameters
addressthe IPv6-Address
prefix_lenthe length of the network-prefix

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

References device_visible_name, execute_shellcommand(), inet_pton(), and ret.

Referenced by main().

339 {
340  int ret = EINVAL;
341  char command[LINE_LEN];
342  struct sockaddr_in6 sa6;
343 
344  /*
345  * parse the new address
346  */
347  memset (&sa6, 0, sizeof (struct sockaddr_in6));
348  sa6.sin6_family = AF_INET6;
349  if (1 != inet_pton (AF_INET6, address, &sa6.sin6_addr.s6_addr))
350  {
351  fprintf (stderr, "ERROR: Failed to parse address `%s': %s\n", address,
352  strerror (errno));
353  return -1;
354  }
355 
356  /*
357  * prepare the command
358  */
359  snprintf (command, LINE_LEN,
360  "netsh interface ipv6 add address \"%s\" %s/%d store=active",
361  device_visible_name, address, prefix_len);
362  /*
363  * Set the address
364  */
365  ret = execute_shellcommand (command);
366 
367  /* Did it work?*/
368  if (0 != ret)
369  fprintf (stderr, "FATAL: Setting IPv6 address failed: %s\n", strerror (ret));
370  return ret;
371 }
static char device_visible_name[256]
Device&#39;s visible Name, used to identify a network device in netsh.
static int ret
Final status code.
Definition: gnunet-arm.c:89
static int inet_pton(int af, const char *cp, struct in_addr *buf)
Convert IPv4 address from text to binary form.
static int execute_shellcommand(const char *command)
Wrapper for executing a shellcommand in windows.
static char * address
GNS address for this phone.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ remove_address6()

static void remove_address6 ( const char *  address)
static

Removes the IPv6-Address given in address from the interface dev.

Parameters
addressthe IPv4-Address

Definition at line 380 of file gnunet-helper-exit-windows.c.

References device_visible_name, execute_shellcommand(), and ret.

Referenced by main().

381 {
382  char command[LINE_LEN];
383  int ret = EINVAL;
384 
385  // sanity checking was already done in set_address6
386  /*
387  * prepare the command
388  */
389  snprintf (command, LINE_LEN,
390  "netsh interface ipv6 delete address \"%s\" store=persistent",
392  /*
393  * Set the address
394  */
395  ret = execute_shellcommand (command);
396 
397  /* Did it work?*/
398  if (0 != ret)
399  fprintf (stderr, "FATAL: removing IPv6 address failed: %s\n", strerror (ret));
400 }
static char device_visible_name[256]
Device&#39;s visible Name, used to identify a network device in netsh.
static int ret
Final status code.
Definition: gnunet-arm.c:89
static int execute_shellcommand(const char *command)
Wrapper for executing a shellcommand in windows.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_address4()

static int set_address4 ( const char *  address,
const char *  mask 
)
static

Sets the IPv4-Address given in address on the interface dev.

Parameters
addressthe IPv4-Address
maskthe netmask

Definition at line 410 of file gnunet-helper-exit-windows.c.

References device_visible_name, execute_shellcommand(), inet_pton(), and ret.

Referenced by main().

411 {
412  int ret = EINVAL;
413  char command[LINE_LEN];
414 
415  struct sockaddr_in addr;
416  addr.sin_family = AF_INET;
417 
418  /*
419  * Parse the address
420  */
421  if (1 != inet_pton (AF_INET, address, &addr.sin_addr.s_addr))
422  {
423  fprintf (stderr, "ERROR: Failed to parse address `%s': %s\n", address,
424  strerror (errno));
425  return -1;
426  }
427  // Set Device to Subnet-Mode?
428  // do we really need tun.c:2925 ?
429 
430  /*
431  * prepare the command
432  */
433  snprintf (command, LINE_LEN,
434  "netsh interface ipv4 add address \"%s\" %s %s store=active",
436  /*
437  * Set the address
438  */
439  ret = execute_shellcommand (command);
440 
441  /* Did it work?*/
442  if (0 != ret)
443  fprintf (stderr, "FATAL: Setting IPv4 address failed: %s\n", strerror (ret));
444  return ret;
445 }
static char device_visible_name[256]
Device&#39;s visible Name, used to identify a network device in netsh.
static int ret
Final status code.
Definition: gnunet-arm.c:89
static int inet_pton(int af, const char *cp, struct in_addr *buf)
Convert IPv4 address from text to binary form.
static int execute_shellcommand(const char *command)
Wrapper for executing a shellcommand in windows.
static char * address
GNS address for this phone.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ remove_address4()

static void remove_address4 ( const char *  address)
static

Removes the IPv4-Address given in address from the interface dev.

Parameters
addressthe IPv4-Address

Definition at line 454 of file gnunet-helper-exit-windows.c.

References device_visible_name, execute_shellcommand(), and ret.

Referenced by main().

455 {
456  char command[LINE_LEN];
457  int ret = EINVAL;
458 
459  // sanity checking was already done in set_address4
460 
461  /*
462  * prepare the command
463  */
464  snprintf (command, LINE_LEN,
465  "netsh interface ipv4 delete address \"%s\" gateway=all store=persistent",
467  /*
468  * Set the address
469  */
470  ret = execute_shellcommand (command);
471 
472  /* Did it work?*/
473  if (0 != ret)
474  fprintf (stderr, "FATAL: removing IPv4 address failed: %s\n", strerror (ret));
475 }
static char device_visible_name[256]
Device&#39;s visible Name, used to identify a network device in netsh.
static int ret
Final status code.
Definition: gnunet-arm.c:89
static int execute_shellcommand(const char *command)
Wrapper for executing a shellcommand in windows.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ setup_interface()

static BOOL setup_interface ( )
static

Setup a new virtual interface to use for tunneling.

Returns
: TRUE if setup was successful, else FALSE

Set the device's hardware ID and add it to a list. This information will later on identify this device in registry.

this is kind of over-complicated, but allows keeps things independent of how the openvpn-hwid is actually stored.

A HWID list is double-\0 terminated and \0 separated

Locate the inf-file, we need to store it somewhere where the system can find it. We need to pick the correct driver for win32/win64.

Bootstrap our device info using the drivers inf-file

Collect all the other needed information... let the system fill our this form

Definition at line 484 of file gnunet-helper-exit-windows.c.

References DeviceInfo, DeviceNode, GNUNET_assert, GNUNET_strlcpy(), HARDWARE_ID, INF_FILE, INF_FILE64, is_win64(), and secondary_hwid.

Referenced by init_tun().

485 {
486  /*
487  * where to find our inf-file. (+ the "full" path, after windows found")
488  *
489  * We do not directly input all the props here, because openvpn will update
490  * these details over time.
491  */
492  char inf_file_path[MAX_PATH];
493  char * temp_inf_filename;
494  char hwidlist[LINE_LEN + 4];
495  char class_name[128];
496  GUID class_guid;
497  int str_length = 0;
498 
503  str_length = GNUNET_strlcpy (hwidlist,
504  HARDWARE_ID,
505  sizeof (hwidlist)) + 1;
512  str_length = strlen (hwidlist) + 1;
513  str_length += GNUNET_strlcpy (&hwidlist[str_length],
515  sizeof (hwidlist) - str_length) + 1;
516  GNUNET_assert (str_length < sizeof (hwidlist));
517  hwidlist[str_length] = '\0';
518  ++str_length;
519 
524  if (is_win64())
525  GetFullPathNameA (INF_FILE64, MAX_PATH, inf_file_path, &temp_inf_filename);
526  else
527  GetFullPathNameA (INF_FILE, MAX_PATH, inf_file_path, &temp_inf_filename);
528 
529  fprintf (stderr, "INFO: Located our driver's .inf file at %s\n", inf_file_path);
533  if ( ! SetupDiGetINFClassA (inf_file_path,
534  &class_guid,
535  class_name, sizeof (class_name) / sizeof (char),
536  NULL))
537  return FALSE;
538 
543  DeviceInfo = SetupDiCreateDeviceInfoList (&class_guid, NULL);
544  if (DeviceInfo == INVALID_HANDLE_VALUE)
545  return FALSE;
546 
547  DeviceNode.cbSize = sizeof (SP_DEVINFO_DATA);
548  if ( ! SetupDiCreateDeviceInfoA (DeviceInfo,
549  class_name,
550  &class_guid,
551  NULL,
552  0,
553  DICD_GENERATE_ID,
554  &DeviceNode))
555  return FALSE;
556 
557  /* Deploy all the information collected into the registry */
558  if ( ! SetupDiSetDeviceRegistryPropertyA (DeviceInfo,
559  &DeviceNode,
560  SPDRP_HARDWAREID,
561  (LPBYTE) hwidlist,
562  str_length * sizeof (char)))
563  return FALSE;
564 
565  /* Install our new class(=device) into the system */
566  if ( ! SetupDiCallClassInstaller (DIF_REGISTERDEVICE,
567  DeviceInfo,
568  &DeviceNode))
569  return FALSE;
570 
571  /* This system call tends to take a while (several seconds!) on
572  "modern" Windoze systems */
573  if ( ! UpdateDriverForPlugAndPlayDevicesA (NULL,
575  inf_file_path,
576  INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE,
577  NULL)) //reboot required? NEVER!
578  return FALSE;
579 
580  fprintf (stderr, "DEBUG: successfully created a network device\n");
581  return TRUE;
582 }
#define HARDWARE_ID
Hardware ID used in the inf-file.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define INF_FILE
Name or Path+Name of our win32 driver.
#define INF_FILE64
Name or Path+Name of our win64 driver.
static char secondary_hwid[LINE_LEN/2]
Our local process&#39; PID.
BOOL is_win64()
Determines if the host OS is win32 or win64.
static HDEVINFO DeviceInfo
This is our own local instance of a virtual network interface It is (somewhat) equivalent to using tu...
static SP_DEVINFO_DATA DeviceNode
Registry Key we hand over to windows to spawn a new virtual interface.
size_t GNUNET_strlcpy(char *dst, const char *src, size_t n)
Like strlcpy but portable.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ remove_interface()

static BOOL remove_interface ( )
static

Remove our new virtual interface to use for tunneling.

This function must be called AFTER setup_interface!

Returns
: TRUE if destruction was successful, else FALSE

Definition at line 592 of file gnunet-helper-exit-windows.c.

References DeviceInfo, and DeviceNode.

Referenced by main().

593 {
594  SP_REMOVEDEVICE_PARAMS remove;
595 
596  if (INVALID_HANDLE_VALUE == DeviceInfo)
597  return FALSE;
598 
599  remove.ClassInstallHeader.cbSize = sizeof (SP_CLASSINSTALL_HEADER);
600  remove.HwProfile = 0;
601  remove.Scope = DI_REMOVEDEVICE_GLOBAL;
602  remove.ClassInstallHeader.InstallFunction = DIF_REMOVE;
603  /*
604  * 1. Prepare our existing device information set, and place the
605  * uninstall related information into the structure
606  */
607  if ( ! SetupDiSetClassInstallParamsA (DeviceInfo,
608  (PSP_DEVINFO_DATA) & DeviceNode,
609  &remove.ClassInstallHeader,
610  sizeof (remove)))
611  return FALSE;
612  /*
613  * 2. Uninstall the virtual interface using the class installer
614  */
615  if ( ! SetupDiCallClassInstaller (DIF_REMOVE,
616  DeviceInfo,
617  (PSP_DEVINFO_DATA) & DeviceNode))
618  return FALSE;
619 
620  SetupDiDestroyDeviceInfoList (DeviceInfo);
621 
622  fprintf (stderr, "DEBUG: removed interface successfully\n");
623 
624  return TRUE;
625 }
static HDEVINFO DeviceInfo
This is our own local instance of a virtual network interface It is (somewhat) equivalent to using tu...
static SP_DEVINFO_DATA DeviceNode
Registry Key we hand over to windows to spawn a new virtual interface.
Here is the caller graph for this function:

◆ resolve_interface_name()

static BOOL resolve_interface_name ( )
static

Do all the lookup necessary to retrieve the inteface's actual name off the registry.

Returns
: TRUE if we were able to lookup the interface's name, else FALSE

Definition at line 635 of file gnunet-helper-exit-windows.c.

References cleanup(), device_guid, device_visible_name, DeviceNode, GNUNET_strlcpy(), INTERFACE_REGISTRY_LOCATION, len, query_key, and status.

Referenced by init_tun().

636 {
637  SP_DEVINFO_LIST_DETAIL_DATA device_details;
638  char pnp_instance_id [MAX_DEVICE_ID_LEN];
639  HKEY adapter_key_handle;
640  LONG status;
641  DWORD len;
642  int i = 0;
643  int retrys;
644  BOOL retval = FALSE;
645  char adapter[] = INTERFACE_REGISTRY_LOCATION;
646 
647  /* We can obtain the PNP instance ID from our setupapi handle */
648  device_details.cbSize = sizeof (device_details);
649  if (CR_SUCCESS != CM_Get_Device_ID_ExA (DeviceNode.DevInst,
650  (PCHAR) pnp_instance_id,
651  MAX_DEVICE_ID_LEN,
652  0, //must be 0
653  NULL)) //hMachine, we are local
654  return FALSE;
655 
656  fprintf (stderr, "DEBUG: Resolving interface name for network device %s\n",pnp_instance_id);
657 
658  /* Registry is incredibly slow, retry for up to 30 seconds to allow registry to refresh */
659  for (retrys = 0; retrys < 120 && !retval; retrys++)
660  {
661  /* sleep for 250ms*/
662  Sleep (250);
663 
664  /* Now we can use this ID to locate the correct networks interface in registry */
665  if (ERROR_SUCCESS != RegOpenKeyExA (
666  HKEY_LOCAL_MACHINE,
667  adapter,
668  0,
669  KEY_READ,
670  &adapter_key_handle))
671  return FALSE;
672 
673  /* Of course there is a multitude of entries here, with arbitrary names,
674  * thus we need to iterate through there.
675  */
676  while (!retval)
677  {
678  char instance_key[256];
679  char query_key [256];
680  HKEY instance_key_handle;
681  char pnpinstanceid_name[] = "PnpInstanceID";
682  char pnpinstanceid_value[256];
683  char adaptername_name[] = "Name";
684  DWORD data_type;
685 
686  len = 256 * sizeof (char);
687  /* optain a subkey of {4D36E972-E325-11CE-BFC1-08002BE10318} */
688  status = RegEnumKeyExA (
689  adapter_key_handle,
690  i,
691  instance_key,
692  &len,
693  NULL,
694  NULL,
695  NULL,
696  NULL);
697 
698  /* this may fail due to one of two reasons:
699  * we are at the end of the list*/
700  if (ERROR_NO_MORE_ITEMS == status)
701  break;
702  // * we found a broken registry key, continue with the next key.
703  if (ERROR_SUCCESS != status)
704  goto cleanup;
705 
706  /* prepare our new query string: */
707  snprintf (query_key, 256, "%s\\%s\\Connection",
708  adapter,
709  instance_key);
710 
711  /* look inside instance_key\\Connection */
712  if (ERROR_SUCCESS != RegOpenKeyExA (
713  HKEY_LOCAL_MACHINE,
714  query_key,
715  0,
716  KEY_READ,
717  &instance_key_handle))
718  goto cleanup;
719 
720  /* now, read our PnpInstanceID */
721  len = sizeof (pnpinstanceid_value);
722  status = RegQueryValueExA (instance_key_handle,
723  pnpinstanceid_name,
724  NULL, //reserved, always NULL according to MSDN
725  &data_type,
726  (LPBYTE) pnpinstanceid_value,
727  &len);
728 
729  if (status != ERROR_SUCCESS || data_type != REG_SZ)
730  goto cleanup;
731 
732  /* compare the value we got to our devices PNPInstanceID*/
733  if (0 != strncmp (pnpinstanceid_value, pnp_instance_id,
734  sizeof (pnpinstanceid_value) / sizeof (char)))
735  goto cleanup;
736 
737  len = sizeof (device_visible_name);
738  status = RegQueryValueExA (
739  instance_key_handle,
740  adaptername_name,
741  NULL, //reserved, always NULL according to MSDN
742  &data_type,
743  (LPBYTE) device_visible_name,
744  &len);
745 
746  if (status != ERROR_SUCCESS || data_type != REG_SZ)
747  goto cleanup;
748 
749  /*
750  * we have successfully found OUR instance,
751  * save the device GUID before exiting
752  */
753  GNUNET_strlcpy (device_guid, instance_key, sizeof (device_guid));
754  retval = TRUE;
755  fprintf (stderr, "DEBUG: Interface Name lookup succeeded on retry %d, got \"%s\" %s\n", retrys, device_visible_name, device_guid);
756 
757 cleanup:
758  RegCloseKey (instance_key_handle);
759 
760  ++i;
761  }
762 
763  RegCloseKey (adapter_key_handle);
764  }
765  return retval;
766 }
static char device_visible_name[256]
Device&#39;s visible Name, used to identify a network device in netsh.
static char * query_key
The key for the query.
uint16_t status
See PRISM_STATUS_*-constants.
static void cleanup(void *cls)
Function scheduled as very last function, cleans up after us.
static char device_guid[256]
GUID of our virtual device in the form of {12345678-1234-1234-1234-123456789abc} - in hex...
static SP_DEVINFO_DATA DeviceNode
Registry Key we hand over to windows to spawn a new virtual interface.
#define INTERFACE_REGISTRY_LOCATION
Location of the network interface list resides in registry.
size_t GNUNET_strlcpy(char *dst, const char *src, size_t n)
Like strlcpy but portable.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_tapw32_version()

static BOOL check_tapw32_version ( HANDLE  handle)
static

Determines the version of the installed TAP32 driver and checks if it's sufficiently new for GNUNET.

Parameters
handlethe handle to our tap device
Returns
TRUE if the version is sufficient, else FALSE

Definition at line 776 of file gnunet-helper-exit-windows.c.

References len, TAP_WIN_IOCTL_GET_VERSION, TAP_WIN_MIN_MAJOR, and TAP_WIN_MIN_MINOR.

Referenced by init_tun().

777 {
778  ULONG version[3];
779  DWORD len;
780  memset (&(version), 0, sizeof (version));
781 
782  if (DeviceIoControl (handle, TAP_WIN_IOCTL_GET_VERSION,
783  &version, sizeof (version),
784  &version, sizeof (version), &len, NULL))
785  fprintf (stderr, "INFO: TAP-Windows Driver Version %d.%d %s\n",
786  (int) version[0],
787  (int) version[1],
788  (version[2] ? "(DEBUG)" : ""));
789 
790  if ((version[0] != TAP_WIN_MIN_MAJOR) ||
791  (version[1] < TAP_WIN_MIN_MINOR )){
792  fprintf (stderr, "FATAL: This version of gnunet requires a TAP-Windows driver that is at least version %d.%d\n",
795  return FALSE;
796  }
797 
798  return TRUE;
799 }
#define TAP_WIN_MIN_MINOR
Minimum minor-id of the driver version we can work with.
#define TAP_WIN_IOCTL_GET_VERSION
Definition: tap-windows.h:46
#define TAP_WIN_MIN_MAJOR
Minimum major-id of the driver version we can work with.
static struct GNUNET_DNS_Handle * handle
Handle to transport service.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
Here is the caller graph for this function:

◆ init_tun()

static HANDLE init_tun ( )
static

Creates a tun-interface called dev;.

Returns
the fd to the tun or -1 on error

Definition at line 808 of file gnunet-helper-exit-windows.c.

References check_tapw32_version(), device_guid, io_facility::handle, resolve_interface_name(), setup_interface(), TAP_WIN_SUFFIX, and USERMODEDEVICEDIR.

Referenced by main().

809 {
810  char device_path[256];
811  HANDLE handle;
812 
813  if (! setup_interface ())
814  {
815  errno = ENODEV;
816  return INVALID_HANDLE_VALUE;
817  }
818 
819  if (! resolve_interface_name ())
820  {
821  errno = ENODEV;
822  return INVALID_HANDLE_VALUE;
823  }
824 
825  /* Open Windows TAP-Windows adapter */
826  snprintf (device_path, sizeof (device_path), "%s%s%s",
828  device_guid,
830 
831  handle = CreateFile (
832  device_path,
833  GENERIC_READ | GENERIC_WRITE,
834  0, /* was: FILE_SHARE_READ */
835  0,
836  OPEN_EXISTING,
837  FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
838  0
839  );
840 
841  if (INVALID_HANDLE_VALUE == handle)
842  {
843  fprintf (stderr, "FATAL: CreateFile failed on TAP device: %s\n", device_path);
844  return handle;
845  }
846 
847  /* get driver version info */
848  if (! check_tapw32_version (handle))
849  {
850  CloseHandle (handle);
851  return INVALID_HANDLE_VALUE;
852  }
853 
854  /* TODO (opt?): get MTU-Size */
855 
856  fprintf (stderr, "DEBUG: successfully opened TAP device\n");
857  return handle;
858 }
static BOOL resolve_interface_name()
Do all the lookup necessary to retrieve the inteface&#39;s actual name off the registry.
#define TAP_WIN_SUFFIX
Definition: tap-windows.h:79
static BOOL setup_interface()
Setup a new virtual interface to use for tunneling.
static struct GNUNET_DNS_Handle * handle
Handle to transport service.
static char device_guid[256]
GUID of our virtual device in the form of {12345678-1234-1234-1234-123456789abc} - in hex...
#define USERMODEDEVICEDIR
Definition: tap-windows.h:76
static BOOL check_tapw32_version(HANDLE handle)
Determines the version of the installed TAP32 driver and checks if it&#39;s sufficiently new for GNUNET...
Here is the call graph for this function:
Here is the caller graph for this function:

◆ tun_up()

static BOOL tun_up ( HANDLE  handle)
static

Brings a TAP device up and sets it to connected state.

Parameters
handlethe handle to our TAP device
Returns
True if the operation succeeded, else false

Definition at line 868 of file gnunet-helper-exit-windows.c.

References len, status, TAP32_POSTUP_WAITTIME, and TAP_WIN_IOCTL_SET_MEDIA_STATUS.

Referenced by run().

869 {
870  ULONG status = TRUE;
871  DWORD len;
872  if (! DeviceIoControl (handle, TAP_WIN_IOCTL_SET_MEDIA_STATUS,
873  &status, sizeof (status),
874  &status, sizeof (status), &len, NULL))
875  {
876  fprintf (stderr, "FATAL: TAP driver ignored request to UP interface (DeviceIoControl call)\n");
877  return FALSE;
878  }
879 
880  /* Wait for the device to go UP, might take some time. */
881  Sleep (TAP32_POSTUP_WAITTIME * 1000);
882  fprintf (stderr, "DEBUG: successfully set TAP device to UP\n");
883 
884  return TRUE;
885 }
#define TAP_WIN_IOCTL_SET_MEDIA_STATUS
Definition: tap-windows.h:50
uint16_t status
See PRISM_STATUS_*-constants.
static struct GNUNET_DNS_Handle * handle
Handle to transport service.
#define TAP32_POSTUP_WAITTIME
Time in seconds to wait for our virtual device to go up after telling it to do so.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
Here is the caller graph for this function:

◆ attempt_read_tap()

static BOOL attempt_read_tap ( struct io_facility input_facility,
struct io_facility output_facility 
)
static

Attempts to read off an input facility (tap or named pipe) in overlapped mode.

1. If the input facility is in IOSTATE_READY, it will issue a new read operation to the input handle. Then it goes into IOSTATE_QUEUED state. In case the read succeeded instantly the input facility enters 3.

2. If the input facility is in IOSTATE_QUEUED state, it will check if the queued read has finished already. If it has finished, go to state 3. If it has failed, set IOSTATE_FAILED

3. If the output facility is in state IOSTATE_READY, the read-buffer is copied to the output buffer. The input facility enters state IOSTATE_READY The output facility enters state IOSTATE_READY If the output facility is in state IOSTATE_QUEUED, the input facility enters IOSTATE_WAITING

IOSTATE_WAITING is reset by the output facility, once it has completed.

Parameters
input_facilityinput named pipe or file to work with.
output_facilityoutput pipe or file to hand over data to.
Returns
false if an event reset was impossible (OS error), else true

Definition at line 914 of file gnunet-helper-exit-windows.c.

References io_facility::buffer, io_facility::buffer_size, io_facility::facility_state, GNUNET_memcpy, GNUNET_MESSAGE_TYPE_VPN_HELPER, io_facility::handle, IOSTATE_FAILED, IOSTATE_QUEUED, IOSTATE_READY, IOSTATE_RESUME, IOSTATE_WAITING, io_facility::overlapped, io_facility::path_open, size, GNUNET_MessageHeader::size, and GNUNET_MessageHeader::type.

Referenced by run().

916 {
917  struct GNUNET_MessageHeader * hdr;
918  unsigned short size;
919 
920  switch (input_facility->facility_state)
921  {
922  case IOSTATE_READY:
923  {
924  if (! ResetEvent (input_facility->overlapped.hEvent))
925  {
926  return FALSE;
927  }
928 
929  input_facility->buffer_size = 0;
930 
931  /* Check how the task is handled */
932  if (ReadFile (input_facility->handle,
933  input_facility->buffer,
934  sizeof (input_facility->buffer) - sizeof (struct GNUNET_MessageHeader),
935  &input_facility->buffer_size,
936  &input_facility->overlapped))
937  {/* async event processed immediately*/
938 
939  /* reset event manually*/
940  if (! SetEvent (input_facility->overlapped.hEvent))
941  return FALSE;
942 
943  fprintf (stderr, "DEBUG: tap read succeeded immediately\n");
944 
945  /* we successfully read something from the TAP and now need to
946  * send it our via STDOUT. Is that possible at the moment? */
947  if ((IOSTATE_READY == output_facility->facility_state ||
948  IOSTATE_WAITING == output_facility->facility_state)
949  && (0 < input_facility->buffer_size))
950  { /* hand over this buffers content and apply message header for gnunet */
951  hdr = (struct GNUNET_MessageHeader *) output_facility->buffer;
952  size = input_facility->buffer_size + sizeof (struct GNUNET_MessageHeader);
953 
954  GNUNET_memcpy (output_facility->buffer + sizeof (struct GNUNET_MessageHeader),
955  input_facility->buffer,
956  input_facility->buffer_size);
957 
958  output_facility->buffer_size = size;
959  hdr->size = htons (size);
960  hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
961  output_facility->facility_state = IOSTATE_READY;
962  }
963  else if (0 < input_facility->buffer_size)
964  /* If we have have read our buffer, wait for our write-partner*/
965  input_facility->facility_state = IOSTATE_WAITING;
966  }
967  else /* operation was either queued or failed*/
968  {
969  int err = GetLastError ();
970  if (ERROR_IO_PENDING == err)
971  { /* operation queued */
972  input_facility->facility_state = IOSTATE_QUEUED;
973  }
974  else
975  { /* error occurred, let the rest of the elements finish */
976  input_facility->path_open = FALSE;
977  input_facility->facility_state = IOSTATE_FAILED;
978  if (IOSTATE_WAITING == output_facility->facility_state)
979  output_facility->path_open = FALSE;
980 
981  fprintf (stderr, "FATAL: Read from handle failed, allowing write to finish\n");
982  }
983  }
984  }
985  return TRUE;
986  // We are queued and should check if the read has finished
987  case IOSTATE_QUEUED:
988  {
989  // there was an operation going on already, check if that has completed now.
990 
991  if (GetOverlappedResult (input_facility->handle,
992  &input_facility->overlapped,
993  &input_facility->buffer_size,
994  FALSE))
995  {/* successful return for a queued operation */
996  if (! ResetEvent (input_facility->overlapped.hEvent))
997  return FALSE;
998 
999  fprintf (stderr, "DEBUG: tap read succeeded delayed\n");
1000 
1001  /* we successfully read something from the TAP and now need to
1002  * send it our via STDOUT. Is that possible at the moment? */
1003  if ((IOSTATE_READY == output_facility->facility_state ||
1004  IOSTATE_WAITING == output_facility->facility_state)
1005  && 0 < input_facility->buffer_size)
1006  { /* hand over this buffers content and apply message header for gnunet */
1007  hdr = (struct GNUNET_MessageHeader *) output_facility->buffer;
1008  size = input_facility->buffer_size + sizeof (struct GNUNET_MessageHeader);
1009 
1010  GNUNET_memcpy (output_facility->buffer + sizeof (struct GNUNET_MessageHeader),
1011  input_facility->buffer,
1012  input_facility->buffer_size);
1013 
1014  output_facility->buffer_size = size;
1015  hdr->size = htons(size);
1016  hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1017  output_facility->facility_state = IOSTATE_READY;
1018  input_facility->facility_state = IOSTATE_READY;
1019  }
1020  else if (0 < input_facility->buffer_size)
1021  { /* If we have have read our buffer, wait for our write-partner*/
1022  input_facility->facility_state = IOSTATE_WAITING;
1023  // TODO: shall we attempt to fill our buffer or should we wait for our write-partner to finish?
1024  }
1025  }
1026  else
1027  { /* operation still pending/queued or failed? */
1028  int err = GetLastError ();
1029  if ((ERROR_IO_INCOMPLETE != err) && (ERROR_IO_PENDING != err))
1030  { /* error occurred, let the rest of the elements finish */
1031  input_facility->path_open = FALSE;
1032  input_facility->facility_state = IOSTATE_FAILED;
1033  if (IOSTATE_WAITING == output_facility->facility_state)
1034  output_facility->path_open = FALSE;
1035  fprintf (stderr, "FATAL: Read from handle failed, allowing write to finish\n");
1036  }
1037  }
1038  }
1039  return TRUE;
1040  case IOSTATE_RESUME:
1041  hdr = (struct GNUNET_MessageHeader *) output_facility->buffer;
1042  size = input_facility->buffer_size + sizeof (struct GNUNET_MessageHeader);
1043 
1044  GNUNET_memcpy (output_facility->buffer + sizeof (struct GNUNET_MessageHeader),
1045  input_facility->buffer,
1046  input_facility->buffer_size);
1047 
1048  output_facility->buffer_size = size;
1049  hdr->size = htons (size);
1050  hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1051  output_facility->facility_state = IOSTATE_READY;
1052  input_facility->facility_state = IOSTATE_READY;
1053  return TRUE;
1054  default:
1055  return TRUE;
1056  }
1057 }
BOOL path_open
If the path is open or blocked in general (used for quickly checking)
overlapped I/O has been queued
DWORD buffer_size
How much of this buffer was used when reading or how much data can be written.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
OVERLAPPED overlapped
Overlaped IO structure used for asynchronous IO in windows.
Operlapped IO states for facility objects overlapped I/O has failed, stop processing.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_memcpy(dst, src, n)
static unsigned int size
Size of the "table".
Definition: peer.c:67
there is a full buffer waiting
enum IO_State facility_state
The mode the state machine associated with this object is in.
unsigned char buffer[65536]
Buffer for reading things to and writing from...
overlapped I/O is ready for work
HANDLE handle
Windows Object-Handle (used for accessing TAP and STDIN/STDOUT)
Header for all communications.
overlapped I/O has finished, but is waiting for it&#39;s write-partner
#define GNUNET_MESSAGE_TYPE_VPN_HELPER
Type of messages between the gnunet-vpn-helper and the daemon.
Here is the caller graph for this function:

◆ attempt_read_stdin()

static BOOL attempt_read_stdin ( struct io_facility input_facility,
struct io_facility output_facility 
)
static

Attempts to read off an input facility (tap or named pipe) in overlapped mode.

1. If the input facility is in IOSTATE_READY, it will issue a new read operation to the input handle. Then it goes into IOSTATE_QUEUED state. In case the read succeeded instantly the input facility enters 3.

2. If the input facility is in IOSTATE_QUEUED state, it will check if the queued read has finished already. If it has finished, go to state 3. If it has failed, set IOSTATE_FAILED

3. If the facility is finished with ready The read-buffer is copied to the output buffer, except for the GNUNET_MessageHeader. The input facility enters state IOSTATE_READY The output facility enters state IOSTATE_READY If the output facility is in state IOSTATE_QUEUED, the input facility enters IOSTATE_WAITING

IOSTATE_WAITING is reset by the output facility, once it has completed.

Parameters
input_facilityinput named pipe or file to work with.
output_facilityoutput pipe or file to hand over data to.
Returns
false if an event reset was impossible (OS error), else true

Definition at line 1087 of file gnunet-helper-exit-windows.c.

References io_facility::buffer, io_facility::buffer_size, io_facility::buffer_size_processed, io_facility::facility_state, GNUNET_memcpy, GNUNET_MESSAGE_TYPE_VPN_HELPER, io_facility::handle, IOSTATE_FAILED, IOSTATE_QUEUED, IOSTATE_READY, IOSTATE_RESUME, IOSTATE_WAITING, io_facility::overlapped, io_facility::path_open, GNUNET_MessageHeader::size, and GNUNET_MessageHeader::type.

Referenced by run().

1089 {
1090  struct GNUNET_MessageHeader * hdr;
1091 
1092  switch (input_facility->facility_state)
1093  {
1094  case IOSTATE_READY:
1095  {
1096  input_facility->buffer_size = 0;
1097 
1098 partial_read_iostate_ready:
1099  if (! ResetEvent (input_facility->overlapped.hEvent))
1100  return FALSE;
1101 
1102  /* Check how the task is handled */
1103  if (ReadFile (input_facility->handle,
1104  input_facility->buffer + input_facility->buffer_size,
1105  sizeof (input_facility->buffer) - input_facility->buffer_size,
1106  &input_facility->buffer_size_processed,
1107  &input_facility->overlapped))
1108  {/* async event processed immediately*/
1109  hdr = (struct GNUNET_MessageHeader *) input_facility->buffer;
1110 
1111  /* reset event manually*/
1112  if (!SetEvent (input_facility->overlapped.hEvent))
1113  return FALSE;
1114 
1115  fprintf (stderr, "DEBUG: stdin read succeeded immediately\n");
1116  input_facility->buffer_size += input_facility->buffer_size_processed;
1117 
1118  if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER ||
1119  ntohs (hdr->size) > sizeof (input_facility->buffer))
1120  {
1121  fprintf (stderr, "WARNING: Protocol violation, got GNUnet Message type %h, size %h\n", ntohs (hdr->type), ntohs (hdr->size));
1122  input_facility->facility_state = IOSTATE_READY;
1123  return TRUE;
1124  }
1125  /* we got the a part of a packet */
1126  if (ntohs (hdr->size) > input_facility->buffer_size)
1127  goto partial_read_iostate_ready;
1128 
1129  /* have we read more than 0 bytes of payload? (sizeread > header)*/
1130  if (input_facility->buffer_size > sizeof (struct GNUNET_MessageHeader) &&
1131  ((IOSTATE_READY == output_facility->facility_state) ||
1132  (IOSTATE_WAITING == output_facility->facility_state)))
1133  {/* we successfully read something from the TAP and now need to
1134  * send it our via STDOUT. Is that possible at the moment? */
1135 
1136  /* hand over this buffers content and strip gnunet message header */
1137  GNUNET_memcpy (output_facility->buffer,
1138  input_facility->buffer + sizeof (struct GNUNET_MessageHeader),
1139  input_facility->buffer_size - sizeof (struct GNUNET_MessageHeader));
1140  output_facility->buffer_size = input_facility->buffer_size - sizeof (struct GNUNET_MessageHeader);
1141  output_facility->facility_state = IOSTATE_READY;
1142  input_facility->facility_state = IOSTATE_READY;
1143  }
1144  else if (input_facility->buffer_size > sizeof (struct GNUNET_MessageHeader))
1145  /* If we have have read our buffer, wait for our write-partner*/
1146  input_facility->facility_state = IOSTATE_WAITING;
1147  else /* we read nothing */
1148  input_facility->facility_state = IOSTATE_READY;
1149  }
1150  else /* operation was either queued or failed*/
1151  {
1152  int err = GetLastError ();
1153  if (ERROR_IO_PENDING == err) /* operation queued */
1154  input_facility->facility_state = IOSTATE_QUEUED;
1155  else
1156  { /* error occurred, let the rest of the elements finish */
1157  input_facility->path_open = FALSE;
1158  input_facility->facility_state = IOSTATE_FAILED;
1159  if (IOSTATE_WAITING == output_facility->facility_state)
1160  output_facility->path_open = FALSE;
1161 
1162  fprintf (stderr, "FATAL: Read from handle failed, allowing write to finish\n");
1163  }
1164  }
1165  }
1166  return TRUE;
1167  // We are queued and should check if the read has finished
1168  case IOSTATE_QUEUED:
1169  {
1170  // there was an operation going on already, check if that has completed now.
1171  if (GetOverlappedResult (input_facility->handle,
1172  &input_facility->overlapped,
1173  &input_facility->buffer_size_processed,
1174  FALSE))
1175  {/* successful return for a queued operation */
1176  hdr = (struct GNUNET_MessageHeader *) input_facility->buffer;
1177 
1178  if (! ResetEvent (input_facility->overlapped.hEvent))
1179  return FALSE;
1180 
1181  fprintf (stderr, "DEBUG: stdin read succeeded delayed\n");
1182  input_facility->buffer_size += input_facility->buffer_size_processed;
1183 
1184  if ((ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1185  (ntohs (hdr->size) > sizeof (input_facility->buffer)))
1186  {
1187  fprintf (stderr, "WARNING: Protocol violation, got GNUnet Message type %h, size %h\n", ntohs (hdr->type), ntohs (hdr->size));
1188  input_facility->facility_state = IOSTATE_READY;
1189  return TRUE;
1190  }
1191  /* we got the a part of a packet */
1192  if (ntohs (hdr->size) > input_facility->buffer_size );
1193  goto partial_read_iostate_ready;
1194 
1195  /* we successfully read something from the TAP and now need to
1196  * send it our via STDOUT. Is that possible at the moment? */
1197  if ((IOSTATE_READY == output_facility->facility_state ||
1198  IOSTATE_WAITING == output_facility->facility_state)
1199  && input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader))
1200  { /* hand over this buffers content and strip gnunet message header */
1201  GNUNET_memcpy (output_facility->buffer,
1202  input_facility->buffer + sizeof(struct GNUNET_MessageHeader),
1203  input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader));
1204  output_facility->buffer_size = input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader);
1205  output_facility->facility_state = IOSTATE_READY;
1206  input_facility->facility_state = IOSTATE_READY;
1207  }
1208  else if (input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader))
1209  input_facility->facility_state = IOSTATE_WAITING;
1210  else
1211  input_facility->facility_state = IOSTATE_READY;
1212  }
1213  else
1214  { /* operation still pending/queued or failed? */
1215  int err = GetLastError ();
1216  if ((ERROR_IO_INCOMPLETE != err) && (ERROR_IO_PENDING != err))
1217  { /* error occurred, let the rest of the elements finish */
1218  input_facility->path_open = FALSE;
1219  input_facility->facility_state = IOSTATE_FAILED;
1220  if (IOSTATE_WAITING == output_facility->facility_state)
1221  output_facility->path_open = FALSE;
1222  fprintf (stderr, "FATAL: Read from handle failed, allowing write to finish\n");
1223  }
1224  }
1225  }
1226  return TRUE;
1227  case IOSTATE_RESUME: /* Our buffer was filled already but our write facility was busy. */
1228  GNUNET_memcpy (output_facility->buffer,
1229  input_facility->buffer + sizeof (struct GNUNET_MessageHeader),
1230  input_facility->buffer_size - sizeof (struct GNUNET_MessageHeader));
1231  output_facility->buffer_size = input_facility->buffer_size - sizeof (struct GNUNET_MessageHeader);
1232  output_facility->facility_state = IOSTATE_READY;
1233  input_facility->facility_state = IOSTATE_READY;
1234  return TRUE;
1235  default:
1236  return TRUE;
1237  }
1238 }
BOOL path_open
If the path is open or blocked in general (used for quickly checking)
overlapped I/O has been queued
DWORD buffer_size_processed
Amount of data actually written or read by readfile/writefile.
DWORD buffer_size
How much of this buffer was used when reading or how much data can be written.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
OVERLAPPED overlapped
Overlaped IO structure used for asynchronous IO in windows.
Operlapped IO states for facility objects overlapped I/O has failed, stop processing.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_memcpy(dst, src, n)
there is a full buffer waiting
enum IO_State facility_state
The mode the state machine associated with this object is in.
unsigned char buffer[65536]
Buffer for reading things to and writing from...
overlapped I/O is ready for work
HANDLE handle
Windows Object-Handle (used for accessing TAP and STDIN/STDOUT)
Header for all communications.
overlapped I/O has finished, but is waiting for it&#39;s write-partner
#define GNUNET_MESSAGE_TYPE_VPN_HELPER
Type of messages between the gnunet-vpn-helper and the daemon.
Here is the caller graph for this function:

◆ attempt_write()

static BOOL attempt_write ( struct io_facility output_facility,
struct io_facility input_facility 
)
static

Attempts to write to an output facility (tap or named pipe) in overlapped mode.

TODO: high level description

Parameters
output_facilityoutput pipe or file to hand over data to.
input_facilityinput named pipe or file to work with.
Returns
false if an event reset was impossible (OS error), else true

Definition at line 1251 of file gnunet-helper-exit-windows.c.

References io_facility::buffer, io_facility::buffer_size, io_facility::buffer_size_processed, io_facility::buffer_size_written, io_facility::facility_state, io_facility::handle, IOSTATE_FAILED, IOSTATE_QUEUED, IOSTATE_READY, IOSTATE_RESUME, IOSTATE_WAITING, io_facility::overlapped, and io_facility::path_open.

Referenced by run().

1253 {
1254  switch (output_facility->facility_state)
1255  {
1256  case IOSTATE_READY:
1257  output_facility->buffer_size_written = 0;
1258 
1259 continue_partial_write:
1260  if (! ResetEvent (output_facility->overlapped.hEvent))
1261  return FALSE;
1262 
1263  /* Check how the task was handled */
1264  if (WriteFile (output_facility->handle,
1265  output_facility->buffer + output_facility->buffer_size_written,
1266  output_facility->buffer_size - output_facility->buffer_size_written,
1267  &output_facility->buffer_size_processed,
1268  &output_facility->overlapped))
1269  {/* async event processed immediately*/
1270 
1271  fprintf (stderr, "DEBUG: write succeeded immediately\n");
1272  output_facility->buffer_size_written += output_facility->buffer_size_processed;
1273 
1274  /* reset event manually*/
1275  if (! SetEvent (output_facility->overlapped.hEvent))
1276  return FALSE;
1277 
1278  /* partial write */
1279  if (output_facility->buffer_size_written < output_facility->buffer_size)
1280  goto continue_partial_write;
1281 
1282  /* we are now waiting for our buffer to be filled*/
1283  output_facility->facility_state = IOSTATE_WAITING;
1284 
1285  /* we successfully wrote something and now need to reset our reader */
1286  if (IOSTATE_WAITING == input_facility->facility_state)
1287  input_facility->facility_state = IOSTATE_RESUME;
1288  else if (IOSTATE_FAILED == input_facility->facility_state)
1289  output_facility->path_open = FALSE;
1290  }
1291  else /* operation was either queued or failed*/
1292  {
1293  int err = GetLastError ();
1294  if (ERROR_IO_PENDING == err)
1295  { /* operation queued */
1296  output_facility->facility_state = IOSTATE_QUEUED;
1297  }
1298  else
1299  { /* error occurred, close this path */
1300  output_facility->path_open = FALSE;
1301  output_facility->facility_state = IOSTATE_FAILED;
1302  fprintf (stderr, "FATAL: Write to handle failed, exiting\n");
1303  }
1304  }
1305  return TRUE;
1306  case IOSTATE_QUEUED:
1307  // there was an operation going on already, check if that has completed now.
1308 
1309  if (GetOverlappedResult (output_facility->handle,
1310  &output_facility->overlapped,
1311  &output_facility->buffer_size_processed,
1312  FALSE))
1313  {/* successful return for a queued operation */
1314  if (! ResetEvent (output_facility->overlapped.hEvent))
1315  return FALSE;
1316 
1317  fprintf (stderr, "DEBUG: write succeeded delayed\n");
1318  output_facility->buffer_size_written += output_facility->buffer_size_processed;
1319 
1320  /* partial write */
1321  if (output_facility->buffer_size_written < output_facility->buffer_size)
1322  goto continue_partial_write;
1323 
1324  /* we are now waiting for our buffer to be filled*/
1325  output_facility->facility_state = IOSTATE_WAITING;
1326 
1327  /* we successfully wrote something and now need to reset our reader */
1328  if (IOSTATE_WAITING == input_facility->facility_state)
1329  input_facility->facility_state = IOSTATE_RESUME;
1330  else if (IOSTATE_FAILED == input_facility->facility_state)
1331  output_facility->path_open = FALSE;
1332  }
1333  else
1334  { /* operation still pending/queued or failed? */
1335  int err = GetLastError ();
1336  if ((ERROR_IO_INCOMPLETE != err) && (ERROR_IO_PENDING != err))
1337  { /* error occurred, close this path */
1338  output_facility->path_open = FALSE;
1339  output_facility->facility_state = IOSTATE_FAILED;
1340  fprintf (stderr, "FATAL: Write to handle failed, exiting\n");
1341  }
1342  }
1343  default:
1344  return TRUE;
1345  }
1346 }
BOOL path_open
If the path is open or blocked in general (used for quickly checking)
overlapped I/O has been queued
DWORD buffer_size_processed
Amount of data actually written or read by readfile/writefile.
DWORD buffer_size
How much of this buffer was used when reading or how much data can be written.
OVERLAPPED overlapped
Overlaped IO structure used for asynchronous IO in windows.
Operlapped IO states for facility objects overlapped I/O has failed, stop processing.
there is a full buffer waiting
enum IO_State facility_state
The mode the state machine associated with this object is in.
unsigned char buffer[65536]
Buffer for reading things to and writing from...
overlapped I/O is ready for work
HANDLE handle
Windows Object-Handle (used for accessing TAP and STDIN/STDOUT)
overlapped I/O has finished, but is waiting for it&#39;s write-partner
DWORD buffer_size_written
How much of this buffer we have written in total.
Here is the caller graph for this function:

◆ initialize_io_facility()

static BOOL initialize_io_facility ( struct io_facility elem,
int  initial_state,
BOOL  signaled 
)
static

Initialize a overlapped structure.

Parameters
elemthe element to initilize
initial_statethe initial state for this instance
signaledif the hEvent created should default to signaled or not
Returns
true on success, else false

Definition at line 1358 of file gnunet-helper-exit-windows.c.

References io_facility::buffer_size, io_facility::facility_state, io_facility::handle, io_facility::overlapped, and io_facility::path_open.

Referenced by run().

1361 {
1362  elem->path_open = TRUE;
1363  elem->handle = INVALID_HANDLE_VALUE;
1364  elem->facility_state = initial_state;
1365  elem->buffer_size = 0;
1366  elem->overlapped.hEvent = CreateEvent (NULL, TRUE, signaled, NULL);
1367  if (NULL == elem->overlapped.hEvent)
1368  return FALSE;
1369 
1370  return TRUE;
1371 }
BOOL path_open
If the path is open or blocked in general (used for quickly checking)
DWORD buffer_size
How much of this buffer was used when reading or how much data can be written.
OVERLAPPED overlapped
Overlaped IO structure used for asynchronous IO in windows.
enum IO_State facility_state
The mode the state machine associated with this object is in.
HANDLE handle
Windows Object-Handle (used for accessing TAP and STDIN/STDOUT)
Here is the caller graph for this function:

◆ run()

static void run ( HANDLE  tap_handle)
static

Start forwarding to and from the tunnel.

Parameters
tap_handledevice handle for interacting with the Virtual interface

Definition at line 1380 of file gnunet-helper-exit-windows.c.

References attempt_read_stdin(), attempt_read_tap(), attempt_write(), io_facility::handle, initialize_io_facility(), IOSTATE_READY, IOSTATE_WAITING, io_facility::path_open, privilege_testing, ReOpenFile(), and tun_up().

Referenced by main().

1381 {
1382  /* IO-Facility for reading from our virtual interface */
1383  struct io_facility tap_read;
1384  /* IO-Facility for writing to our virtual interface */
1385  struct io_facility tap_write;
1386  /* IO-Facility for reading from stdin */
1387  struct io_facility std_in;
1388  /* IO-Facility for writing to stdout */
1389  struct io_facility std_out;
1390 
1391  HANDLE parent_std_in_handle = GetStdHandle (STD_INPUT_HANDLE);
1392  HANDLE parent_std_out_handle = GetStdHandle (STD_OUTPUT_HANDLE);
1393 
1394  /* tun up: */
1395  /* we do this HERE and not beforehand (in init_tun()), in contrast to openvpn
1396  * to remove the need to flush the arp cache, handle DHCP and wrong IPs.
1397  *
1398  * DHCP and such are all features we will never use in gnunet afaik.
1399  * But for openvpn those are essential.
1400  */
1401  if ((privilege_testing) || (! tun_up (tap_handle) ))
1402  goto teardown_final;
1403 
1404  /* Initialize our overlapped IO structures*/
1405  if (! (initialize_io_facility (&tap_read, IOSTATE_READY, FALSE)
1406  && initialize_io_facility (&tap_write, IOSTATE_WAITING, TRUE)
1407  && initialize_io_facility (&std_in, IOSTATE_READY, FALSE)
1408  && initialize_io_facility (&std_out, IOSTATE_WAITING, TRUE)))
1409  goto teardown_final;
1410 
1411  /* Handles for STDIN and STDOUT */
1412  tap_read.handle = tap_handle;
1413  tap_write.handle = tap_handle;
1414 
1415 #ifdef DEBUG_TO_CONSOLE
1416  /* Debug output to console STDIN/STDOUT*/
1417  std_in.handle = parent_std_in_handle;
1418  std_out.handle = parent_std_out_handle;
1419 
1420 #else
1421  fprintf (stderr, "DEBUG: reopening stdin/out for overlapped IO\n");
1422  /*
1423  * Find out the types of our handles.
1424  * This part is a problem, because in windows we need to handle files,
1425  * pipes and the console differently.
1426  */
1427  if ((FILE_TYPE_PIPE != GetFileType (parent_std_in_handle)) ||
1428  (FILE_TYPE_PIPE != GetFileType (parent_std_out_handle)))
1429  {
1430  fprintf (stderr, "ERROR: stdin/stdout must be named pipes\n");
1431  goto teardown;
1432  }
1433 
1434  std_in.handle = ReOpenFile (parent_std_in_handle,
1435  GENERIC_READ,
1436  FILE_SHARE_WRITE | FILE_SHARE_READ,
1437  FILE_FLAG_OVERLAPPED);
1438 
1439  if (INVALID_HANDLE_VALUE == std_in.handle)
1440  {
1441  fprintf (stderr, "FATAL: Could not reopen stdin for in overlapped mode, has to be a named pipe\n");
1442  goto teardown;
1443  }
1444 
1445  std_out.handle = ReOpenFile (parent_std_out_handle,
1446  GENERIC_WRITE,
1447  FILE_SHARE_READ,
1448  FILE_FLAG_OVERLAPPED);
1449 
1450  if (INVALID_HANDLE_VALUE == std_out.handle)
1451  {
1452  fprintf (stderr, "FATAL: Could not reopen stdout for in overlapped mode, has to be a named pipe\n");
1453  goto teardown;
1454  }
1455 #endif
1456 
1457  fprintf (stderr, "DEBUG: mainloop has begun\n");
1458 
1459  while (std_out.path_open || tap_write.path_open)
1460  {
1461  /* perform READ from stdin if possible */
1462  if (std_in.path_open && (! attempt_read_stdin (&std_in, &tap_write)))
1463  break;
1464 
1465  /* perform READ from tap if possible */
1466  if (tap_read.path_open && (! attempt_read_tap (&tap_read, &std_out)))
1467  break;
1468 
1469  /* perform WRITE to tap if possible */
1470  if (tap_write.path_open && (! attempt_write (&tap_write, &std_in)))
1471  break;
1472 
1473  /* perform WRITE to STDOUT if possible */
1474  if (std_out.path_open && (! attempt_write (&std_out, &tap_read)))
1475  break;
1476  }
1477  fprintf (stderr, "DEBUG: teardown initiated\n");
1478 
1479 teardown:
1480 
1481  CancelIo (tap_handle);
1482  CancelIo (std_in.handle);
1483  CancelIo (std_out.handle);
1484 
1485 teardown_final:
1486 
1487  CloseHandle (tap_handle);
1488 }
static BOOL initialize_io_facility(struct io_facility *elem, int initial_state, BOOL signaled)
Initialize a overlapped structure.
static BOOL attempt_read_tap(struct io_facility *input_facility, struct io_facility *output_facility)
Attempts to read off an input facility (tap or named pipe) in overlapped mode.
static BOOL attempt_read_stdin(struct io_facility *input_facility, struct io_facility *output_facility)
Attempts to read off an input facility (tap or named pipe) in overlapped mode.
static boolean privilege_testing
Will this binary be run in permissions testing mode?
static BOOL attempt_write(struct io_facility *output_facility, struct io_facility *input_facility)
Attempts to write to an output facility (tap or named pipe) in overlapped mode.
overlapped I/O is ready for work
static BOOL tun_up(HANDLE handle)
Brings a TAP device up and sets it to connected state.
overlapped I/O has finished, but is waiting for it&#39;s write-partner
A IO Object + read/writebuffer + buffer-size for windows asynchronous IO handling.
WINBASEAPI HANDLE WINAPI ReOpenFile(HANDLE, DWORD, DWORD, DWORD)
ReOpenFile is only available as of XP SP2 and 2003 SP1.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char **  argv 
)

Open VPN tunnel interface.

Parameters
argcmust be 6
argv0: binary name ("gnunet-helper-exit") 1: tunnel interface name ("gnunet-exit") 2: IPv4 "physical" interface name ("eth0"), or "-" to not do IPv4 NAT 3: IPv6 address ("::1"), or "-" to skip IPv6 4: IPv6 netmask length in bits ("64") [ignored if #4 is "-"] 5: IPv4 address ("1.2.3.4"), or "-" to skip IPv4 6: IPv4 netmask ("255.255.0.0") [ignored if #4 is "-"]

Definition at line 1504 of file gnunet-helper-exit-windows.c.

References address, cleanup(), device_visible_name, execute_shellcommand(), global_ret, GNUNET_strlcpy(), io_facility::handle, init_tun(), privilege_testing, remove_address4(), remove_address6(), remove_interface(), run(), secondary_hwid, set_address4(), and set_address6().

1505 {
1506  char hwid[LINE_LEN];
1507  HANDLE handle;
1508  int global_ret = 1;
1509  int local_ret = EINVAL;
1510  BOOL have_ip4 = FALSE;
1511  BOOL have_ip6 = FALSE;
1512  BOOL have_nat44 = FALSE;
1513 
1514  if ( (1 < argc) && (0 != strcmp (argv[1], "-d"))){
1515  privilege_testing = TRUE;
1516  fprintf (stderr,
1517  "%s",
1518  "DEBUG: Running binary in privilege testing mode.");
1519  argv++;
1520  argc--;
1521  }
1522 
1523  if (6 != argc)
1524  {
1525  fprintf (stderr,
1526  "%s",
1527  "FATAL: must supply 6 arguments\nUsage:\ngnunet-helper-exit [-d] <if name prefix> <uplink-interface name> <address6 or \"-\"> <netbits6> <address4 or \"-\"> <netmask4>\n");
1528  return 1;
1529  }
1530 
1531  GNUNET_strlcpy (hwid, argv[1], sizeof (hwid));
1532 
1533  /*
1534  * We use our PID for finding/resolving the control-panel name of our virtual
1535  * device. PIDs are (of course) unique at runtime, thus we can safely use it
1536  * as additional hardware-id for our device.
1537  */
1538  snprintf (secondary_hwid, LINE_LEN / 2, "%s-%d",
1539  hwid,
1540  _getpid ());
1541 
1542  if (INVALID_HANDLE_VALUE == (handle = init_tun ()))
1543  {
1544  fprintf (stderr, "FATAL: could not initialize virtual-interface %s with IPv6 %s/%s and IPv4 %s/%s\n",
1545  hwid,
1546  argv[3],
1547  argv[4],
1548  argv[5],
1549  argv[6]);
1550  global_ret = -1;
1551  goto cleanup;
1552  }
1553 
1554  fprintf (stderr, "DEBUG: Setting IPs, if needed\n");
1555  if (0 != strcmp (argv[3], "-"))
1556  {
1557  char command[LINE_LEN];
1558  const char *address = argv[3];
1559  long prefix_len = atol (argv[4]);
1560 
1561  if ((prefix_len < 1) || (prefix_len > 127))
1562  {
1563  fprintf (stderr, "FATAL: ipv6 prefix_len out of range\n");
1564  global_ret = -1;
1565  goto cleanup;
1566  }
1567 
1568  fprintf (stderr, "DEBUG: Setting IP6 address: %s/%d\n", address, prefix_len);
1569  if (0 != (global_ret = set_address6 (address, prefix_len)))
1570  goto cleanup;
1571 
1572  have_ip6 = TRUE;
1573 
1574  /* install our the windows NAT module*/
1575  fprintf (stderr, "DEBUG: Setting IPv6 Forwarding for internal and external interface.\n");
1576  /* outside interface (maybe that's already set) */
1577  snprintf (command, LINE_LEN,
1578  "netsh interface ipv6 set interface interface=\"%s\" metric=1 forwarding=enabled store=active",
1579  argv[2]);
1580  local_ret = execute_shellcommand (command);
1581  if (0 != local_ret)
1582  {
1583  fprintf (stderr, "FATAL: Could not enable forwarding via netsh: %s\n", strerror (local_ret));
1584  goto cleanup;
1585  }
1586  /* internal interface */
1587  snprintf (command, LINE_LEN,
1588  "netsh interface ipv6 set interface interface=\"%s\" metric=1 forwarding=enabled advertise=enabled store=active",
1590  local_ret = execute_shellcommand (command);
1591  if (0 != local_ret)
1592  {
1593  fprintf (stderr, "FATAL: Could not enable forwarding via netsh: %s\n", strerror (local_ret));
1594  goto cleanup;
1595  }
1596  /* we can keep IPv6 forwarding around, as all interfaces have
1597  * their forwarding mode reset to false at bootup. */
1598  }
1599 
1600  if (0 != strcmp (argv[5], "-"))
1601  {
1602  const char *address = argv[5];
1603  const char *mask = argv[6];
1604 
1605  fprintf (stderr, "DEBUG: Setting IP4 address: %s/%s\n", address, mask);
1606  if (0 != (global_ret = set_address4 (address, mask)))
1607  goto cleanup;
1608 
1609  // setup NAPT, if possible
1610  /* MS has REMOVED the routing/nat capabilities from Vista+, thus
1611  * we can not setup NAT like in XP or on the server. Actually the
1612  * the only feasible solution seems to be to use
1613  * Internet Connection Sharing, which introduces a horde of problems
1614  * such as sending out rogue-RAs on the external interface in an ipv6
1615  * network.
1616  * Thus, below stuff ONLY works on
1617  * WinXP SP3
1618  * Win Server 2003 SP1+
1619  * Win Server 2008
1620  * ...
1621  */
1622  have_ip4 = TRUE;
1623  if (0 != strcmp (argv[2], "-"))
1624  {
1625  char command[LINE_LEN];
1626 
1627  /* install our the windows NAT module*/
1628  fprintf (stderr, "DEBUG: Adding NAPT/Masquerading between external IF %s and mine.\n", argv[2]);
1629  local_ret = execute_shellcommand ("netsh routing ip nat install");
1630  if (0 != local_ret)
1631  {
1632  fprintf (stderr, "FATAL: Could not install NAPT support via Netsh: %s\n", strerror (local_ret));
1633  goto cleanup;
1634  }
1635  /* external IF */
1636  snprintf (command, LINE_LEN,
1637  "netsh routing ip nat add interface \"%s\" full", /*full = NAPT (addr+port)*/
1638  argv[2]);
1639  local_ret = execute_shellcommand (command);
1640  if (0 != local_ret)
1641  {
1642  fprintf (stderr, "FATAL: IPv4-NAPT on external interface failed: %s\n", strerror (local_ret));
1643  goto cleanup;
1644  }
1645  /* private/internal/virtual IF */
1646  snprintf (command, LINE_LEN,
1647  "netsh routing ip nat add interface \"%s\" private",
1649  local_ret = execute_shellcommand (command);
1650  if (0 != local_ret)
1651  {
1652  fprintf (stderr, "FATAL: IPv4-NAPT on internal interface failed: %s\n", strerror (local_ret));
1653  goto cleanup;
1654 
1655  have_nat44 = TRUE;
1656  }
1657  }
1658  }
1659 
1660  run (handle);
1661 cleanup:
1662 
1663  if (have_ip4) {
1664  const char *address = argv[5];
1665  if (have_nat44) {
1666  char command[LINE_LEN];
1667  fprintf(stderr, "DEBUG: removing IP4 NAPT from virtual interface \n");
1668  snprintf(command, LINE_LEN,
1669  "netsh routing ip nat del interface \"%s\"",
1671  local_ret = execute_shellcommand(command);
1672  if (0 != local_ret)
1673  fprintf(stderr, "WARNING: Could not remove IPv4-NAPT from internal interface, hopefully this will have no effect in future runs: %s\n", strerror(local_ret));
1674  }
1675 
1676  fprintf(stderr, "DEBUG: Removing IP4 address\n");
1677  remove_address4 (address);
1678  }
1679  if (have_ip6)
1680  {
1681  const char *address = argv[3];
1682  fprintf (stderr, "DEBUG: Removing IP6 address\n");
1683  remove_address6 (address);
1684  }
1685 
1686  fprintf (stderr, "DEBUG: removing interface\n");
1687  remove_interface ();
1688  fprintf (stderr, "DEBUG: graceful exit completed\n");
1689 
1690  return global_ret;
1691 }
static int set_address6(const char *address, unsigned long prefix_len)
Sets the IPv6-Address given in address on the interface dev.
static HANDLE init_tun()
Creates a tun-interface called dev;.
static char device_visible_name[256]
Device&#39;s visible Name, used to identify a network device in netsh.
static void run(HANDLE tap_handle)
Start forwarding to and from the tunnel.
static int set_address4(const char *address, const char *mask)
Sets the IPv4-Address given in address on the interface dev.
static void cleanup(void *cls)
Function scheduled as very last function, cleans up after us.
static struct GNUNET_DNS_Handle * handle
Handle to transport service.
static BOOL remove_interface()
Remove our new virtual interface to use for tunneling.
static char secondary_hwid[LINE_LEN/2]
Our local process&#39; PID.
static boolean privilege_testing
Will this binary be run in permissions testing mode?
static void remove_address4(const char *address)
Removes the IPv4-Address given in address from the interface dev.
static void remove_address6(const char *address)
Removes the IPv6-Address given in address from the interface dev.
static int execute_shellcommand(const char *command)
Wrapper for executing a shellcommand in windows.
static char * address
GNS address for this phone.
size_t GNUNET_strlcpy(char *dst, const char *src, size_t n)
Like strlcpy but portable.
static int global_ret
Return value from main.
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 77 of file gnunet-helper-exit-windows.c.

Referenced by main(), and run().

◆ secondary_hwid

char secondary_hwid[LINE_LEN/2]
static

Our local process' PID.

Used for creating a sufficiently unique additional hardware ID for our device.

Definition at line 131 of file gnunet-helper-exit-windows.c.

Referenced by main(), and setup_interface().

◆ device_visible_name

char device_visible_name[256]
static

Device's visible Name, used to identify a network device in netsh.

eg: "Local Area Connection 9"

Definition at line 137 of file gnunet-helper-exit-windows.c.

Referenced by main(), remove_address4(), remove_address6(), resolve_interface_name(), set_address4(), and set_address6().

◆ DeviceInfo

HDEVINFO DeviceInfo = INVALID_HANDLE_VALUE
static

This is our own local instance of a virtual network interface It is (somewhat) equivalent to using tun/tap in unixoid systems.

Upon initialization, we create such an device node. Upon termination, we remove it again.

If we crash this device might stay around.

Definition at line 148 of file gnunet-helper-exit-windows.c.

Referenced by remove_interface(), and setup_interface().

◆ DeviceNode

SP_DEVINFO_DATA DeviceNode
static

Registry Key we hand over to windows to spawn a new virtual interface.

Definition at line 153 of file gnunet-helper-exit-windows.c.

Referenced by remove_interface(), resolve_interface_name(), and setup_interface().

◆ device_guid

char device_guid[256]
static

GUID of our virtual device in the form of {12345678-1234-1234-1234-123456789abc} - in hex.

Definition at line 159 of file gnunet-helper-exit-windows.c.

Referenced by init_tun(), and resolve_interface_name().