uncrustify as demanded.
[oweals/gnunet.git] / src / vpn / gnunet-helper-vpn-windows.c
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  */
20 /**
21  * @file vpn/gnunet-helper-vpn-windows.c
22  * @brief the helper for the VPN service in win32 builds.
23  * Opens a virtual network-interface, sends data received on the if to stdout,
24  * sends data received on stdin to the interface
25  * @author Christian M. Fuchs
26  *
27  * The following list of people have reviewed this code and considered
28  * it safe since the last modification (if you reviewed it, please
29  * have your name added to the list):
30  *
31  */
32
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"
47 /**
48  * Need 'struct GNUNET_HashCode' and 'struct GNUNET_PeerIdentity'.
49  */
50 #include "gnunet_crypto_lib.h"
51 /**
52  * Need 'struct GNUNET_MessageHeader'.
53  */
54 #include "gnunet_common.h"
55
56 /**
57  * Need VPN message types.
58  */
59 #include "gnunet_protocols.h"
60
61 /**
62  * Should we print (interesting|debug) messages that can happen during
63  * normal operation?
64  */
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
74 /**
75  * Will this binary be run in permissions testing mode?
76  */
77 static boolean privilege_testing = FALSE;
78
79 /**
80  * Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
81  */
82 #define MAX_SIZE 65536
83
84 /**
85  * Name or Path+Name of our win32 driver.
86  * The .sys and .cat files HAVE to be in the same location as this file!
87  */
88 #define INF_FILE "share/gnunet/openvpn-tap32/tapw32/OemWin2k.inf"
89
90 /**
91  * Name or Path+Name of our win64 driver.
92  * The .sys and .cat files HAVE to be in the same location as this file!
93  */
94 #define INF_FILE64 "share/gnunet/openvpn-tap32/tapw64/OemWin2k.inf"
95
96 /**
97  * Hardware ID used in the inf-file.
98  * This might change over time, as openvpn advances their driver
99  */
100 #define HARDWARE_ID "tap0901"
101
102 /**
103  * Minimum major-id of the driver version we can work with
104  */
105 #define TAP_WIN_MIN_MAJOR 9
106
107 /**
108  * Minimum minor-id of the driver version we can work with.
109  * v <= 7 has buggy IPv6.
110  * v == 8 is broken for small IPv4 Packets
111  */
112 #define TAP_WIN_MIN_MINOR 9
113
114 /**
115  * Time in seconds to wait for our virtual device to go up after telling it to do so.
116  *
117  * openvpn doesn't specify a value, 4 seems sane for testing, even for openwrt
118  * (in fact, 4 was chosen by a fair dice roll...)
119  */
120 #define TAP32_POSTUP_WAITTIME 4
121
122 /**
123  * Location of the network interface list resides in registry.
124  */
125 #define INTERFACE_REGISTRY_LOCATION "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
126
127 /**
128  * Our local process' PID. Used for creating a sufficiently unique additional
129  * hardware ID for our device.
130  */
131 static char secondary_hwid[LINE_LEN / 2];
132
133 /**
134  * Device's visible Name, used to identify a network device in netsh.
135  * eg: "Local Area Connection 9"
136  */
137 static char device_visible_name[256];
138
139 /**
140  * This is our own local instance of a virtual network interface
141  * It is (somewhat) equivalent to using tun/tap in unixoid systems
142  *
143  * Upon initialization, we create such an device node.
144  * Upon termination, we remove it again.
145  *
146  * If we crash this device might stay around.
147  */
148 static HDEVINFO DeviceInfo = INVALID_HANDLE_VALUE;
149
150 /**
151  * Registry Key we hand over to windows to spawn a new virtual interface
152  */
153 static SP_DEVINFO_DATA DeviceNode;
154
155 /**
156  * GUID of our virtual device in the form of
157  * {12345678-1234-1234-1234-123456789abc} - in hex
158  */
159 static char device_guid[256];
160
161
162 /**
163  * Possible states of an IO facility.
164  */
165 enum IO_State {
166   /**
167    * overlapped I/O is ready for work
168    */
169   IOSTATE_READY = 0,
170
171   /**
172    * overlapped I/O has been queued
173    */
174   IOSTATE_QUEUED,
175
176   /**
177    * overlapped I/O has finished, but is waiting for it's write-partner
178    */
179   IOSTATE_WAITING,
180
181   /**
182    * there is a full buffer waiting
183    */
184   IOSTATE_RESUME,
185
186   /**
187    * Operlapped IO states for facility objects
188    * overlapped I/O has failed, stop processing
189    */
190   IOSTATE_FAILED
191 };
192
193
194 /**
195  * A IO Object + read/writebuffer + buffer-size for windows asynchronous IO handling
196  */
197 struct io_facility {
198   /**
199    * The mode the state machine associated with this object is in.
200    */
201   enum IO_State facility_state;
202
203   /**
204    * If the path is open or blocked in general (used for quickly checking)
205    */
206   BOOL path_open; // BOOL is winbool (int), NOT boolean (unsigned char)!
207
208   /**
209    * Windows Object-Handle (used for accessing TAP and STDIN/STDOUT)
210    */
211   HANDLE handle;
212
213   /**
214    * Overlaped IO structure used for asynchronous IO in windows.
215    */
216   OVERLAPPED overlapped;
217
218   /**
219    * Buffer for reading things to and writing from...
220    */
221   unsigned char buffer[MAX_SIZE];
222
223   /**
224    * How much of this buffer was used when reading or how much data can be written
225    */
226   DWORD buffer_size;
227
228   /**
229    * Amount of data actually written or read by readfile/writefile.
230    */
231   DWORD buffer_size_processed;
232
233   /**
234    * How much of this buffer we have writte in total
235    */
236   DWORD buffer_size_written;
237 };
238
239 /**
240  * ReOpenFile is only available as of XP SP2 and 2003 SP1
241  */
242 WINBASEAPI HANDLE WINAPI ReOpenFile(HANDLE, DWORD, DWORD, DWORD);
243
244 /**
245  * IsWow64Process definition for our is_win64, as this is a kernel function
246  */
247 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
248
249
250 /**
251  * Like strlcpy but portable. The given string @a src is copied until its null
252  * byte or until @a n - 1 bytes have been read. The destination buffer is
253  * guaranteed to be null-terminated.
254  *
255  * @param dst destination of the copy (must be @a n bytes long)
256  * @param src source of the copy (at most @a n - 1 bytes will be read)
257  * @param n the length of the string to copy, including its terminating null
258  *          byte
259  * @return the length of the string that was copied, excluding the terminating
260  *         null byte
261  */
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
276 /**
277  * Determines if the host OS is win32 or win64
278  *
279  * @return true if
280  */
281 BOOL
282 is_win64()
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 }
299 /**
300  * Wrapper for executing a shellcommand in windows.
301  *
302  * @param command - the command + parameters to execute
303  * @return * exitcode of the program executed,
304  *         * EINVAL (cmd/file not found)
305  *         * EPIPE (could not read STDOUT)
306  */
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
327 /**
328  * @brief Sets the IPv6-Address given in address on the interface dev
329  *
330  * @param address the IPv6-Address
331  * @param prefix_len the length of the network-prefix
332  */
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
370 /**
371  * @brief Removes the IPv6-Address given in address from the interface dev
372  *
373  * @param address the IPv4-Address
374  */
375 static void
376 remove_address6(const char *address)
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",
387            device_visible_name);
388   /*
389    * Set the address
390    */
391   ret = execute_shellcommand(command);
392
393   /* Did it work?*/
394   if (0 != ret)
395     fprintf(stderr,
396             "FATAL: removing IPv6 address failed: %s\n",
397             strerror(ret));
398 }
399
400
401 /**
402  * @brief Sets the IPv4-Address given in address on the interface dev
403  *
404  * @param address the IPv4-Address
405  * @param mask the netmask
406  */
407 static int
408 set_address4(const char *address, const char *mask)
409 {
410   int ret = EINVAL;
411   char command[LINE_LEN];
412
413   struct sockaddr_in addr;
414
415   addr.sin_family = AF_INET;
416
417   /*
418    * Parse the address
419    */
420   if (1 != inet_pton(AF_INET, address, &addr.sin_addr.s_addr))
421     {
422       fprintf(stderr, "ERROR: Failed to parse address `%s': %s\n", address,
423               strerror(errno));
424       return -1;
425     }
426   // Set Device to Subnet-Mode? do we really need openvpn/tun.c:2925 ?
427
428   /*
429    * prepare the command
430    */
431   snprintf(command, LINE_LEN,
432            "netsh interface ipv4 add address \"%s\" %s %s store=active",
433            device_visible_name, address, mask);
434   /*
435    * Set the address
436    */
437   ret = execute_shellcommand(command);
438
439   /* Did it work?*/
440   if (0 != ret)
441     fprintf(stderr,
442             "FATAL: Setting IPv4 address failed: %s\n",
443             strerror(ret));
444   return ret;
445 }
446
447
448 /**
449  * @brief Removes the IPv4-Address given in address from the interface dev
450  *
451  * @param address the IPv4-Address
452  */
453 static void
454 remove_address4(const char *address)
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",
466            device_visible_name);
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
478 /**
479  * Setup a new virtual interface to use for tunneling.
480  *
481  * @return: TRUE if setup was successful, else FALSE
482  */
483 static BOOL
484 setup_interface()
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
499   /**
500    * Set the device's hardware ID and add it to a list.
501    * This information will later on identify this device in registry.
502    */
503   str_len = GNUNET_strlcpy(hwidlist,
504                            HARDWARE_ID,
505                            sizeof(hwidList)) + 1;
506   /**
507    * this is kind of over-complicated, but allows keeps things independent of
508    * how the openvpn-hwid is actually stored.
509    *
510    * A HWID list is double-\0 terminated and \0 separated
511    */
512   str_len += GNUNET_strlcpy(&hwidlist[str_length],
513                             secondary_hwid,
514                             sizeof(hwidlist) - str_len) + 1;
515   GNUNET_assert(str_len < sizeof(hwidlist));
516   hwidlist[str_len] = '\0';
517   ++str_len;
518
519   /**
520    * Locate the inf-file, we need to store it somewhere where the system can
521    * find it. We need to pick the correct driver for win32/win64.
522    */
523   if (is_win64())
524     GetFullPathNameA(INF_FILE64, MAX_PATH, inf_file_path, &temp_inf_filename);
525   else
526     GetFullPathNameA(INF_FILE, MAX_PATH, inf_file_path, &temp_inf_filename);
527
528   fprintf(stderr, "INFO: Located our driver's .inf file at %s\n", inf_file_path);
529   /**
530    * Bootstrap our device info using the drivers inf-file
531    */
532   if (!SetupDiGetINFClassA(inf_file_path,
533                            &class_guid,
534                            class_name, sizeof(class_name) / sizeof(char),
535                            NULL))
536     return FALSE;
537
538   /**
539    * Collect all the other needed information...
540    * let the system fill our this form
541    */
542   DeviceInfo = SetupDiCreateDeviceInfoList(&class_guid, NULL);
543   if (DeviceInfo == INVALID_HANDLE_VALUE)
544     return FALSE;
545
546   DeviceNode.cbSize = sizeof(SP_DEVINFO_DATA);
547   if (!SetupDiCreateDeviceInfoA(DeviceInfo,
548                                 class_name,
549                                 &class_guid,
550                                 NULL,
551                                 0,
552                                 DICD_GENERATE_ID,
553                                 &DeviceNode))
554     return FALSE;
555
556   /* Deploy all the information collected into the registry */
557   if (!SetupDiSetDeviceRegistryPropertyA(DeviceInfo,
558                                          &DeviceNode,
559                                          SPDRP_HARDWAREID,
560                                          (LPBYTE)hwidlist,
561                                          str_length * sizeof(char)))
562     return FALSE;
563
564   /* Install our new class(=device) into the system */
565   if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE,
566                                  DeviceInfo,
567                                  &DeviceNode))
568     return FALSE;
569
570   /* This system call tends to take a while (several seconds!) on
571      "modern" Windoze systems */
572   if (!UpdateDriverForPlugAndPlayDevicesA(NULL,
573                                           secondary_hwid,
574                                           inf_file_path,
575                                           INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE,
576                                           NULL))  //reboot required? NEVER!
577     return FALSE;
578
579   fprintf(stderr, "DEBUG: successfully created a network device\n");
580   return TRUE;
581 }
582
583
584 /**
585  * Remove our new virtual interface to use for tunneling.
586  * This function must be called AFTER setup_interface!
587  *
588  * @return: TRUE if destruction was successful, else FALSE
589  */
590 static BOOL
591 remove_interface()
592 {
593   SP_REMOVEDEVICE_PARAMS remove;
594
595   if (INVALID_HANDLE_VALUE == DeviceInfo)
596     return FALSE;
597
598   remove.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
599   remove.HwProfile = 0;
600   remove.Scope = DI_REMOVEDEVICE_GLOBAL;
601   remove.ClassInstallHeader.InstallFunction = DIF_REMOVE;
602   /*
603    * 1. Prepare our existing device information set, and place the
604    *    uninstall related information into the structure
605    */
606   if (!SetupDiSetClassInstallParamsA(DeviceInfo,
607                                      (PSP_DEVINFO_DATA)&DeviceNode,
608                                      &remove.ClassInstallHeader,
609                                      sizeof(remove)))
610     return FALSE;
611   /*
612    * 2. Uninstall the virtual interface using the class installer
613    */
614   if (!SetupDiCallClassInstaller(DIF_REMOVE,
615                                  DeviceInfo,
616                                  (PSP_DEVINFO_DATA)&DeviceNode))
617     return FALSE;
618
619   SetupDiDestroyDeviceInfoList(DeviceInfo);
620
621   fprintf(stderr, "DEBUG: removed interface successfully\n");
622
623   return TRUE;
624 }
625
626
627 /**
628  * Do all the lookup necessary to retrieve the inteface's actual name
629  * off the registry.
630  *
631  * @return: TRUE if we were able to lookup the interface's name, else FALSE
632  */
633 static BOOL
634 resolve_interface_name()
635 {
636   SP_DEVINFO_LIST_DETAIL_DATA device_details;
637   char pnp_instance_id [MAX_DEVICE_ID_LEN];
638   HKEY adapter_key_handle;
639   LONG status;
640   DWORD len;
641   int i = 0;
642   int retrys;
643   BOOL retval = FALSE;
644   char adapter[] = INTERFACE_REGISTRY_LOCATION;
645
646   /* We can obtain the PNP instance ID from our setupapi handle */
647   device_details.cbSize = sizeof(device_details);
648   if (CR_SUCCESS != CM_Get_Device_ID_ExA(DeviceNode.DevInst,
649                                          (PCHAR)pnp_instance_id,
650                                          MAX_DEVICE_ID_LEN,
651                                          0,  //must be 0
652                                          NULL))  //hMachine, we are local
653     return FALSE;
654
655   fprintf(stderr, "DEBUG: Resolving interface name for network device %s\n", pnp_instance_id);
656
657   /* Registry is incredibly slow, retry for up to 30 seconds to allow registry to refresh */
658   for (retrys = 0; retrys < 120 && !retval; retrys++)
659     {
660       /* sleep for 250ms*/
661       Sleep(250);
662
663       /* Now we can use this ID to locate the correct networks interface in registry */
664       if (ERROR_SUCCESS != RegOpenKeyExA(
665             HKEY_LOCAL_MACHINE,
666             adapter,
667             0,
668             KEY_READ,
669             &adapter_key_handle))
670         return FALSE;
671
672       /* Of course there is a multitude of entries here, with arbitrary names,
673        * thus we need to iterate through there.
674        */
675       while (!retval)
676         {
677           char instance_key[256];
678           char query_key [256];
679           HKEY instance_key_handle;
680           char pnpinstanceid_name[] = "PnpInstanceID";
681           char pnpinstanceid_value[256];
682           char adaptername_name[] = "Name";
683           DWORD data_type;
684
685           len = 256 * sizeof(char);
686           /* optain a subkey of {4D36E972-E325-11CE-BFC1-08002BE10318} */
687           status = RegEnumKeyExA(
688             adapter_key_handle,
689             i,
690             instance_key,
691             &len,
692             NULL,
693             NULL,
694             NULL,
695             NULL);
696
697           /* this may fail due to one of two reasons:
698            * we are at the end of the list*/
699           if (ERROR_NO_MORE_ITEMS == status)
700             break;
701           // * we found a broken registry key, continue with the next key.
702           if (ERROR_SUCCESS != status)
703             goto cleanup;
704
705           /* prepare our new query string: */
706           snprintf(query_key, 256, "%s\\%s\\Connection",
707                    adapter,
708                    instance_key);
709
710           /* look inside instance_key\\Connection */
711           if (ERROR_SUCCESS != RegOpenKeyExA(
712                 HKEY_LOCAL_MACHINE,
713                 query_key,
714                 0,
715                 KEY_READ,
716                 &instance_key_handle))
717             goto cleanup;
718
719           /* now, read our PnpInstanceID */
720           len = sizeof(pnpinstanceid_value);
721           status = RegQueryValueExA(instance_key_handle,
722                                     pnpinstanceid_name,
723                                     NULL,  //reserved, always NULL according to MSDN
724                                     &data_type,
725                                     (LPBYTE)pnpinstanceid_value,
726                                     &len);
727
728           if (status != ERROR_SUCCESS || data_type != REG_SZ)
729             goto cleanup;
730
731           /* compare the value we got to our devices PNPInstanceID*/
732           if (0 != strncmp(pnpinstanceid_value, pnp_instance_id,
733                            sizeof(pnpinstanceid_value) / sizeof(char)))
734             goto cleanup;
735
736           len = sizeof(device_visible_name);
737           status = RegQueryValueExA(
738             instance_key_handle,
739             adaptername_name,
740             NULL,                          //reserved, always NULL according to MSDN
741             &data_type,
742             (LPBYTE)device_visible_name,
743             &len);
744
745           if (status != ERROR_SUCCESS || data_type != REG_SZ)
746             goto cleanup;
747
748           /*
749            * we have successfully found OUR instance,
750            * save the device GUID before exiting
751            */
752           GNUNET_strlcpy(device_guid, instance_key, sizeof(device_guid));
753           retval = TRUE;
754           fprintf(stderr, "DEBUG: Interface Name lookup succeeded on retry %d, got \"%s\" %s\n", retrys, device_visible_name, device_guid);
755
756 cleanup:
757           RegCloseKey(instance_key_handle);
758
759           ++i;
760         }
761
762       RegCloseKey(adapter_key_handle);
763     }
764   return retval;
765 }
766
767
768 /**
769  * Determines the version of the installed TAP32 driver and checks if it's sufficiently new for GNUNET
770  *
771  * @param handle the handle to our tap device
772  * @return TRUE if the version is sufficient, else FALSE
773  */
774 static BOOL
775 check_tapw32_version(HANDLE handle)
776 {
777   ULONG version[3];
778   DWORD len;
779
780   memset(&(version), 0, sizeof(version));
781
782   if (DeviceIoControl(handle, TAP_WIN_IOCTL_GET_VERSION,
783                       &version, sizeof(version),
784                       &version, sizeof(version), &len, NULL))
785     fprintf(stderr, "INFO: TAP-Windows Driver Version %d.%d %s\n",
786             (int)version[0],
787             (int)version[1],
788             (version[2] ? "(DEBUG)" : ""));
789
790   if ((version[0] != TAP_WIN_MIN_MAJOR) ||
791       (version[1] < TAP_WIN_MIN_MINOR))
792     {
793       fprintf(stderr, "FATAL:  This version of gnunet requires a TAP-Windows driver that is at least version %d.%d\n",
794               TAP_WIN_MIN_MAJOR,
795               TAP_WIN_MIN_MINOR);
796       return FALSE;
797     }
798
799   return TRUE;
800 }
801
802
803 /**
804  * Creates a tun-interface called dev;
805  *
806  * @return the fd to the tun or -1 on error
807  */
808 static HANDLE
809 init_tun()
810 {
811   char device_path[256];
812   HANDLE handle;
813
814   if (!setup_interface())
815     {
816       errno = ENODEV;
817       return INVALID_HANDLE_VALUE;
818     }
819
820   if (!resolve_interface_name())
821     {
822       errno = ENODEV;
823       return INVALID_HANDLE_VALUE;
824     }
825
826   /* Open Windows TAP-Windows adapter */
827   snprintf(device_path, sizeof(device_path), "%s%s%s",
828            USERMODEDEVICEDIR,
829            device_guid,
830            TAP_WIN_SUFFIX);
831
832   handle = CreateFile(
833     device_path,
834     GENERIC_READ | GENERIC_WRITE,
835     0,                    /* was: FILE_SHARE_READ */
836     0,
837     OPEN_EXISTING,
838     FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
839     0
840     );
841
842   if (INVALID_HANDLE_VALUE == handle)
843     {
844       fprintf(stderr, "FATAL: CreateFile failed on TAP device: %s\n", device_path);
845       return handle;
846     }
847
848   /* get driver version info */
849   if (!check_tapw32_version(handle))
850     {
851       CloseHandle(handle);
852       return INVALID_HANDLE_VALUE;
853     }
854
855   /* TODO (opt?): get MTU-Size */
856
857   fprintf(stderr, "DEBUG: successfully opened TAP device\n");
858   return handle;
859 }
860
861
862 /**
863  * Brings a TAP device up and sets it to connected state.
864  *
865  * @param handle the handle to our TAP device
866  * @return True if the operation succeeded, else false
867  */
868 static BOOL
869 tun_up(HANDLE handle)
870 {
871   ULONG status = TRUE;
872   DWORD len;
873
874   if (!DeviceIoControl(handle, TAP_WIN_IOCTL_SET_MEDIA_STATUS,
875                        &status, sizeof(status),
876                        &status, sizeof(status), &len, NULL))
877     {
878       fprintf(stderr, "FATAL: TAP driver ignored request to UP interface (DeviceIoControl call)\n");
879       return FALSE;
880     }
881
882   /* Wait for the device to go UP, might take some time. */
883   Sleep(TAP32_POSTUP_WAITTIME * 1000);
884   fprintf(stderr, "DEBUG: successfully set TAP device to UP\n");
885
886   return TRUE;
887 }
888
889
890 /**
891  * Attempts to read off an input facility (tap or named pipe) in overlapped mode.
892  *
893  * 1.
894  * If the input facility is in IOSTATE_READY, it will issue a new read operation to the
895  * input handle. Then it goes into IOSTATE_QUEUED state.
896  * In case the read succeeded instantly the input facility enters 3.
897  *
898  * 2.
899  * If the input facility is in IOSTATE_QUEUED state, it will check if the queued read has finished already.
900  * If it has finished, go to state 3.
901  * If it has failed, set IOSTATE_FAILED
902  *
903  * 3.
904  * If the output facility is in state IOSTATE_READY, the read-buffer is copied to the output buffer.
905  *   The input facility enters state IOSTATE_READY
906  *   The output facility enters state IOSTATE_READY
907  * If the output facility is in state IOSTATE_QUEUED, the input facility enters IOSTATE_WAITING
908  *
909  * IOSTATE_WAITING is reset by the output facility, once it has completed.
910  *
911  * @param input_facility input named pipe or file to work with.
912  * @param output_facility output pipe or file to hand over data to.
913  * @return false if an event reset was impossible (OS error), else true
914  */
915 static BOOL
916 attempt_read_tap(struct io_facility * input_facility,
917                  struct io_facility * output_facility)
918 {
919   struct GNUNET_MessageHeader * hdr;
920   unsigned short size;
921
922   switch (input_facility->facility_state)
923     {
924     case IOSTATE_READY:
925     {
926       if (!ResetEvent(input_facility->overlapped.hEvent))
927         {
928           return FALSE;
929         }
930
931       input_facility->buffer_size = 0;
932
933       /* Check how the task is handled */
934       if (ReadFile(input_facility->handle,
935                    input_facility->buffer,
936                    sizeof(input_facility->buffer) - sizeof(struct GNUNET_MessageHeader),
937                    &input_facility->buffer_size,
938                    &input_facility->overlapped))
939         {  /* async event processed immediately*/
940           /* reset event manually*/
941           if (!SetEvent(input_facility->overlapped.hEvent))
942             return FALSE;
943
944           fprintf(stderr, "DEBUG: tap read succeeded immediately\n");
945
946           /* we successfully read something from the TAP and now need to
947            * send it our via STDOUT. Is that possible at the moment? */
948           if ((IOSTATE_READY == output_facility->facility_state ||
949                IOSTATE_WAITING == output_facility->facility_state)
950               && (0 < input_facility->buffer_size))
951             {   /* hand over this buffers content and apply message header for gnunet */
952               hdr = (struct GNUNET_MessageHeader *)output_facility->buffer;
953               size = input_facility->buffer_size + sizeof(struct GNUNET_MessageHeader);
954
955               GNUNET_memcpy(output_facility->buffer + sizeof(struct GNUNET_MessageHeader),
956                             input_facility->buffer,
957                             input_facility->buffer_size);
958
959               output_facility->buffer_size = size;
960               hdr->size = htons(size);
961               hdr->type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER);
962               output_facility->facility_state = IOSTATE_READY;
963             }
964           else if (0 < input_facility->buffer_size)
965             /* If we have have read our buffer, wait for our write-partner*/
966             input_facility->facility_state = IOSTATE_WAITING;
967         }
968       else   /* operation was either queued or failed*/
969         {
970           int err = GetLastError();
971           if (ERROR_IO_PENDING == err)
972             {   /* operation queued */
973               input_facility->facility_state = IOSTATE_QUEUED;
974             }
975           else
976             {   /* error occurred, let the rest of the elements finish */
977               input_facility->path_open = FALSE;
978               input_facility->facility_state = IOSTATE_FAILED;
979               if (IOSTATE_WAITING == output_facility->facility_state)
980                 output_facility->path_open = FALSE;
981
982               fprintf(stderr, "FATAL: Read from handle failed, allowing write to finish\n");
983             }
984         }
985     }
986       return TRUE;
987
988     // We are queued and should check if the read has finished
989     case IOSTATE_QUEUED:
990     {
991       // there was an operation going on already, check if that has completed now.
992
993       if (GetOverlappedResult(input_facility->handle,
994                               &input_facility->overlapped,
995                               &input_facility->buffer_size,
996                               FALSE))
997         {  /* successful return for a queued operation */
998           if (!ResetEvent(input_facility->overlapped.hEvent))
999             return FALSE;
1000
1001           fprintf(stderr, "DEBUG: tap read succeeded delayed\n");
1002
1003           /* we successfully read something from the TAP and now need to
1004            * send it our via STDOUT. Is that possible at the moment? */
1005           if ((IOSTATE_READY == output_facility->facility_state ||
1006                IOSTATE_WAITING == output_facility->facility_state)
1007               && 0 < input_facility->buffer_size)
1008             {   /* hand over this buffers content and apply message header for gnunet */
1009               hdr = (struct GNUNET_MessageHeader *)output_facility->buffer;
1010               size = input_facility->buffer_size + sizeof(struct GNUNET_MessageHeader);
1011
1012               GNUNET_memcpy(output_facility->buffer + sizeof(struct GNUNET_MessageHeader),
1013                             input_facility->buffer,
1014                             input_facility->buffer_size);
1015
1016               output_facility->buffer_size = size;
1017               hdr->size = htons(size);
1018               hdr->type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER);
1019               output_facility->facility_state = IOSTATE_READY;
1020               input_facility->facility_state = IOSTATE_READY;
1021             }
1022           else if (0 < input_facility->buffer_size)
1023             {   /* If we have have read our buffer, wait for our write-partner*/
1024               input_facility->facility_state = IOSTATE_WAITING;
1025               // TODO: shall we attempt to fill our buffer or should we wait for our write-partner to finish?
1026             }
1027         }
1028       else
1029         {   /* operation still pending/queued or failed? */
1030           int err = GetLastError();
1031           if ((ERROR_IO_INCOMPLETE != err) && (ERROR_IO_PENDING != err))
1032             {   /* error occurred, let the rest of the elements finish */
1033               input_facility->path_open = FALSE;
1034               input_facility->facility_state = IOSTATE_FAILED;
1035               if (IOSTATE_WAITING == output_facility->facility_state)
1036                 output_facility->path_open = FALSE;
1037               fprintf(stderr, "FATAL: Read from handle failed, allowing write to finish\n");
1038             }
1039         }
1040     }
1041       return TRUE;
1042
1043     case IOSTATE_RESUME:
1044       hdr = (struct GNUNET_MessageHeader *)output_facility->buffer;
1045       size = input_facility->buffer_size + sizeof(struct GNUNET_MessageHeader);
1046
1047       GNUNET_memcpy(output_facility->buffer + sizeof(struct GNUNET_MessageHeader),
1048                     input_facility->buffer,
1049                     input_facility->buffer_size);
1050
1051       output_facility->buffer_size = size;
1052       hdr->size = htons(size);
1053       hdr->type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER);
1054       output_facility->facility_state = IOSTATE_READY;
1055       input_facility->facility_state = IOSTATE_READY;
1056       return TRUE;
1057
1058     default:
1059       return TRUE;
1060     }
1061 }
1062
1063
1064 /**
1065  * Attempts to read off an input facility (tap or named pipe) in overlapped mode.
1066  *
1067  * 1.
1068  * If the input facility is in IOSTATE_READY, it will issue a new read operation to the
1069  * input handle. Then it goes into IOSTATE_QUEUED state.
1070  * In case the read succeeded instantly the input facility enters 3.
1071  *
1072  * 2.
1073  * If the input facility is in IOSTATE_QUEUED state, it will check if the queued read has finished already.
1074  * If it has finished, go to state 3.
1075  * If it has failed, set IOSTATE_FAILED
1076  *
1077  * 3.
1078  * If the facility is finished with ready
1079  *   The read-buffer is copied to the output buffer, except for the GNUNET_MessageHeader.
1080  *   The input facility enters state IOSTATE_READY
1081  *   The output facility enters state IOSTATE_READY
1082  * If the output facility is in state IOSTATE_QUEUED, the input facility enters IOSTATE_WAITING
1083  *
1084  * IOSTATE_WAITING is reset by the output facility, once it has completed.
1085  *
1086  * @param input_facility input named pipe or file to work with.
1087  * @param output_facility output pipe or file to hand over data to.
1088  * @return false if an event reset was impossible (OS error), else true
1089  */
1090 static BOOL
1091 attempt_read_stdin(struct io_facility * input_facility,
1092                    struct io_facility * output_facility)
1093 {
1094   struct GNUNET_MessageHeader * hdr;
1095
1096   switch (input_facility->facility_state)
1097     {
1098     case IOSTATE_READY:
1099     {
1100       input_facility->buffer_size = 0;
1101
1102 partial_read_iostate_ready:
1103       if (!ResetEvent(input_facility->overlapped.hEvent))
1104         return FALSE;
1105
1106       /* Check how the task is handled */
1107       if (ReadFile(input_facility->handle,
1108                    input_facility->buffer + input_facility->buffer_size,
1109                    sizeof(input_facility->buffer) - input_facility->buffer_size,
1110                    &input_facility->buffer_size_processed,
1111                    &input_facility->overlapped))
1112         {  /* async event processed immediately*/
1113           hdr = (struct GNUNET_MessageHeader *)input_facility->buffer;
1114
1115           /* reset event manually*/
1116           if (!SetEvent(input_facility->overlapped.hEvent))
1117             return FALSE;
1118
1119           fprintf(stderr, "DEBUG: stdin read succeeded immediately\n");
1120           input_facility->buffer_size += input_facility->buffer_size_processed;
1121
1122           if (ntohs(hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER ||
1123               ntohs(hdr->size) > sizeof(input_facility->buffer))
1124             {
1125               fprintf(stderr, "WARNING: Protocol violation, got GNUnet Message type %h, size %h\n", ntohs(hdr->type), ntohs(hdr->size));
1126               input_facility->facility_state = IOSTATE_READY;
1127               return TRUE;
1128             }
1129           /* we got the a part of a packet */
1130           if (ntohs(hdr->size) > input_facility->buffer_size)
1131             goto partial_read_iostate_ready;
1132
1133           /* have we read more than 0 bytes of payload? (sizeread > header)*/
1134           if (input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader) &&
1135               ((IOSTATE_READY == output_facility->facility_state) ||
1136                (IOSTATE_WAITING == output_facility->facility_state)))
1137             {  /* we successfully read something from the TAP and now need to
1138                 * send it our via STDOUT. Is that possible at the moment? */
1139               /* hand over this buffers content and strip gnunet message header */
1140               GNUNET_memcpy(output_facility->buffer,
1141                             input_facility->buffer + sizeof(struct GNUNET_MessageHeader),
1142                             input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader));
1143               output_facility->buffer_size = input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader);
1144               output_facility->facility_state = IOSTATE_READY;
1145               input_facility->facility_state = IOSTATE_READY;
1146             }
1147           else if (input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader))
1148             /* If we have have read our buffer, wait for our write-partner*/
1149             input_facility->facility_state = IOSTATE_WAITING;
1150           else   /* we read nothing */
1151             input_facility->facility_state = IOSTATE_READY;
1152         }
1153       else   /* operation was either queued or failed*/
1154         {
1155           int err = GetLastError();
1156           if (ERROR_IO_PENDING == err)   /* operation queued */
1157             input_facility->facility_state = IOSTATE_QUEUED;
1158           else
1159             {   /* error occurred, let the rest of the elements finish */
1160               input_facility->path_open = FALSE;
1161               input_facility->facility_state = IOSTATE_FAILED;
1162               if (IOSTATE_WAITING == output_facility->facility_state)
1163                 output_facility->path_open = FALSE;
1164
1165               fprintf(stderr, "FATAL: Read from handle failed, allowing write to finish\n");
1166             }
1167         }
1168     }
1169       return TRUE;
1170
1171     // We are queued and should check if the read has finished
1172     case IOSTATE_QUEUED:
1173     {
1174       // there was an operation going on already, check if that has completed now.
1175       if (GetOverlappedResult(input_facility->handle,
1176                               &input_facility->overlapped,
1177                               &input_facility->buffer_size_processed,
1178                               FALSE))
1179         {  /* successful return for a queued operation */
1180           hdr = (struct GNUNET_MessageHeader *)input_facility->buffer;
1181
1182           if (!ResetEvent(input_facility->overlapped.hEvent))
1183             return FALSE;
1184
1185           fprintf(stderr, "DEBUG: stdin read succeeded delayed\n");
1186           input_facility->buffer_size += input_facility->buffer_size_processed;
1187
1188           if ((ntohs(hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1189               (ntohs(hdr->size) > sizeof(input_facility->buffer)))
1190             {
1191               fprintf(stderr, "WARNING: Protocol violation, got GNUnet Message type %h, size %h\n", ntohs(hdr->type), ntohs(hdr->size));
1192               input_facility->facility_state = IOSTATE_READY;
1193               return TRUE;
1194             }
1195           /* we got the a part of a packet */
1196           if (ntohs(hdr->size) > input_facility->buffer_size)
1197             ;
1198           goto partial_read_iostate_ready;
1199
1200           /* we successfully read something from the TAP and now need to
1201            * send it our via STDOUT. Is that possible at the moment? */
1202           if ((IOSTATE_READY == output_facility->facility_state ||
1203                IOSTATE_WAITING == output_facility->facility_state)
1204               && input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader))
1205             {   /* hand over this buffers content and strip gnunet message header */
1206               GNUNET_memcpy(output_facility->buffer,
1207                             input_facility->buffer + sizeof(struct GNUNET_MessageHeader),
1208                             input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader));
1209               output_facility->buffer_size = input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader);
1210               output_facility->facility_state = IOSTATE_READY;
1211               input_facility->facility_state = IOSTATE_READY;
1212             }
1213           else if (input_facility->buffer_size > sizeof(struct GNUNET_MessageHeader))
1214             input_facility->facility_state = IOSTATE_WAITING;
1215           else
1216             input_facility->facility_state = IOSTATE_READY;
1217         }
1218       else
1219         {   /* operation still pending/queued or failed? */
1220           int err = GetLastError();
1221           if ((ERROR_IO_INCOMPLETE != err) && (ERROR_IO_PENDING != err))
1222             {   /* error occurred, let the rest of the elements finish */
1223               input_facility->path_open = FALSE;
1224               input_facility->facility_state = IOSTATE_FAILED;
1225               if (IOSTATE_WAITING == output_facility->facility_state)
1226                 output_facility->path_open = FALSE;
1227               fprintf(stderr, "FATAL: Read from handle failed, allowing write to finish\n");
1228             }
1229         }
1230     }
1231       return TRUE;
1232
1233     case IOSTATE_RESUME: /* Our buffer was filled already but our write facility was busy. */
1234       GNUNET_memcpy(output_facility->buffer,
1235                     input_facility->buffer + sizeof(struct GNUNET_MessageHeader),
1236                     input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader));
1237       output_facility->buffer_size = input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader);
1238       output_facility->facility_state = IOSTATE_READY;
1239       input_facility->facility_state = IOSTATE_READY;
1240       return TRUE;
1241
1242     default:
1243       return TRUE;
1244     }
1245 }
1246
1247
1248 /**
1249  * Attempts to write to an output facility (tap or named pipe) in overlapped mode.
1250  *
1251  * TODO: high level description
1252  *
1253  * @param output_facility output pipe or file to hand over data to.
1254  * @param input_facility input named pipe or file to work with.
1255  * @return false if an event reset was impossible (OS error), else true
1256  */
1257 static BOOL
1258 attempt_write(struct io_facility * output_facility,
1259               struct io_facility * input_facility)
1260 {
1261   switch (output_facility->facility_state)
1262     {
1263     case IOSTATE_READY:
1264       output_facility->buffer_size_written = 0;
1265
1266 continue_partial_write:
1267       if (!ResetEvent(output_facility->overlapped.hEvent))
1268         return FALSE;
1269
1270       /* Check how the task was handled */
1271       if (WriteFile(output_facility->handle,
1272                     output_facility->buffer + output_facility->buffer_size_written,
1273                     output_facility->buffer_size - output_facility->buffer_size_written,
1274                     &output_facility->buffer_size_processed,
1275                     &output_facility->overlapped))
1276         {/* async event processed immediately*/
1277           fprintf(stderr, "DEBUG: write succeeded immediately\n");
1278           output_facility->buffer_size_written += output_facility->buffer_size_processed;
1279
1280           /* reset event manually*/
1281           if (!SetEvent(output_facility->overlapped.hEvent))
1282             return FALSE;
1283
1284           /* partial write */
1285           if (output_facility->buffer_size_written < output_facility->buffer_size)
1286             goto continue_partial_write;
1287
1288           /* we are now waiting for our buffer to be filled*/
1289           output_facility->facility_state = IOSTATE_WAITING;
1290
1291           /* we successfully wrote something and now need to reset our reader */
1292           if (IOSTATE_WAITING == input_facility->facility_state)
1293             input_facility->facility_state = IOSTATE_RESUME;
1294           else if (IOSTATE_FAILED == input_facility->facility_state)
1295             output_facility->path_open = FALSE;
1296         }
1297       else /* operation was either queued or failed*/
1298         {
1299           int err = GetLastError();
1300           if (ERROR_IO_PENDING == err)
1301             { /* operation queued */
1302               output_facility->facility_state = IOSTATE_QUEUED;
1303             }
1304           else
1305             { /* error occurred, close this path */
1306               output_facility->path_open = FALSE;
1307               output_facility->facility_state = IOSTATE_FAILED;
1308               fprintf(stderr, "FATAL: Write to handle failed, exiting\n");
1309             }
1310         }
1311       return TRUE;
1312
1313     case IOSTATE_QUEUED:
1314       // there was an operation going on already, check if that has completed now.
1315
1316       if (GetOverlappedResult(output_facility->handle,
1317                               &output_facility->overlapped,
1318                               &output_facility->buffer_size_processed,
1319                               FALSE))
1320         {/* successful return for a queued operation */
1321           if (!ResetEvent(output_facility->overlapped.hEvent))
1322             return FALSE;
1323
1324           fprintf(stderr, "DEBUG: write succeeded delayed\n");
1325           output_facility->buffer_size_written += output_facility->buffer_size_processed;
1326
1327           /* partial write */
1328           if (output_facility->buffer_size_written < output_facility->buffer_size)
1329             goto continue_partial_write;
1330
1331           /* we are now waiting for our buffer to be filled*/
1332           output_facility->facility_state = IOSTATE_WAITING;
1333
1334           /* we successfully wrote something and now need to reset our reader */
1335           if (IOSTATE_WAITING == input_facility->facility_state)
1336             input_facility->facility_state = IOSTATE_RESUME;
1337           else if (IOSTATE_FAILED == input_facility->facility_state)
1338             output_facility->path_open = FALSE;
1339         }
1340       else
1341         { /* operation still pending/queued or failed? */
1342           int err = GetLastError();
1343           if ((ERROR_IO_INCOMPLETE != err) && (ERROR_IO_PENDING != err))
1344             { /* error occurred, close this path */
1345               output_facility->path_open = FALSE;
1346               output_facility->facility_state = IOSTATE_FAILED;
1347               fprintf(stderr, "FATAL: Write to handle failed, exiting\n");
1348             }
1349         }
1350
1351     default:
1352       return TRUE;
1353     }
1354 }
1355
1356
1357 /**
1358  * Initialize a overlapped structure
1359  *
1360  * @param elem the element to initilize
1361  * @param initial_state the initial state for this instance
1362  * @param signaled if the hEvent created should default to signaled or not
1363  * @return true on success, else false
1364  */
1365 static BOOL
1366 initialize_io_facility(struct io_facility * elem,
1367                        int initial_state,
1368                        BOOL signaled)
1369 {
1370   elem->path_open = TRUE;
1371   elem->handle = INVALID_HANDLE_VALUE;
1372   elem->facility_state = initial_state;
1373   elem->buffer_size = 0;
1374   elem->overlapped.hEvent = CreateEvent(NULL, TRUE, signaled, NULL);
1375   if (NULL == elem->overlapped.hEvent)
1376     return FALSE;
1377
1378   return TRUE;
1379 }
1380
1381
1382 /**
1383  * Start forwarding to and from the tunnel.
1384  *
1385  * @param tap_handle device handle for interacting with the Virtual interface
1386  */
1387 static void
1388 run(HANDLE tap_handle)
1389 {
1390   /* IO-Facility for reading from our virtual interface */
1391   struct io_facility tap_read;
1392   /* IO-Facility for writing to our virtual interface */
1393   struct io_facility tap_write;
1394   /* IO-Facility for reading from stdin */
1395   struct io_facility std_in;
1396   /* IO-Facility for writing to stdout */
1397   struct io_facility std_out;
1398
1399   HANDLE parent_std_in_handle = GetStdHandle(STD_INPUT_HANDLE);
1400   HANDLE parent_std_out_handle = GetStdHandle(STD_OUTPUT_HANDLE);
1401
1402   /* tun up: */
1403   /* we do this HERE and not beforehand (in init_tun()), in contrast to openvpn
1404    * to remove the need to flush the arp cache, handle DHCP and wrong IPs.
1405    *
1406    * DHCP and such are all features we will never use in gnunet afaik.
1407    * But for openvpn those are essential.
1408    */
1409   if ((privilege_testing) || (!tun_up(tap_handle)))
1410     goto teardown_final;
1411
1412   /* Initialize our overlapped IO structures*/
1413   if (!(initialize_io_facility(&tap_read, IOSTATE_READY, FALSE)
1414         && initialize_io_facility(&tap_write, IOSTATE_WAITING, TRUE)
1415         && initialize_io_facility(&std_in, IOSTATE_READY, FALSE)
1416         && initialize_io_facility(&std_out, IOSTATE_WAITING, TRUE)))
1417     goto teardown_final;
1418
1419   /* Handles for STDIN and STDOUT */
1420   tap_read.handle = tap_handle;
1421   tap_write.handle = tap_handle;
1422
1423 #ifdef DEBUG_TO_CONSOLE
1424   /* Debug output to console STDIN/STDOUT*/
1425   std_in.handle = parent_std_in_handle;
1426   std_out.handle = parent_std_out_handle;
1427 #else
1428   fprintf(stderr, "DEBUG: reopening stdin/out for overlapped IO\n");
1429   /*
1430    * Find out the types of our handles.
1431    * This part is a problem, because in windows we need to handle files,
1432    * pipes and the console differently.
1433    */
1434   if ((FILE_TYPE_PIPE != GetFileType(parent_std_in_handle)) ||
1435       (FILE_TYPE_PIPE != GetFileType(parent_std_out_handle)))
1436     {
1437       fprintf(stderr, "ERROR: stdin/stdout must be named pipes\n");
1438       goto teardown;
1439     }
1440
1441   std_in.handle = ReOpenFile(parent_std_in_handle,
1442                              GENERIC_READ,
1443                              FILE_SHARE_WRITE | FILE_SHARE_READ,
1444                              FILE_FLAG_OVERLAPPED);
1445
1446   if (INVALID_HANDLE_VALUE == std_in.handle)
1447     {
1448       fprintf(stderr, "FATAL: Could not reopen stdin for in overlapped mode, has to be a named pipe\n");
1449       goto teardown;
1450     }
1451
1452   std_out.handle = ReOpenFile(parent_std_out_handle,
1453                               GENERIC_WRITE,
1454                               FILE_SHARE_READ,
1455                               FILE_FLAG_OVERLAPPED);
1456
1457   if (INVALID_HANDLE_VALUE == std_out.handle)
1458     {
1459       fprintf(stderr, "FATAL: Could not reopen stdout for in overlapped mode, has to be a named pipe\n");
1460       goto teardown;
1461     }
1462 #endif
1463
1464   fprintf(stderr, "DEBUG: mainloop has begun\n");
1465
1466   while (std_out.path_open || tap_write.path_open)
1467     {
1468       /* perform READ from stdin if possible */
1469       if (std_in.path_open && (!attempt_read_stdin(&std_in, &tap_write)))
1470         break;
1471
1472       /* perform READ from tap if possible */
1473       if (tap_read.path_open && (!attempt_read_tap(&tap_read, &std_out)))
1474         break;
1475
1476       /* perform WRITE to tap if possible */
1477       if (tap_write.path_open && (!attempt_write(&tap_write, &std_in)))
1478         break;
1479
1480       /* perform WRITE to STDOUT if possible */
1481       if (std_out.path_open && (!attempt_write(&std_out, &tap_read)))
1482         break;
1483     }
1484
1485   fprintf(stderr, "DEBUG: teardown initiated\n");
1486 teardown:
1487   CancelIo(tap_handle);
1488   CancelIo(std_in.handle);
1489   CancelIo(std_out.handle);
1490 teardown_final:
1491   CloseHandle(tap_handle);
1492 }
1493
1494
1495 /**
1496  * Open VPN tunnel interface.
1497  *
1498  * @param argc must be 6
1499  * @param argv 0: binary name (gnunet-helper-vpn)
1500  *             [1: dryrun/testrun (does not execute mainloop)]
1501  *             2: tunnel interface prefix (gnunet-vpn)
1502  *             3: IPv6 address (::1), "-" to disable
1503  *             4: IPv6 netmask length in bits (64), ignored if #2 is "-"
1504  *             5: IPv4 address (1.2.3.4), "-" to disable
1505  *             6: IPv4 netmask (255.255.0.0), ignored if #4 is "-"
1506  */
1507 int
1508 main(int argc, char **argv)
1509 {
1510   char hwid[LINE_LEN];
1511   HANDLE handle;
1512   int global_ret = 0;
1513   BOOL have_ip4 = FALSE;
1514   BOOL have_ip6 = FALSE;
1515
1516   if (argc > 1 && 0 == strcmp(argv[1], "-d"))
1517     {
1518       privilege_testing = TRUE;
1519       fprintf(stderr,
1520               "%s",
1521               "DEBUG: Running binary in privilege testing mode.");
1522       argv++;
1523       argc--;
1524     }
1525
1526   if (6 != argc)
1527     {
1528       fprintf(stderr,
1529               "%s",
1530               "FATAL: must supply 5 arguments\nUsage:\ngnunet-helper-vpn [-d] <if name prefix> <address6 or \"-\"> <netbits6> <address4 or \"-\"> <netmask4>\n");
1531       return 1;
1532     }
1533
1534   GNUNET_strlcpy(hwid, argv[1], sizeof(hwid));
1535
1536   /*
1537    * We use our PID for finding/resolving the control-panel name of our virtual
1538    * device. PIDs are (of course) unique at runtime, thus we can safely use it
1539    * as additional hardware-id for our device.
1540    */
1541   snprintf(secondary_hwid, LINE_LEN / 2, "%s-%d",
1542            hwid,
1543            _getpid());
1544
1545   if (INVALID_HANDLE_VALUE == (handle = init_tun()))
1546     {
1547       fprintf(stderr, "FATAL: could not initialize virtual-interface %s with IPv6 %s/%s and IPv4 %s/%s\n",
1548               hwid,
1549               argv[2],
1550               argv[3],
1551               argv[4],
1552               argv[5]);
1553       global_ret = -1;
1554       goto cleanup;
1555     }
1556
1557   fprintf(stderr, "DEBUG: Setting IPs, if needed\n");
1558   if (0 != strcmp(argv[2], "-"))
1559     {
1560       const char *address = argv[2];
1561       long prefix_len = atol(argv[3]);
1562
1563       if ((prefix_len < 1) || (prefix_len > 127))
1564         {
1565           fprintf(stderr, "FATAL: ipv6 prefix_len out of range\n");
1566           global_ret = -1;
1567           goto cleanup;
1568         }
1569
1570       fprintf(stderr, "DEBUG: Setting IP6 address: %s/%d\n", address, prefix_len);
1571       if (0 != (global_ret = set_address6(address, prefix_len)))
1572         goto cleanup;
1573
1574       have_ip6 = TRUE;
1575     }
1576
1577   if (0 != strcmp(argv[4], "-"))
1578     {
1579       const char *address = argv[4];
1580       const char *mask = argv[5];
1581
1582       fprintf(stderr, "DEBUG: Setting IP4 address: %s/%s\n", address, mask);
1583       if (0 != (global_ret = set_address4(address, mask)))
1584         goto cleanup;
1585
1586       have_ip4 = TRUE;
1587     }
1588
1589   run(handle);
1590 cleanup:
1591
1592   if (have_ip4)
1593     {
1594       const char *address = argv[4];
1595       fprintf(stderr, "DEBUG: Removing IP4 address\n");
1596       remove_address4(address);
1597     }
1598   if (have_ip6)
1599     {
1600       const char *address = argv[2];
1601       fprintf(stderr, "DEBUG: Removing IP6 address\n");
1602       remove_address6(address);
1603     }
1604
1605   fprintf(stderr, "DEBUG: removing interface\n");
1606   remove_interface();
1607   fprintf(stderr, "DEBUG: graceful exit completed\n");
1608
1609   return global_ret;
1610 }