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