There are now four states for the OI facilities:
[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 /**
22  * @file vpn/gnunet-helper-vpn-windows.c
23  * @brief the helper for the VPN service in win32 builds. 
24  * Opens a virtual network-interface, sends data received on the if to stdout, 
25  * sends data received on stdin to the interface
26  * @author Christian M. Fuchs
27  *
28  * The following list of people have reviewed this code and considered
29  * it safe since the last modification (if you reviewed it, please
30  * have your name added to the list):
31  *
32  */
33
34 #include <stdio.h>
35 #include <windows.h>
36 #include <setupapi.h>
37 #include <ddk/cfgmgr32.h>
38 #include "platform.h"
39 #include "tap-windows.h"
40 #include <Winsock2.h>
41
42 /**
43  * Need 'struct GNUNET_MessageHeader'.
44  */
45 #include "gnunet_common.h"
46
47 /**
48  * Need VPN message types.
49  */
50 #include "gnunet_protocols.h"
51
52 /**
53  * Should we print (interesting|debug) messages that can happen during
54  * normal operation?
55  */
56 #define DEBUG GNUNET_NO
57
58 /**
59  * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE)
60  */
61 #define MAX_SIZE 65536
62
63 /**
64  * Name or Path+Name of our driver in Unicode.
65  * The .sys and .cat files HAVE to be in the same location as this file!
66  */
67 #define INF_FILE "tapw32.inf"
68
69 /**
70  * Hardware ID used in the inf-file. 
71  * This might change over time, as openvpn advances their driver
72  */
73 #define HARDWARE_ID "TAP0901"
74
75 /**
76  * Component ID if our driver
77  */
78 #define TAP_WIN_COMPONENT_ID "tap0901"
79
80 /**
81  * Minimum major-id of the driver version we can work with
82  */
83 #define TAP_WIN_MIN_MAJOR 9
84
85 /**
86  * Minimum minor-id of the driver version we can work with. 
87  * v <= 7 has buggy IPv6.
88  * v == 8 is broken for small IPv4 Packets
89  */
90 #define TAP_WIN_MIN_MINOR 9
91
92 /**
93  * Time in seconds to wait for our virtual device to go up after telling it to do so.
94  * 
95  * openvpn doesn't specify a value, 4 seems sane for testing, even for openwrt
96  * (in fact, 4 was chosen by a fair dice roll...)
97  */
98 #define TAP32_POSTUP_WAITTIME 4
99
100 /**
101  * Location of the network interface list resides in registry.
102  * TODO: is this fixed on all version of windows? Checked with XP and 7
103  */
104 #define INTERFACE_REGISTRY_LOCATION "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
105
106 /**
107  * Our local process' PID. Used for creating a sufficiently unique additional 
108  * hardware ID for our device.
109  */
110 static char secondary_hwid[LINE_LEN / 2];
111
112 /**
113  * Device's visible Name, used to identify a network device in netsh.
114  * eg: "Local Area Connection 9"
115  */
116 static char device_visible_name[256];
117
118 /** 
119  * This is our own local instance of a virtual network interface
120  * It is (somewhat) equivalent to using tun/tap in unixoid systems
121  * 
122  * Upon initialization, we create such an device node.
123  * Upon termination, we remove it again.
124  * 
125  * If we crash this device might stay around.
126  */
127 static HDEVINFO DeviceInfo = INVALID_HANDLE_VALUE;
128
129 /**
130  * Registry Key we hand over to windows to spawn a new virtual interface
131  */
132 static SP_DEVINFO_DATA DeviceNode;
133
134 /**
135  * GUID of our virtual device in the form of 
136  * {12345678-1234-1234-1234-123456789abc} - in hex
137  */
138 static char device_guid[256];
139
140 /* Overlapped IO Begins here (warning: nasty!) */
141
142 /** 
143  * A overlapped-IO Object + read/writebuffer + buffer-size for windows asynchronous IO handling
144  */
145 struct overlapped_facility
146 {
147   int iostate;
148   BOOL status; // BOOL is winbool, NOT boolean!
149   BOOL path_open;
150   DWORD flags;
151
152   OVERLAPPED overlapped;
153
154   DWORD buffer_size;
155   unsigned char buffer[MAX_SIZE];
156 };
157
158 /** 
159  * Operlapped IO states for facility objects
160  */
161 #define IOSTATE_FAILED          -1 /* overlapped I/O has failed, stop processing */
162 #define IOSTATE_READY            0 /* overlapped I/O is ready for work */
163 #define IOSTATE_QUEUED           1 /* overlapped I/O has been queued */
164 #define IOSTATE_WAITING          3 /* overlapped I/O has finished, but is waiting for it's write-partner */
165
166 #if WINVER < 0x0600
167
168 /**
169  * inet_pton() wrapper for WSAStringToAddress()
170  *
171  * this is needed as long as we support WinXP, because only Vista+ support 
172  * inet_pton at all, and mingw does not yet offer inet_pton/ntop at all
173  * 
174  * @param af - IN - the aftype this address is supposed to be (v4/v6) 
175  * @param src - IN - the presentation form of the address
176  * @param dst - OUT - the numerical form of the address
177  * @return 0 on success, 1 on failure
178  */
179 int
180 inet_pton (int af, const char *src, void *dst)
181 {
182   struct sockaddr_storage addr;
183   int size = sizeof (addr);
184   char local_copy[INET6_ADDRSTRLEN + 1];
185
186   ZeroMemory (&addr, sizeof (addr));
187   /* stupid non-const API */
188   strncpy (local_copy, src, INET6_ADDRSTRLEN + 1);
189   local_copy[INET6_ADDRSTRLEN] = 0;
190
191   if (WSAStringToAddressA (local_copy, af, NULL, (struct sockaddr *) &addr, &size) == 0)
192     {
193       switch (af)
194         {
195         case AF_INET:
196           *(struct in_addr *) dst = ((struct sockaddr_in *) &addr)->sin_addr;
197           return 1;
198         case AF_INET6:
199           *(struct in6_addr *) dst = ((struct sockaddr_in6 *) &addr)->sin6_addr;
200           return 1;
201         }
202     }
203   return 0;
204 }
205 #endif
206
207 /**
208  * Wrapper for executing a shellcommand in windows.
209  * 
210  * @param command - the command + parameters to execute
211  * @return * exitcode of the program executed, 
212  *         * EINVAL (cmd/file not found)
213  *         * EPIPE (could not read STDOUT)
214  */
215 static int
216 execute_shellcommand (char * command)
217 {
218   FILE *pipe;
219
220   if (NULL == command ||
221       NULL == (pipe = _popen (command, "rt")))
222     return EINVAL;
223
224 #ifdef TESTING
225   {
226     char output[LINE_LEN];
227
228     printf ("executed command: %s", command);
229     while (NULL != fgets (output, sizeof (output), pipe))
230       printf (output);
231   }
232 #endif
233
234   if (!feof (pipe))
235     return EPIPE;
236
237   return _pclose (pipe);
238 }
239
240 /**
241  * @brief Sets the IPv6-Address given in address on the interface dev
242  *
243  * @param address the IPv6-Address
244  * @param prefix_len the length of the network-prefix
245  */
246 static void
247 set_address6 (const char *address, unsigned long prefix_len)
248 {
249   int ret = EINVAL;
250   char command[LINE_LEN];
251   struct sockaddr_in6 sa6;
252
253   /*
254    * parse the new address
255    */
256   memset (&sa6, 0, sizeof (struct sockaddr_in6));
257   sa6.sin6_family = AF_INET6;
258   if (1 != inet_pton (AF_INET6, address, &sa6.sin6_addr.s6_addr))
259     {
260       fprintf (stderr, "Failed to parse address `%s': %s\n", address,
261                strerror (errno));
262       exit (1);
263     }
264
265   /*
266    * prepare the command
267    */
268   snprintf (command, LINE_LEN,
269             "netsh interface ipv6 add address \"%s\" %s/%d",
270             device_visible_name, address, prefix_len);
271   /*
272    * Set the address
273    */
274   ret = execute_shellcommand (command);
275
276   /* Did it work?*/
277   if (0 != ret)
278     {
279       fprintf (stderr, "Setting IPv6 address failed: %s\n", strerror (ret));
280       exit (1); // FIXME: return error code, shut down interface / unload driver
281     }
282 }
283
284 /**
285  * @brief Sets the IPv4-Address given in address on the interface dev
286  *
287  * @param dev the interface to configure
288  * @param address the IPv4-Address
289  * @param mask the netmask
290  */
291 static void
292 set_address4 (const char *address, const char *mask)
293 {
294   int ret = EINVAL;
295   char command[LINE_LEN];
296
297   struct sockaddr_in addr;
298   addr.sin_family = AF_INET;
299
300   /*
301    * Parse the address
302    */
303   if (1 != inet_pton (AF_INET, address, &addr.sin_addr.s_addr))
304     {
305       fprintf (stderr, "Failed to parse address `%s': %s\n", address,
306                strerror (errno));
307       exit (1);
308     }
309
310   /*
311    * prepare the command
312    */
313   snprintf (command, LINE_LEN,
314             "netsh interface ipv4 add address \"%s\" %s %s",
315             device_visible_name, address, mask);
316   /*
317    * Set the address
318    */
319   ret = execute_shellcommand (command);
320
321   /* Did it work?*/
322   if (0 != ret)
323     {
324       fprintf (stderr, "Setting IPv4 address failed: %s\n", strerror (ret));
325       exit (1); // FIXME: return error code, shut down interface / unload driver
326     }
327 }
328
329 /**
330  * Setup a new virtual interface to use for tunneling. 
331  * 
332  * @return: TRUE if setup was successful, else FALSE
333  */
334 static boolean
335 setup_interface ()
336 {
337   /*
338    * where to find our inf-file. (+ the "full" path, after windows found")
339    * 
340    * We do not directly input all the props here, because openvpn will update
341    * these details over time.
342    */
343   char inf_file_path[MAX_PATH];
344   char hwidlist[LINE_LEN + 4];
345   char class_name[128];
346   GUID class_guid;
347   int str_lenth = 0;
348
349   /** 
350    * Set the device's hardware ID and add it to a list.
351    * This information will later on identify this device in registry. 
352    * 
353    * TODO: Currently we just use TAP0901 as HWID, 
354    * but we might want to add additional information
355    */
356   strncpy (hwidlist, HARDWARE_ID, LINE_LEN);
357   /**
358    * this is kind of over-complicated, but allows keeps things independent of 
359    * how the openvpn-hwid is actually stored. 
360    * 
361    * A HWID list is double-\0 terminated and \0 separated
362    */
363   str_lenth = strlen (hwidlist) + 1;
364   strncpy (&hwidlist[str_lenth], secondary_hwid, LINE_LEN - str_lenth);
365
366   /** 
367    * Locate the inf-file, we need to store it somewhere where the system can
368    * find it. A good choice would be CWD/PDW or %WINDIR$\system32\
369    * 
370    * TODO: How about win64 in the future? 
371    *       We need to use a different driver for amd64/i386 !
372    */
373   GetFullPathNameA (INF_FILE, MAX_PATH, inf_file_path, NULL);
374
375   /** 
376    * Bootstrap our device info using the drivers inf-file
377    */
378   if (!SetupDiGetINFClassA (inf_file_path,
379                             &class_guid,
380                             class_name, sizeof (class_name) / sizeof (char),
381                             NULL))
382     return FALSE;
383
384   /** 
385    * Collect all the other needed information... 
386    * let the system fill our this form 
387    */
388   DeviceInfo = SetupDiCreateDeviceInfoList (&class_guid, NULL);
389   if (DeviceInfo == INVALID_HANDLE_VALUE)
390     return FALSE;
391
392   DeviceNode.cbSize = sizeof (SP_DEVINFO_DATA);
393   if (!SetupDiCreateDeviceInfoA (DeviceInfo,
394                                  class_name,
395                                  &class_guid,
396                                  NULL,
397                                  NULL,
398                                  DICD_GENERATE_ID,
399                                  &DeviceNode))
400     return FALSE;
401
402   /* Deploy all the information collected into the registry */
403   if (!SetupDiSetDeviceRegistryPropertyA (DeviceInfo,
404                                           &DeviceNode,
405                                           SPDRP_HARDWAREID,
406                                           (LPBYTE) hwidlist,
407                                           (strlen (hwidlist) + 2) * sizeof (char)))
408     return FALSE;
409
410   /* Install our new class(=device) into the system */
411   if (!SetupDiCallClassInstaller (DIF_REGISTERDEVICE,
412                                   DeviceInfo,
413                                   &DeviceNode))
414     return FALSE;
415
416   return TRUE;
417 }
418
419 /**
420  * Remove our new virtual interface to use for tunneling. 
421  * This function must be called AFTER setup_interface!
422  * 
423  * @return: TRUE if destruction was successful, else FALSE
424  */
425 static boolean
426 remove_interface ()
427 {
428   SP_REMOVEDEVICE_PARAMS remove;
429
430   if (INVALID_HANDLE_VALUE == DeviceInfo)
431     return FALSE;
432
433   remove.ClassInstallHeader.cbSize = sizeof (SP_CLASSINSTALL_HEADER);
434   remove.HwProfile = 0;
435   remove.Scope = DI_REMOVEDEVICE_GLOBAL;
436   remove.ClassInstallHeader.InstallFunction = DIF_REMOVE;
437   /*
438    * 1. Prepare our existing device information set, and place the 
439    *    uninstall related information into the structure
440    */
441   if (!SetupDiSetClassInstallParamsA (DeviceInfo,
442                                       (PSP_DEVINFO_DATA) & DeviceNode,
443                                       &remove.ClassInstallHeader,
444                                       sizeof (remove)))
445     return FALSE;
446   /*
447    * 2. Uninstall the virtual interface using the class installer
448    */
449   if (!SetupDiCallClassInstaller (DIF_REMOVE,
450                                   DeviceInfo,
451                                   (PSP_DEVINFO_DATA) & DeviceNode))
452     return FALSE;
453
454   SetupDiDestroyDeviceInfoList (DeviceInfo);
455
456   return TRUE;
457 }
458
459 /**
460  * Do all the lookup necessary to retrieve the inteface's actual name
461  * off the registry. 
462  * 
463  * @return: TRUE if we were able to lookup the interface's name, else FALSE
464  */
465 static boolean
466 resolve_interface_name ()
467 {
468
469   SP_DEVINFO_LIST_DETAIL_DATA device_details;
470   char pnp_instance_id [MAX_DEVICE_ID_LEN];
471   HKEY adapter_key_handle;
472   LONG status;
473   DWORD len;
474   int i = 0;
475   boolean retval = FALSE;
476   char adapter[] = INTERFACE_REGISTRY_LOCATION;
477
478   /* We can obtain the PNP instance ID from our setupapi handle */
479   device_details.cbSize = sizeof (device_details);
480   if (CR_SUCCESS != CM_Get_Device_ID_ExA (DeviceNode.DevInst,
481                                           (PCHAR) pnp_instance_id,
482                                           MAX_DEVICE_ID_LEN,
483                                           0, //must be 0
484                                           NULL)) //hMachine, we are local
485     return FALSE;
486
487   /* Now we can use this ID to locate the correct networks interface in registry */
488   if (ERROR_SUCCESS != RegOpenKeyExA (
489                                       HKEY_LOCAL_MACHINE,
490                                       adapter,
491                                       0,
492                                       KEY_READ,
493                                       &adapter_key_handle))
494     return FALSE;
495
496   /* Of course there is a multitude of entries here, with arbitrary names, 
497    * thus we need to iterate through there.
498    */
499   while (!retval)
500     {
501       char instance_key[256];
502       char query_key [256];
503       HKEY instance_key_handle;
504       char pnpinstanceid_name[] = "PnpInstanceID";
505       char pnpinstanceid_value[256];
506       char adaptername_name[] = "Name";
507       DWORD data_type;
508
509       len = sizeof (adapter_key_handle);
510       /* optain a subkey of {4D36E972-E325-11CE-BFC1-08002BE10318} */
511       status = RegEnumKeyExA (
512                               adapter_key_handle,
513                               i,
514                               instance_key,
515                               &len,
516                               NULL,
517                               NULL,
518                               NULL,
519                               NULL);
520
521       /* this may fail due to one of two reasons: 
522        * we are at the end of the list*/
523       if (ERROR_NO_MORE_ITEMS == status)
524         break;
525       // * we found a broken registry key, continue with the next key.
526       if (ERROR_SUCCESS != status)
527         goto cleanup;
528
529       /* prepare our new query string: */
530       snprintf (query_key, 256, "%s\\%s\\Connection",
531                 INTERFACE_REGISTRY_LOCATION,
532                 instance_key);
533
534       /* look inside instance_key\\Connection */
535       status = RegOpenKeyExA (
536                               HKEY_LOCAL_MACHINE,
537                               query_key,
538                               0,
539                               KEY_READ,
540                               &instance_key_handle);
541
542       if (status != ERROR_SUCCESS)
543         continue;
544
545       /* now, read our PnpInstanceID */
546       len = sizeof (pnpinstanceid_value);
547       status = RegQueryValueExA (instance_key_handle,
548                                  pnpinstanceid_name,
549                                  NULL, //reserved, always NULL according to MSDN
550                                  &data_type,
551                                  (LPBYTE) pnpinstanceid_value,
552                                  &len);
553
554       if (status != ERROR_SUCCESS || data_type != REG_SZ)
555         goto cleanup;
556
557       /* compare the value we got to our devices PNPInstanceID*/
558       if (0 != strncmp (pnpinstanceid_value, pnp_instance_id,
559                         sizeof (pnpinstanceid_value) / sizeof (char)))
560         goto cleanup;
561
562       len = sizeof (device_visible_name);
563       status = RegQueryValueExA (
564                                  instance_key_handle,
565                                  adaptername_name,
566                                  NULL, //reserved, always NULL according to MSDN
567                                  &data_type,
568                                  (LPBYTE) device_visible_name,
569                                  &len);
570
571       if (status != ERROR_SUCCESS || data_type != REG_SZ)
572         goto cleanup;
573
574       /* 
575        * we have successfully found OUR instance, 
576        * save the device GUID before exiting
577        */
578
579       strncpy (device_guid, instance_key, 256);
580       retval = TRUE;
581
582 cleanup:
583       RegCloseKey (instance_key_handle);
584
585       ++i;
586     }
587
588   RegCloseKey (adapter_key_handle);
589
590   return retval;
591 }
592
593 static boolean
594 check_tapw32_version (HANDLE handle)
595 {
596   {
597     ULONG version[3];
598     DWORD len;
599     memset (&(version), 0, sizeof (version));
600
601
602     if (DeviceIoControl (handle, TAP_WIN_IOCTL_GET_VERSION,
603                          &version, sizeof (version),
604                          &version, sizeof (version), &len, NULL))
605       {
606 #ifdef TESTING
607         fprintf (stderr, "TAP-Windows Driver Version %d.%d %s",
608                  (int) version[0],
609                  (int) version[1],
610                  (version[2] ? "(DEBUG)" : ""));
611 #endif
612       }
613
614     if (version[0] != TAP_WIN_MIN_MAJOR || version[1] < TAP_WIN_MIN_MINOR)
615       {
616         fprintf (stderr, "ERROR:  This version of gnunet requires a TAP-Windows driver that is at least version %d.%d!\n",
617                  TAP_WIN_MIN_MAJOR,
618                  TAP_WIN_MIN_MINOR);
619         return FALSE;
620       }
621     return TRUE;
622   }
623 }
624
625 /**
626  * Creates a tun-interface called dev;
627  *
628  * @return the fd to the tun or -1 on error
629  */
630 static HANDLE
631 init_tun ()
632 {
633   char device_path[256];
634   HANDLE handle;
635
636   if (!setup_interface ())
637     {
638       errno = ENODEV;
639       return INVALID_HANDLE_VALUE;
640     }
641
642   if (!resolve_interface_name ())
643     {
644       errno = ENODEV;
645       return INVALID_HANDLE_VALUE;
646     }
647
648   /* Open Windows TAP-Windows adapter */
649   snprintf (device_path, sizeof (device_path), "%s%s%s",
650             USERMODEDEVICEDIR,
651             device_guid,
652             TAP_WIN_SUFFIX);
653
654   handle = CreateFile (
655                        device_path,
656                        GENERIC_READ | GENERIC_WRITE,
657                        0, /* was: FILE_SHARE_READ */
658                        0,
659                        OPEN_EXISTING,
660                        FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
661                        0
662                        );
663
664   if (handle == INVALID_HANDLE_VALUE)
665     {
666       fprintf (stderr, "CreateFile failed on TAP device: %s\n", device_path);
667       return handle;
668     }
669
670   /* get driver version info */
671   if (!check_tapw32_version (handle))
672     {
673       CloseHandle (handle);
674       return INVALID_HANDLE_VALUE;
675     }
676
677   /* TODO (opt?): get MTU-Size */
678
679   return handle;
680 }
681
682 static boolean
683 tun_up (HANDLE handle)
684 {
685   ULONG status = TRUE;
686   DWORD len;
687   if (DeviceIoControl (handle, TAP_WIN_IOCTL_SET_MEDIA_STATUS,
688                        &status, sizeof (status),
689                        &status, sizeof (status), &len, NULL))
690     {
691       fprintf (stderr, "The TAP-Windows driver ignored our request to set the interface UP (TAP_WIN_IOCTL_SET_MEDIA_STATUS DeviceIoControl call)!\n");
692       return FALSE;
693     }
694
695   /* Wait for the device to go UP, might take some time. */
696   Sleep ((TAP32_POSTUP_WAITTIME)*1000);
697
698   return TRUE;
699
700 }
701
702 static boolean
703 attempt_std_in (  struct overlapped_facility * std_in,
704                   struct overlapped_facility * tap_write)
705 {
706   return TRUE;
707 }
708
709 static boolean
710 attempt_tap_read (HANDLE tap_handle,
711                   struct overlapped_facility * tap_read,
712                   struct overlapped_facility * std_out)
713 {
714
715   if (IOSTATE_READY == tap_read->iostate)
716     {
717       if (!ResetEvent (tap_read->overlapped.hEvent))
718         {
719           return FALSE;
720         }
721       tap_read->status = ReadFile (tap_handle,
722                                   &tap_read->buffer[MAX_SIZE],
723                                   MAX_SIZE,
724                                   &tap_read->buffer_size,
725                                   &tap_read->overlapped);
726
727       /* Check how the task is handled */
728       if (tap_read->status)
729         {/* async event processed immediately*/
730
731           /* reset event manually*/
732           if (!SetEvent (tap_read->overlapped.hEvent))
733             return FALSE;
734
735           /* we successfully read something from the TAP and now need to
736            * send it our via STDOUT. Is that possible at the moment? */
737           if (IOSTATE_READY == std_out->iostate && 0 < tap_read->buffer_size)
738             { /* hand over this buffers content */
739               memcpy (std_out->buffer,
740                       tap_read->buffer,
741                       MAX_SIZE);
742               std_out->buffer_size = tap_read->buffer_size;
743               std_out->iostate = IOSTATE_READY;
744             }
745           else if (0 < tap_read->buffer_size)
746             { /* If we have have read our buffer, wait for our write-partner*/
747               tap_read->iostate = IOSTATE_WAITING;
748               // TODO: shall we attempt to fill our bufferm or should we wait for our write-partner to finish?
749             }
750         }
751       else /* operation was either queued or failed*/
752         {
753           int err = GetLastError ();
754           if (ERROR_IO_PENDING == err)
755             { /* operation queued */
756               tap_read->iostate = IOSTATE_QUEUED;
757             }
758           else
759             { /* error occurred, let the rest of the elements finish */
760               tap_read->path_open = FALSE;
761               tap_read->iostate = IOSTATE_FAILED;
762             }
763         }
764     }
765     // We are queued and should check if the read has finished
766   else if (IOSTATE_QUEUED == tap_read->iostate )
767     {
768       // there was an operation going on already, check if that has completed now.
769       tap_read->status = GetOverlappedResult (tap_handle,
770                                              &tap_read->overlapped,
771                                              &tap_read->buffer_size,
772                                              FALSE);
773       if (tap_read->status)
774         {/* successful return for a queued operation */
775           if (!ResetEvent (tap_read->overlapped.hEvent))
776             return FALSE;
777
778           /* we successfully read something from the TAP and now need to
779            * send it our via STDOUT. Is that possible at the moment? */
780           if (IOSTATE_READY == std_out->iostate && 0 < tap_read->buffer_size )
781             { /* hand over this buffers content */
782               memcpy (std_out->buffer,
783                       tap_read->buffer,
784                       MAX_SIZE);
785               std_out->buffer_size = tap_read->buffer_size;
786               std_out->iostate = IOSTATE_READY;
787               tap_read->iostate = IOSTATE_READY;
788             }
789           else if (0 < tap_read->buffer_size)
790             { /* If we have have read our buffer, wait for our write-partner*/
791               tap_read->iostate = IOSTATE_WAITING;
792               // TODO: shall we attempt to fill our bufferm or should we wait for our write-partner to finish?
793             }
794         }
795       else
796         { /* operation still pending/queued or failed? */
797           int err = GetLastError ();
798           if (ERROR_IO_INCOMPLETE != err && ERROR_IO_PENDING != err )
799             { /* error occurred, let the rest of the elements finish */
800               tap_read->path_open = FALSE;
801               tap_read->iostate = IOSTATE_FAILED;
802             }
803         }
804     }
805   return TRUE;
806 }
807
808 static boolean
809 attempt_tap_write (HANDLE tap_handle,
810                   struct overlapped_facility * tap_write,
811                   struct overlapped_facility * std_in)
812 {
813   return TRUE;
814 }
815
816 static boolean
817 attempt_std_out ( struct overlapped_facility * std_out,
818                   struct overlapped_facility * tap_read)
819 {
820   return TRUE;
821 }
822
823 /**
824  * Initialize a overlapped structure
825  * 
826  * @param elem the element to initilize
827  * @param initial_state the initial state for this instance
828  * @param signaled if the hEvent created should default to signaled or not
829  * @return true on success, else false
830  */
831 static boolean
832 initialize_overlapped_facility (struct overlapped_facility * elem,
833                                 BOOL initial_state,
834                                 BOOL signaled)
835 {
836
837   elem->path_open = TRUE;
838   elem->status = initial_state;
839   elem->iostate = 0;
840   elem->buffer_size = 0;
841   elem->overlapped.hEvent = CreateEvent (NULL, TRUE, signaled, NULL);
842   if (NULL == elem->overlapped.hEvent)
843     return FALSE;
844
845   return TRUE;
846 }
847
848 /**
849  * Start forwarding to and from the tunnel.
850  *
851  * @param fd_tun tunnel FD
852  */
853 static void
854 run (HANDLE tap_handle)
855 {
856   /* IO-Facility for reading from our virtual interface */
857   struct overlapped_facility tap_read;
858   /* IO-Facility for writing to our virtual interface */
859   struct overlapped_facility tap_write;
860   /* IO-Facility for reading from stdin */
861   struct overlapped_facility std_in;
862   /* IO-Facility for writing to stdout */
863   struct overlapped_facility std_out;
864
865   /* tun up: */
866   /* we do this HERE and not beforehand (in init_tun()), in contrast to openvpn
867    * to remove the need to flush the arp cache, handle DHCP and wrong IPs.
868    *  
869    * DHCP and such are all features we will never use in gnunet afaik.
870    * But for openvpn those are essential.
871    */
872   if (!tun_up (tap_handle))
873     goto teardown;
874
875   /* Initialize our overlapped IO structures*/
876   if (initialize_overlapped_facility (&tap_read, TRUE, FALSE)
877       && initialize_overlapped_facility (&tap_write, FALSE, TRUE)
878       && initialize_overlapped_facility (&std_in, TRUE, FALSE)
879       && initialize_overlapped_facility (&std_out, FALSE, TRUE))
880     goto teardown;
881
882
883   //openvpn  
884   // Set Device to Subnet-Mode? 
885   // do we really need tun.c:2925 ?
886   // Why does openvpn assign IPv4's there??? Foobar??
887
888   // Setup should be complete here.
889   // If something is missing, check init.c:3400+
890
891   // mainloop:
892   // tunnel_point_to_point
893   // openvpn.c:62
894
895   while (std_in.path_open
896          || std_out.path_open
897          || tap_read.path_open
898          || tap_write.path_open)
899     {
900       /* perform READ from stdin if possible */
901       if ((std_in.path_open && tap_write.path_open)
902           || IOSTATE_QUEUED == std_in.iostate)
903         if (!attempt_std_in (&std_in, &tap_write))
904           break;
905
906       /* perform READ from tap if possible */
907       if ((tap_read.path_open && std_out.path_open)
908           || IOSTATE_QUEUED == tap_read.iostate )
909         if (!attempt_tap_read (tap_handle, &tap_read, &std_out))
910           break;
911
912       /* perform WRITE to tap if possible */
913       if ( IOSTATE_READY == tap_write.iostate && tap_write.path_open )
914         if (!attempt_tap_write (tap_handle, &tap_write, &std_in))
915           break;
916
917       /* perform WRITE to STDOUT if possible */
918       if ( IOSTATE_READY == std_out.iostate && std_out.path_open)
919         if (!attempt_std_out (&std_out, &tap_read))
920           break;
921       
922       // check if any path is blocked
923     }
924 teardown:
925   ;
926   //init.c:3472
927 }
928
929 /**
930  * Open VPN tunnel interface.
931  *
932  * @param argc must be 6
933  * @param argv 0: binary name (gnunet-helper-vpn)
934  *             1: tunnel interface name (gnunet-vpn)
935  *             2: IPv6 address (::1), "-" to disable
936  *             3: IPv6 netmask length in bits (64), ignored if #2 is "-"
937  *             4: IPv4 address (1.2.3.4), "-" to disable
938  *             5: IPv4 netmask (255.255.0.0), ignored if #4 is "-"
939  */
940 int
941 main (int argc, char **argv)
942 {
943   char hwid[LINE_LEN];
944   HANDLE handle;
945   int global_ret;
946
947   if (6 != argc)
948     {
949       fprintf (stderr, "Fatal: must supply 5 arguments!\n");
950       return 1;
951     }
952
953   strncpy (hwid, argv[1], LINE_LEN);
954   hwid[LINE_LEN - 1] = '\0';
955
956   /* 
957    * We use our PID for finding/resolving the control-panel name of our virtual 
958    * device. PIDs are (of course) unique at runtime, thus we can safely use it 
959    * as additional hardware-id for our device.
960    */
961   snprintf (secondary_hwid, LINE_LEN / 2, "%s-%d",
962             hwid,
963             _getpid ());
964
965   if (INVALID_HANDLE_VALUE == (handle = init_tun ()))
966     {
967       fprintf (stderr, "Fatal: could not initialize virtual-interface %s with IPv6 %s/%s and IPv4 %s/%s\n",
968                hwid,
969                argv[2],
970                argv[3],
971                argv[4],
972                argv[5]);
973       return 1;
974     }
975
976   if (0 != strcmp (argv[2], "-"))
977     {
978       const char *address = argv[2];
979       long prefix_len = atol (argv[3]);
980
981       if ((prefix_len < 1) || (prefix_len > 127))
982         {
983           fprintf (stderr, "Fatal: prefix_len out of range\n");
984           global_ret = -1;
985           goto cleanup;
986         }
987
988       set_address6 (address, prefix_len);
989     }
990
991   if (0 != strcmp (argv[4], "-"))
992     {
993       const char *address = argv[4];
994       const char *mask = argv[5];
995
996       set_address4 (address, mask);
997     }
998
999   //eventuell: 
1000   // tap_allow_nonadmin_access
1001   //tun.c:2023
1002
1003   run (handle);
1004   global_ret = 0;
1005 cleanup:
1006   remove_interface ();
1007
1008   return global_ret;
1009 }