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