2 This file is part of GNUnet.
3 (C) 2010, 2012 Christian Grothoff
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file vpn/gnunet-helper-vpn-windows.c
23 * @brief the helper for the VPN service in win32 builds.
24 * Opens a virtual network-interface, sends data received on the if to stdout,
25 * sends data received on stdin to the interface
26 * @author Christian M. Fuchs
28 * The following list of people have reviewed this code and considered
29 * it safe since the last modification (if you reviewed it, please
30 * have your name added to the list):
37 #include <ddk/cfgmgr32.h>
38 #include <ddk/newdev.h>
41 #include "tap-windows.h"
43 * Need 'struct GNUNET_MessageHeader'.
45 #include "gnunet_common.h"
48 * Need VPN message types.
50 #include "gnunet_protocols.h"
53 * Should we print (interesting|debug) messages that can happen during
56 #define DEBUG GNUNET_NO
59 * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE)
61 #define MAX_SIZE 65536
64 * Name or Path+Name of our driver in Unicode.
65 * The .sys and .cat files HAVE to be in the same location as this file!
67 #define INF_FILE "OemWin2k.inf"
70 * Hardware ID used in the inf-file.
71 * This might change over time, as openvpn advances their driver
73 #define HARDWARE_ID "TAP0901"
76 * Component ID if our driver
78 #define TAP_WIN_COMPONENT_ID "tap0901"
81 * Minimum major-id of the driver version we can work with
83 #define TAP_WIN_MIN_MAJOR 9
86 * Minimum minor-id of the driver version we can work with.
87 * v <= 7 has buggy IPv6.
88 * v == 8 is broken for small IPv4 Packets
90 #define TAP_WIN_MIN_MINOR 9
93 * Time in seconds to wait for our virtual device to go up after telling it to do so.
95 * openvpn doesn't specify a value, 4 seems sane for testing, even for openwrt
96 * (in fact, 4 was chosen by a fair dice roll...)
98 #define TAP32_POSTUP_WAITTIME 4
101 * Location of the network interface list resides in registry.
103 #define INTERFACE_REGISTRY_LOCATION "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
106 * Our local process' PID. Used for creating a sufficiently unique additional
107 * hardware ID for our device.
109 static char secondary_hwid[LINE_LEN / 2];
112 * Device's visible Name, used to identify a network device in netsh.
113 * eg: "Local Area Connection 9"
115 static char device_visible_name[256];
118 * This is our own local instance of a virtual network interface
119 * It is (somewhat) equivalent to using tun/tap in unixoid systems
121 * Upon initialization, we create such an device node.
122 * Upon termination, we remove it again.
124 * If we crash this device might stay around.
126 static HDEVINFO DeviceInfo = INVALID_HANDLE_VALUE;
129 * Registry Key we hand over to windows to spawn a new virtual interface
131 static SP_DEVINFO_DATA DeviceNode;
134 * GUID of our virtual device in the form of
135 * {12345678-1234-1234-1234-123456789abc} - in hex
137 static char device_guid[256];
140 * A IO Object + read/writebuffer + buffer-size for windows asynchronous IO handling
146 BOOL path_open; // BOOL is winbool, NOT boolean!
150 OVERLAPPED overlapped;
152 DWORD buffer_size_written;
153 unsigned char buffer[MAX_SIZE];
157 * Operlapped IO states for facility objects
159 #define IOSTATE_FAILED -1 /* overlapped I/O has failed, stop processing */
160 #define IOSTATE_READY 0 /* overlapped I/O is ready for work */
161 #define IOSTATE_QUEUED 1 /* overlapped I/O has been queued */
162 #define IOSTATE_WAITING 3 /* overlapped I/O has finished, but is waiting for it's write-partner */
165 * ReOpenFile is only available as of XP SP2 and 2003 SP1
167 WINBASEAPI HANDLE WINAPI ReOpenFile (HANDLE, DWORD, DWORD, DWORD);
170 * Wrapper for executing a shellcommand in windows.
172 * @param command - the command + parameters to execute
173 * @return * exitcode of the program executed,
174 * * EINVAL (cmd/file not found)
175 * * EPIPE (could not read STDOUT)
178 execute_shellcommand (char * command)
182 if (NULL == command ||
183 NULL == (pipe = _popen (command, "rt")))
187 char output[LINE_LEN];
188 while (NULL != fgets (output, sizeof (output), pipe))
192 return _pclose (pipe);
196 * @brief Sets the IPv6-Address given in address on the interface dev
198 * @param address the IPv6-Address
199 * @param prefix_len the length of the network-prefix
202 set_address6 (const char *address, unsigned long prefix_len)
205 char command[LINE_LEN];
206 struct sockaddr_in6 sa6;
209 * parse the new address
211 memset (&sa6, 0, sizeof (struct sockaddr_in6));
212 sa6.sin6_family = AF_INET6;
213 if (1 != inet_pton (AF_INET6, address, &sa6.sin6_addr.s6_addr))
215 fprintf (stderr, "Failed to parse address `%s': %s\n", address,
221 * prepare the command
223 snprintf (command, LINE_LEN,
224 "netsh interface ipv6 add address \"%s\" %s/%d",
225 device_visible_name, address, prefix_len);
229 ret = execute_shellcommand (command);
233 fprintf (stderr, "Setting IPv6 address failed: %s\n", strerror (ret));
238 * @brief Sets the IPv4-Address given in address on the interface dev
240 * @param dev the interface to configure
241 * @param address the IPv4-Address
242 * @param mask the netmask
245 set_address4 (const char *address, const char *mask)
248 char command[LINE_LEN];
250 struct sockaddr_in addr;
251 addr.sin_family = AF_INET;
256 if (1 != inet_pton (AF_INET, address, &addr.sin_addr.s_addr))
258 fprintf (stderr, "Failed to parse address `%s': %s\n", address,
262 // Set Device to Subnet-Mode?
263 // do we really need tun.c:2925 ?
266 * prepare the command
268 snprintf (command, LINE_LEN,
269 "netsh interface ipv4 add address \"%s\" %s %s",
270 device_visible_name, address, mask);
274 ret = execute_shellcommand (command);
278 fprintf (stderr, "Setting IPv4 address failed: %s\n", strerror (ret));
283 * Setup a new virtual interface to use for tunneling.
285 * @return: TRUE if setup was successful, else FALSE
291 * where to find our inf-file. (+ the "full" path, after windows found")
293 * We do not directly input all the props here, because openvpn will update
294 * these details over time.
296 char inf_file_path[MAX_PATH];
297 char * temp_inf_filename;
298 char hwidlist[LINE_LEN + 4];
299 char class_name[128];
304 * Set the device's hardware ID and add it to a list.
305 * This information will later on identify this device in registry.
307 strncpy (hwidlist, HARDWARE_ID, LINE_LEN);
309 * this is kind of over-complicated, but allows keeps things independent of
310 * how the openvpn-hwid is actually stored.
312 * A HWID list is double-\0 terminated and \0 separated
314 str_length = strlen (hwidlist) + 1;
315 strncpy (&hwidlist[str_length], secondary_hwid, LINE_LEN);
316 str_length += strlen (&hwidlist[str_length]) + 1;
319 * Locate the inf-file, we need to store it somewhere where the system can
320 * find it. A good choice would be CWD/PDW or %WINDIR$\system32\
322 * TODO: How about win64 in the future?
323 * We need to use a different driver for amd64/i386 !
325 GetFullPathNameA (INF_FILE, MAX_PATH, inf_file_path, &temp_inf_filename);
328 * Bootstrap our device info using the drivers inf-file
330 if (!SetupDiGetINFClassA (inf_file_path,
332 class_name, sizeof (class_name) / sizeof (char),
337 * Collect all the other needed information...
338 * let the system fill our this form
340 DeviceInfo = SetupDiCreateDeviceInfoList (&class_guid, NULL);
341 if (DeviceInfo == INVALID_HANDLE_VALUE)
344 DeviceNode.cbSize = sizeof (SP_DEVINFO_DATA);
345 if (!SetupDiCreateDeviceInfoA (DeviceInfo,
354 /* Deploy all the information collected into the registry */
355 if (!SetupDiSetDeviceRegistryPropertyA (DeviceInfo,
359 str_length * sizeof (char)))
362 /* Install our new class(=device) into the system */
363 if (!SetupDiCallClassInstaller (DIF_REGISTERDEVICE,
368 if (!UpdateDriverForPlugAndPlayDevicesA (NULL,
371 INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE,
372 NULL)) //reboot required? NEVER!
379 * Remove our new virtual interface to use for tunneling.
380 * This function must be called AFTER setup_interface!
382 * @return: TRUE if destruction was successful, else FALSE
387 SP_REMOVEDEVICE_PARAMS remove;
389 if (INVALID_HANDLE_VALUE == DeviceInfo)
392 remove.ClassInstallHeader.cbSize = sizeof (SP_CLASSINSTALL_HEADER);
393 remove.HwProfile = 0;
394 remove.Scope = DI_REMOVEDEVICE_GLOBAL;
395 remove.ClassInstallHeader.InstallFunction = DIF_REMOVE;
397 * 1. Prepare our existing device information set, and place the
398 * uninstall related information into the structure
400 if (!SetupDiSetClassInstallParamsA (DeviceInfo,
401 (PSP_DEVINFO_DATA) & DeviceNode,
402 &remove.ClassInstallHeader,
406 * 2. Uninstall the virtual interface using the class installer
408 if (!SetupDiCallClassInstaller (DIF_REMOVE,
410 (PSP_DEVINFO_DATA) & DeviceNode))
413 SetupDiDestroyDeviceInfoList (DeviceInfo);
419 * Do all the lookup necessary to retrieve the inteface's actual name
422 * @return: TRUE if we were able to lookup the interface's name, else FALSE
425 resolve_interface_name ()
428 SP_DEVINFO_LIST_DETAIL_DATA device_details;
429 char pnp_instance_id [MAX_DEVICE_ID_LEN];
430 HKEY adapter_key_handle;
434 boolean retval = FALSE;
435 char adapter[] = INTERFACE_REGISTRY_LOCATION;
437 /* Registry is incredibly slow, wait a few seconds for it to refresh */
440 /* We can obtain the PNP instance ID from our setupapi handle */
441 device_details.cbSize = sizeof (device_details);
442 if (CR_SUCCESS != CM_Get_Device_ID_ExA (DeviceNode.DevInst,
443 (PCHAR) pnp_instance_id,
446 NULL)) //hMachine, we are local
449 /* Now we can use this ID to locate the correct networks interface in registry */
450 if (ERROR_SUCCESS != RegOpenKeyExA (
455 &adapter_key_handle))
458 /* Of course there is a multitude of entries here, with arbitrary names,
459 * thus we need to iterate through there.
463 char instance_key[256];
464 char query_key [256];
465 HKEY instance_key_handle;
466 char pnpinstanceid_name[] = "PnpInstanceID";
467 char pnpinstanceid_value[256];
468 char adaptername_name[] = "Name";
471 len = 256 * sizeof (char);
472 /* optain a subkey of {4D36E972-E325-11CE-BFC1-08002BE10318} */
473 status = RegEnumKeyExA (
483 /* this may fail due to one of two reasons:
484 * we are at the end of the list*/
485 if (ERROR_NO_MORE_ITEMS == status)
487 // * we found a broken registry key, continue with the next key.
488 if (ERROR_SUCCESS != status)
491 /* prepare our new query string: */
492 snprintf (query_key, 256, "%s\\%s\\Connection",
496 /* look inside instance_key\\Connection */
497 status = RegOpenKeyExA (
502 &instance_key_handle);
504 if (status != ERROR_SUCCESS)
507 /* now, read our PnpInstanceID */
508 len = sizeof (pnpinstanceid_value);
509 status = RegQueryValueExA (instance_key_handle,
511 NULL, //reserved, always NULL according to MSDN
513 (LPBYTE) pnpinstanceid_value,
516 if (status != ERROR_SUCCESS || data_type != REG_SZ)
519 /* compare the value we got to our devices PNPInstanceID*/
520 if (0 != strncmp (pnpinstanceid_value, pnp_instance_id,
521 sizeof (pnpinstanceid_value) / sizeof (char)))
524 len = sizeof (device_visible_name);
525 status = RegQueryValueExA (
528 NULL, //reserved, always NULL according to MSDN
530 (LPBYTE) device_visible_name,
533 if (status != ERROR_SUCCESS || data_type != REG_SZ)
537 * we have successfully found OUR instance,
538 * save the device GUID before exiting
541 strncpy (device_guid, instance_key, 256);
545 RegCloseKey (instance_key_handle);
550 RegCloseKey (adapter_key_handle);
556 check_tapw32_version (HANDLE handle)
561 memset (&(version), 0, sizeof (version));
564 if (DeviceIoControl (handle, TAP_WIN_IOCTL_GET_VERSION,
565 &version, sizeof (version),
566 &version, sizeof (version), &len, NULL))
569 fprintf (stderr, "TAP-Windows Driver Version %d.%d %s",
572 (version[2] ? "(DEBUG)" : ""));
576 if (version[0] != TAP_WIN_MIN_MAJOR || version[1] < TAP_WIN_MIN_MINOR)
578 fprintf (stderr, "ERROR: This version of gnunet requires a TAP-Windows driver that is at least version %d.%d!\n",
588 * Creates a tun-interface called dev;
590 * @return the fd to the tun or -1 on error
595 char device_path[256];
598 if (!setup_interface ())
601 return INVALID_HANDLE_VALUE;
604 if (!resolve_interface_name ())
607 return INVALID_HANDLE_VALUE;
610 /* Open Windows TAP-Windows adapter */
611 snprintf (device_path, sizeof (device_path), "%s%s%s",
616 handle = CreateFile (
618 GENERIC_READ | GENERIC_WRITE,
619 0, /* was: FILE_SHARE_READ */
622 FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
626 if (handle == INVALID_HANDLE_VALUE)
628 fprintf (stderr, "CreateFile failed on TAP device: %s\n", device_path);
632 /* get driver version info */
633 if (!check_tapw32_version (handle))
635 CloseHandle (handle);
636 return INVALID_HANDLE_VALUE;
639 /* TODO (opt?): get MTU-Size */
645 * Brings a TAP device up and sets it to connected state.
647 * @param handle the handle to our TAP device
648 * @return True if the operation succeeded, else false
651 tun_up (HANDLE handle)
655 if (DeviceIoControl (handle, TAP_WIN_IOCTL_SET_MEDIA_STATUS,
656 &status, sizeof (status),
657 &status, sizeof (status), &len, NULL))
659 fprintf (stderr, "The TAP-Windows driver ignored our request to set the interface UP (TAP_WIN_IOCTL_SET_MEDIA_STATUS DeviceIoControl call)!\n");
663 /* Wait for the device to go UP, might take some time. */
664 Sleep ((TAP32_POSTUP_WAITTIME)*1000);
671 * Attempts to read off an input facility (tap or named pipe) in overlapped mode.
674 * If the input facility is in IOSTATE_READY, it will issue a new read operation to the
675 * input handle. Then it goes into IOSTATE_QUEUED state.
676 * In case the read succeeded instantly the input facility enters 3.
679 * If the input facility is in IOSTATE_QUEUED state, it will check if the queued read has finished already.
680 * If it has finished, go to state 3.
681 * If it has failed, set IOSTATE_FAILED
684 * If the output facility is in state IOSTATE_READY, the read-buffer is copied to the output buffer.
685 * The input facility enters state IOSTATE_READY
686 * The output facility enters state IOSTATE_READY
687 * If the output facility is in state IOSTATE_QUEUED, the input facility enters IOSTATE_WAITING
689 * IOSTATE_WAITING is reset by the output facility, once it has completed.
691 * @param input_facility input named pipe or file to work with.
692 * @param output_facility output pipe or file to hand over data to.
693 * @return false if an event reset was impossible (OS error), else true
696 attempt_read (struct io_facility * input_facility,
697 struct io_facility * output_facility)
700 if (IOSTATE_READY == input_facility->facility_state)
702 if (!ResetEvent (input_facility->overlapped.hEvent))
706 input_facility->status = ReadFile (input_facility->handle,
707 input_facility->buffer,
709 &input_facility->buffer_size,
710 &input_facility->overlapped);
712 /* Check how the task is handled */
713 if (input_facility->status)
714 {/* async event processed immediately*/
716 /* reset event manually*/
717 if (!SetEvent (input_facility->overlapped.hEvent))
720 /* we successfully read something from the TAP and now need to
721 * send it our via STDOUT. Is that possible at the moment? */
722 if ((IOSTATE_READY == output_facility->facility_state ||
723 IOSTATE_WAITING == output_facility->facility_state)
724 && 0 < input_facility->buffer_size)
725 { /* hand over this buffers content */
726 memcpy (output_facility->buffer,
727 input_facility->buffer,
729 output_facility->buffer_size = input_facility->buffer_size;
730 output_facility->facility_state = IOSTATE_READY;
732 else if (0 < input_facility->buffer_size)
733 { /* If we have have read our buffer, wait for our write-partner*/
734 input_facility->facility_state = IOSTATE_WAITING;
735 // TODO: shall we attempt to fill our buffer or should we wait for our write-partner to finish?
738 else /* operation was either queued or failed*/
740 int err = GetLastError ();
741 if (ERROR_IO_PENDING == err)
742 { /* operation queued */
743 input_facility->facility_state = IOSTATE_QUEUED;
746 { /* error occurred, let the rest of the elements finish */
747 input_facility->path_open = FALSE;
748 input_facility->facility_state = IOSTATE_FAILED;
749 if (IOSTATE_WAITING == output_facility->facility_state)
750 output_facility->path_open = FALSE;
752 fprintf (stderr, "Fatal: Read from handle failed, allowing write to finish!\n");
756 // We are queued and should check if the read has finished
757 else if (IOSTATE_QUEUED == input_facility->facility_state)
759 // there was an operation going on already, check if that has completed now.
760 input_facility->status = GetOverlappedResult (input_facility->handle,
761 &input_facility->overlapped,
762 &input_facility->buffer_size,
764 if (input_facility->status)
765 {/* successful return for a queued operation */
766 if (!ResetEvent (input_facility->overlapped.hEvent))
769 /* we successfully read something from the TAP and now need to
770 * send it our via STDOUT. Is that possible at the moment? */
771 if ((IOSTATE_READY == output_facility->facility_state ||
772 IOSTATE_WAITING == output_facility->facility_state)
773 && 0 < input_facility->buffer_size)
774 { /* hand over this buffers content */
775 memcpy (output_facility->buffer,
776 input_facility->buffer,
778 output_facility->buffer_size = input_facility->buffer_size;
779 output_facility->facility_state = IOSTATE_READY;
780 input_facility->facility_state = IOSTATE_READY;
782 else if (0 < input_facility->buffer_size)
783 { /* If we have have read our buffer, wait for our write-partner*/
784 input_facility->facility_state = IOSTATE_WAITING;
785 // TODO: shall we attempt to fill our buffer or should we wait for our write-partner to finish?
789 { /* operation still pending/queued or failed? */
790 int err = GetLastError ();
791 if (ERROR_IO_INCOMPLETE != err && ERROR_IO_PENDING != err)
792 { /* error occurred, let the rest of the elements finish */
793 input_facility->path_open = FALSE;
794 input_facility->facility_state = IOSTATE_FAILED;
795 if (IOSTATE_WAITING == output_facility->facility_state)
796 output_facility->path_open = FALSE;
797 fprintf (stderr, "Fatal: Read from handle failed, allowing write to finish!\n");
805 * Attempts to write to an output facility (tap or named pipe) in overlapped mode.
807 * TODO: high level description
809 * @param output_facility output pipe or file to hand over data to.
810 * @param input_facility input named pipe or file to work with.
811 * @return false if an event reset was impossible (OS error), else true
814 attempt_write (struct io_facility * output_facility,
815 struct io_facility * input_facility)
817 if (IOSTATE_READY == output_facility->facility_state
818 && output_facility->buffer_size > 0)
820 if (!ResetEvent (output_facility->overlapped.hEvent))
825 output_facility->status = WriteFile (output_facility->handle,
826 output_facility->buffer,
827 output_facility->buffer_size,
828 &output_facility->buffer_size_written,
829 &output_facility->overlapped);
831 /* Check how the task is handled */
832 if (output_facility->status &&
833 output_facility->buffer_size_written == output_facility->buffer_size)
834 {/* async event processed immediately*/
836 /* reset event manually*/
837 if (!SetEvent (output_facility->overlapped.hEvent))
840 /* we are now waiting for our buffer to be filled*/
841 output_facility->facility_state = IOSTATE_WAITING;
842 output_facility->buffer_size = 0;
843 output_facility->buffer_size_written = 0;
845 /* we successfully wrote something and now need to reset our reader */
846 if (IOSTATE_WAITING == input_facility->facility_state)
847 input_facility->facility_state = IOSTATE_READY;
848 else if (IOSTATE_FAILED == input_facility->facility_state)
849 output_facility->path_open = FALSE;
851 else /* operation was either queued or failed*/
853 int err = GetLastError ();
854 if (ERROR_IO_PENDING == err)
855 { /* operation queued */
856 output_facility->facility_state = IOSTATE_QUEUED;
859 { /* error occurred, close this path */
860 output_facility->path_open = FALSE;
861 output_facility->facility_state = IOSTATE_FAILED;
862 fprintf (stderr, "Fatal: Write to handle failed, exiting!\n");
867 else if (IOSTATE_QUEUED == output_facility->facility_state)
869 // there was an operation going on already, check if that has completed now.
870 output_facility->status = GetOverlappedResult (output_facility->handle,
871 &output_facility->overlapped,
872 &output_facility->buffer_size_written,
874 if (output_facility->status &&
875 output_facility->buffer_size_written == output_facility->buffer_size)
876 {/* successful return for a queued operation */
877 if (!ResetEvent (output_facility->overlapped.hEvent))
880 /* we are now waiting for our buffer to be filled*/
881 output_facility->facility_state = IOSTATE_WAITING;
882 output_facility->buffer_size = 0;
883 output_facility->buffer_size_written = 0;
885 /* we successfully wrote something and now need to reset our reader */
886 if (IOSTATE_WAITING == input_facility->facility_state)
887 input_facility->facility_state = IOSTATE_READY;
888 else if (IOSTATE_FAILED == input_facility->facility_state)
889 output_facility->path_open = FALSE;
892 { /* operation still pending/queued or failed? */
893 int err = GetLastError ();
894 if (ERROR_IO_INCOMPLETE != err && ERROR_IO_PENDING != err)
895 { /* error occurred, close this path */
896 output_facility->path_open = FALSE;
897 output_facility->facility_state = IOSTATE_FAILED;
898 fprintf (stderr, "Fatal: Write to handle failed, exiting!\n");
907 * Initialize a overlapped structure
909 * @param elem the element to initilize
910 * @param initial_state the initial state for this instance
911 * @param signaled if the hEvent created should default to signaled or not
912 * @return true on success, else false
915 initialize_io_facility (struct io_facility * elem,
920 elem->path_open = TRUE;
921 elem->status = initial_state;
922 elem->handle = INVALID_HANDLE_VALUE;
923 elem->facility_state = 0;
924 elem->buffer_size = 0;
925 elem->overlapped.hEvent = CreateEvent (NULL, TRUE, signaled, NULL);
926 if (NULL == elem->overlapped.hEvent)
933 * Start forwarding to and from the tunnel.
935 * @param fd_tun tunnel FD
938 run (HANDLE tap_handle)
940 /* IO-Facility for reading from our virtual interface */
941 struct io_facility tap_read;
942 /* IO-Facility for writing to our virtual interface */
943 struct io_facility tap_write;
944 /* IO-Facility for reading from stdin */
945 struct io_facility std_in;
946 /* IO-Facility for writing to stdout */
947 struct io_facility std_out;
949 HANDLE parent_std_in_handle = GetStdHandle (STD_INPUT_HANDLE);
950 HANDLE parent_std_out_handle = GetStdHandle (STD_OUTPUT_HANDLE);
953 /* we do this HERE and not beforehand (in init_tun()), in contrast to openvpn
954 * to remove the need to flush the arp cache, handle DHCP and wrong IPs.
956 * DHCP and such are all features we will never use in gnunet afaik.
957 * But for openvpn those are essential.
959 if (!tun_up (tap_handle))
962 /* Initialize our overlapped IO structures*/
963 if (!(initialize_io_facility (&tap_read, TRUE, FALSE)
964 && initialize_io_facility (&tap_write, FALSE, TRUE)
965 && initialize_io_facility (&std_in, TRUE, FALSE)
966 && initialize_io_facility (&std_out, FALSE, TRUE)))
969 /* Handles for STDIN and STDOUT */
970 tap_read.handle = tap_handle;
971 tap_write.handle = tap_handle;
974 * Find out the types of our handles.
975 * This part is a problem, because in windows we need to handle files,
976 * pipes and the console differently.
978 if (FILE_TYPE_PIPE != GetFileType (parent_std_in_handle) ||
979 FILE_TYPE_PIPE != GetFileType (parent_std_out_handle))
981 fprintf (stderr, "Fatal: stdin/stdout must be named pipes!\n");
985 std_in.handle = ReOpenFile (parent_std_in_handle,
987 FILE_SHARE_WRITE | FILE_SHARE_READ,
988 FILE_FLAG_OVERLAPPED);
990 if (INVALID_HANDLE_VALUE == std_in.handle)
992 fprintf (stderr, "Fatal: Could not reopen stdin for in overlapped mode, has to be a named pipe!\n");
996 std_out.handle = ReOpenFile (parent_std_out_handle,
999 FILE_FLAG_OVERLAPPED);
1001 if (INVALID_HANDLE_VALUE == std_out.handle)
1003 fprintf (stderr, "Fatal: Could not reopen stdout for in overlapped mode, has to be a named pipe!\n");
1007 while (std_out.path_open || tap_write.path_open)
1009 /* perform READ from stdin if possible */
1010 if (std_in.path_open && tap_write.path_open && !attempt_read (&std_in, &tap_write))
1013 /* perform READ from tap if possible */
1014 if (tap_read.path_open && std_out.path_open && !attempt_read (&tap_read, &std_out))
1017 /* perform WRITE to tap if possible */
1018 if (tap_write.path_open && !attempt_write (&tap_write, &std_in))
1021 /* perform WRITE to STDOUT if possible */
1022 if (std_out.path_open && !attempt_write (&std_out, &tap_read))
1028 CancelIo (tap_handle);
1029 CancelIo (std_in.handle);
1030 CancelIo (std_out.handle);
1034 CloseHandle (tap_handle);
1038 * Open VPN tunnel interface.
1040 * @param argc must be 6
1041 * @param argv 0: binary name (gnunet-helper-vpn)
1042 * 1: tunnel interface name (gnunet-vpn)
1043 * 2: IPv6 address (::1), "-" to disable
1044 * 3: IPv6 netmask length in bits (64), ignored if #2 is "-"
1045 * 4: IPv4 address (1.2.3.4), "-" to disable
1046 * 5: IPv4 netmask (255.255.0.0), ignored if #4 is "-"
1049 main (int argc, char **argv)
1051 char hwid[LINE_LEN];
1057 fprintf (stderr, "Fatal: must supply 5 arguments!\n");
1061 strncpy (hwid, argv[1], LINE_LEN);
1062 hwid[LINE_LEN - 1] = '\0';
1065 * We use our PID for finding/resolving the control-panel name of our virtual
1066 * device. PIDs are (of course) unique at runtime, thus we can safely use it
1067 * as additional hardware-id for our device.
1069 snprintf (secondary_hwid, LINE_LEN / 2, "%s-%d",
1073 if (INVALID_HANDLE_VALUE == (handle = init_tun ()))
1075 fprintf (stderr, "Fatal: could not initialize virtual-interface %s with IPv6 %s/%s and IPv4 %s/%s\n",
1085 if (0 != strcmp (argv[2], "-"))
1087 const char *address = argv[2];
1088 long prefix_len = atol (argv[3]);
1090 if ((prefix_len < 1) || (prefix_len > 127))
1092 fprintf (stderr, "Fatal: prefix_len out of range\n");
1097 if (0 != (global_ret = set_address6 (address, prefix_len)))
1101 if (0 != strcmp (argv[4], "-"))
1103 const char *address = argv[4];
1104 const char *mask = argv[5];
1106 if (0 != (global_ret = set_address4 (address, mask)))
1114 remove_interface ();