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 
165 enum IO_State {
170 
175 
180 
185 
191 };
192 
193 
197 struct io_facility {
202 
206  BOOL path_open; // BOOL is winbool (int), NOT boolean (unsigned char)!
207 
211  HANDLE handle;
212 
216  OVERLAPPED overlapped;
217 
221  unsigned char buffer[MAX_SIZE];
222 
226  DWORD buffer_size;
227 
231  DWORD buffer_size_processed;
232 
236  DWORD buffer_size_written;
237 };
238 
242 WINBASEAPI HANDLE WINAPI ReOpenFile(HANDLE, DWORD, DWORD, DWORD);
243 
247 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
248 
249 
262 size_t
263 GNUNET_strlcpy(char *dst, const char *src, size_t n)
264 {
265  size_t ret;
266  size_t slen;
267 
268  GNUNET_assert(0 != n);
269  slen = strnlen(src, n - 1);
270  memcpy(dst, src, slen);
271  dst[slen] = '\0';
272  return slen;
273 }
274 
275 
281 BOOL
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 }
307 static int
308 execute_shellcommand(const char *command)
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 }
325 
326 
333 static int
334 set_address6(const char *address, unsigned long prefix_len)
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 }
368 
369 
375 static void
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,
396  "FATAL: removing IPv6 address failed: %s\n",
397  strerror(ret));
398 }
399 
400 
407 static int
408 set_address4(const char *address, const char *mask)
409 {
410  int ret = EINVAL;
411  char command[LINE_LEN];
412 
413  struct sockaddr_in addr;
414 
415  addr.sin_family = AF_INET;
416 
417  /*
418  * Parse the address
419  */
420  if (1 != inet_pton(AF_INET, address, &addr.sin_addr.s_addr))
421  {
422  fprintf(stderr, "ERROR: Failed to parse address `%s': %s\n", address,
423  strerror(errno));
424  return -1;
425  }
426  // Set Device to Subnet-Mode? do we really need openvpn/tun.c:2925 ?
427 
428  /*
429  * prepare the command
430  */
431  snprintf(command, LINE_LEN,
432  "netsh interface ipv4 add address \"%s\" %s %s store=active",
433  device_visible_name, address, mask);
434  /*
435  * Set the address
436  */
437  ret = execute_shellcommand(command);
438 
439  /* Did it work?*/
440  if (0 != ret)
441  fprintf(stderr,
442  "FATAL: Setting IPv4 address failed: %s\n",
443  strerror(ret));
444  return ret;
445 }
446 
447 
453 static void
455 {
456  char command[LINE_LEN];
457  int ret = EINVAL;
458 
459  // sanity checking was already done in set_address4
460 
461  /*
462  * prepare the command
463  */
464  snprintf(command, LINE_LEN,
465  "netsh interface ipv4 delete address \"%s\" gateway=all store=persistent",
467  /*
468  * Set the address
469  */
470  ret = execute_shellcommand(command);
471 
472  /* Did it work?*/
473  if (0 != ret)
474  fprintf(stderr, "FATAL: removing IPv4 address failed: %s\n", strerror(ret));
475 }
476 
477 
483 static BOOL
485 {
486  /*
487  * where to find our inf-file. (+ the "full" path, after windows found")
488  *
489  * We do not directly input all the props here, because openvpn will update
490  * these details over time.
491  */
492  char inf_file_path[MAX_PATH];
493  char * temp_inf_filename;
494  char hwidlist[LINE_LEN + 4];
495  char class_name[128];
496  GUID class_guid;
497  int str_length = 0;
498 
503  str_len = GNUNET_strlcpy(hwidlist,
504  HARDWARE_ID,
505  sizeof(hwidList)) + 1;
512  str_len += GNUNET_strlcpy(&hwidlist[str_length],
514  sizeof(hwidlist) - str_len) + 1;
515  GNUNET_assert(str_len < sizeof(hwidlist));
516  hwidlist[str_len] = '\0';
517  ++str_len;
518 
523  if (is_win64())
524  GetFullPathNameA(INF_FILE64, MAX_PATH, inf_file_path, &temp_inf_filename);
525  else
526  GetFullPathNameA(INF_FILE, MAX_PATH, inf_file_path, &temp_inf_filename);
527 
528  fprintf(stderr, "INFO: Located our driver's .inf file at %s\n", inf_file_path);
532  if (!SetupDiGetINFClassA(inf_file_path,
533  &class_guid,
534  class_name, sizeof(class_name) / sizeof(char),
535  NULL))
536  return FALSE;
537 
542  DeviceInfo = SetupDiCreateDeviceInfoList(&class_guid, NULL);
543  if (DeviceInfo == INVALID_HANDLE_VALUE)
544  return FALSE;
545 
546  DeviceNode.cbSize = sizeof(SP_DEVINFO_DATA);
547  if (!SetupDiCreateDeviceInfoA(DeviceInfo,
548  class_name,
549  &class_guid,
550  NULL,
551  0,
552  DICD_GENERATE_ID,
553  &DeviceNode))
554  return FALSE;
555 
556  /* Deploy all the information collected into the registry */
557  if (!SetupDiSetDeviceRegistryPropertyA(DeviceInfo,
558  &DeviceNode,
559  SPDRP_HARDWAREID,
560  (LPBYTE)hwidlist,
561  str_length * sizeof(char)))
562  return FALSE;
563 
564  /* Install our new class(=device) into the system */
565  if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE,
566  DeviceInfo,
567  &DeviceNode))
568  return FALSE;
569 
570  /* This system call tends to take a while (several seconds!) on
571  "modern" Windoze systems */
572  if (!UpdateDriverForPlugAndPlayDevicesA(NULL,
574  inf_file_path,
575  INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE,
576  NULL)) //reboot required? NEVER!
577  return FALSE;
578 
579  fprintf(stderr, "DEBUG: successfully created a network device\n");
580  return TRUE;
581 }
582 
583 
590 static BOOL
592 {
593  SP_REMOVEDEVICE_PARAMS remove;
594 
595  if (INVALID_HANDLE_VALUE == DeviceInfo)
596  return FALSE;
597 
598  remove.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
599  remove.HwProfile = 0;
600  remove.Scope = DI_REMOVEDEVICE_GLOBAL;
601  remove.ClassInstallHeader.InstallFunction = DIF_REMOVE;
602  /*
603  * 1. Prepare our existing device information set, and place the
604  * uninstall related information into the structure
605  */
606  if (!SetupDiSetClassInstallParamsA(DeviceInfo,
607  (PSP_DEVINFO_DATA)&DeviceNode,
608  &remove.ClassInstallHeader,
609  sizeof(remove)))
610  return FALSE;
611  /*
612  * 2. Uninstall the virtual interface using the class installer
613  */
614  if (!SetupDiCallClassInstaller(DIF_REMOVE,
615  DeviceInfo,
616  (PSP_DEVINFO_DATA)&DeviceNode))
617  return FALSE;
618 
619  SetupDiDestroyDeviceInfoList(DeviceInfo);
620 
621  fprintf(stderr, "DEBUG: removed interface successfully\n");
622 
623  return TRUE;
624 }
625 
626 
633 static BOOL
635 {
636  SP_DEVINFO_LIST_DETAIL_DATA device_details;
637  char pnp_instance_id [MAX_DEVICE_ID_LEN];
638  HKEY adapter_key_handle;
639  LONG status;
640  DWORD len;
641  int i = 0;
642  int retrys;
643  BOOL retval = FALSE;
644  char adapter[] = INTERFACE_REGISTRY_LOCATION;
645 
646  /* We can obtain the PNP instance ID from our setupapi handle */
647  device_details.cbSize = sizeof(device_details);
648  if (CR_SUCCESS != CM_Get_Device_ID_ExA(DeviceNode.DevInst,
649  (PCHAR)pnp_instance_id,
650  MAX_DEVICE_ID_LEN,
651  0, //must be 0
652  NULL)) //hMachine, we are local
653  return FALSE;
654 
655  fprintf(stderr, "DEBUG: Resolving interface name for network device %s\n", pnp_instance_id);
656 
657  /* Registry is incredibly slow, retry for up to 30 seconds to allow registry to refresh */
658  for (retrys = 0; retrys < 120 && !retval; retrys++)
659  {
660  /* sleep for 250ms*/
661  Sleep(250);
662 
663  /* Now we can use this ID to locate the correct networks interface in registry */
664  if (ERROR_SUCCESS != RegOpenKeyExA(
665  HKEY_LOCAL_MACHINE,
666  adapter,
667  0,
668  KEY_READ,
669  &adapter_key_handle))
670  return FALSE;
671 
672  /* Of course there is a multitude of entries here, with arbitrary names,
673  * thus we need to iterate through there.
674  */
675  while (!retval)
676  {
677  char instance_key[256];
678  char query_key [256];
679  HKEY instance_key_handle;
680  char pnpinstanceid_name[] = "PnpInstanceID";
681  char pnpinstanceid_value[256];
682  char adaptername_name[] = "Name";
683  DWORD data_type;
684 
685  len = 256 * sizeof(char);
686  /* optain a subkey of {4D36E972-E325-11CE-BFC1-08002BE10318} */
687  status = RegEnumKeyExA(
688  adapter_key_handle,
689  i,
690  instance_key,
691  &len,
692  NULL,
693  NULL,
694  NULL,
695  NULL);
696 
697  /* this may fail due to one of two reasons:
698  * we are at the end of the list*/
699  if (ERROR_NO_MORE_ITEMS == status)
700  break;
701  // * we found a broken registry key, continue with the next key.
702  if (ERROR_SUCCESS != status)
703  goto cleanup;
704 
705  /* prepare our new query string: */
706  snprintf(query_key, 256, "%s\\%s\\Connection",
707  adapter,
708  instance_key);
709 
710  /* look inside instance_key\\Connection */
711  if (ERROR_SUCCESS != RegOpenKeyExA(
712  HKEY_LOCAL_MACHINE,
713  query_key,
714  0,
715  KEY_READ,
716  &instance_key_handle))
717  goto cleanup;
718 
719  /* now, read our PnpInstanceID */
720  len = sizeof(pnpinstanceid_value);
721  status = RegQueryValueExA(instance_key_handle,
722  pnpinstanceid_name,
723  NULL, //reserved, always NULL according to MSDN
724  &data_type,
725  (LPBYTE)pnpinstanceid_value,
726  &len);
727 
728  if (status != ERROR_SUCCESS || data_type != REG_SZ)
729  goto cleanup;
730 
731  /* compare the value we got to our devices PNPInstanceID*/
732  if (0 != strncmp(pnpinstanceid_value, pnp_instance_id,
733  sizeof(pnpinstanceid_value) / sizeof(char)))
734  goto cleanup;
735 
736  len = sizeof(device_visible_name);
737  status = RegQueryValueExA(
738  instance_key_handle,
739  adaptername_name,
740  NULL, //reserved, always NULL according to MSDN
741  &data_type,
742  (LPBYTE)device_visible_name,
743  &len);
744 
745  if (status != ERROR_SUCCESS || data_type != REG_SZ)
746  goto cleanup;
747 
748  /*
749  * we have successfully found OUR instance,
750  * save the device GUID before exiting
751  */
752  GNUNET_strlcpy(device_guid, instance_key, sizeof(device_guid));
753  retval = TRUE;
754  fprintf(stderr, "DEBUG: Interface Name lookup succeeded on retry %d, got \"%s\" %s\n", retrys, device_visible_name, device_guid);
755 
756 cleanup:
757  RegCloseKey(instance_key_handle);
758 
759  ++i;
760  }
761 
762  RegCloseKey(adapter_key_handle);
763  }
764  return retval;
765 }
766 
767 
774 static BOOL
776 {
777  ULONG version[3];
778  DWORD len;
779 
780  memset(&(version), 0, sizeof(version));
781 
782  if (DeviceIoControl(handle, TAP_WIN_IOCTL_GET_VERSION,
783  &version, sizeof(version),
784  &version, sizeof(version), &len, NULL))
785  fprintf(stderr, "INFO: TAP-Windows Driver Version %d.%d %s\n",
786  (int)version[0],
787  (int)version[1],
788  (version[2] ? "(DEBUG)" : ""));
789 
790  if ((version[0] != TAP_WIN_MIN_MAJOR) ||
791  (version[1] < TAP_WIN_MIN_MINOR))
792  {
793  fprintf(stderr, "FATAL: This version of gnunet requires a TAP-Windows driver that is at least version %d.%d\n",
796  return FALSE;
797  }
798 
799  return TRUE;
800 }
801 
802 
808 static HANDLE
810 {
811  char device_path[256];
812  HANDLE handle;
813 
814  if (!setup_interface())
815  {
816  errno = ENODEV;
817  return INVALID_HANDLE_VALUE;
818  }
819 
820  if (!resolve_interface_name())
821  {
822  errno = ENODEV;
823  return INVALID_HANDLE_VALUE;
824  }
825 
826  /* Open Windows TAP-Windows adapter */
827  snprintf(device_path, sizeof(device_path), "%s%s%s",
829  device_guid,
831 
832  handle = CreateFile(
833  device_path,
834  GENERIC_READ | GENERIC_WRITE,
835  0, /* was: FILE_SHARE_READ */
836  0,
837  OPEN_EXISTING,
838  FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
839  0
840  );
841 
842  if (INVALID_HANDLE_VALUE == handle)
843  {
844  fprintf(stderr, "FATAL: CreateFile failed on TAP device: %s\n", device_path);
845  return handle;
846  }
847 
848  /* get driver version info */
849  if (!check_tapw32_version(handle))
850  {
851  CloseHandle(handle);
852  return INVALID_HANDLE_VALUE;
853  }
854 
855  /* TODO (opt?): get MTU-Size */
856 
857  fprintf(stderr, "DEBUG: successfully opened TAP device\n");
858  return handle;
859 }
860 
861 
868 static BOOL
869 tun_up(HANDLE handle)
870 {
871  ULONG status = TRUE;
872  DWORD len;
873 
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  /* reset event manually*/
941  if (!SetEvent(input_facility->overlapped.hEvent))
942  return FALSE;
943 
944  fprintf(stderr, "DEBUG: tap read succeeded immediately\n");
945 
946  /* we successfully read something from the TAP and now need to
947  * send it our via STDOUT. Is that possible at the moment? */
948  if ((IOSTATE_READY == output_facility->facility_state ||
949  IOSTATE_WAITING == output_facility->facility_state)
950  && (0 < input_facility->buffer_size))
951  { /* hand over this buffers content and apply message header for gnunet */
952  hdr = (struct GNUNET_MessageHeader *)output_facility->buffer;
953  size = input_facility->buffer_size + sizeof(struct GNUNET_MessageHeader);
954 
955  GNUNET_memcpy(output_facility->buffer + sizeof(struct GNUNET_MessageHeader),
956  input_facility->buffer,
957  input_facility->buffer_size);
958 
959  output_facility->buffer_size = size;
960  hdr->size = htons(size);
961  hdr->type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER);
962  output_facility->facility_state = IOSTATE_READY;
963  }
964  else if (0 < input_facility->buffer_size)
965  /* If we have have read our buffer, wait for our write-partner*/
966  input_facility->facility_state = IOSTATE_WAITING;
967  }
968  else /* operation was either queued or failed*/
969  {
970  int err = GetLastError();
971  if (ERROR_IO_PENDING == err)
972  { /* operation queued */
973  input_facility->facility_state = IOSTATE_QUEUED;
974  }
975  else
976  { /* error occurred, let the rest of the elements finish */
977  input_facility->path_open = FALSE;
978  input_facility->facility_state = IOSTATE_FAILED;
979  if (IOSTATE_WAITING == output_facility->facility_state)
980  output_facility->path_open = FALSE;
981 
982  fprintf(stderr, "FATAL: Read from handle failed, allowing write to finish\n");
983  }
984  }
985  }
986  return TRUE;
987 
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 
1043  case IOSTATE_RESUME:
1044  hdr = (struct GNUNET_MessageHeader *)output_facility->buffer;
1045  size = input_facility->buffer_size + sizeof(struct GNUNET_MessageHeader);
1046 
1047  GNUNET_memcpy(output_facility->buffer + sizeof(struct GNUNET_MessageHeader),
1048  input_facility->buffer,
1049  input_facility->buffer_size);
1050 
1051  output_facility->buffer_size = size;
1052  hdr->size = htons(size);
1053  hdr->type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER);
1054  output_facility->facility_state = IOSTATE_READY;
1055  input_facility->facility_state = IOSTATE_READY;
1056  return TRUE;
1057 
1058  default:
1059  return TRUE;
1060  }
1061 }
1062 
1063 
1090 static BOOL
1091 attempt_read_stdin(struct io_facility * input_facility,
1092  struct io_facility * output_facility)
1093 {
1094  struct GNUNET_MessageHeader * hdr;
1095 
1096  switch (input_facility->facility_state)
1097  {
1098  case IOSTATE_READY:
1099  {
1100  input_facility->buffer_size = 0;
1101 
1102 partial_read_iostate_ready:
1103  if (!ResetEvent(input_facility->overlapped.hEvent))
1104  return FALSE;
1105 
1106  /* Check how the task is handled */
1107  if (ReadFile(input_facility->handle,
1108  input_facility->buffer + input_facility->buffer_size,
1109  sizeof(input_facility->buffer) - input_facility->buffer_size,
1110  &input_facility->buffer_size_processed,
1111  &input_facility->overlapped))
1112  { /* async event processed immediately*/
1113  hdr = (struct GNUNET_MessageHeader *)input_facility->buffer;
1114 
1115  /* reset event manually*/
1116  if (!SetEvent(input_facility->overlapped.hEvent))
1117  return FALSE;
1118 
1119  fprintf(stderr, "DEBUG: stdin read succeeded immediately\n");
1120  input_facility->buffer_size += input_facility->buffer_size_processed;
1121 
1122  if (ntohs(hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER ||
1123  ntohs(hdr->size) > sizeof(input_facility->buffer))
1124  {
1125  fprintf(stderr, "WARNING: Protocol violation, got GNUnet Message type %h, size %h\n", ntohs(hdr->type), ntohs(hdr->size));
1126  input_facility->facility_state = IOSTATE_READY;
1127  return TRUE;
1128  }
1129  /* we got the a part of a packet */
1130  if (ntohs(hdr->size) > input_facility->buffer_size)
1131  goto partial_read_iostate_ready;
1132 
1133  /* have we read more than 0 bytes of payload? (sizeread > header)*/
1134  if (input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader) &&
1135  ((IOSTATE_READY == output_facility->facility_state) ||
1136  (IOSTATE_WAITING == output_facility->facility_state)))
1137  { /* we successfully read something from the TAP and now need to
1138  * send it our via STDOUT. Is that possible at the moment? */
1139  /* hand over this buffers content and strip gnunet message header */
1140  GNUNET_memcpy(output_facility->buffer,
1141  input_facility->buffer + sizeof(struct GNUNET_MessageHeader),
1142  input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader));
1143  output_facility->buffer_size = input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader);
1144  output_facility->facility_state = IOSTATE_READY;
1145  input_facility->facility_state = IOSTATE_READY;
1146  }
1147  else if (input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader))
1148  /* If we have have read our buffer, wait for our write-partner*/
1149  input_facility->facility_state = IOSTATE_WAITING;
1150  else /* we read nothing */
1151  input_facility->facility_state = IOSTATE_READY;
1152  }
1153  else /* operation was either queued or failed*/
1154  {
1155  int err = GetLastError();
1156  if (ERROR_IO_PENDING == err) /* operation queued */
1157  input_facility->facility_state = IOSTATE_QUEUED;
1158  else
1159  { /* error occurred, let the rest of the elements finish */
1160  input_facility->path_open = FALSE;
1161  input_facility->facility_state = IOSTATE_FAILED;
1162  if (IOSTATE_WAITING == output_facility->facility_state)
1163  output_facility->path_open = FALSE;
1164 
1165  fprintf(stderr, "FATAL: Read from handle failed, allowing write to finish\n");
1166  }
1167  }
1168  }
1169  return TRUE;
1170 
1171  // We are queued and should check if the read has finished
1172  case IOSTATE_QUEUED:
1173  {
1174  // there was an operation going on already, check if that has completed now.
1175  if (GetOverlappedResult(input_facility->handle,
1176  &input_facility->overlapped,
1177  &input_facility->buffer_size_processed,
1178  FALSE))
1179  { /* successful return for a queued operation */
1180  hdr = (struct GNUNET_MessageHeader *)input_facility->buffer;
1181 
1182  if (!ResetEvent(input_facility->overlapped.hEvent))
1183  return FALSE;
1184 
1185  fprintf(stderr, "DEBUG: stdin read succeeded delayed\n");
1186  input_facility->buffer_size += input_facility->buffer_size_processed;
1187 
1188  if ((ntohs(hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1189  (ntohs(hdr->size) > sizeof(input_facility->buffer)))
1190  {
1191  fprintf(stderr, "WARNING: Protocol violation, got GNUnet Message type %h, size %h\n", ntohs(hdr->type), ntohs(hdr->size));
1192  input_facility->facility_state = IOSTATE_READY;
1193  return TRUE;
1194  }
1195  /* we got the a part of a packet */
1196  if (ntohs(hdr->size) > input_facility->buffer_size)
1197  ;
1198  goto partial_read_iostate_ready;
1199 
1200  /* we successfully read something from the TAP and now need to
1201  * send it our via STDOUT. Is that possible at the moment? */
1202  if ((IOSTATE_READY == output_facility->facility_state ||
1203  IOSTATE_WAITING == output_facility->facility_state)
1204  && input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader))
1205  { /* hand over this buffers content and strip gnunet message header */
1206  GNUNET_memcpy(output_facility->buffer,
1207  input_facility->buffer + sizeof(struct GNUNET_MessageHeader),
1208  input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader));
1209  output_facility->buffer_size = input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader);
1210  output_facility->facility_state = IOSTATE_READY;
1211  input_facility->facility_state = IOSTATE_READY;
1212  }
1213  else if (input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader))
1214  input_facility->facility_state = IOSTATE_WAITING;
1215  else
1216  input_facility->facility_state = IOSTATE_READY;
1217  }
1218  else
1219  { /* operation still pending/queued or failed? */
1220  int err = GetLastError();
1221  if ((ERROR_IO_INCOMPLETE != err) && (ERROR_IO_PENDING != err))
1222  { /* error occurred, let the rest of the elements finish */
1223  input_facility->path_open = FALSE;
1224  input_facility->facility_state = IOSTATE_FAILED;
1225  if (IOSTATE_WAITING == output_facility->facility_state)
1226  output_facility->path_open = FALSE;
1227  fprintf(stderr, "FATAL: Read from handle failed, allowing write to finish\n");
1228  }
1229  }
1230  }
1231  return TRUE;
1232 
1233  case IOSTATE_RESUME: /* Our buffer was filled already but our write facility was busy. */
1234  GNUNET_memcpy(output_facility->buffer,
1235  input_facility->buffer + sizeof(struct GNUNET_MessageHeader),
1236  input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader));
1237  output_facility->buffer_size = input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader);
1238  output_facility->facility_state = IOSTATE_READY;
1239  input_facility->facility_state = IOSTATE_READY;
1240  return TRUE;
1241 
1242  default:
1243  return TRUE;
1244  }
1245 }
1246 
1247 
1257 static BOOL
1258 attempt_write(struct io_facility * output_facility,
1259  struct io_facility * input_facility)
1260 {
1261  switch (output_facility->facility_state)
1262  {
1263  case IOSTATE_READY:
1264  output_facility->buffer_size_written = 0;
1265 
1266 continue_partial_write:
1267  if (!ResetEvent(output_facility->overlapped.hEvent))
1268  return FALSE;
1269 
1270  /* Check how the task was handled */
1271  if (WriteFile(output_facility->handle,
1272  output_facility->buffer + output_facility->buffer_size_written,
1273  output_facility->buffer_size - output_facility->buffer_size_written,
1274  &output_facility->buffer_size_processed,
1275  &output_facility->overlapped))
1276  {/* async event processed immediately*/
1277  fprintf(stderr, "DEBUG: write succeeded immediately\n");
1278  output_facility->buffer_size_written += output_facility->buffer_size_processed;
1279 
1280  /* reset event manually*/
1281  if (!SetEvent(output_facility->overlapped.hEvent))
1282  return FALSE;
1283 
1284  /* partial write */
1285  if (output_facility->buffer_size_written < output_facility->buffer_size)
1286  goto continue_partial_write;
1287 
1288  /* we are now waiting for our buffer to be filled*/
1289  output_facility->facility_state = IOSTATE_WAITING;
1290 
1291  /* we successfully wrote something and now need to reset our reader */
1292  if (IOSTATE_WAITING == input_facility->facility_state)
1293  input_facility->facility_state = IOSTATE_RESUME;
1294  else if (IOSTATE_FAILED == input_facility->facility_state)
1295  output_facility->path_open = FALSE;
1296  }
1297  else /* operation was either queued or failed*/
1298  {
1299  int err = GetLastError();
1300  if (ERROR_IO_PENDING == err)
1301  { /* operation queued */
1302  output_facility->facility_state = IOSTATE_QUEUED;
1303  }
1304  else
1305  { /* error occurred, close this path */
1306  output_facility->path_open = FALSE;
1307  output_facility->facility_state = IOSTATE_FAILED;
1308  fprintf(stderr, "FATAL: Write to handle failed, exiting\n");
1309  }
1310  }
1311  return TRUE;
1312 
1313  case IOSTATE_QUEUED:
1314  // there was an operation going on already, check if that has completed now.
1315 
1316  if (GetOverlappedResult(output_facility->handle,
1317  &output_facility->overlapped,
1318  &output_facility->buffer_size_processed,
1319  FALSE))
1320  {/* successful return for a queued operation */
1321  if (!ResetEvent(output_facility->overlapped.hEvent))
1322  return FALSE;
1323 
1324  fprintf(stderr, "DEBUG: write succeeded delayed\n");
1325  output_facility->buffer_size_written += output_facility->buffer_size_processed;
1326 
1327  /* partial write */
1328  if (output_facility->buffer_size_written < output_facility->buffer_size)
1329  goto continue_partial_write;
1330 
1331  /* we are now waiting for our buffer to be filled*/
1332  output_facility->facility_state = IOSTATE_WAITING;
1333 
1334  /* we successfully wrote something and now need to reset our reader */
1335  if (IOSTATE_WAITING == input_facility->facility_state)
1336  input_facility->facility_state = IOSTATE_RESUME;
1337  else if (IOSTATE_FAILED == input_facility->facility_state)
1338  output_facility->path_open = FALSE;
1339  }
1340  else
1341  { /* operation still pending/queued or failed? */
1342  int err = GetLastError();
1343  if ((ERROR_IO_INCOMPLETE != err) && (ERROR_IO_PENDING != err))
1344  { /* error occurred, close this path */
1345  output_facility->path_open = FALSE;
1346  output_facility->facility_state = IOSTATE_FAILED;
1347  fprintf(stderr, "FATAL: Write to handle failed, exiting\n");
1348  }
1349  }
1350 
1351  default:
1352  return TRUE;
1353  }
1354 }
1355 
1356 
1365 static BOOL
1367  int initial_state,
1368  BOOL signaled)
1369 {
1370  elem->path_open = TRUE;
1371  elem->handle = INVALID_HANDLE_VALUE;
1372  elem->facility_state = initial_state;
1373  elem->buffer_size = 0;
1374  elem->overlapped.hEvent = CreateEvent(NULL, TRUE, signaled, NULL);
1375  if (NULL == elem->overlapped.hEvent)
1376  return FALSE;
1377 
1378  return TRUE;
1379 }
1380 
1381 
1387 static void
1388 run(HANDLE tap_handle)
1389 {
1390  /* IO-Facility for reading from our virtual interface */
1391  struct io_facility tap_read;
1392  /* IO-Facility for writing to our virtual interface */
1393  struct io_facility tap_write;
1394  /* IO-Facility for reading from stdin */
1395  struct io_facility std_in;
1396  /* IO-Facility for writing to stdout */
1397  struct io_facility std_out;
1398 
1399  HANDLE parent_std_in_handle = GetStdHandle(STD_INPUT_HANDLE);
1400  HANDLE parent_std_out_handle = GetStdHandle(STD_OUTPUT_HANDLE);
1401 
1402  /* tun up: */
1403  /* we do this HERE and not beforehand (in init_tun()), in contrast to openvpn
1404  * to remove the need to flush the arp cache, handle DHCP and wrong IPs.
1405  *
1406  * DHCP and such are all features we will never use in gnunet afaik.
1407  * But for openvpn those are essential.
1408  */
1409  if ((privilege_testing) || (!tun_up(tap_handle)))
1410  goto teardown_final;
1411 
1412  /* Initialize our overlapped IO structures*/
1413  if (!(initialize_io_facility(&tap_read, IOSTATE_READY, FALSE)
1414  && initialize_io_facility(&tap_write, IOSTATE_WAITING, TRUE)
1415  && initialize_io_facility(&std_in, IOSTATE_READY, FALSE)
1416  && initialize_io_facility(&std_out, IOSTATE_WAITING, TRUE)))
1417  goto teardown_final;
1418 
1419  /* Handles for STDIN and STDOUT */
1420  tap_read.handle = tap_handle;
1421  tap_write.handle = tap_handle;
1422 
1423 #ifdef DEBUG_TO_CONSOLE
1424  /* Debug output to console STDIN/STDOUT*/
1425  std_in.handle = parent_std_in_handle;
1426  std_out.handle = parent_std_out_handle;
1427 #else
1428  fprintf(stderr, "DEBUG: reopening stdin/out for overlapped IO\n");
1429  /*
1430  * Find out the types of our handles.
1431  * This part is a problem, because in windows we need to handle files,
1432  * pipes and the console differently.
1433  */
1434  if ((FILE_TYPE_PIPE != GetFileType(parent_std_in_handle)) ||
1435  (FILE_TYPE_PIPE != GetFileType(parent_std_out_handle)))
1436  {
1437  fprintf(stderr, "ERROR: stdin/stdout must be named pipes\n");
1438  goto teardown;
1439  }
1440 
1441  std_in.handle = ReOpenFile(parent_std_in_handle,
1442  GENERIC_READ,
1443  FILE_SHARE_WRITE | FILE_SHARE_READ,
1444  FILE_FLAG_OVERLAPPED);
1445 
1446  if (INVALID_HANDLE_VALUE == std_in.handle)
1447  {
1448  fprintf(stderr, "FATAL: Could not reopen stdin for in overlapped mode, has to be a named pipe\n");
1449  goto teardown;
1450  }
1451 
1452  std_out.handle = ReOpenFile(parent_std_out_handle,
1453  GENERIC_WRITE,
1454  FILE_SHARE_READ,
1455  FILE_FLAG_OVERLAPPED);
1456 
1457  if (INVALID_HANDLE_VALUE == std_out.handle)
1458  {
1459  fprintf(stderr, "FATAL: Could not reopen stdout for in overlapped mode, has to be a named pipe\n");
1460  goto teardown;
1461  }
1462 #endif
1463 
1464  fprintf(stderr, "DEBUG: mainloop has begun\n");
1465 
1466  while (std_out.path_open || tap_write.path_open)
1467  {
1468  /* perform READ from stdin if possible */
1469  if (std_in.path_open && (!attempt_read_stdin(&std_in, &tap_write)))
1470  break;
1471 
1472  /* perform READ from tap if possible */
1473  if (tap_read.path_open && (!attempt_read_tap(&tap_read, &std_out)))
1474  break;
1475 
1476  /* perform WRITE to tap if possible */
1477  if (tap_write.path_open && (!attempt_write(&tap_write, &std_in)))
1478  break;
1479 
1480  /* perform WRITE to STDOUT if possible */
1481  if (std_out.path_open && (!attempt_write(&std_out, &tap_read)))
1482  break;
1483  }
1484 
1485  fprintf(stderr, "DEBUG: teardown initiated\n");
1486 teardown:
1487  CancelIo(tap_handle);
1488  CancelIo(std_in.handle);
1489  CancelIo(std_out.handle);
1490 teardown_final:
1491  CloseHandle(tap_handle);
1492 }
1493 
1494 
1507 int
1508 main(int argc, char **argv)
1509 {
1510  char hwid[LINE_LEN];
1511  HANDLE handle;
1512  int global_ret = 0;
1513  BOOL have_ip4 = FALSE;
1514  BOOL have_ip6 = FALSE;
1515 
1516  if (argc > 1 && 0 == strcmp(argv[1], "-d"))
1517  {
1518  privilege_testing = TRUE;
1519  fprintf(stderr,
1520  "%s",
1521  "DEBUG: Running binary in privilege testing mode.");
1522  argv++;
1523  argc--;
1524  }
1525 
1526  if (6 != argc)
1527  {
1528  fprintf(stderr,
1529  "%s",
1530  "FATAL: must supply 5 arguments\nUsage:\ngnunet-helper-vpn [-d] <if name prefix> <address6 or \"-\"> <netbits6> <address4 or \"-\"> <netmask4>\n");
1531  return 1;
1532  }
1533 
1534  GNUNET_strlcpy(hwid, argv[1], sizeof(hwid));
1535 
1536  /*
1537  * We use our PID for finding/resolving the control-panel name of our virtual
1538  * device. PIDs are (of course) unique at runtime, thus we can safely use it
1539  * as additional hardware-id for our device.
1540  */
1541  snprintf(secondary_hwid, LINE_LEN / 2, "%s-%d",
1542  hwid,
1543  _getpid());
1544 
1545  if (INVALID_HANDLE_VALUE == (handle = init_tun()))
1546  {
1547  fprintf(stderr, "FATAL: could not initialize virtual-interface %s with IPv6 %s/%s and IPv4 %s/%s\n",
1548  hwid,
1549  argv[2],
1550  argv[3],
1551  argv[4],
1552  argv[5]);
1553  global_ret = -1;
1554  goto cleanup;
1555  }
1556 
1557  fprintf(stderr, "DEBUG: Setting IPs, if needed\n");
1558  if (0 != strcmp(argv[2], "-"))
1559  {
1560  const char *address = argv[2];
1561  long prefix_len = atol(argv[3]);
1562 
1563  if ((prefix_len < 1) || (prefix_len > 127))
1564  {
1565  fprintf(stderr, "FATAL: ipv6 prefix_len out of range\n");
1566  global_ret = -1;
1567  goto cleanup;
1568  }
1569 
1570  fprintf(stderr, "DEBUG: Setting IP6 address: %s/%d\n", address, prefix_len);
1571  if (0 != (global_ret = set_address6(address, prefix_len)))
1572  goto cleanup;
1573 
1574  have_ip6 = TRUE;
1575  }
1576 
1577  if (0 != strcmp(argv[4], "-"))
1578  {
1579  const char *address = argv[4];
1580  const char *mask = argv[5];
1581 
1582  fprintf(stderr, "DEBUG: Setting IP4 address: %s/%s\n", address, mask);
1583  if (0 != (global_ret = set_address4(address, mask)))
1584  goto cleanup;
1585 
1586  have_ip4 = TRUE;
1587  }
1588 
1589  run(handle);
1590 cleanup:
1591 
1592  if (have_ip4)
1593  {
1594  const char *address = argv[4];
1595  fprintf(stderr, "DEBUG: Removing IP4 address\n");
1596  remove_address4(address);
1597  }
1598  if (have_ip6)
1599  {
1600  const char *address = argv[2];
1601  fprintf(stderr, "DEBUG: Removing IP6 address\n");
1602  remove_address6(address);
1603  }
1604 
1605  fprintf(stderr, "DEBUG: removing interface\n");
1606  remove_interface();
1607  fprintf(stderr, "DEBUG: graceful exit completed\n");
1608 
1609  return global_ret;
1610 }
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:66
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.