GNUnet  0.10.x
gnunet-helper-vpn-windows.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2010, 2012 Christian Grothoff
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
33 #include <stdio.h>
34 #include <Winsock2.h>
35 #include <windows.h>
36 #include <setupapi.h>
37 #ifndef __MINGW64_VERSION_MAJOR
38 #include <ddk/cfgmgr32.h>
39 #include <ddk/newdev.h>
40 #else
41 #include <cfgmgr32.h>
42 #include <newdev.h>
43 #endif
44 #include <time.h>
45 #include "platform.h"
46 #include "tap-windows.h"
50 #include "gnunet_crypto_lib.h"
54 #include "gnunet_common.h"
55 
59 #include "gnunet_protocols.h"
60 
65 #define DEBUG GNUNET_NO
66 
67 #if DEBUG
68 /* FIXME: define with varargs... */
69 #define LOG_DEBUG(msg) fprintf (stderr, "%s", msg);
70 #else
71 #define LOG_DEBUG(msg) do {} while (0)
72 #endif
73 
77 static boolean privilege_testing = FALSE;
78 
82 #define MAX_SIZE 65536
83 
88 #define INF_FILE "share/gnunet/openvpn-tap32/tapw32/OemWin2k.inf"
89 
94 #define INF_FILE64 "share/gnunet/openvpn-tap32/tapw64/OemWin2k.inf"
95 
100 #define HARDWARE_ID "tap0901"
101 
105 #define TAP_WIN_MIN_MAJOR 9
106 
112 #define TAP_WIN_MIN_MINOR 9
113 
120 #define TAP32_POSTUP_WAITTIME 4
121 
125 #define INTERFACE_REGISTRY_LOCATION "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
126 
131 static char secondary_hwid[LINE_LEN / 2];
132 
137 static char device_visible_name[256];
138 
148 static HDEVINFO DeviceInfo = INVALID_HANDLE_VALUE;
149 
153 static SP_DEVINFO_DATA DeviceNode;
154 
159 static char device_guid[256];
160 
161 
166 {
167 
172 
177 
182 
187 
193 
194 };
195 
196 
200 struct io_facility
201 {
206 
210  BOOL path_open; // BOOL is winbool (int), NOT boolean (unsigned char)!
211 
215  HANDLE handle;
216 
220  OVERLAPPED overlapped;
221 
225  unsigned char buffer[MAX_SIZE];
226 
230  DWORD buffer_size;
231 
235  DWORD buffer_size_processed;
236 
240  DWORD buffer_size_written;
241 };
242 
246 WINBASEAPI HANDLE WINAPI ReOpenFile (HANDLE, DWORD, DWORD, DWORD);
247 
251 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
252 
253 
266 size_t
267 GNUNET_strlcpy(char *dst, const char *src, size_t n)
268 {
269  size_t ret;
270  size_t slen;
271 
272  GNUNET_assert (0 != n);
273  slen = strnlen (src, n - 1);
274  memcpy (dst, src, slen);
275  dst[slen] = '\0';
276  return slen;
277 }
278 
279 
285 BOOL
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 }
311 static int
312 execute_shellcommand (const char *command)
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 }
329 
330 
337 static int
338 set_address6 (const char *address, unsigned long prefix_len)
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 }
372 
373 
379 static void
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,
400  "FATAL: removing IPv6 address failed: %s\n",
401  strerror (ret));
402 }
403 
404 
411 static int
412 set_address4 (const char *address, const char *mask)
413 {
414  int ret = EINVAL;
415  char command[LINE_LEN];
416 
417  struct sockaddr_in addr;
418  addr.sin_family = AF_INET;
419 
420  /*
421  * Parse the address
422  */
423  if (1 != inet_pton (AF_INET, address, &addr.sin_addr.s_addr))
424  {
425  fprintf (stderr, "ERROR: Failed to parse address `%s': %s\n", address,
426  strerror (errno));
427  return -1;
428  }
429  // Set Device to Subnet-Mode? do we really need openvpn/tun.c:2925 ?
430 
431  /*
432  * prepare the command
433  */
434  snprintf (command, LINE_LEN,
435  "netsh interface ipv4 add address \"%s\" %s %s store=active",
436  device_visible_name, address, mask);
437  /*
438  * Set the address
439  */
440  ret = execute_shellcommand (command);
441 
442  /* Did it work?*/
443  if (0 != ret)
444  fprintf (stderr,
445  "FATAL: Setting IPv4 address failed: %s\n",
446  strerror (ret));
447  return ret;
448 }
449 
450 
456 static void
458 {
459  char command[LINE_LEN];
460  int ret = EINVAL;
461 
462  // sanity checking was already done in set_address4
463 
464  /*
465  * prepare the command
466  */
467  snprintf (command, LINE_LEN,
468  "netsh interface ipv4 delete address \"%s\" gateway=all store=persistent",
470  /*
471  * Set the address
472  */
473  ret = execute_shellcommand (command);
474 
475  /* Did it work?*/
476  if (0 != ret)
477  fprintf (stderr, "FATAL: removing IPv4 address failed: %s\n", strerror (ret));
478 }
479 
480 
486 static BOOL
488 {
489  /*
490  * where to find our inf-file. (+ the "full" path, after windows found")
491  *
492  * We do not directly input all the props here, because openvpn will update
493  * these details over time.
494  */
495  char inf_file_path[MAX_PATH];
496  char * temp_inf_filename;
497  char hwidlist[LINE_LEN + 4];
498  char class_name[128];
499  GUID class_guid;
500  int str_length = 0;
501 
506  str_len = GNUNET_strlcpy (hwidlist,
507  HARDWARE_ID,
508  sizeof (hwidList)) + 1;
515  str_len += GNUNET_strlcpy (&hwidlist[str_length],
517  sizeof (hwidlist) - str_len) + 1;
518  GNUNET_assert (str_len < sizeof (hwidlist));
519  hwidlist[str_len] = '\0';
520  ++str_len;
521 
526  if (is_win64())
527  GetFullPathNameA (INF_FILE64, MAX_PATH, inf_file_path, &temp_inf_filename);
528  else
529  GetFullPathNameA (INF_FILE, MAX_PATH, inf_file_path, &temp_inf_filename);
530 
531  fprintf (stderr, "INFO: Located our driver's .inf file at %s\n", inf_file_path);
535  if ( ! SetupDiGetINFClassA (inf_file_path,
536  &class_guid,
537  class_name, sizeof (class_name) / sizeof (char),
538  NULL))
539  return FALSE;
540 
545  DeviceInfo = SetupDiCreateDeviceInfoList (&class_guid, NULL);
546  if (DeviceInfo == INVALID_HANDLE_VALUE)
547  return FALSE;
548 
549  DeviceNode.cbSize = sizeof (SP_DEVINFO_DATA);
550  if ( ! SetupDiCreateDeviceInfoA (DeviceInfo,
551  class_name,
552  &class_guid,
553  NULL,
554  0,
555  DICD_GENERATE_ID,
556  &DeviceNode))
557  return FALSE;
558 
559  /* Deploy all the information collected into the registry */
560  if ( ! SetupDiSetDeviceRegistryPropertyA (DeviceInfo,
561  &DeviceNode,
562  SPDRP_HARDWAREID,
563  (LPBYTE) hwidlist,
564  str_length * sizeof (char)))
565  return FALSE;
566 
567  /* Install our new class(=device) into the system */
568  if ( ! SetupDiCallClassInstaller (DIF_REGISTERDEVICE,
569  DeviceInfo,
570  &DeviceNode))
571  return FALSE;
572 
573  /* This system call tends to take a while (several seconds!) on
574  "modern" Windoze systems */
575  if ( ! UpdateDriverForPlugAndPlayDevicesA (NULL,
577  inf_file_path,
578  INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE,
579  NULL)) //reboot required? NEVER!
580  return FALSE;
581 
582  fprintf (stderr, "DEBUG: successfully created a network device\n");
583  return TRUE;
584 }
585 
586 
593 static BOOL
595 {
596  SP_REMOVEDEVICE_PARAMS remove;
597 
598  if (INVALID_HANDLE_VALUE == DeviceInfo)
599  return FALSE;
600 
601  remove.ClassInstallHeader.cbSize = sizeof (SP_CLASSINSTALL_HEADER);
602  remove.HwProfile = 0;
603  remove.Scope = DI_REMOVEDEVICE_GLOBAL;
604  remove.ClassInstallHeader.InstallFunction = DIF_REMOVE;
605  /*
606  * 1. Prepare our existing device information set, and place the
607  * uninstall related information into the structure
608  */
609  if ( ! SetupDiSetClassInstallParamsA (DeviceInfo,
610  (PSP_DEVINFO_DATA) & DeviceNode,
611  &remove.ClassInstallHeader,
612  sizeof (remove)))
613  return FALSE;
614  /*
615  * 2. Uninstall the virtual interface using the class installer
616  */
617  if ( ! SetupDiCallClassInstaller (DIF_REMOVE,
618  DeviceInfo,
619  (PSP_DEVINFO_DATA) & DeviceNode))
620  return FALSE;
621 
622  SetupDiDestroyDeviceInfoList (DeviceInfo);
623 
624  fprintf (stderr, "DEBUG: removed interface successfully\n");
625 
626  return TRUE;
627 }
628 
629 
636 static BOOL
638 {
639  SP_DEVINFO_LIST_DETAIL_DATA device_details;
640  char pnp_instance_id [MAX_DEVICE_ID_LEN];
641  HKEY adapter_key_handle;
642  LONG status;
643  DWORD len;
644  int i = 0;
645  int retrys;
646  BOOL retval = FALSE;
647  char adapter[] = INTERFACE_REGISTRY_LOCATION;
648 
649  /* We can obtain the PNP instance ID from our setupapi handle */
650  device_details.cbSize = sizeof (device_details);
651  if (CR_SUCCESS != CM_Get_Device_ID_ExA (DeviceNode.DevInst,
652  (PCHAR) pnp_instance_id,
653  MAX_DEVICE_ID_LEN,
654  0, //must be 0
655  NULL)) //hMachine, we are local
656  return FALSE;
657 
658  fprintf (stderr, "DEBUG: Resolving interface name for network device %s\n",pnp_instance_id);
659 
660  /* Registry is incredibly slow, retry for up to 30 seconds to allow registry to refresh */
661  for (retrys = 0; retrys < 120 && !retval; retrys++)
662  {
663  /* sleep for 250ms*/
664  Sleep (250);
665 
666  /* Now we can use this ID to locate the correct networks interface in registry */
667  if (ERROR_SUCCESS != RegOpenKeyExA (
668  HKEY_LOCAL_MACHINE,
669  adapter,
670  0,
671  KEY_READ,
672  &adapter_key_handle))
673  return FALSE;
674 
675  /* Of course there is a multitude of entries here, with arbitrary names,
676  * thus we need to iterate through there.
677  */
678  while (!retval)
679  {
680  char instance_key[256];
681  char query_key [256];
682  HKEY instance_key_handle;
683  char pnpinstanceid_name[] = "PnpInstanceID";
684  char pnpinstanceid_value[256];
685  char adaptername_name[] = "Name";
686  DWORD data_type;
687 
688  len = 256 * sizeof (char);
689  /* optain a subkey of {4D36E972-E325-11CE-BFC1-08002BE10318} */
690  status = RegEnumKeyExA (
691  adapter_key_handle,
692  i,
693  instance_key,
694  &len,
695  NULL,
696  NULL,
697  NULL,
698  NULL);
699 
700  /* this may fail due to one of two reasons:
701  * we are at the end of the list*/
702  if (ERROR_NO_MORE_ITEMS == status)
703  break;
704  // * we found a broken registry key, continue with the next key.
705  if (ERROR_SUCCESS != status)
706  goto cleanup;
707 
708  /* prepare our new query string: */
709  snprintf (query_key, 256, "%s\\%s\\Connection",
710  adapter,
711  instance_key);
712 
713  /* look inside instance_key\\Connection */
714  if (ERROR_SUCCESS != RegOpenKeyExA (
715  HKEY_LOCAL_MACHINE,
716  query_key,
717  0,
718  KEY_READ,
719  &instance_key_handle))
720  goto cleanup;
721 
722  /* now, read our PnpInstanceID */
723  len = sizeof (pnpinstanceid_value);
724  status = RegQueryValueExA (instance_key_handle,
725  pnpinstanceid_name,
726  NULL, //reserved, always NULL according to MSDN
727  &data_type,
728  (LPBYTE) pnpinstanceid_value,
729  &len);
730 
731  if (status != ERROR_SUCCESS || data_type != REG_SZ)
732  goto cleanup;
733 
734  /* compare the value we got to our devices PNPInstanceID*/
735  if (0 != strncmp (pnpinstanceid_value, pnp_instance_id,
736  sizeof (pnpinstanceid_value) / sizeof (char)))
737  goto cleanup;
738 
739  len = sizeof (device_visible_name);
740  status = RegQueryValueExA (
741  instance_key_handle,
742  adaptername_name,
743  NULL, //reserved, always NULL according to MSDN
744  &data_type,
745  (LPBYTE) device_visible_name,
746  &len);
747 
748  if (status != ERROR_SUCCESS || data_type != REG_SZ)
749  goto cleanup;
750 
751  /*
752  * we have successfully found OUR instance,
753  * save the device GUID before exiting
754  */
755  GNUNET_strlcpy (device_guid, instance_key, sizeof (device_guid));
756  retval = TRUE;
757  fprintf (stderr, "DEBUG: Interface Name lookup succeeded on retry %d, got \"%s\" %s\n", retrys, device_visible_name, device_guid);
758 
759 cleanup:
760  RegCloseKey (instance_key_handle);
761 
762  ++i;
763  }
764 
765  RegCloseKey (adapter_key_handle);
766  }
767  return retval;
768 }
769 
770 
777 static BOOL
779 {
780  ULONG version[3];
781  DWORD len;
782  memset (&(version), 0, sizeof (version));
783 
784  if (DeviceIoControl (handle, TAP_WIN_IOCTL_GET_VERSION,
785  &version, sizeof (version),
786  &version, sizeof (version), &len, NULL))
787  fprintf (stderr, "INFO: TAP-Windows Driver Version %d.%d %s\n",
788  (int) version[0],
789  (int) version[1],
790  (version[2] ? "(DEBUG)" : ""));
791 
792  if ((version[0] != TAP_WIN_MIN_MAJOR) ||
793  (version[1] < TAP_WIN_MIN_MINOR )){
794  fprintf (stderr, "FATAL: This version of gnunet requires a TAP-Windows driver that is at least version %d.%d\n",
797  return FALSE;
798  }
799 
800  return TRUE;
801 }
802 
803 
809 static HANDLE
811 {
812  char device_path[256];
813  HANDLE handle;
814 
815  if (! setup_interface ())
816  {
817  errno = ENODEV;
818  return INVALID_HANDLE_VALUE;
819  }
820 
821  if (! resolve_interface_name ())
822  {
823  errno = ENODEV;
824  return INVALID_HANDLE_VALUE;
825  }
826 
827  /* Open Windows TAP-Windows adapter */
828  snprintf (device_path, sizeof (device_path), "%s%s%s",
830  device_guid,
832 
833  handle = CreateFile (
834  device_path,
835  GENERIC_READ | GENERIC_WRITE,
836  0, /* was: FILE_SHARE_READ */
837  0,
838  OPEN_EXISTING,
839  FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
840  0
841  );
842 
843  if (INVALID_HANDLE_VALUE == handle)
844  {
845  fprintf (stderr, "FATAL: CreateFile failed on TAP device: %s\n", device_path);
846  return handle;
847  }
848 
849  /* get driver version info */
850  if (! check_tapw32_version (handle))
851  {
852  CloseHandle (handle);
853  return INVALID_HANDLE_VALUE;
854  }
855 
856  /* TODO (opt?): get MTU-Size */
857 
858  fprintf (stderr, "DEBUG: successfully opened TAP device\n");
859  return handle;
860 }
861 
862 
869 static BOOL
870 tun_up (HANDLE handle)
871 {
872  ULONG status = TRUE;
873  DWORD len;
874  if (! DeviceIoControl (handle, TAP_WIN_IOCTL_SET_MEDIA_STATUS,
875  &status, sizeof (status),
876  &status, sizeof (status), &len, NULL))
877  {
878  fprintf (stderr, "FATAL: TAP driver ignored request to UP interface (DeviceIoControl call)\n");
879  return FALSE;
880  }
881 
882  /* Wait for the device to go UP, might take some time. */
883  Sleep (TAP32_POSTUP_WAITTIME * 1000);
884  fprintf (stderr, "DEBUG: successfully set TAP device to UP\n");
885 
886  return TRUE;
887 }
888 
889 
915 static BOOL
916 attempt_read_tap (struct io_facility * input_facility,
917  struct io_facility * output_facility)
918 {
919  struct GNUNET_MessageHeader * hdr;
920  unsigned short size;
921 
922  switch (input_facility->facility_state)
923  {
924  case IOSTATE_READY:
925  {
926  if (! ResetEvent (input_facility->overlapped.hEvent))
927  {
928  return FALSE;
929  }
930 
931  input_facility->buffer_size = 0;
932 
933  /* Check how the task is handled */
934  if (ReadFile (input_facility->handle,
935  input_facility->buffer,
936  sizeof (input_facility->buffer) - sizeof (struct GNUNET_MessageHeader),
937  &input_facility->buffer_size,
938  &input_facility->overlapped))
939  {/* async event processed immediately*/
940 
941  /* reset event manually*/
942  if (! SetEvent (input_facility->overlapped.hEvent))
943  return FALSE;
944 
945  fprintf (stderr, "DEBUG: tap read succeeded immediately\n");
946 
947  /* we successfully read something from the TAP and now need to
948  * send it our via STDOUT. Is that possible at the moment? */
949  if ((IOSTATE_READY == output_facility->facility_state ||
950  IOSTATE_WAITING == output_facility->facility_state)
951  && (0 < input_facility->buffer_size))
952  { /* hand over this buffers content and apply message header for gnunet */
953  hdr = (struct GNUNET_MessageHeader *) output_facility->buffer;
954  size = input_facility->buffer_size + sizeof (struct GNUNET_MessageHeader);
955 
956  GNUNET_memcpy (output_facility->buffer + sizeof (struct GNUNET_MessageHeader),
957  input_facility->buffer,
958  input_facility->buffer_size);
959 
960  output_facility->buffer_size = size;
961  hdr->size = htons (size);
962  hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
963  output_facility->facility_state = IOSTATE_READY;
964  }
965  else if (0 < input_facility->buffer_size)
966  /* If we have have read our buffer, wait for our write-partner*/
967  input_facility->facility_state = IOSTATE_WAITING;
968  }
969  else /* operation was either queued or failed*/
970  {
971  int err = GetLastError ();
972  if (ERROR_IO_PENDING == err)
973  { /* operation queued */
974  input_facility->facility_state = IOSTATE_QUEUED;
975  }
976  else
977  { /* error occurred, let the rest of the elements finish */
978  input_facility->path_open = FALSE;
979  input_facility->facility_state = IOSTATE_FAILED;
980  if (IOSTATE_WAITING == output_facility->facility_state)
981  output_facility->path_open = FALSE;
982 
983  fprintf (stderr, "FATAL: Read from handle failed, allowing write to finish\n");
984  }
985  }
986  }
987  return TRUE;
988  // We are queued and should check if the read has finished
989  case IOSTATE_QUEUED:
990  {
991  // there was an operation going on already, check if that has completed now.
992 
993  if (GetOverlappedResult (input_facility->handle,
994  &input_facility->overlapped,
995  &input_facility->buffer_size,
996  FALSE))
997  {/* successful return for a queued operation */
998  if (! ResetEvent (input_facility->overlapped.hEvent))
999  return FALSE;
1000 
1001  fprintf (stderr, "DEBUG: tap read succeeded delayed\n");
1002 
1003  /* we successfully read something from the TAP and now need to
1004  * send it our via STDOUT. Is that possible at the moment? */
1005  if ((IOSTATE_READY == output_facility->facility_state ||
1006  IOSTATE_WAITING == output_facility->facility_state)
1007  && 0 < input_facility->buffer_size)
1008  { /* hand over this buffers content and apply message header for gnunet */
1009  hdr = (struct GNUNET_MessageHeader *) output_facility->buffer;
1010  size = input_facility->buffer_size + sizeof (struct GNUNET_MessageHeader);
1011 
1012  GNUNET_memcpy (output_facility->buffer + sizeof (struct GNUNET_MessageHeader),
1013  input_facility->buffer,
1014  input_facility->buffer_size);
1015 
1016  output_facility->buffer_size = size;
1017  hdr->size = htons(size);
1018  hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1019  output_facility->facility_state = IOSTATE_READY;
1020  input_facility->facility_state = IOSTATE_READY;
1021  }
1022  else if (0 < input_facility->buffer_size)
1023  { /* If we have have read our buffer, wait for our write-partner*/
1024  input_facility->facility_state = IOSTATE_WAITING;
1025  // TODO: shall we attempt to fill our buffer or should we wait for our write-partner to finish?
1026  }
1027  }
1028  else
1029  { /* operation still pending/queued or failed? */
1030  int err = GetLastError ();
1031  if ((ERROR_IO_INCOMPLETE != err) && (ERROR_IO_PENDING != err))
1032  { /* error occurred, let the rest of the elements finish */
1033  input_facility->path_open = FALSE;
1034  input_facility->facility_state = IOSTATE_FAILED;
1035  if (IOSTATE_WAITING == output_facility->facility_state)
1036  output_facility->path_open = FALSE;
1037  fprintf (stderr, "FATAL: Read from handle failed, allowing write to finish\n");
1038  }
1039  }
1040  }
1041  return TRUE;
1042  case IOSTATE_RESUME:
1043  hdr = (struct GNUNET_MessageHeader *) output_facility->buffer;
1044  size = input_facility->buffer_size + sizeof (struct GNUNET_MessageHeader);
1045 
1046  GNUNET_memcpy (output_facility->buffer + sizeof (struct GNUNET_MessageHeader),
1047  input_facility->buffer,
1048  input_facility->buffer_size);
1049 
1050  output_facility->buffer_size = size;
1051  hdr->size = htons (size);
1052  hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1053  output_facility->facility_state = IOSTATE_READY;
1054  input_facility->facility_state = IOSTATE_READY;
1055  return TRUE;
1056  default:
1057  return TRUE;
1058  }
1059 }
1060 
1061 
1088 static BOOL
1089 attempt_read_stdin (struct io_facility * input_facility,
1090  struct io_facility * output_facility)
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 
1138  /* hand over this buffers content and strip gnunet message header */
1139  GNUNET_memcpy (output_facility->buffer,
1140  input_facility->buffer + sizeof (struct GNUNET_MessageHeader),
1141  input_facility->buffer_size - sizeof (struct GNUNET_MessageHeader));
1142  output_facility->buffer_size = input_facility->buffer_size - sizeof (struct GNUNET_MessageHeader);
1143  output_facility->facility_state = IOSTATE_READY;
1144  input_facility->facility_state = IOSTATE_READY;
1145  }
1146  else if (input_facility->buffer_size > sizeof (struct GNUNET_MessageHeader))
1147  /* If we have have read our buffer, wait for our write-partner*/
1148  input_facility->facility_state = IOSTATE_WAITING;
1149  else /* we read nothing */
1150  input_facility->facility_state = IOSTATE_READY;
1151  }
1152  else /* operation was either queued or failed*/
1153  {
1154  int err = GetLastError ();
1155  if (ERROR_IO_PENDING == err) /* operation queued */
1156  input_facility->facility_state = IOSTATE_QUEUED;
1157  else
1158  { /* error occurred, let the rest of the elements finish */
1159  input_facility->path_open = FALSE;
1160  input_facility->facility_state = IOSTATE_FAILED;
1161  if (IOSTATE_WAITING == output_facility->facility_state)
1162  output_facility->path_open = FALSE;
1163 
1164  fprintf (stderr, "FATAL: Read from handle failed, allowing write to finish\n");
1165  }
1166  }
1167  }
1168  return TRUE;
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  goto partial_read_iostate_ready;
1196 
1197  /* we successfully read something from the TAP and now need to
1198  * send it our via STDOUT. Is that possible at the moment? */
1199  if ((IOSTATE_READY == output_facility->facility_state ||
1200  IOSTATE_WAITING == output_facility->facility_state)
1201  && input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader))
1202  { /* hand over this buffers content and strip gnunet message header */
1203  GNUNET_memcpy (output_facility->buffer,
1204  input_facility->buffer + sizeof(struct GNUNET_MessageHeader),
1205  input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader));
1206  output_facility->buffer_size = input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader);
1207  output_facility->facility_state = IOSTATE_READY;
1208  input_facility->facility_state = IOSTATE_READY;
1209  }
1210  else if (input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader))
1211  input_facility->facility_state = IOSTATE_WAITING;
1212  else
1213  input_facility->facility_state = IOSTATE_READY;
1214  }
1215  else
1216  { /* operation still pending/queued or failed? */
1217  int err = GetLastError ();
1218  if ((ERROR_IO_INCOMPLETE != err) && (ERROR_IO_PENDING != err))
1219  { /* error occurred, let the rest of the elements finish */
1220  input_facility->path_open = FALSE;
1221  input_facility->facility_state = IOSTATE_FAILED;
1222  if (IOSTATE_WAITING == output_facility->facility_state)
1223  output_facility->path_open = FALSE;
1224  fprintf (stderr, "FATAL: Read from handle failed, allowing write to finish\n");
1225  }
1226  }
1227  }
1228  return TRUE;
1229  case IOSTATE_RESUME: /* Our buffer was filled already but our write facility was busy. */
1230  GNUNET_memcpy (output_facility->buffer,
1231  input_facility->buffer + sizeof (struct GNUNET_MessageHeader),
1232  input_facility->buffer_size - sizeof (struct GNUNET_MessageHeader));
1233  output_facility->buffer_size = input_facility->buffer_size - sizeof (struct GNUNET_MessageHeader);
1234  output_facility->facility_state = IOSTATE_READY;
1235  input_facility->facility_state = IOSTATE_READY;
1236  return TRUE;
1237  default:
1238  return TRUE;
1239  }
1240 }
1241 
1242 
1252 static BOOL
1253 attempt_write (struct io_facility * output_facility,
1254  struct io_facility * input_facility)
1255 {
1256  switch (output_facility->facility_state)
1257  {
1258  case IOSTATE_READY:
1259  output_facility->buffer_size_written = 0;
1260 
1261 continue_partial_write:
1262  if (! ResetEvent (output_facility->overlapped.hEvent))
1263  return FALSE;
1264 
1265  /* Check how the task was handled */
1266  if (WriteFile (output_facility->handle,
1267  output_facility->buffer + output_facility->buffer_size_written,
1268  output_facility->buffer_size - output_facility->buffer_size_written,
1269  &output_facility->buffer_size_processed,
1270  &output_facility->overlapped))
1271  {/* async event processed immediately*/
1272 
1273  fprintf (stderr, "DEBUG: write succeeded immediately\n");
1274  output_facility->buffer_size_written += output_facility->buffer_size_processed;
1275 
1276  /* reset event manually*/
1277  if (! SetEvent (output_facility->overlapped.hEvent))
1278  return FALSE;
1279 
1280  /* partial write */
1281  if (output_facility->buffer_size_written < output_facility->buffer_size)
1282  goto continue_partial_write;
1283 
1284  /* we are now waiting for our buffer to be filled*/
1285  output_facility->facility_state = IOSTATE_WAITING;
1286 
1287  /* we successfully wrote something and now need to reset our reader */
1288  if (IOSTATE_WAITING == input_facility->facility_state)
1289  input_facility->facility_state = IOSTATE_RESUME;
1290  else if (IOSTATE_FAILED == input_facility->facility_state)
1291  output_facility->path_open = FALSE;
1292  }
1293  else /* operation was either queued or failed*/
1294  {
1295  int err = GetLastError ();
1296  if (ERROR_IO_PENDING == err)
1297  { /* operation queued */
1298  output_facility->facility_state = IOSTATE_QUEUED;
1299  }
1300  else
1301  { /* error occurred, close this path */
1302  output_facility->path_open = FALSE;
1303  output_facility->facility_state = IOSTATE_FAILED;
1304  fprintf (stderr, "FATAL: Write to handle failed, exiting\n");
1305  }
1306  }
1307  return TRUE;
1308  case IOSTATE_QUEUED:
1309  // there was an operation going on already, check if that has completed now.
1310 
1311  if (GetOverlappedResult (output_facility->handle,
1312  &output_facility->overlapped,
1313  &output_facility->buffer_size_processed,
1314  FALSE))
1315  {/* successful return for a queued operation */
1316  if (! ResetEvent (output_facility->overlapped.hEvent))
1317  return FALSE;
1318 
1319  fprintf (stderr, "DEBUG: write succeeded delayed\n");
1320  output_facility->buffer_size_written += output_facility->buffer_size_processed;
1321 
1322  /* partial write */
1323  if (output_facility->buffer_size_written < output_facility->buffer_size)
1324  goto continue_partial_write;
1325 
1326  /* we are now waiting for our buffer to be filled*/
1327  output_facility->facility_state = IOSTATE_WAITING;
1328 
1329  /* we successfully wrote something and now need to reset our reader */
1330  if (IOSTATE_WAITING == input_facility->facility_state)
1331  input_facility->facility_state = IOSTATE_RESUME;
1332  else if (IOSTATE_FAILED == input_facility->facility_state)
1333  output_facility->path_open = FALSE;
1334  }
1335  else
1336  { /* operation still pending/queued or failed? */
1337  int err = GetLastError ();
1338  if ((ERROR_IO_INCOMPLETE != err) && (ERROR_IO_PENDING != err))
1339  { /* error occurred, close this path */
1340  output_facility->path_open = FALSE;
1341  output_facility->facility_state = IOSTATE_FAILED;
1342  fprintf (stderr, "FATAL: Write to handle failed, exiting\n");
1343  }
1344  }
1345  default:
1346  return TRUE;
1347  }
1348 }
1349 
1350 
1359 static BOOL
1361  int initial_state,
1362  BOOL signaled)
1363 {
1364  elem->path_open = TRUE;
1365  elem->handle = INVALID_HANDLE_VALUE;
1366  elem->facility_state = initial_state;
1367  elem->buffer_size = 0;
1368  elem->overlapped.hEvent = CreateEvent (NULL, TRUE, signaled, NULL);
1369  if (NULL == elem->overlapped.hEvent)
1370  return FALSE;
1371 
1372  return TRUE;
1373 }
1374 
1375 
1381 static void
1382 run (HANDLE tap_handle)
1383 {
1384  /* IO-Facility for reading from our virtual interface */
1385  struct io_facility tap_read;
1386  /* IO-Facility for writing to our virtual interface */
1387  struct io_facility tap_write;
1388  /* IO-Facility for reading from stdin */
1389  struct io_facility std_in;
1390  /* IO-Facility for writing to stdout */
1391  struct io_facility std_out;
1392 
1393  HANDLE parent_std_in_handle = GetStdHandle (STD_INPUT_HANDLE);
1394  HANDLE parent_std_out_handle = GetStdHandle (STD_OUTPUT_HANDLE);
1395 
1396  /* tun up: */
1397  /* we do this HERE and not beforehand (in init_tun()), in contrast to openvpn
1398  * to remove the need to flush the arp cache, handle DHCP and wrong IPs.
1399  *
1400  * DHCP and such are all features we will never use in gnunet afaik.
1401  * But for openvpn those are essential.
1402  */
1403  if ((privilege_testing) || (! tun_up (tap_handle)))
1404  goto teardown_final;
1405 
1406  /* Initialize our overlapped IO structures*/
1407  if (! (initialize_io_facility (&tap_read, IOSTATE_READY, FALSE)
1408  && initialize_io_facility (&tap_write, IOSTATE_WAITING, TRUE)
1409  && initialize_io_facility (&std_in, IOSTATE_READY, FALSE)
1410  && initialize_io_facility (&std_out, IOSTATE_WAITING, TRUE)))
1411  goto teardown_final;
1412 
1413  /* Handles for STDIN and STDOUT */
1414  tap_read.handle = tap_handle;
1415  tap_write.handle = tap_handle;
1416 
1417 #ifdef DEBUG_TO_CONSOLE
1418  /* Debug output to console STDIN/STDOUT*/
1419  std_in.handle = parent_std_in_handle;
1420  std_out.handle = parent_std_out_handle;
1421 
1422 #else
1423  fprintf (stderr, "DEBUG: reopening stdin/out for overlapped IO\n");
1424  /*
1425  * Find out the types of our handles.
1426  * This part is a problem, because in windows we need to handle files,
1427  * pipes and the console differently.
1428  */
1429  if ((FILE_TYPE_PIPE != GetFileType (parent_std_in_handle)) ||
1430  (FILE_TYPE_PIPE != GetFileType (parent_std_out_handle)))
1431  {
1432  fprintf (stderr, "ERROR: stdin/stdout must be named pipes\n");
1433  goto teardown;
1434  }
1435 
1436  std_in.handle = ReOpenFile (parent_std_in_handle,
1437  GENERIC_READ,
1438  FILE_SHARE_WRITE | FILE_SHARE_READ,
1439  FILE_FLAG_OVERLAPPED);
1440 
1441  if (INVALID_HANDLE_VALUE == std_in.handle)
1442  {
1443  fprintf (stderr, "FATAL: Could not reopen stdin for in overlapped mode, has to be a named pipe\n");
1444  goto teardown;
1445  }
1446 
1447  std_out.handle = ReOpenFile (parent_std_out_handle,
1448  GENERIC_WRITE,
1449  FILE_SHARE_READ,
1450  FILE_FLAG_OVERLAPPED);
1451 
1452  if (INVALID_HANDLE_VALUE == std_out.handle)
1453  {
1454  fprintf (stderr, "FATAL: Could not reopen stdout for in overlapped mode, has to be a named pipe\n");
1455  goto teardown;
1456  }
1457 #endif
1458 
1459  fprintf (stderr, "DEBUG: mainloop has begun\n");
1460 
1461  while (std_out.path_open || tap_write.path_open)
1462  {
1463  /* perform READ from stdin if possible */
1464  if (std_in.path_open && (! attempt_read_stdin (&std_in, &tap_write)))
1465  break;
1466 
1467  /* perform READ from tap if possible */
1468  if (tap_read.path_open && (! attempt_read_tap (&tap_read, &std_out)))
1469  break;
1470 
1471  /* perform WRITE to tap if possible */
1472  if (tap_write.path_open && (! attempt_write (&tap_write, &std_in)))
1473  break;
1474 
1475  /* perform WRITE to STDOUT if possible */
1476  if (std_out.path_open && (! attempt_write (&std_out, &tap_read)))
1477  break;
1478  }
1479 
1480  fprintf (stderr, "DEBUG: teardown initiated\n");
1481 teardown:
1482  CancelIo (tap_handle);
1483  CancelIo (std_in.handle);
1484  CancelIo (std_out.handle);
1485 teardown_final:
1486  CloseHandle (tap_handle);
1487 }
1488 
1489 
1502 int
1503 main (int argc, char **argv)
1504 {
1505  char hwid[LINE_LEN];
1506  HANDLE handle;
1507  int global_ret = 0;
1508  BOOL have_ip4 = FALSE;
1509  BOOL have_ip6 = FALSE;
1510 
1511  if (argc > 1 && 0 == strcmp (argv[1], "-d")){
1512  privilege_testing = TRUE;
1513  fprintf (stderr,
1514  "%s",
1515  "DEBUG: Running binary in privilege testing mode.");
1516  argv++;
1517  argc--;
1518  }
1519 
1520  if (6 != argc)
1521  {
1522  fprintf (stderr,
1523  "%s",
1524  "FATAL: must supply 5 arguments\nUsage:\ngnunet-helper-vpn [-d] <if name prefix> <address6 or \"-\"> <netbits6> <address4 or \"-\"> <netmask4>\n");
1525  return 1;
1526  }
1527 
1528  GNUNET_strlcpy (hwid, argv[1], sizeof (hwid));
1529 
1530  /*
1531  * We use our PID for finding/resolving the control-panel name of our virtual
1532  * device. PIDs are (of course) unique at runtime, thus we can safely use it
1533  * as additional hardware-id for our device.
1534  */
1535  snprintf (secondary_hwid, LINE_LEN / 2, "%s-%d",
1536  hwid,
1537  _getpid ());
1538 
1539  if (INVALID_HANDLE_VALUE == (handle = init_tun ()))
1540  {
1541  fprintf (stderr, "FATAL: could not initialize virtual-interface %s with IPv6 %s/%s and IPv4 %s/%s\n",
1542  hwid,
1543  argv[2],
1544  argv[3],
1545  argv[4],
1546  argv[5]);
1547  global_ret = -1;
1548  goto cleanup;
1549  }
1550 
1551  fprintf (stderr, "DEBUG: Setting IPs, if needed\n");
1552  if (0 != strcmp (argv[2], "-"))
1553  {
1554  const char *address = argv[2];
1555  long prefix_len = atol (argv[3]);
1556 
1557  if ((prefix_len < 1) || (prefix_len > 127))
1558  {
1559  fprintf (stderr, "FATAL: ipv6 prefix_len out of range\n");
1560  global_ret = -1;
1561  goto cleanup;
1562  }
1563 
1564  fprintf (stderr, "DEBUG: Setting IP6 address: %s/%d\n",address,prefix_len);
1565  if (0 != (global_ret = set_address6 (address, prefix_len)))
1566  goto cleanup;
1567 
1568  have_ip6 = TRUE;
1569  }
1570 
1571  if (0 != strcmp (argv[4], "-"))
1572  {
1573  const char *address = argv[4];
1574  const char *mask = argv[5];
1575 
1576  fprintf (stderr, "DEBUG: Setting IP4 address: %s/%s\n",address,mask);
1577  if (0 != (global_ret = set_address4 (address, mask)))
1578  goto cleanup;
1579 
1580  have_ip4 = TRUE;
1581  }
1582 
1583  run (handle);
1584 cleanup:
1585 
1586  if (have_ip4)
1587  {
1588  const char *address = argv[4];
1589  fprintf (stderr, "DEBUG: Removing IP4 address\n");
1590  remove_address4 (address);
1591  }
1592  if (have_ip6)
1593  {
1594  const char *address = argv[2];
1595  fprintf (stderr, "DEBUG: Removing IP6 address\n");
1596  remove_address6 (address);
1597  }
1598 
1599  fprintf (stderr, "DEBUG: removing interface\n");
1600  remove_interface ();
1601  fprintf (stderr, "DEBUG: graceful exit completed\n");
1602 
1603  return global_ret;
1604 }
overlapped I/O has been queued
static BOOL remove_interface()
Remove our new virtual interface to use for tunneling.
BOOL path_open
If the path is open or blocked in general (used for quickly checking)
there is a full buffer waiting
static int set_address4(const char *address, const char *mask)
Sets the IPv4-Address given in address on the interface dev.
#define MAX_SIZE
Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
#define TAP_WIN_SUFFIX
Definition: tap-windows.h:79
DWORD buffer_size_processed
Amount of data actually written or read by readfile/writefile.
static SP_DEVINFO_DATA DeviceNode
Registry Key we hand over to windows to spawn a new virtual interface.
TAP32 virtual network driver defines.
static void run(HANDLE tap_handle)
Start forwarding to and from the tunnel.
#define TAP32_POSTUP_WAITTIME
Time in seconds to wait for our virtual device to go up after telling it to do so.
static char device_visible_name[256]
Device&#39;s visible Name, used to identify a network device in netsh.
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...
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define TAP_WIN_MIN_MAJOR
Minimum major-id of the driver version we can work with.
static char device_guid[256]
GUID of our virtual device in the form of {12345678-1234-1234-1234-123456789abc} - in hex...
static void remove_address6(const char *address)
Removes the IPv6-Address given in address from the interface dev.
static char * query_key
The key for the query.
DWORD buffer_size
How much of this buffer was used when reading or how much data can be written.
#define TAP_WIN_IOCTL_GET_VERSION
Definition: tap-windows.h:46
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
int main(int argc, char **argv)
Open VPN tunnel interface.
#define TAP_WIN_IOCTL_SET_MEDIA_STATUS
Definition: tap-windows.h:50
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 int ret
Final status code.
Definition: gnunet-arm.c:89
OVERLAPPED overlapped
Overlaped IO structure used for asynchronous IO in windows.
static char secondary_hwid[LINE_LEN/2]
Our local process&#39; PID.
static BOOL initialize_io_facility(struct io_facility *elem, int initial_state, BOOL signaled)
Initialize a overlapped structure.
cryptographic primitives for GNUnet
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_memcpy(dst, src, n)
static HANDLE init_tun()
Creates a tun-interface called dev;.
#define INF_FILE
Name or Path+Name of our win32 driver.
uint16_t status
See PRISM_STATUS_*-constants.
static void cleanup(void *cls)
Function scheduled as very last function, cleans up after us.
static BOOL tun_up(HANDLE handle)
Brings a TAP device up and sets it to connected state.
static int set_address6(const char *address, unsigned long prefix_len)
Sets the IPv6-Address given in address on the interface dev.
static void remove_address4(const char *address)
Removes the IPv4-Address given in address from the interface dev.
BOOL(WINAPI * LPFN_ISWOW64PROCESS)(HANDLE, PBOOL)
IsWow64Process definition for our is_win64, as this is a kernel function.
#define INF_FILE64
Name or Path+Name of our win64 driver.
static int execute_shellcommand(const char *command)
Wrapper for executing a shellcommand in windows.
static BOOL resolve_interface_name()
Do all the lookup necessary to retrieve the inteface&#39;s actual name off the registry.
IO_State
Possible states of an IO facility.
static unsigned int size
Size of the "table".
Definition: peer.c:67
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 HDEVINFO DeviceInfo
This is our own local instance of a virtual network interface It is (somewhat) equivalent to using tu...
static boolean privilege_testing
Will this binary be run in permissions testing mode?
enum IO_State facility_state
The mode the state machine associated with this object is in.
overlapped I/O is ready for work
unsigned char buffer[65536]
Buffer for reading things to and writing from...
static BOOL setup_interface()
Setup a new virtual interface to use for tunneling.
WINBASEAPI HANDLE WINAPI ReOpenFile(HANDLE, DWORD, DWORD, DWORD)
ReOpenFile is only available as of XP SP2 and 2003 SP1.
#define USERMODEDEVICEDIR
Definition: tap-windows.h:76
#define TAP_WIN_MIN_MINOR
Minimum minor-id of the driver version we can work with.
HANDLE handle
Windows Object-Handle (used for accessing TAP and STDIN/STDOUT)
static int inet_pton(int af, const char *cp, struct in_addr *buf)
Convert IPv4 address from text to binary form.
overlapped I/O has finished, but is waiting for it&#39;s write-partner
Header for all communications.
BOOL is_win64()
Determines if the host OS is win32 or win64.
#define INTERFACE_REGISTRY_LOCATION
Location of the network interface list resides in registry.
commonly used definitions; globals in this file are exempt from the rule that the module name ("commo...
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.
A IO Object + read/writebuffer + buffer-size for windows asynchronous IO handling.
#define HARDWARE_ID
Hardware ID used in the inf-file.
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.
static size_t strnlen(const char *s, size_t n)
Operlapped IO states for facility objects overlapped I/O has failed, stop processing.
#define GNUNET_MESSAGE_TYPE_VPN_HELPER
Type of messages between the gnunet-vpn-helper and the daemon.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
DWORD buffer_size_written
How much of this buffer we have written in total.