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 247 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.

165  {
169  IOSTATE_READY = 0,
170 
175 
180 
185 
191 };
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 282 of file gnunet-helper-exit-windows.c.

Referenced by setup_interface().

283 {
284 #if defined(_WIN64)
285  //this is a win64 binary,
286  return TRUE;
287 #elif defined(_WIN32)
288  //this is a 32bit binary, and we need to check if we are running in WOW64
289  BOOL success = FALSE;
290  BOOL on_wow64 = FALSE;
291  LPFN_ISWOW64PROCESS IsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process");
292 
293  if (NULL != IsWow64Process)
294  success = IsWow64Process(GetCurrentProcess(), &on_wow64);
295 
296  return success && on_wow64;
297 #endif
298 }
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 308 of file gnunet-helper-exit-windows.c.

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

309 {
310  FILE *pipe;
311 
312  if ((NULL == command) ||
313  (NULL == (pipe = _popen(command, "rt"))))
314  return EINVAL;
315 
316 #if DEBUG
317  fprintf(stderr, "DEBUG: Command output: \n");
318  char output[LINE_LEN];
319  while (NULL != fgets(output, sizeof(output), pipe))
320  fprintf(stderr, "%s", output);
321 #endif
322 
323  return _pclose(pipe);
324 }
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 334 of file gnunet-helper-exit-windows.c.

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

Referenced by main().

335 {
336  int ret = EINVAL;
337  char command[LINE_LEN];
338  struct sockaddr_in6 sa6;
339 
340  /*
341  * parse the new address
342  */
343  memset(&sa6, 0, sizeof(struct sockaddr_in6));
344  sa6.sin6_family = AF_INET6;
345  if (1 != inet_pton(AF_INET6, address, &sa6.sin6_addr.s6_addr))
346  {
347  fprintf(stderr, "ERROR: Failed to parse address `%s': %s\n", address,
348  strerror(errno));
349  return -1;
350  }
351 
352  /*
353  * prepare the command
354  */
355  snprintf(command, LINE_LEN,
356  "netsh interface ipv6 add address \"%s\" %s/%d store=active",
357  device_visible_name, address, prefix_len);
358  /*
359  * Set the address
360  */
361  ret = execute_shellcommand(command);
362 
363  /* Did it work?*/
364  if (0 != ret)
365  fprintf(stderr, "FATAL: Setting IPv6 address failed: %s\n", strerror(ret));
366  return ret;
367 }
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 376 of file gnunet-helper-exit-windows.c.

References device_visible_name, execute_shellcommand(), and ret.

Referenced by main().

377 {
378  char command[LINE_LEN];
379  int ret = EINVAL;
380 
381  // sanity checking was already done in set_address6
382  /*
383  * prepare the command
384  */
385  snprintf(command, LINE_LEN,
386  "netsh interface ipv6 delete address \"%s\" store=persistent",
388  /*
389  * Set the address
390  */
391  ret = execute_shellcommand(command);
392 
393  /* Did it work?*/
394  if (0 != ret)
395  fprintf(stderr, "FATAL: removing IPv6 address failed: %s\n", strerror(ret));
396 }
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 406 of file gnunet-helper-exit-windows.c.

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

Referenced by main().

407 {
408  int ret = EINVAL;
409  char command[LINE_LEN];
410 
411  struct sockaddr_in addr;
412 
413  addr.sin_family = AF_INET;
414 
415  /*
416  * Parse the address
417  */
418  if (1 != inet_pton(AF_INET, address, &addr.sin_addr.s_addr))
419  {
420  fprintf(stderr, "ERROR: Failed to parse address `%s': %s\n", address,
421  strerror(errno));
422  return -1;
423  }
424  // Set Device to Subnet-Mode?
425  // do we really need tun.c:2925 ?
426 
427  /*
428  * prepare the command
429  */
430  snprintf(command, LINE_LEN,
431  "netsh interface ipv4 add address \"%s\" %s %s store=active",
433  /*
434  * Set the address
435  */
436  ret = execute_shellcommand(command);
437 
438  /* Did it work?*/
439  if (0 != ret)
440  fprintf(stderr, "FATAL: Setting IPv4 address failed: %s\n", strerror(ret));
441  return ret;
442 }
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 451 of file gnunet-helper-exit-windows.c.

References device_visible_name, execute_shellcommand(), and ret.

Referenced by main().

452 {
453  char command[LINE_LEN];
454  int ret = EINVAL;
455 
456  // sanity checking was already done in set_address4
457 
458  /*
459  * prepare the command
460  */
461  snprintf(command, LINE_LEN,
462  "netsh interface ipv4 delete address \"%s\" gateway=all store=persistent",
464  /*
465  * Set the address
466  */
467  ret = execute_shellcommand(command);
468 
469  /* Did it work?*/
470  if (0 != ret)
471  fprintf(stderr, "FATAL: removing IPv4 address failed: %s\n", strerror(ret));
472 }
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 481 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().

482 {
483  /*
484  * where to find our inf-file. (+ the "full" path, after windows found")
485  *
486  * We do not directly input all the props here, because openvpn will update
487  * these details over time.
488  */
489  char inf_file_path[MAX_PATH];
490  char * temp_inf_filename;
491  char hwidlist[LINE_LEN + 4];
492  char class_name[128];
493  GUID class_guid;
494  int str_length = 0;
495 
500  str_length = GNUNET_strlcpy(hwidlist,
501  HARDWARE_ID,
502  sizeof(hwidlist)) + 1;
509  str_length = strlen(hwidlist) + 1;
510  str_length += GNUNET_strlcpy(&hwidlist[str_length],
512  sizeof(hwidlist) - str_length) + 1;
513  GNUNET_assert(str_length < sizeof(hwidlist));
514  hwidlist[str_length] = '\0';
515  ++str_length;
516 
521  if (is_win64())
522  GetFullPathNameA(INF_FILE64, MAX_PATH, inf_file_path, &temp_inf_filename);
523  else
524  GetFullPathNameA(INF_FILE, MAX_PATH, inf_file_path, &temp_inf_filename);
525 
526  fprintf(stderr, "INFO: Located our driver's .inf file at %s\n", inf_file_path);
530  if (!SetupDiGetINFClassA(inf_file_path,
531  &class_guid,
532  class_name, sizeof(class_name) / sizeof(char),
533  NULL))
534  return FALSE;
535 
540  DeviceInfo = SetupDiCreateDeviceInfoList(&class_guid, NULL);
541  if (DeviceInfo == INVALID_HANDLE_VALUE)
542  return FALSE;
543 
544  DeviceNode.cbSize = sizeof(SP_DEVINFO_DATA);
545  if (!SetupDiCreateDeviceInfoA(DeviceInfo,
546  class_name,
547  &class_guid,
548  NULL,
549  0,
550  DICD_GENERATE_ID,
551  &DeviceNode))
552  return FALSE;
553 
554  /* Deploy all the information collected into the registry */
555  if (!SetupDiSetDeviceRegistryPropertyA(DeviceInfo,
556  &DeviceNode,
557  SPDRP_HARDWAREID,
558  (LPBYTE)hwidlist,
559  str_length * sizeof(char)))
560  return FALSE;
561 
562  /* Install our new class(=device) into the system */
563  if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE,
564  DeviceInfo,
565  &DeviceNode))
566  return FALSE;
567 
568  /* This system call tends to take a while (several seconds!) on
569  "modern" Windoze systems */
570  if (!UpdateDriverForPlugAndPlayDevicesA(NULL,
572  inf_file_path,
573  INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE,
574  NULL)) //reboot required? NEVER!
575  return FALSE;
576 
577  fprintf(stderr, "DEBUG: successfully created a network device\n");
578  return TRUE;
579 }
#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 589 of file gnunet-helper-exit-windows.c.

References DeviceInfo, and DeviceNode.

Referenced by main().

590 {
591  SP_REMOVEDEVICE_PARAMS remove;
592 
593  if (INVALID_HANDLE_VALUE == DeviceInfo)
594  return FALSE;
595 
596  remove.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
597  remove.HwProfile = 0;
598  remove.Scope = DI_REMOVEDEVICE_GLOBAL;
599  remove.ClassInstallHeader.InstallFunction = DIF_REMOVE;
600  /*
601  * 1. Prepare our existing device information set, and place the
602  * uninstall related information into the structure
603  */
604  if (!SetupDiSetClassInstallParamsA(DeviceInfo,
605  (PSP_DEVINFO_DATA)&DeviceNode,
606  &remove.ClassInstallHeader,
607  sizeof(remove)))
608  return FALSE;
609  /*
610  * 2. Uninstall the virtual interface using the class installer
611  */
612  if (!SetupDiCallClassInstaller(DIF_REMOVE,
613  DeviceInfo,
614  (PSP_DEVINFO_DATA)&DeviceNode))
615  return FALSE;
616 
617  SetupDiDestroyDeviceInfoList(DeviceInfo);
618 
619  fprintf(stderr, "DEBUG: removed interface successfully\n");
620 
621  return TRUE;
622 }
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 632 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().

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

774 {
775  ULONG version[3];
776  DWORD len;
777 
778  memset(&(version), 0, sizeof(version));
779 
780  if (DeviceIoControl(handle, TAP_WIN_IOCTL_GET_VERSION,
781  &version, sizeof(version),
782  &version, sizeof(version), &len, NULL))
783  fprintf(stderr, "INFO: TAP-Windows Driver Version %d.%d %s\n",
784  (int)version[0],
785  (int)version[1],
786  (version[2] ? "(DEBUG)" : ""));
787 
788  if ((version[0] != TAP_WIN_MIN_MAJOR) ||
789  (version[1] < TAP_WIN_MIN_MINOR))
790  {
791  fprintf(stderr, "FATAL: This version of gnunet requires a TAP-Windows driver that is at least version %d.%d\n",
794  return FALSE;
795  }
796 
797  return TRUE;
798 }
#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 807 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().

808 {
809  char device_path[256];
810  HANDLE handle;
811 
812  if (!setup_interface())
813  {
814  errno = ENODEV;
815  return INVALID_HANDLE_VALUE;
816  }
817 
818  if (!resolve_interface_name())
819  {
820  errno = ENODEV;
821  return INVALID_HANDLE_VALUE;
822  }
823 
824  /* Open Windows TAP-Windows adapter */
825  snprintf(device_path, sizeof(device_path), "%s%s%s",
827  device_guid,
829 
830  handle = CreateFile(
831  device_path,
832  GENERIC_READ | GENERIC_WRITE,
833  0, /* was: FILE_SHARE_READ */
834  0,
835  OPEN_EXISTING,
836  FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
837  0
838  );
839 
840  if (INVALID_HANDLE_VALUE == handle)
841  {
842  fprintf(stderr, "FATAL: CreateFile failed on TAP device: %s\n", device_path);
843  return handle;
844  }
845 
846  /* get driver version info */
847  if (!check_tapw32_version(handle))
848  {
849  CloseHandle(handle);
850  return INVALID_HANDLE_VALUE;
851  }
852 
853  /* TODO (opt?): get MTU-Size */
854 
855  fprintf(stderr, "DEBUG: successfully opened TAP device\n");
856  return handle;
857 }
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 867 of file gnunet-helper-exit-windows.c.

References len, status, TAP32_POSTUP_WAITTIME, and TAP_WIN_IOCTL_SET_MEDIA_STATUS.

Referenced by run().

868 {
869  ULONG status = TRUE;
870  DWORD len;
871 
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  /* reset event manually*/
939  if (!SetEvent(input_facility->overlapped.hEvent))
940  return FALSE;
941 
942  fprintf(stderr, "DEBUG: tap read succeeded immediately\n");
943 
944  /* we successfully read something from the TAP and now need to
945  * send it our via STDOUT. Is that possible at the moment? */
946  if ((IOSTATE_READY == output_facility->facility_state ||
947  IOSTATE_WAITING == output_facility->facility_state)
948  && (0 < input_facility->buffer_size))
949  { /* hand over this buffers content and apply message header for gnunet */
950  hdr = (struct GNUNET_MessageHeader *)output_facility->buffer;
951  size = input_facility->buffer_size + sizeof(struct GNUNET_MessageHeader);
952 
953  GNUNET_memcpy(output_facility->buffer + sizeof(struct GNUNET_MessageHeader),
954  input_facility->buffer,
955  input_facility->buffer_size);
956 
957  output_facility->buffer_size = size;
958  hdr->size = htons(size);
959  hdr->type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER);
960  output_facility->facility_state = IOSTATE_READY;
961  }
962  else if (0 < input_facility->buffer_size)
963  /* If we have have read our buffer, wait for our write-partner*/
964  input_facility->facility_state = IOSTATE_WAITING;
965  }
966  else /* operation was either queued or failed*/
967  {
968  int err = GetLastError();
969  if (ERROR_IO_PENDING == err)
970  { /* operation queued */
971  input_facility->facility_state = IOSTATE_QUEUED;
972  }
973  else
974  { /* error occurred, let the rest of the elements finish */
975  input_facility->path_open = FALSE;
976  input_facility->facility_state = IOSTATE_FAILED;
977  if (IOSTATE_WAITING == output_facility->facility_state)
978  output_facility->path_open = FALSE;
979 
980  fprintf(stderr, "FATAL: Read from handle failed, allowing write to finish\n");
981  }
982  }
983  }
984  return TRUE;
985 
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 
1041  case IOSTATE_RESUME:
1042  hdr = (struct GNUNET_MessageHeader *)output_facility->buffer;
1043  size = input_facility->buffer_size + sizeof(struct GNUNET_MessageHeader);
1044 
1045  GNUNET_memcpy(output_facility->buffer + sizeof(struct GNUNET_MessageHeader),
1046  input_facility->buffer,
1047  input_facility->buffer_size);
1048 
1049  output_facility->buffer_size = size;
1050  hdr->size = htons(size);
1051  hdr->type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER);
1052  output_facility->facility_state = IOSTATE_READY;
1053  input_facility->facility_state = IOSTATE_READY;
1054  return TRUE;
1055 
1056  default:
1057  return TRUE;
1058  }
1059 }
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:66
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 1089 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().

1091 {
1092  struct GNUNET_MessageHeader * hdr;
1093 
1094  switch (input_facility->facility_state)
1095  {
1096  case IOSTATE_READY:
1097  {
1098  input_facility->buffer_size = 0;
1099 
1100 partial_read_iostate_ready:
1101  if (!ResetEvent(input_facility->overlapped.hEvent))
1102  return FALSE;
1103 
1104  /* Check how the task is handled */
1105  if (ReadFile(input_facility->handle,
1106  input_facility->buffer + input_facility->buffer_size,
1107  sizeof(input_facility->buffer) - input_facility->buffer_size,
1108  &input_facility->buffer_size_processed,
1109  &input_facility->overlapped))
1110  { /* async event processed immediately*/
1111  hdr = (struct GNUNET_MessageHeader *)input_facility->buffer;
1112 
1113  /* reset event manually*/
1114  if (!SetEvent(input_facility->overlapped.hEvent))
1115  return FALSE;
1116 
1117  fprintf(stderr, "DEBUG: stdin read succeeded immediately\n");
1118  input_facility->buffer_size += input_facility->buffer_size_processed;
1119 
1120  if (ntohs(hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER ||
1121  ntohs(hdr->size) > sizeof(input_facility->buffer))
1122  {
1123  fprintf(stderr, "WARNING: Protocol violation, got GNUnet Message type %h, size %h\n", ntohs(hdr->type), ntohs(hdr->size));
1124  input_facility->facility_state = IOSTATE_READY;
1125  return TRUE;
1126  }
1127  /* we got the a part of a packet */
1128  if (ntohs(hdr->size) > input_facility->buffer_size)
1129  goto partial_read_iostate_ready;
1130 
1131  /* have we read more than 0 bytes of payload? (sizeread > header)*/
1132  if (input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader) &&
1133  ((IOSTATE_READY == output_facility->facility_state) ||
1134  (IOSTATE_WAITING == output_facility->facility_state)))
1135  { /* we successfully read something from the TAP and now need to
1136  * send it our via STDOUT. Is that possible at the moment? */
1137  /* hand over this buffers content and strip gnunet message header */
1138  GNUNET_memcpy(output_facility->buffer,
1139  input_facility->buffer + sizeof(struct GNUNET_MessageHeader),
1140  input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader));
1141  output_facility->buffer_size = input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader);
1142  output_facility->facility_state = IOSTATE_READY;
1143  input_facility->facility_state = IOSTATE_READY;
1144  }
1145  else if (input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader))
1146  /* If we have have read our buffer, wait for our write-partner*/
1147  input_facility->facility_state = IOSTATE_WAITING;
1148  else /* we read nothing */
1149  input_facility->facility_state = IOSTATE_READY;
1150  }
1151  else /* operation was either queued or failed*/
1152  {
1153  int err = GetLastError();
1154  if (ERROR_IO_PENDING == err) /* operation queued */
1155  input_facility->facility_state = IOSTATE_QUEUED;
1156  else
1157  { /* error occurred, let the rest of the elements finish */
1158  input_facility->path_open = FALSE;
1159  input_facility->facility_state = IOSTATE_FAILED;
1160  if (IOSTATE_WAITING == output_facility->facility_state)
1161  output_facility->path_open = FALSE;
1162 
1163  fprintf(stderr, "FATAL: Read from handle failed, allowing write to finish\n");
1164  }
1165  }
1166  }
1167  return TRUE;
1168 
1169  // We are queued and should check if the read has finished
1170  case IOSTATE_QUEUED:
1171  {
1172  // there was an operation going on already, check if that has completed now.
1173  if (GetOverlappedResult(input_facility->handle,
1174  &input_facility->overlapped,
1175  &input_facility->buffer_size_processed,
1176  FALSE))
1177  { /* successful return for a queued operation */
1178  hdr = (struct GNUNET_MessageHeader *)input_facility->buffer;
1179 
1180  if (!ResetEvent(input_facility->overlapped.hEvent))
1181  return FALSE;
1182 
1183  fprintf(stderr, "DEBUG: stdin read succeeded delayed\n");
1184  input_facility->buffer_size += input_facility->buffer_size_processed;
1185 
1186  if ((ntohs(hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1187  (ntohs(hdr->size) > sizeof(input_facility->buffer)))
1188  {
1189  fprintf(stderr, "WARNING: Protocol violation, got GNUnet Message type %h, size %h\n", ntohs(hdr->type), ntohs(hdr->size));
1190  input_facility->facility_state = IOSTATE_READY;
1191  return TRUE;
1192  }
1193  /* we got the a part of a packet */
1194  if (ntohs(hdr->size) > input_facility->buffer_size)
1195  ;
1196  goto partial_read_iostate_ready;
1197 
1198  /* we successfully read something from the TAP and now need to
1199  * send it our via STDOUT. Is that possible at the moment? */
1200  if ((IOSTATE_READY == output_facility->facility_state ||
1201  IOSTATE_WAITING == output_facility->facility_state)
1202  && input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader))
1203  { /* hand over this buffers content and strip gnunet message header */
1204  GNUNET_memcpy(output_facility->buffer,
1205  input_facility->buffer + sizeof(struct GNUNET_MessageHeader),
1206  input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader));
1207  output_facility->buffer_size = input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader);
1208  output_facility->facility_state = IOSTATE_READY;
1209  input_facility->facility_state = IOSTATE_READY;
1210  }
1211  else if (input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader))
1212  input_facility->facility_state = IOSTATE_WAITING;
1213  else
1214  input_facility->facility_state = IOSTATE_READY;
1215  }
1216  else
1217  { /* operation still pending/queued or failed? */
1218  int err = GetLastError();
1219  if ((ERROR_IO_INCOMPLETE != err) && (ERROR_IO_PENDING != err))
1220  { /* error occurred, let the rest of the elements finish */
1221  input_facility->path_open = FALSE;
1222  input_facility->facility_state = IOSTATE_FAILED;
1223  if (IOSTATE_WAITING == output_facility->facility_state)
1224  output_facility->path_open = FALSE;
1225  fprintf(stderr, "FATAL: Read from handle failed, allowing write to finish\n");
1226  }
1227  }
1228  }
1229  return TRUE;
1230 
1231  case IOSTATE_RESUME: /* Our buffer was filled already but our write facility was busy. */
1232  GNUNET_memcpy(output_facility->buffer,
1233  input_facility->buffer + sizeof(struct GNUNET_MessageHeader),
1234  input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader));
1235  output_facility->buffer_size = input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader);
1236  output_facility->facility_state = IOSTATE_READY;
1237  input_facility->facility_state = IOSTATE_READY;
1238  return TRUE;
1239 
1240  default:
1241  return TRUE;
1242  }
1243 }
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 1256 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().

1258 {
1259  switch (output_facility->facility_state)
1260  {
1261  case IOSTATE_READY:
1262  output_facility->buffer_size_written = 0;
1263 
1264 continue_partial_write:
1265  if (!ResetEvent(output_facility->overlapped.hEvent))
1266  return FALSE;
1267 
1268  /* Check how the task was handled */
1269  if (WriteFile(output_facility->handle,
1270  output_facility->buffer + output_facility->buffer_size_written,
1271  output_facility->buffer_size - output_facility->buffer_size_written,
1272  &output_facility->buffer_size_processed,
1273  &output_facility->overlapped))
1274  {/* async event processed immediately*/
1275  fprintf(stderr, "DEBUG: write succeeded immediately\n");
1276  output_facility->buffer_size_written += output_facility->buffer_size_processed;
1277 
1278  /* reset event manually*/
1279  if (!SetEvent(output_facility->overlapped.hEvent))
1280  return FALSE;
1281 
1282  /* partial write */
1283  if (output_facility->buffer_size_written < output_facility->buffer_size)
1284  goto continue_partial_write;
1285 
1286  /* we are now waiting for our buffer to be filled*/
1287  output_facility->facility_state = IOSTATE_WAITING;
1288 
1289  /* we successfully wrote something and now need to reset our reader */
1290  if (IOSTATE_WAITING == input_facility->facility_state)
1291  input_facility->facility_state = IOSTATE_RESUME;
1292  else if (IOSTATE_FAILED == input_facility->facility_state)
1293  output_facility->path_open = FALSE;
1294  }
1295  else /* operation was either queued or failed*/
1296  {
1297  int err = GetLastError();
1298  if (ERROR_IO_PENDING == err)
1299  { /* operation queued */
1300  output_facility->facility_state = IOSTATE_QUEUED;
1301  }
1302  else
1303  { /* error occurred, close this path */
1304  output_facility->path_open = FALSE;
1305  output_facility->facility_state = IOSTATE_FAILED;
1306  fprintf(stderr, "FATAL: Write to handle failed, exiting\n");
1307  }
1308  }
1309  return TRUE;
1310 
1311  case IOSTATE_QUEUED:
1312  // there was an operation going on already, check if that has completed now.
1313 
1314  if (GetOverlappedResult(output_facility->handle,
1315  &output_facility->overlapped,
1316  &output_facility->buffer_size_processed,
1317  FALSE))
1318  {/* successful return for a queued operation */
1319  if (!ResetEvent(output_facility->overlapped.hEvent))
1320  return FALSE;
1321 
1322  fprintf(stderr, "DEBUG: write succeeded delayed\n");
1323  output_facility->buffer_size_written += output_facility->buffer_size_processed;
1324 
1325  /* partial write */
1326  if (output_facility->buffer_size_written < output_facility->buffer_size)
1327  goto continue_partial_write;
1328 
1329  /* we are now waiting for our buffer to be filled*/
1330  output_facility->facility_state = IOSTATE_WAITING;
1331 
1332  /* we successfully wrote something and now need to reset our reader */
1333  if (IOSTATE_WAITING == input_facility->facility_state)
1334  input_facility->facility_state = IOSTATE_RESUME;
1335  else if (IOSTATE_FAILED == input_facility->facility_state)
1336  output_facility->path_open = FALSE;
1337  }
1338  else
1339  { /* operation still pending/queued or failed? */
1340  int err = GetLastError();
1341  if ((ERROR_IO_INCOMPLETE != err) && (ERROR_IO_PENDING != err))
1342  { /* error occurred, close this path */
1343  output_facility->path_open = FALSE;
1344  output_facility->facility_state = IOSTATE_FAILED;
1345  fprintf(stderr, "FATAL: Write to handle failed, exiting\n");
1346  }
1347  }
1348 
1349  default:
1350  return TRUE;
1351  }
1352 }
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 1364 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().

1367 {
1368  elem->path_open = TRUE;
1369  elem->handle = INVALID_HANDLE_VALUE;
1370  elem->facility_state = initial_state;
1371  elem->buffer_size = 0;
1372  elem->overlapped.hEvent = CreateEvent(NULL, TRUE, signaled, NULL);
1373  if (NULL == elem->overlapped.hEvent)
1374  return FALSE;
1375 
1376  return TRUE;
1377 }
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 1386 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().

1387 {
1388  /* IO-Facility for reading from our virtual interface */
1389  struct io_facility tap_read;
1390  /* IO-Facility for writing to our virtual interface */
1391  struct io_facility tap_write;
1392  /* IO-Facility for reading from stdin */
1393  struct io_facility std_in;
1394  /* IO-Facility for writing to stdout */
1395  struct io_facility std_out;
1396 
1397  HANDLE parent_std_in_handle = GetStdHandle(STD_INPUT_HANDLE);
1398  HANDLE parent_std_out_handle = GetStdHandle(STD_OUTPUT_HANDLE);
1399 
1400  /* tun up: */
1401  /* we do this HERE and not beforehand (in init_tun()), in contrast to openvpn
1402  * to remove the need to flush the arp cache, handle DHCP and wrong IPs.
1403  *
1404  * DHCP and such are all features we will never use in gnunet afaik.
1405  * But for openvpn those are essential.
1406  */
1407  if ((privilege_testing) || (!tun_up(tap_handle)))
1408  goto teardown_final;
1409 
1410  /* Initialize our overlapped IO structures*/
1411  if (!(initialize_io_facility(&tap_read, IOSTATE_READY, FALSE)
1412  && initialize_io_facility(&tap_write, IOSTATE_WAITING, TRUE)
1413  && initialize_io_facility(&std_in, IOSTATE_READY, FALSE)
1414  && initialize_io_facility(&std_out, IOSTATE_WAITING, TRUE)))
1415  goto teardown_final;
1416 
1417  /* Handles for STDIN and STDOUT */
1418  tap_read.handle = tap_handle;
1419  tap_write.handle = tap_handle;
1420 
1421 #ifdef DEBUG_TO_CONSOLE
1422  /* Debug output to console STDIN/STDOUT*/
1423  std_in.handle = parent_std_in_handle;
1424  std_out.handle = parent_std_out_handle;
1425 #else
1426  fprintf(stderr, "DEBUG: reopening stdin/out for overlapped IO\n");
1427  /*
1428  * Find out the types of our handles.
1429  * This part is a problem, because in windows we need to handle files,
1430  * pipes and the console differently.
1431  */
1432  if ((FILE_TYPE_PIPE != GetFileType(parent_std_in_handle)) ||
1433  (FILE_TYPE_PIPE != GetFileType(parent_std_out_handle)))
1434  {
1435  fprintf(stderr, "ERROR: stdin/stdout must be named pipes\n");
1436  goto teardown;
1437  }
1438 
1439  std_in.handle = ReOpenFile(parent_std_in_handle,
1440  GENERIC_READ,
1441  FILE_SHARE_WRITE | FILE_SHARE_READ,
1442  FILE_FLAG_OVERLAPPED);
1443 
1444  if (INVALID_HANDLE_VALUE == std_in.handle)
1445  {
1446  fprintf(stderr, "FATAL: Could not reopen stdin for in overlapped mode, has to be a named pipe\n");
1447  goto teardown;
1448  }
1449 
1450  std_out.handle = ReOpenFile(parent_std_out_handle,
1451  GENERIC_WRITE,
1452  FILE_SHARE_READ,
1453  FILE_FLAG_OVERLAPPED);
1454 
1455  if (INVALID_HANDLE_VALUE == std_out.handle)
1456  {
1457  fprintf(stderr, "FATAL: Could not reopen stdout for in overlapped mode, has to be a named pipe\n");
1458  goto teardown;
1459  }
1460 #endif
1461 
1462  fprintf(stderr, "DEBUG: mainloop has begun\n");
1463 
1464  while (std_out.path_open || tap_write.path_open)
1465  {
1466  /* perform READ from stdin if possible */
1467  if (std_in.path_open && (!attempt_read_stdin(&std_in, &tap_write)))
1468  break;
1469 
1470  /* perform READ from tap if possible */
1471  if (tap_read.path_open && (!attempt_read_tap(&tap_read, &std_out)))
1472  break;
1473 
1474  /* perform WRITE to tap if possible */
1475  if (tap_write.path_open && (!attempt_write(&tap_write, &std_in)))
1476  break;
1477 
1478  /* perform WRITE to STDOUT if possible */
1479  if (std_out.path_open && (!attempt_write(&std_out, &tap_read)))
1480  break;
1481  }
1482  fprintf(stderr, "DEBUG: teardown initiated\n");
1483 
1484 teardown:
1485 
1486  CancelIo(tap_handle);
1487  CancelIo(std_in.handle);
1488  CancelIo(std_out.handle);
1489 
1490 teardown_final:
1491 
1492  CloseHandle(tap_handle);
1493 }
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 1509 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().

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