GNUnet  0.10.x
gnunet-helper-exit-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 
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 
236 
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, "FATAL: removing IPv6 address failed: %s\n", strerror (ret));
400 }
401 
402 
409 static int
410 set_address4 (const char *address, const char *mask)
411 {
412  int ret = EINVAL;
413  char command[LINE_LEN];
414 
415  struct sockaddr_in addr;
416  addr.sin_family = AF_INET;
417 
418  /*
419  * Parse the address
420  */
421  if (1 != inet_pton (AF_INET, address, &addr.sin_addr.s_addr))
422  {
423  fprintf (stderr, "ERROR: Failed to parse address `%s': %s\n", address,
424  strerror (errno));
425  return -1;
426  }
427  // Set Device to Subnet-Mode?
428  // do we really need tun.c:2925 ?
429 
430  /*
431  * prepare the command
432  */
433  snprintf (command, LINE_LEN,
434  "netsh interface ipv4 add address \"%s\" %s %s store=active",
435  device_visible_name, address, mask);
436  /*
437  * Set the address
438  */
439  ret = execute_shellcommand (command);
440 
441  /* Did it work?*/
442  if (0 != ret)
443  fprintf (stderr, "FATAL: Setting IPv4 address failed: %s\n", strerror (ret));
444  return ret;
445 }
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_length = GNUNET_strlcpy (hwidlist,
504  HARDWARE_ID,
505  sizeof (hwidlist)) + 1;
512  str_length = strlen (hwidlist) + 1;
513  str_length += GNUNET_strlcpy (&hwidlist[str_length],
515  sizeof (hwidlist) - str_length) + 1;
516  GNUNET_assert (str_length < sizeof (hwidlist));
517  hwidlist[str_length] = '\0';
518  ++str_length;
519 
524  if (is_win64())
525  GetFullPathNameA (INF_FILE64, MAX_PATH, inf_file_path, &temp_inf_filename);
526  else
527  GetFullPathNameA (INF_FILE, MAX_PATH, inf_file_path, &temp_inf_filename);
528 
529  fprintf (stderr, "INFO: Located our driver's .inf file at %s\n", inf_file_path);
533  if ( ! SetupDiGetINFClassA (inf_file_path,
534  &class_guid,
535  class_name, sizeof (class_name) / sizeof (char),
536  NULL))
537  return FALSE;
538 
543  DeviceInfo = SetupDiCreateDeviceInfoList (&class_guid, NULL);
544  if (DeviceInfo == INVALID_HANDLE_VALUE)
545  return FALSE;
546 
547  DeviceNode.cbSize = sizeof (SP_DEVINFO_DATA);
548  if ( ! SetupDiCreateDeviceInfoA (DeviceInfo,
549  class_name,
550  &class_guid,
551  NULL,
552  0,
553  DICD_GENERATE_ID,
554  &DeviceNode))
555  return FALSE;
556 
557  /* Deploy all the information collected into the registry */
558  if ( ! SetupDiSetDeviceRegistryPropertyA (DeviceInfo,
559  &DeviceNode,
560  SPDRP_HARDWAREID,
561  (LPBYTE) hwidlist,
562  str_length * sizeof (char)))
563  return FALSE;
564 
565  /* Install our new class(=device) into the system */
566  if ( ! SetupDiCallClassInstaller (DIF_REGISTERDEVICE,
567  DeviceInfo,
568  &DeviceNode))
569  return FALSE;
570 
571  /* This system call tends to take a while (several seconds!) on
572  "modern" Windoze systems */
573  if ( ! UpdateDriverForPlugAndPlayDevicesA (NULL,
575  inf_file_path,
576  INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE,
577  NULL)) //reboot required? NEVER!
578  return FALSE;
579 
580  fprintf (stderr, "DEBUG: successfully created a network device\n");
581  return TRUE;
582 }
583 
584 
591 static BOOL
593 {
594  SP_REMOVEDEVICE_PARAMS remove;
595 
596  if (INVALID_HANDLE_VALUE == DeviceInfo)
597  return FALSE;
598 
599  remove.ClassInstallHeader.cbSize = sizeof (SP_CLASSINSTALL_HEADER);
600  remove.HwProfile = 0;
601  remove.Scope = DI_REMOVEDEVICE_GLOBAL;
602  remove.ClassInstallHeader.InstallFunction = DIF_REMOVE;
603  /*
604  * 1. Prepare our existing device information set, and place the
605  * uninstall related information into the structure
606  */
607  if ( ! SetupDiSetClassInstallParamsA (DeviceInfo,
608  (PSP_DEVINFO_DATA) & DeviceNode,
609  &remove.ClassInstallHeader,
610  sizeof (remove)))
611  return FALSE;
612  /*
613  * 2. Uninstall the virtual interface using the class installer
614  */
615  if ( ! SetupDiCallClassInstaller (DIF_REMOVE,
616  DeviceInfo,
617  (PSP_DEVINFO_DATA) & DeviceNode))
618  return FALSE;
619 
620  SetupDiDestroyDeviceInfoList (DeviceInfo);
621 
622  fprintf (stderr, "DEBUG: removed interface successfully\n");
623 
624  return TRUE;
625 }
626 
627 
634 static BOOL
636 {
637  SP_DEVINFO_LIST_DETAIL_DATA device_details;
638  char pnp_instance_id [MAX_DEVICE_ID_LEN];
639  HKEY adapter_key_handle;
640  LONG status;
641  DWORD len;
642  int i = 0;
643  int retrys;
644  BOOL retval = FALSE;
645  char adapter[] = INTERFACE_REGISTRY_LOCATION;
646 
647  /* We can obtain the PNP instance ID from our setupapi handle */
648  device_details.cbSize = sizeof (device_details);
649  if (CR_SUCCESS != CM_Get_Device_ID_ExA (DeviceNode.DevInst,
650  (PCHAR) pnp_instance_id,
651  MAX_DEVICE_ID_LEN,
652  0, //must be 0
653  NULL)) //hMachine, we are local
654  return FALSE;
655 
656  fprintf (stderr, "DEBUG: Resolving interface name for network device %s\n",pnp_instance_id);
657 
658  /* Registry is incredibly slow, retry for up to 30 seconds to allow registry to refresh */
659  for (retrys = 0; retrys < 120 && !retval; retrys++)
660  {
661  /* sleep for 250ms*/
662  Sleep (250);
663 
664  /* Now we can use this ID to locate the correct networks interface in registry */
665  if (ERROR_SUCCESS != RegOpenKeyExA (
666  HKEY_LOCAL_MACHINE,
667  adapter,
668  0,
669  KEY_READ,
670  &adapter_key_handle))
671  return FALSE;
672 
673  /* Of course there is a multitude of entries here, with arbitrary names,
674  * thus we need to iterate through there.
675  */
676  while (!retval)
677  {
678  char instance_key[256];
679  char query_key [256];
680  HKEY instance_key_handle;
681  char pnpinstanceid_name[] = "PnpInstanceID";
682  char pnpinstanceid_value[256];
683  char adaptername_name[] = "Name";
684  DWORD data_type;
685 
686  len = 256 * sizeof (char);
687  /* optain a subkey of {4D36E972-E325-11CE-BFC1-08002BE10318} */
688  status = RegEnumKeyExA (
689  adapter_key_handle,
690  i,
691  instance_key,
692  &len,
693  NULL,
694  NULL,
695  NULL,
696  NULL);
697 
698  /* this may fail due to one of two reasons:
699  * we are at the end of the list*/
700  if (ERROR_NO_MORE_ITEMS == status)
701  break;
702  // * we found a broken registry key, continue with the next key.
703  if (ERROR_SUCCESS != status)
704  goto cleanup;
705 
706  /* prepare our new query string: */
707  snprintf (query_key, 256, "%s\\%s\\Connection",
708  adapter,
709  instance_key);
710 
711  /* look inside instance_key\\Connection */
712  if (ERROR_SUCCESS != RegOpenKeyExA (
713  HKEY_LOCAL_MACHINE,
714  query_key,
715  0,
716  KEY_READ,
717  &instance_key_handle))
718  goto cleanup;
719 
720  /* now, read our PnpInstanceID */
721  len = sizeof (pnpinstanceid_value);
722  status = RegQueryValueExA (instance_key_handle,
723  pnpinstanceid_name,
724  NULL, //reserved, always NULL according to MSDN
725  &data_type,
726  (LPBYTE) pnpinstanceid_value,
727  &len);
728 
729  if (status != ERROR_SUCCESS || data_type != REG_SZ)
730  goto cleanup;
731 
732  /* compare the value we got to our devices PNPInstanceID*/
733  if (0 != strncmp (pnpinstanceid_value, pnp_instance_id,
734  sizeof (pnpinstanceid_value) / sizeof (char)))
735  goto cleanup;
736 
737  len = sizeof (device_visible_name);
738  status = RegQueryValueExA (
739  instance_key_handle,
740  adaptername_name,
741  NULL, //reserved, always NULL according to MSDN
742  &data_type,
743  (LPBYTE) device_visible_name,
744  &len);
745 
746  if (status != ERROR_SUCCESS || data_type != REG_SZ)
747  goto cleanup;
748 
749  /*
750  * we have successfully found OUR instance,
751  * save the device GUID before exiting
752  */
753  GNUNET_strlcpy (device_guid, instance_key, sizeof (device_guid));
754  retval = TRUE;
755  fprintf (stderr, "DEBUG: Interface Name lookup succeeded on retry %d, got \"%s\" %s\n", retrys, device_visible_name, device_guid);
756 
757 cleanup:
758  RegCloseKey (instance_key_handle);
759 
760  ++i;
761  }
762 
763  RegCloseKey (adapter_key_handle);
764  }
765  return retval;
766 }
767 
768 
775 static BOOL
777 {
778  ULONG version[3];
779  DWORD len;
780  memset (&(version), 0, sizeof (version));
781 
782  if (DeviceIoControl (handle, TAP_WIN_IOCTL_GET_VERSION,
783  &version, sizeof (version),
784  &version, sizeof (version), &len, NULL))
785  fprintf (stderr, "INFO: TAP-Windows Driver Version %d.%d %s\n",
786  (int) version[0],
787  (int) version[1],
788  (version[2] ? "(DEBUG)" : ""));
789 
790  if ((version[0] != TAP_WIN_MIN_MAJOR) ||
791  (version[1] < TAP_WIN_MIN_MINOR )){
792  fprintf (stderr, "FATAL: This version of gnunet requires a TAP-Windows driver that is at least version %d.%d\n",
795  return FALSE;
796  }
797 
798  return TRUE;
799 }
800 
801 
807 static HANDLE
809 {
810  char device_path[256];
811  HANDLE handle;
812 
813  if (! setup_interface ())
814  {
815  errno = ENODEV;
816  return INVALID_HANDLE_VALUE;
817  }
818 
819  if (! resolve_interface_name ())
820  {
821  errno = ENODEV;
822  return INVALID_HANDLE_VALUE;
823  }
824 
825  /* Open Windows TAP-Windows adapter */
826  snprintf (device_path, sizeof (device_path), "%s%s%s",
828  device_guid,
830 
831  handle = CreateFile (
832  device_path,
833  GENERIC_READ | GENERIC_WRITE,
834  0, /* was: FILE_SHARE_READ */
835  0,
836  OPEN_EXISTING,
837  FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
838  0
839  );
840 
841  if (INVALID_HANDLE_VALUE == handle)
842  {
843  fprintf (stderr, "FATAL: CreateFile failed on TAP device: %s\n", device_path);
844  return handle;
845  }
846 
847  /* get driver version info */
848  if (! check_tapw32_version (handle))
849  {
850  CloseHandle (handle);
851  return INVALID_HANDLE_VALUE;
852  }
853 
854  /* TODO (opt?): get MTU-Size */
855 
856  fprintf (stderr, "DEBUG: successfully opened TAP device\n");
857  return handle;
858 }
859 
860 
867 static BOOL
868 tun_up (HANDLE handle)
869 {
870  ULONG status = TRUE;
871  DWORD len;
872  if (! DeviceIoControl (handle, TAP_WIN_IOCTL_SET_MEDIA_STATUS,
873  &status, sizeof (status),
874  &status, sizeof (status), &len, NULL))
875  {
876  fprintf (stderr, "FATAL: TAP driver ignored request to UP interface (DeviceIoControl call)\n");
877  return FALSE;
878  }
879 
880  /* Wait for the device to go UP, might take some time. */
881  Sleep (TAP32_POSTUP_WAITTIME * 1000);
882  fprintf (stderr, "DEBUG: successfully set TAP device to UP\n");
883 
884  return TRUE;
885 }
886 
887 
913 static BOOL
914 attempt_read_tap (struct io_facility * input_facility,
915  struct io_facility * output_facility)
916 {
917  struct GNUNET_MessageHeader * hdr;
918  unsigned short size;
919 
920  switch (input_facility->facility_state)
921  {
922  case IOSTATE_READY:
923  {
924  if (! ResetEvent (input_facility->overlapped.hEvent))
925  {
926  return FALSE;
927  }
928 
929  input_facility->buffer_size = 0;
930 
931  /* Check how the task is handled */
932  if (ReadFile (input_facility->handle,
933  input_facility->buffer,
934  sizeof (input_facility->buffer) - sizeof (struct GNUNET_MessageHeader),
935  &input_facility->buffer_size,
936  &input_facility->overlapped))
937  {/* async event processed immediately*/
938 
939  /* reset event manually*/
940  if (! SetEvent (input_facility->overlapped.hEvent))
941  return FALSE;
942 
943  fprintf (stderr, "DEBUG: tap read succeeded immediately\n");
944 
945  /* we successfully read something from the TAP and now need to
946  * send it our via STDOUT. Is that possible at the moment? */
947  if ((IOSTATE_READY == output_facility->facility_state ||
948  IOSTATE_WAITING == output_facility->facility_state)
949  && (0 < input_facility->buffer_size))
950  { /* hand over this buffers content and apply message header for gnunet */
951  hdr = (struct GNUNET_MessageHeader *) output_facility->buffer;
952  size = input_facility->buffer_size + sizeof (struct GNUNET_MessageHeader);
953 
954  GNUNET_memcpy (output_facility->buffer + sizeof (struct GNUNET_MessageHeader),
955  input_facility->buffer,
956  input_facility->buffer_size);
957 
958  output_facility->buffer_size = size;
959  hdr->size = htons (size);
960  hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
961  output_facility->facility_state = IOSTATE_READY;
962  }
963  else if (0 < input_facility->buffer_size)
964  /* If we have have read our buffer, wait for our write-partner*/
965  input_facility->facility_state = IOSTATE_WAITING;
966  }
967  else /* operation was either queued or failed*/
968  {
969  int err = GetLastError ();
970  if (ERROR_IO_PENDING == err)
971  { /* operation queued */
972  input_facility->facility_state = IOSTATE_QUEUED;
973  }
974  else
975  { /* error occurred, let the rest of the elements finish */
976  input_facility->path_open = FALSE;
977  input_facility->facility_state = IOSTATE_FAILED;
978  if (IOSTATE_WAITING == output_facility->facility_state)
979  output_facility->path_open = FALSE;
980 
981  fprintf (stderr, "FATAL: Read from handle failed, allowing write to finish\n");
982  }
983  }
984  }
985  return TRUE;
986  // We are queued and should check if the read has finished
987  case IOSTATE_QUEUED:
988  {
989  // there was an operation going on already, check if that has completed now.
990 
991  if (GetOverlappedResult (input_facility->handle,
992  &input_facility->overlapped,
993  &input_facility->buffer_size,
994  FALSE))
995  {/* successful return for a queued operation */
996  if (! ResetEvent (input_facility->overlapped.hEvent))
997  return FALSE;
998 
999  fprintf (stderr, "DEBUG: tap read succeeded delayed\n");
1000 
1001  /* we successfully read something from the TAP and now need to
1002  * send it our via STDOUT. Is that possible at the moment? */
1003  if ((IOSTATE_READY == output_facility->facility_state ||
1004  IOSTATE_WAITING == output_facility->facility_state)
1005  && 0 < input_facility->buffer_size)
1006  { /* hand over this buffers content and apply message header for gnunet */
1007  hdr = (struct GNUNET_MessageHeader *) output_facility->buffer;
1008  size = input_facility->buffer_size + sizeof (struct GNUNET_MessageHeader);
1009 
1010  GNUNET_memcpy (output_facility->buffer + sizeof (struct GNUNET_MessageHeader),
1011  input_facility->buffer,
1012  input_facility->buffer_size);
1013 
1014  output_facility->buffer_size = size;
1015  hdr->size = htons(size);
1016  hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1017  output_facility->facility_state = IOSTATE_READY;
1018  input_facility->facility_state = IOSTATE_READY;
1019  }
1020  else if (0 < input_facility->buffer_size)
1021  { /* If we have have read our buffer, wait for our write-partner*/
1022  input_facility->facility_state = IOSTATE_WAITING;
1023  // TODO: shall we attempt to fill our buffer or should we wait for our write-partner to finish?
1024  }
1025  }
1026  else
1027  { /* operation still pending/queued or failed? */
1028  int err = GetLastError ();
1029  if ((ERROR_IO_INCOMPLETE != err) && (ERROR_IO_PENDING != err))
1030  { /* error occurred, let the rest of the elements finish */
1031  input_facility->path_open = FALSE;
1032  input_facility->facility_state = IOSTATE_FAILED;
1033  if (IOSTATE_WAITING == output_facility->facility_state)
1034  output_facility->path_open = FALSE;
1035  fprintf (stderr, "FATAL: Read from handle failed, allowing write to finish\n");
1036  }
1037  }
1038  }
1039  return TRUE;
1040  case IOSTATE_RESUME:
1041  hdr = (struct GNUNET_MessageHeader *) output_facility->buffer;
1042  size = input_facility->buffer_size + sizeof (struct GNUNET_MessageHeader);
1043 
1044  GNUNET_memcpy (output_facility->buffer + sizeof (struct GNUNET_MessageHeader),
1045  input_facility->buffer,
1046  input_facility->buffer_size);
1047 
1048  output_facility->buffer_size = size;
1049  hdr->size = htons (size);
1050  hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1051  output_facility->facility_state = IOSTATE_READY;
1052  input_facility->facility_state = IOSTATE_READY;
1053  return TRUE;
1054  default:
1055  return TRUE;
1056  }
1057 }
1058 
1059 
1086 static BOOL
1087 attempt_read_stdin (struct io_facility * input_facility,
1088  struct io_facility * output_facility)
1089 {
1090  struct GNUNET_MessageHeader * hdr;
1091 
1092  switch (input_facility->facility_state)
1093  {
1094  case IOSTATE_READY:
1095  {
1096  input_facility->buffer_size = 0;
1097 
1098 partial_read_iostate_ready:
1099  if (! ResetEvent (input_facility->overlapped.hEvent))
1100  return FALSE;
1101 
1102  /* Check how the task is handled */
1103  if (ReadFile (input_facility->handle,
1104  input_facility->buffer + input_facility->buffer_size,
1105  sizeof (input_facility->buffer) - input_facility->buffer_size,
1106  &input_facility->buffer_size_processed,
1107  &input_facility->overlapped))
1108  {/* async event processed immediately*/
1109  hdr = (struct GNUNET_MessageHeader *) input_facility->buffer;
1110 
1111  /* reset event manually*/
1112  if (!SetEvent (input_facility->overlapped.hEvent))
1113  return FALSE;
1114 
1115  fprintf (stderr, "DEBUG: stdin read succeeded immediately\n");
1116  input_facility->buffer_size += input_facility->buffer_size_processed;
1117 
1118  if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER ||
1119  ntohs (hdr->size) > sizeof (input_facility->buffer))
1120  {
1121  fprintf (stderr, "WARNING: Protocol violation, got GNUnet Message type %h, size %h\n", ntohs (hdr->type), ntohs (hdr->size));
1122  input_facility->facility_state = IOSTATE_READY;
1123  return TRUE;
1124  }
1125  /* we got the a part of a packet */
1126  if (ntohs (hdr->size) > input_facility->buffer_size)
1127  goto partial_read_iostate_ready;
1128 
1129  /* have we read more than 0 bytes of payload? (sizeread > header)*/
1130  if (input_facility->buffer_size > sizeof (struct GNUNET_MessageHeader) &&
1131  ((IOSTATE_READY == output_facility->facility_state) ||
1132  (IOSTATE_WAITING == output_facility->facility_state)))
1133  {/* we successfully read something from the TAP and now need to
1134  * send it our via STDOUT. Is that possible at the moment? */
1135 
1136  /* hand over this buffers content and strip gnunet message header */
1137  GNUNET_memcpy (output_facility->buffer,
1138  input_facility->buffer + sizeof (struct GNUNET_MessageHeader),
1139  input_facility->buffer_size - sizeof (struct GNUNET_MessageHeader));
1140  output_facility->buffer_size = input_facility->buffer_size - sizeof (struct GNUNET_MessageHeader);
1141  output_facility->facility_state = IOSTATE_READY;
1142  input_facility->facility_state = IOSTATE_READY;
1143  }
1144  else if (input_facility->buffer_size > sizeof (struct GNUNET_MessageHeader))
1145  /* If we have have read our buffer, wait for our write-partner*/
1146  input_facility->facility_state = IOSTATE_WAITING;
1147  else /* we read nothing */
1148  input_facility->facility_state = IOSTATE_READY;
1149  }
1150  else /* operation was either queued or failed*/
1151  {
1152  int err = GetLastError ();
1153  if (ERROR_IO_PENDING == err) /* operation queued */
1154  input_facility->facility_state = IOSTATE_QUEUED;
1155  else
1156  { /* error occurred, let the rest of the elements finish */
1157  input_facility->path_open = FALSE;
1158  input_facility->facility_state = IOSTATE_FAILED;
1159  if (IOSTATE_WAITING == output_facility->facility_state)
1160  output_facility->path_open = FALSE;
1161 
1162  fprintf (stderr, "FATAL: Read from handle failed, allowing write to finish\n");
1163  }
1164  }
1165  }
1166  return TRUE;
1167  // We are queued and should check if the read has finished
1168  case IOSTATE_QUEUED:
1169  {
1170  // there was an operation going on already, check if that has completed now.
1171  if (GetOverlappedResult (input_facility->handle,
1172  &input_facility->overlapped,
1173  &input_facility->buffer_size_processed,
1174  FALSE))
1175  {/* successful return for a queued operation */
1176  hdr = (struct GNUNET_MessageHeader *) input_facility->buffer;
1177 
1178  if (! ResetEvent (input_facility->overlapped.hEvent))
1179  return FALSE;
1180 
1181  fprintf (stderr, "DEBUG: stdin read succeeded delayed\n");
1182  input_facility->buffer_size += input_facility->buffer_size_processed;
1183 
1184  if ((ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1185  (ntohs (hdr->size) > sizeof (input_facility->buffer)))
1186  {
1187  fprintf (stderr, "WARNING: Protocol violation, got GNUnet Message type %h, size %h\n", ntohs (hdr->type), ntohs (hdr->size));
1188  input_facility->facility_state = IOSTATE_READY;
1189  return TRUE;
1190  }
1191  /* we got the a part of a packet */
1192  if (ntohs (hdr->size) > input_facility->buffer_size );
1193  goto partial_read_iostate_ready;
1194 
1195  /* we successfully read something from the TAP and now need to
1196  * send it our via STDOUT. Is that possible at the moment? */
1197  if ((IOSTATE_READY == output_facility->facility_state ||
1198  IOSTATE_WAITING == output_facility->facility_state)
1199  && input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader))
1200  { /* hand over this buffers content and strip gnunet message header */
1201  GNUNET_memcpy (output_facility->buffer,
1202  input_facility->buffer + sizeof(struct GNUNET_MessageHeader),
1203  input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader));
1204  output_facility->buffer_size = input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader);
1205  output_facility->facility_state = IOSTATE_READY;
1206  input_facility->facility_state = IOSTATE_READY;
1207  }
1208  else if (input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader))
1209  input_facility->facility_state = IOSTATE_WAITING;
1210  else
1211  input_facility->facility_state = IOSTATE_READY;
1212  }
1213  else
1214  { /* operation still pending/queued or failed? */
1215  int err = GetLastError ();
1216  if ((ERROR_IO_INCOMPLETE != err) && (ERROR_IO_PENDING != err))
1217  { /* error occurred, let the rest of the elements finish */
1218  input_facility->path_open = FALSE;
1219  input_facility->facility_state = IOSTATE_FAILED;
1220  if (IOSTATE_WAITING == output_facility->facility_state)
1221  output_facility->path_open = FALSE;
1222  fprintf (stderr, "FATAL: Read from handle failed, allowing write to finish\n");
1223  }
1224  }
1225  }
1226  return TRUE;
1227  case IOSTATE_RESUME: /* Our buffer was filled already but our write facility was busy. */
1228  GNUNET_memcpy (output_facility->buffer,
1229  input_facility->buffer + sizeof (struct GNUNET_MessageHeader),
1230  input_facility->buffer_size - sizeof (struct GNUNET_MessageHeader));
1231  output_facility->buffer_size = input_facility->buffer_size - sizeof (struct GNUNET_MessageHeader);
1232  output_facility->facility_state = IOSTATE_READY;
1233  input_facility->facility_state = IOSTATE_READY;
1234  return TRUE;
1235  default:
1236  return TRUE;
1237  }
1238 }
1239 
1240 
1250 static BOOL
1251 attempt_write (struct io_facility * output_facility,
1252  struct io_facility * input_facility)
1253 {
1254  switch (output_facility->facility_state)
1255  {
1256  case IOSTATE_READY:
1257  output_facility->buffer_size_written = 0;
1258 
1259 continue_partial_write:
1260  if (! ResetEvent (output_facility->overlapped.hEvent))
1261  return FALSE;
1262 
1263  /* Check how the task was handled */
1264  if (WriteFile (output_facility->handle,
1265  output_facility->buffer + output_facility->buffer_size_written,
1266  output_facility->buffer_size - output_facility->buffer_size_written,
1267  &output_facility->buffer_size_processed,
1268  &output_facility->overlapped))
1269  {/* async event processed immediately*/
1270 
1271  fprintf (stderr, "DEBUG: write succeeded immediately\n");
1272  output_facility->buffer_size_written += output_facility->buffer_size_processed;
1273 
1274  /* reset event manually*/
1275  if (! SetEvent (output_facility->overlapped.hEvent))
1276  return FALSE;
1277 
1278  /* partial write */
1279  if (output_facility->buffer_size_written < output_facility->buffer_size)
1280  goto continue_partial_write;
1281 
1282  /* we are now waiting for our buffer to be filled*/
1283  output_facility->facility_state = IOSTATE_WAITING;
1284 
1285  /* we successfully wrote something and now need to reset our reader */
1286  if (IOSTATE_WAITING == input_facility->facility_state)
1287  input_facility->facility_state = IOSTATE_RESUME;
1288  else if (IOSTATE_FAILED == input_facility->facility_state)
1289  output_facility->path_open = FALSE;
1290  }
1291  else /* operation was either queued or failed*/
1292  {
1293  int err = GetLastError ();
1294  if (ERROR_IO_PENDING == err)
1295  { /* operation queued */
1296  output_facility->facility_state = IOSTATE_QUEUED;
1297  }
1298  else
1299  { /* error occurred, close this path */
1300  output_facility->path_open = FALSE;
1301  output_facility->facility_state = IOSTATE_FAILED;
1302  fprintf (stderr, "FATAL: Write to handle failed, exiting\n");
1303  }
1304  }
1305  return TRUE;
1306  case IOSTATE_QUEUED:
1307  // there was an operation going on already, check if that has completed now.
1308 
1309  if (GetOverlappedResult (output_facility->handle,
1310  &output_facility->overlapped,
1311  &output_facility->buffer_size_processed,
1312  FALSE))
1313  {/* successful return for a queued operation */
1314  if (! ResetEvent (output_facility->overlapped.hEvent))
1315  return FALSE;
1316 
1317  fprintf (stderr, "DEBUG: write succeeded delayed\n");
1318  output_facility->buffer_size_written += output_facility->buffer_size_processed;
1319 
1320  /* partial write */
1321  if (output_facility->buffer_size_written < output_facility->buffer_size)
1322  goto continue_partial_write;
1323 
1324  /* we are now waiting for our buffer to be filled*/
1325  output_facility->facility_state = IOSTATE_WAITING;
1326 
1327  /* we successfully wrote something and now need to reset our reader */
1328  if (IOSTATE_WAITING == input_facility->facility_state)
1329  input_facility->facility_state = IOSTATE_RESUME;
1330  else if (IOSTATE_FAILED == input_facility->facility_state)
1331  output_facility->path_open = FALSE;
1332  }
1333  else
1334  { /* operation still pending/queued or failed? */
1335  int err = GetLastError ();
1336  if ((ERROR_IO_INCOMPLETE != err) && (ERROR_IO_PENDING != err))
1337  { /* error occurred, close this path */
1338  output_facility->path_open = FALSE;
1339  output_facility->facility_state = IOSTATE_FAILED;
1340  fprintf (stderr, "FATAL: Write to handle failed, exiting\n");
1341  }
1342  }
1343  default:
1344  return TRUE;
1345  }
1346 }
1347 
1348 
1357 static BOOL
1359  int initial_state,
1360  BOOL signaled)
1361 {
1362  elem->path_open = TRUE;
1363  elem->handle = INVALID_HANDLE_VALUE;
1364  elem->facility_state = initial_state;
1365  elem->buffer_size = 0;
1366  elem->overlapped.hEvent = CreateEvent (NULL, TRUE, signaled, NULL);
1367  if (NULL == elem->overlapped.hEvent)
1368  return FALSE;
1369 
1370  return TRUE;
1371 }
1372 
1373 
1379 static void
1380 run (HANDLE tap_handle)
1381 {
1382  /* IO-Facility for reading from our virtual interface */
1383  struct io_facility tap_read;
1384  /* IO-Facility for writing to our virtual interface */
1385  struct io_facility tap_write;
1386  /* IO-Facility for reading from stdin */
1387  struct io_facility std_in;
1388  /* IO-Facility for writing to stdout */
1389  struct io_facility std_out;
1390 
1391  HANDLE parent_std_in_handle = GetStdHandle (STD_INPUT_HANDLE);
1392  HANDLE parent_std_out_handle = GetStdHandle (STD_OUTPUT_HANDLE);
1393 
1394  /* tun up: */
1395  /* we do this HERE and not beforehand (in init_tun()), in contrast to openvpn
1396  * to remove the need to flush the arp cache, handle DHCP and wrong IPs.
1397  *
1398  * DHCP and such are all features we will never use in gnunet afaik.
1399  * But for openvpn those are essential.
1400  */
1401  if ((privilege_testing) || (! tun_up (tap_handle) ))
1402  goto teardown_final;
1403 
1404  /* Initialize our overlapped IO structures*/
1405  if (! (initialize_io_facility (&tap_read, IOSTATE_READY, FALSE)
1406  && initialize_io_facility (&tap_write, IOSTATE_WAITING, TRUE)
1407  && initialize_io_facility (&std_in, IOSTATE_READY, FALSE)
1408  && initialize_io_facility (&std_out, IOSTATE_WAITING, TRUE)))
1409  goto teardown_final;
1410 
1411  /* Handles for STDIN and STDOUT */
1412  tap_read.handle = tap_handle;
1413  tap_write.handle = tap_handle;
1414 
1415 #ifdef DEBUG_TO_CONSOLE
1416  /* Debug output to console STDIN/STDOUT*/
1417  std_in.handle = parent_std_in_handle;
1418  std_out.handle = parent_std_out_handle;
1419 
1420 #else
1421  fprintf (stderr, "DEBUG: reopening stdin/out for overlapped IO\n");
1422  /*
1423  * Find out the types of our handles.
1424  * This part is a problem, because in windows we need to handle files,
1425  * pipes and the console differently.
1426  */
1427  if ((FILE_TYPE_PIPE != GetFileType (parent_std_in_handle)) ||
1428  (FILE_TYPE_PIPE != GetFileType (parent_std_out_handle)))
1429  {
1430  fprintf (stderr, "ERROR: stdin/stdout must be named pipes\n");
1431  goto teardown;
1432  }
1433 
1434  std_in.handle = ReOpenFile (parent_std_in_handle,
1435  GENERIC_READ,
1436  FILE_SHARE_WRITE | FILE_SHARE_READ,
1437  FILE_FLAG_OVERLAPPED);
1438 
1439  if (INVALID_HANDLE_VALUE == std_in.handle)
1440  {
1441  fprintf (stderr, "FATAL: Could not reopen stdin for in overlapped mode, has to be a named pipe\n");
1442  goto teardown;
1443  }
1444 
1445  std_out.handle = ReOpenFile (parent_std_out_handle,
1446  GENERIC_WRITE,
1447  FILE_SHARE_READ,
1448  FILE_FLAG_OVERLAPPED);
1449 
1450  if (INVALID_HANDLE_VALUE == std_out.handle)
1451  {
1452  fprintf (stderr, "FATAL: Could not reopen stdout for in overlapped mode, has to be a named pipe\n");
1453  goto teardown;
1454  }
1455 #endif
1456 
1457  fprintf (stderr, "DEBUG: mainloop has begun\n");
1458 
1459  while (std_out.path_open || tap_write.path_open)
1460  {
1461  /* perform READ from stdin if possible */
1462  if (std_in.path_open && (! attempt_read_stdin (&std_in, &tap_write)))
1463  break;
1464 
1465  /* perform READ from tap if possible */
1466  if (tap_read.path_open && (! attempt_read_tap (&tap_read, &std_out)))
1467  break;
1468 
1469  /* perform WRITE to tap if possible */
1470  if (tap_write.path_open && (! attempt_write (&tap_write, &std_in)))
1471  break;
1472 
1473  /* perform WRITE to STDOUT if possible */
1474  if (std_out.path_open && (! attempt_write (&std_out, &tap_read)))
1475  break;
1476  }
1477  fprintf (stderr, "DEBUG: teardown initiated\n");
1478 
1479 teardown:
1480 
1481  CancelIo (tap_handle);
1482  CancelIo (std_in.handle);
1483  CancelIo (std_out.handle);
1484 
1485 teardown_final:
1486 
1487  CloseHandle (tap_handle);
1488 }
1489 
1490 
1503 int
1504 main (int argc, char **argv)
1505 {
1506  char hwid[LINE_LEN];
1507  HANDLE handle;
1508  int global_ret = 1;
1509  int local_ret = EINVAL;
1510  BOOL have_ip4 = FALSE;
1511  BOOL have_ip6 = FALSE;
1512  BOOL have_nat44 = FALSE;
1513 
1514  if ( (1 < argc) && (0 != strcmp (argv[1], "-d"))){
1515  privilege_testing = TRUE;
1516  fprintf (stderr,
1517  "%s",
1518  "DEBUG: Running binary in privilege testing mode.");
1519  argv++;
1520  argc--;
1521  }
1522 
1523  if (6 != argc)
1524  {
1525  fprintf (stderr,
1526  "%s",
1527  "FATAL: must supply 6 arguments\nUsage:\ngnunet-helper-exit [-d] <if name prefix> <uplink-interface name> <address6 or \"-\"> <netbits6> <address4 or \"-\"> <netmask4>\n");
1528  return 1;
1529  }
1530 
1531  GNUNET_strlcpy (hwid, argv[1], sizeof (hwid));
1532 
1533  /*
1534  * We use our PID for finding/resolving the control-panel name of our virtual
1535  * device. PIDs are (of course) unique at runtime, thus we can safely use it
1536  * as additional hardware-id for our device.
1537  */
1538  snprintf (secondary_hwid, LINE_LEN / 2, "%s-%d",
1539  hwid,
1540  _getpid ());
1541 
1542  if (INVALID_HANDLE_VALUE == (handle = init_tun ()))
1543  {
1544  fprintf (stderr, "FATAL: could not initialize virtual-interface %s with IPv6 %s/%s and IPv4 %s/%s\n",
1545  hwid,
1546  argv[3],
1547  argv[4],
1548  argv[5],
1549  argv[6]);
1550  global_ret = -1;
1551  goto cleanup;
1552  }
1553 
1554  fprintf (stderr, "DEBUG: Setting IPs, if needed\n");
1555  if (0 != strcmp (argv[3], "-"))
1556  {
1557  char command[LINE_LEN];
1558  const char *address = argv[3];
1559  long prefix_len = atol (argv[4]);
1560 
1561  if ((prefix_len < 1) || (prefix_len > 127))
1562  {
1563  fprintf (stderr, "FATAL: ipv6 prefix_len out of range\n");
1564  global_ret = -1;
1565  goto cleanup;
1566  }
1567 
1568  fprintf (stderr, "DEBUG: Setting IP6 address: %s/%d\n", address, prefix_len);
1569  if (0 != (global_ret = set_address6 (address, prefix_len)))
1570  goto cleanup;
1571 
1572  have_ip6 = TRUE;
1573 
1574  /* install our the windows NAT module*/
1575  fprintf (stderr, "DEBUG: Setting IPv6 Forwarding for internal and external interface.\n");
1576  /* outside interface (maybe that's already set) */
1577  snprintf (command, LINE_LEN,
1578  "netsh interface ipv6 set interface interface=\"%s\" metric=1 forwarding=enabled store=active",
1579  argv[2]);
1580  local_ret = execute_shellcommand (command);
1581  if (0 != local_ret)
1582  {
1583  fprintf (stderr, "FATAL: Could not enable forwarding via netsh: %s\n", strerror (local_ret));
1584  goto cleanup;
1585  }
1586  /* internal interface */
1587  snprintf (command, LINE_LEN,
1588  "netsh interface ipv6 set interface interface=\"%s\" metric=1 forwarding=enabled advertise=enabled store=active",
1590  local_ret = execute_shellcommand (command);
1591  if (0 != local_ret)
1592  {
1593  fprintf (stderr, "FATAL: Could not enable forwarding via netsh: %s\n", strerror (local_ret));
1594  goto cleanup;
1595  }
1596  /* we can keep IPv6 forwarding around, as all interfaces have
1597  * their forwarding mode reset to false at bootup. */
1598  }
1599 
1600  if (0 != strcmp (argv[5], "-"))
1601  {
1602  const char *address = argv[5];
1603  const char *mask = argv[6];
1604 
1605  fprintf (stderr, "DEBUG: Setting IP4 address: %s/%s\n", address, mask);
1606  if (0 != (global_ret = set_address4 (address, mask)))
1607  goto cleanup;
1608 
1609  // setup NAPT, if possible
1610  /* MS has REMOVED the routing/nat capabilities from Vista+, thus
1611  * we can not setup NAT like in XP or on the server. Actually the
1612  * the only feasible solution seems to be to use
1613  * Internet Connection Sharing, which introduces a horde of problems
1614  * such as sending out rogue-RAs on the external interface in an ipv6
1615  * network.
1616  * Thus, below stuff ONLY works on
1617  * WinXP SP3
1618  * Win Server 2003 SP1+
1619  * Win Server 2008
1620  * ...
1621  */
1622  have_ip4 = TRUE;
1623  if (0 != strcmp (argv[2], "-"))
1624  {
1625  char command[LINE_LEN];
1626 
1627  /* install our the windows NAT module*/
1628  fprintf (stderr, "DEBUG: Adding NAPT/Masquerading between external IF %s and mine.\n", argv[2]);
1629  local_ret = execute_shellcommand ("netsh routing ip nat install");
1630  if (0 != local_ret)
1631  {
1632  fprintf (stderr, "FATAL: Could not install NAPT support via Netsh: %s\n", strerror (local_ret));
1633  goto cleanup;
1634  }
1635  /* external IF */
1636  snprintf (command, LINE_LEN,
1637  "netsh routing ip nat add interface \"%s\" full", /*full = NAPT (addr+port)*/
1638  argv[2]);
1639  local_ret = execute_shellcommand (command);
1640  if (0 != local_ret)
1641  {
1642  fprintf (stderr, "FATAL: IPv4-NAPT on external interface failed: %s\n", strerror (local_ret));
1643  goto cleanup;
1644  }
1645  /* private/internal/virtual IF */
1646  snprintf (command, LINE_LEN,
1647  "netsh routing ip nat add interface \"%s\" private",
1649  local_ret = execute_shellcommand (command);
1650  if (0 != local_ret)
1651  {
1652  fprintf (stderr, "FATAL: IPv4-NAPT on internal interface failed: %s\n", strerror (local_ret));
1653  goto cleanup;
1654 
1655  have_nat44 = TRUE;
1656  }
1657  }
1658  }
1659 
1660  run (handle);
1661 cleanup:
1662 
1663  if (have_ip4) {
1664  const char *address = argv[5];
1665  if (have_nat44) {
1666  char command[LINE_LEN];
1667  fprintf(stderr, "DEBUG: removing IP4 NAPT from virtual interface \n");
1668  snprintf(command, LINE_LEN,
1669  "netsh routing ip nat del interface \"%s\"",
1671  local_ret = execute_shellcommand(command);
1672  if (0 != local_ret)
1673  fprintf(stderr, "WARNING: Could not remove IPv4-NAPT from internal interface, hopefully this will have no effect in future runs: %s\n", strerror(local_ret));
1674  }
1675 
1676  fprintf(stderr, "DEBUG: Removing IP4 address\n");
1677  remove_address4 (address);
1678  }
1679  if (have_ip6)
1680  {
1681  const char *address = argv[3];
1682  fprintf (stderr, "DEBUG: Removing IP6 address\n");
1683  remove_address6 (address);
1684  }
1685 
1686  fprintf (stderr, "DEBUG: removing interface\n");
1687  remove_interface ();
1688  fprintf (stderr, "DEBUG: graceful exit completed\n");
1689 
1690  return global_ret;
1691 }
static int set_address6(const char *address, unsigned long prefix_len)
Sets the IPv6-Address given in address on the interface dev.
static BOOL initialize_io_facility(struct io_facility *elem, int initial_state, BOOL signaled)
Initialize a overlapped structure.
BOOL path_open
If the path is open or blocked in general (used for quickly checking)
#define HARDWARE_ID
Hardware ID used in the inf-file.
static BOOL resolve_interface_name()
Do all the lookup necessary to retrieve the inteface&#39;s actual name off the registry.
overlapped I/O has been queued
#define TAP_WIN_SUFFIX
Definition: tap-windows.h:79
DWORD buffer_size_processed
Amount of data actually written or read by readfile/writefile.
static HANDLE init_tun()
Creates a tun-interface called dev;.
#define TAP_WIN_MIN_MINOR
Minimum minor-id of the driver version we can work with.
TAP32 virtual network driver defines.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
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.
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
#define TAP_WIN_MIN_MAJOR
Minimum major-id of the driver version we can work with.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
#define TAP_WIN_IOCTL_SET_MEDIA_STATUS
Definition: tap-windows.h:50
static int ret
Final status code.
Definition: gnunet-arm.c:89
static void run(HANDLE tap_handle)
Start forwarding to and from the tunnel.
static BOOL setup_interface()
Setup a new virtual interface to use for tunneling.
#define INF_FILE
Name or Path+Name of our win32 driver.
OVERLAPPED overlapped
Overlaped IO structure used for asynchronous IO in windows.
cryptographic primitives for GNUnet
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 int set_address4(const char *address, const char *mask)
Sets the IPv4-Address given in address on the interface dev.
int main(int argc, char **argv)
Open VPN tunnel interface.
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.
BOOL(WINAPI * LPFN_ISWOW64PROCESS)(HANDLE, PBOOL)
IsWow64Process definition for our is_win64, as this is a kernel function.
uint16_t status
See PRISM_STATUS_*-constants.
static void cleanup(void *cls)
Function scheduled as very last function, cleans up after us.
#define INF_FILE64
Name or Path+Name of our win64 driver.
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.
BOOL is_win64()
Determines if the host OS is win32 or win64.
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.
static void remove_address4(const char *address)
Removes the IPv4-Address given in address from the interface dev.
IO_State
Possible states of an IO facility.
static unsigned int size
Size of the "table".
Definition: peer.c:67
there is a full buffer waiting
static HDEVINFO DeviceInfo
This is our own local instance of a virtual network interface It is (somewhat) equivalent to using tu...
static void remove_address6(const char *address)
Removes the IPv6-Address given in address from the interface dev.
enum IO_State facility_state
The mode the state machine associated with this object is in.
static char device_guid[256]
GUID of our virtual device in the form of {12345678-1234-1234-1234-123456789abc} - in hex...
unsigned char buffer[65536]
Buffer for reading things to and writing from...
#define USERMODEDEVICEDIR
Definition: tap-windows.h:76
overlapped I/O is ready for work
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.
static BOOL tun_up(HANDLE handle)
Brings a TAP device up and sets it to connected state.
#define TAP32_POSTUP_WAITTIME
Time in seconds to wait for our virtual device to go up after telling it to do so.
Header for all communications.
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 MAX_SIZE
Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
overlapped I/O has finished, but is waiting for it&#39;s write-partner
commonly used definitions; globals in this file are exempt from the rule that the module name ("commo...
static int execute_shellcommand(const char *command)
Wrapper for executing a shellcommand in windows.
A IO Object + read/writebuffer + buffer-size for windows asynchronous IO handling.
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.
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)
WINBASEAPI HANDLE WINAPI ReOpenFile(HANDLE, DWORD, DWORD, DWORD)
ReOpenFile is only available as of XP SP2 and 2003 SP1.
#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.