more debugging work.
[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 <ddk/newdev.h>
39 #include <Winsock2.h>
40 #include "platform.h"
41 #include "tap-windows.h"
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 "OemWin2k.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  */
103 #define INTERFACE_REGISTRY_LOCATION "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
104
105 /**
106  * Our local process' PID. Used for creating a sufficiently unique additional 
107  * hardware ID for our device.
108  */
109 static char secondary_hwid[LINE_LEN / 2];
110
111 /**
112  * Device's visible Name, used to identify a network device in netsh.
113  * eg: "Local Area Connection 9"
114  */
115 static char device_visible_name[256];
116
117 /** 
118  * This is our own local instance of a virtual network interface
119  * It is (somewhat) equivalent to using tun/tap in unixoid systems
120  * 
121  * Upon initialization, we create such an device node.
122  * Upon termination, we remove it again.
123  * 
124  * If we crash this device might stay around.
125  */
126 static HDEVINFO DeviceInfo = INVALID_HANDLE_VALUE;
127
128 /**
129  * Registry Key we hand over to windows to spawn a new virtual interface
130  */
131 static SP_DEVINFO_DATA DeviceNode;
132
133 /**
134  * GUID of our virtual device in the form of 
135  * {12345678-1234-1234-1234-123456789abc} - in hex
136  */
137 static char device_guid[256];
138
139 /** 
140  * A IO Object + read/writebuffer + buffer-size for windows asynchronous IO handling
141  */
142 struct io_facility
143 {
144   HANDLE handle;
145
146   BOOL path_open; // BOOL is winbool, NOT boolean!
147   int facility_state;
148   BOOL status;
149
150   OVERLAPPED overlapped;
151   DWORD buffer_size;
152   DWORD buffer_size_written;
153   unsigned char buffer[MAX_SIZE];
154 };
155
156 /** 
157  * Operlapped IO states for facility objects
158  */
159 #define IOSTATE_FAILED          -1 /* overlapped I/O has failed, stop processing */
160 #define IOSTATE_READY            0 /* overlapped I/O is ready for work */
161 #define IOSTATE_QUEUED           1 /* overlapped I/O has been queued */
162 #define IOSTATE_WAITING          3 /* overlapped I/O has finished, but is waiting for it's write-partner */
163
164 /**
165  * ReOpenFile is only available as of XP SP2 and 2003 SP1
166  */
167 WINBASEAPI HANDLE WINAPI ReOpenFile (HANDLE, DWORD, DWORD, DWORD);
168
169 /**
170  * Wrapper for executing a shellcommand in windows.
171  * 
172  * @param command - the command + parameters to execute
173  * @return * exitcode of the program executed, 
174  *         * EINVAL (cmd/file not found)
175  *         * EPIPE (could not read STDOUT)
176  */
177 static int
178 execute_shellcommand (char * command)
179 {
180   FILE *pipe;
181
182   if (NULL == command ||
183       NULL == (pipe = _popen (command, "rt")))
184     return EINVAL;
185
186 #ifdef TESTING
187   char output[LINE_LEN];
188   while (NULL != fgets (output, sizeof (output), pipe))
189     printf (output);
190 #endif
191
192   return _pclose (pipe);
193 }
194
195 /**
196  * @brief Sets the IPv6-Address given in address on the interface dev
197  *
198  * @param address the IPv6-Address
199  * @param prefix_len the length of the network-prefix
200  */
201 static int
202 set_address6 (const char *address, unsigned long prefix_len)
203 {
204   int ret = EINVAL;
205   char command[LINE_LEN];
206   struct sockaddr_in6 sa6;
207
208   /*
209    * parse the new address
210    */
211   memset (&sa6, 0, sizeof (struct sockaddr_in6));
212   sa6.sin6_family = AF_INET6;
213   if (1 != inet_pton (AF_INET6, address, &sa6.sin6_addr.s6_addr))
214     {
215       fprintf (stderr, "Failed to parse address `%s': %s\n", address,
216                strerror (errno));
217       return -1;
218     }
219
220   /*
221    * prepare the command
222    */
223   snprintf (command, LINE_LEN,
224             "netsh interface ipv6 add address \"%s\" %s/%d",
225             device_visible_name, address, prefix_len);
226   /*
227    * Set the address
228    */
229   ret = execute_shellcommand (command);
230
231   /* Did it work?*/
232   if (0 != ret)
233     fprintf (stderr, "Setting IPv6 address failed: %s\n", strerror (ret));
234   return ret;
235 }
236
237 /**
238  * @brief Sets the IPv4-Address given in address on the interface dev
239  *
240  * @param dev the interface to configure
241  * @param address the IPv4-Address
242  * @param mask the netmask
243  */
244 static int
245 set_address4 (const char *address, const char *mask)
246 {
247   int ret = EINVAL;
248   char command[LINE_LEN];
249
250   struct sockaddr_in addr;
251   addr.sin_family = AF_INET;
252
253   /*
254    * Parse the address
255    */
256   if (1 != inet_pton (AF_INET, address, &addr.sin_addr.s_addr))
257     {
258       fprintf (stderr, "Failed to parse address `%s': %s\n", address,
259                strerror (errno));
260       return -1;
261     }
262   // Set Device to Subnet-Mode? 
263   // do we really need tun.c:2925 ?
264
265   /*
266    * prepare the command
267    */
268   snprintf (command, LINE_LEN,
269             "netsh interface ipv4 add address \"%s\" %s %s",
270             device_visible_name, address, mask);
271   /*
272    * Set the address
273    */
274   ret = execute_shellcommand (command);
275
276   /* Did it work?*/
277   if (0 != ret)
278     fprintf (stderr, "Setting IPv4 address failed: %s\n", strerror (ret));
279   return ret;
280 }
281
282 /**
283  * Setup a new virtual interface to use for tunneling. 
284  * 
285  * @return: TRUE if setup was successful, else FALSE
286  */
287 static boolean
288 setup_interface ()
289 {
290   /*
291    * where to find our inf-file. (+ the "full" path, after windows found")
292    * 
293    * We do not directly input all the props here, because openvpn will update
294    * these details over time.
295    */
296   char inf_file_path[MAX_PATH];
297   char * temp_inf_filename;
298   char hwidlist[LINE_LEN + 4];
299   char class_name[128];
300   GUID class_guid;
301   int str_length = 0;
302
303   /** 
304    * Set the device's hardware ID and add it to a list.
305    * This information will later on identify this device in registry. 
306    */
307   strncpy (hwidlist, HARDWARE_ID, LINE_LEN);
308   /**
309    * this is kind of over-complicated, but allows keeps things independent of 
310    * how the openvpn-hwid is actually stored. 
311    * 
312    * A HWID list is double-\0 terminated and \0 separated
313    */
314   str_length = strlen (hwidlist) + 1;
315   strncpy (&hwidlist[str_length], secondary_hwid, LINE_LEN);
316   str_length += strlen (&hwidlist[str_length]) + 1;
317
318   /** 
319    * Locate the inf-file, we need to store it somewhere where the system can
320    * find it. A good choice would be CWD/PDW or %WINDIR$\system32\
321    * 
322    * TODO: How about win64 in the future? 
323    *       We need to use a different driver for amd64/i386 !
324    */
325   GetFullPathNameA (INF_FILE, MAX_PATH, inf_file_path, &temp_inf_filename);
326
327   /** 
328    * Bootstrap our device info using the drivers inf-file
329    */
330   if (!SetupDiGetINFClassA (inf_file_path,
331                             &class_guid,
332                             class_name, sizeof (class_name) / sizeof (char),
333                             NULL))
334     return FALSE;
335
336   /** 
337    * Collect all the other needed information... 
338    * let the system fill our this form 
339    */
340   DeviceInfo = SetupDiCreateDeviceInfoList (&class_guid, NULL);
341   if (DeviceInfo == INVALID_HANDLE_VALUE)
342     return FALSE;
343
344   DeviceNode.cbSize = sizeof (SP_DEVINFO_DATA);
345   if (!SetupDiCreateDeviceInfoA (DeviceInfo,
346                                  class_name,
347                                  &class_guid,
348                                  NULL,
349                                  0,
350                                  DICD_GENERATE_ID,
351                                  &DeviceNode))
352     return FALSE;
353
354   /* Deploy all the information collected into the registry */
355   if (!SetupDiSetDeviceRegistryPropertyA (DeviceInfo,
356                                           &DeviceNode,
357                                           SPDRP_HARDWAREID,
358                                           (LPBYTE) hwidlist,
359                                           str_length * sizeof (char)))
360     return FALSE;
361
362   /* Install our new class(=device) into the system */
363   if (!SetupDiCallClassInstaller (DIF_REGISTERDEVICE,
364                                   DeviceInfo,
365                                   &DeviceNode))
366     return FALSE;
367
368   if (!UpdateDriverForPlugAndPlayDevicesA (NULL,
369                                            secondary_hwid,
370                                            inf_file_path,
371                                            INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE,
372                                            NULL)) //reboot required? NEVER!
373     return FALSE;
374
375   return TRUE;
376 }
377
378 /**
379  * Remove our new virtual interface to use for tunneling. 
380  * This function must be called AFTER setup_interface!
381  * 
382  * @return: TRUE if destruction was successful, else FALSE
383  */
384 static boolean
385 remove_interface ()
386 {
387   SP_REMOVEDEVICE_PARAMS remove;
388
389   if (INVALID_HANDLE_VALUE == DeviceInfo)
390     return FALSE;
391
392   remove.ClassInstallHeader.cbSize = sizeof (SP_CLASSINSTALL_HEADER);
393   remove.HwProfile = 0;
394   remove.Scope = DI_REMOVEDEVICE_GLOBAL;
395   remove.ClassInstallHeader.InstallFunction = DIF_REMOVE;
396   /*
397    * 1. Prepare our existing device information set, and place the 
398    *    uninstall related information into the structure
399    */
400   if (!SetupDiSetClassInstallParamsA (DeviceInfo,
401                                       (PSP_DEVINFO_DATA) & DeviceNode,
402                                       &remove.ClassInstallHeader,
403                                       sizeof (remove)))
404     return FALSE;
405   /*
406    * 2. Uninstall the virtual interface using the class installer
407    */
408   if (!SetupDiCallClassInstaller (DIF_REMOVE,
409                                   DeviceInfo,
410                                   (PSP_DEVINFO_DATA) & DeviceNode))
411     return FALSE;
412
413   SetupDiDestroyDeviceInfoList (DeviceInfo);
414
415   return TRUE;
416 }
417
418 /**
419  * Do all the lookup necessary to retrieve the inteface's actual name
420  * off the registry. 
421  * 
422  * @return: TRUE if we were able to lookup the interface's name, else FALSE
423  */
424 static boolean
425 resolve_interface_name ()
426 {
427
428   SP_DEVINFO_LIST_DETAIL_DATA device_details;
429   char pnp_instance_id [MAX_DEVICE_ID_LEN];
430   HKEY adapter_key_handle;
431   LONG status;
432   DWORD len;
433   int i = 0;
434   boolean retval = FALSE;
435   char adapter[] = INTERFACE_REGISTRY_LOCATION;
436
437   /* Registry is incredibly slow, wait a few seconds for it to refresh */
438   sleep (5);
439
440   /* We can obtain the PNP instance ID from our setupapi handle */
441   device_details.cbSize = sizeof (device_details);
442   if (CR_SUCCESS != CM_Get_Device_ID_ExA (DeviceNode.DevInst,
443                                           (PCHAR) pnp_instance_id,
444                                           MAX_DEVICE_ID_LEN,
445                                           0, //must be 0
446                                           NULL)) //hMachine, we are local
447     return FALSE;
448
449   /* Now we can use this ID to locate the correct networks interface in registry */
450   if (ERROR_SUCCESS != RegOpenKeyExA (
451                                       HKEY_LOCAL_MACHINE,
452                                       adapter,
453                                       0,
454                                       KEY_READ,
455                                       &adapter_key_handle))
456     return FALSE;
457
458   /* Of course there is a multitude of entries here, with arbitrary names, 
459    * thus we need to iterate through there.
460    */
461   while (!retval)
462     {
463       char instance_key[256];
464       char query_key [256];
465       HKEY instance_key_handle;
466       char pnpinstanceid_name[] = "PnpInstanceID";
467       char pnpinstanceid_value[256];
468       char adaptername_name[] = "Name";
469       DWORD data_type;
470
471       len = 256 * sizeof (char);
472       /* optain a subkey of {4D36E972-E325-11CE-BFC1-08002BE10318} */
473       status = RegEnumKeyExA (
474                               adapter_key_handle,
475                               i,
476                               instance_key,
477                               &len,
478                               NULL,
479                               NULL,
480                               NULL,
481                               NULL);
482
483       /* this may fail due to one of two reasons: 
484        * we are at the end of the list*/
485       if (ERROR_NO_MORE_ITEMS == status)
486         break;
487       // * we found a broken registry key, continue with the next key.
488       if (ERROR_SUCCESS != status)
489         goto cleanup;
490
491       /* prepare our new query string: */
492       snprintf (query_key, 256, "%s\\%s\\Connection",
493                 adapter,
494                 instance_key);
495
496       /* look inside instance_key\\Connection */
497       status = RegOpenKeyExA (
498                               HKEY_LOCAL_MACHINE,
499                               query_key,
500                               0,
501                               KEY_READ,
502                               &instance_key_handle);
503
504       if (status != ERROR_SUCCESS)
505         goto cleanup;
506
507       /* now, read our PnpInstanceID */
508       len = sizeof (pnpinstanceid_value);
509       status = RegQueryValueExA (instance_key_handle,
510                                  pnpinstanceid_name,
511                                  NULL, //reserved, always NULL according to MSDN
512                                  &data_type,
513                                  (LPBYTE) pnpinstanceid_value,
514                                  &len);
515
516       if (status != ERROR_SUCCESS || data_type != REG_SZ)
517         goto cleanup;
518
519       /* compare the value we got to our devices PNPInstanceID*/
520       if (0 != strncmp (pnpinstanceid_value, pnp_instance_id,
521                         sizeof (pnpinstanceid_value) / sizeof (char)))
522         goto cleanup;
523
524       len = sizeof (device_visible_name);
525       status = RegQueryValueExA (
526                                  instance_key_handle,
527                                  adaptername_name,
528                                  NULL, //reserved, always NULL according to MSDN
529                                  &data_type,
530                                  (LPBYTE) device_visible_name,
531                                  &len);
532
533       if (status != ERROR_SUCCESS || data_type != REG_SZ)
534         goto cleanup;
535
536       /* 
537        * we have successfully found OUR instance, 
538        * save the device GUID before exiting
539        */
540
541       strncpy (device_guid, instance_key, 256);
542       retval = TRUE;
543
544 cleanup:
545       RegCloseKey (instance_key_handle);
546
547       ++i;
548     }
549
550   RegCloseKey (adapter_key_handle);
551
552   return retval;
553 }
554
555 static boolean
556 check_tapw32_version (HANDLE handle)
557 {
558   {
559     ULONG version[3];
560     DWORD len;
561     memset (&(version), 0, sizeof (version));
562
563
564     if (DeviceIoControl (handle, TAP_WIN_IOCTL_GET_VERSION,
565                          &version, sizeof (version),
566                          &version, sizeof (version), &len, NULL))
567       {
568 #ifdef TESTING
569         fprintf (stderr, "TAP-Windows Driver Version %d.%d %s",
570                  (int) version[0],
571                  (int) version[1],
572                  (version[2] ? "(DEBUG)" : ""));
573 #endif
574       }
575
576     if (version[0] != TAP_WIN_MIN_MAJOR || version[1] < TAP_WIN_MIN_MINOR)
577       {
578         fprintf (stderr, "ERROR:  This version of gnunet requires a TAP-Windows driver that is at least version %d.%d!\n",
579                  TAP_WIN_MIN_MAJOR,
580                  TAP_WIN_MIN_MINOR);
581         return FALSE;
582       }
583     return TRUE;
584   }
585 }
586
587 /**
588  * Creates a tun-interface called dev;
589  *
590  * @return the fd to the tun or -1 on error
591  */
592 static HANDLE
593 init_tun ()
594 {
595   char device_path[256];
596   HANDLE handle;
597
598   if (!setup_interface ())
599     {
600       errno = ENODEV;
601       return INVALID_HANDLE_VALUE;
602     }
603
604   if (!resolve_interface_name ())
605     {
606       errno = ENODEV;
607       return INVALID_HANDLE_VALUE;
608     }
609
610   /* Open Windows TAP-Windows adapter */
611   snprintf (device_path, sizeof (device_path), "%s%s%s",
612             USERMODEDEVICEDIR,
613             device_guid,
614             TAP_WIN_SUFFIX);
615
616   handle = CreateFile (
617                        device_path,
618                        GENERIC_READ | GENERIC_WRITE,
619                        0, /* was: FILE_SHARE_READ */
620                        0,
621                        OPEN_EXISTING,
622                        FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
623                        0
624                        );
625
626   if (handle == INVALID_HANDLE_VALUE)
627     {
628       fprintf (stderr, "CreateFile failed on TAP device: %s\n", device_path);
629       return handle;
630     }
631
632   /* get driver version info */
633   if (!check_tapw32_version (handle))
634     {
635       CloseHandle (handle);
636       return INVALID_HANDLE_VALUE;
637     }
638
639   /* TODO (opt?): get MTU-Size */
640
641   return handle;
642 }
643
644 /**
645  * Brings a TAP device up and sets it to connected state.
646  * 
647  * @param handle the handle to our TAP device 
648  * @return True if the operation succeeded, else false
649  */
650 static boolean
651 tun_up (HANDLE handle)
652 {
653   ULONG status = TRUE;
654   DWORD len;
655   if (DeviceIoControl (handle, TAP_WIN_IOCTL_SET_MEDIA_STATUS,
656                        &status, sizeof (status),
657                        &status, sizeof (status), &len, NULL))
658     {
659       fprintf (stderr, "The TAP-Windows driver ignored our request to set the interface UP (TAP_WIN_IOCTL_SET_MEDIA_STATUS DeviceIoControl call)!\n");
660       return FALSE;
661     }
662
663   /* Wait for the device to go UP, might take some time. */
664   Sleep ((TAP32_POSTUP_WAITTIME)*1000);
665
666   return TRUE;
667
668 }
669
670 /**
671  * Attempts to read off an input facility (tap or named pipe) in overlapped mode.
672  * 
673  * 1. 
674  * If the input facility is in IOSTATE_READY, it will issue a new read operation to the
675  * input handle. Then it goes into IOSTATE_QUEUED state. 
676  * In case the read succeeded instantly the input facility enters 3.
677  * 
678  * 2. 
679  * If the input facility is in IOSTATE_QUEUED state, it will check if the queued read has finished already.
680  * If it has finished, go to state 3.
681  * If it has failed, set IOSTATE_FAILED
682  * 
683  * 3.
684  * If the output facility is in state IOSTATE_READY, the read-buffer is copied to the output buffer.
685  *   The input facility enters state IOSTATE_READY
686  *   The output facility enters state IOSTATE_READY
687  * If the output facility is in state IOSTATE_QUEUED, the input facility enters IOSTATE_WAITING
688  * 
689  * IOSTATE_WAITING is reset by the output facility, once it has completed.
690  * 
691  * @param input_facility input named pipe or file to work with.
692  * @param output_facility output pipe or file to hand over data to.
693  * @return false if an event reset was impossible (OS error), else true
694  */
695 static boolean
696 attempt_read (struct io_facility * input_facility,
697               struct io_facility * output_facility)
698 {
699
700   if (IOSTATE_READY == input_facility->facility_state)
701     {
702       if (!ResetEvent (input_facility->overlapped.hEvent))
703         {
704           return FALSE;
705         }
706       input_facility->status = ReadFile (input_facility->handle,
707                                          input_facility->buffer,
708                                          MAX_SIZE,
709                                          &input_facility->buffer_size,
710                                          &input_facility->overlapped);
711
712       /* Check how the task is handled */
713       if (input_facility->status)
714         {/* async event processed immediately*/
715
716           /* reset event manually*/
717           if (!SetEvent (input_facility->overlapped.hEvent))
718             return FALSE;
719
720           /* we successfully read something from the TAP and now need to
721            * send it our via STDOUT. Is that possible at the moment? */
722           if ((IOSTATE_READY == output_facility->facility_state ||
723                IOSTATE_WAITING == output_facility->facility_state)
724               && 0 < input_facility->buffer_size)
725             { /* hand over this buffers content */
726               memcpy (output_facility->buffer,
727                       input_facility->buffer,
728                       MAX_SIZE);
729               output_facility->buffer_size = input_facility->buffer_size;
730               output_facility->facility_state = IOSTATE_READY;
731             }
732           else if (0 < input_facility->buffer_size)
733             { /* If we have have read our buffer, wait for our write-partner*/
734               input_facility->facility_state = IOSTATE_WAITING;
735               // TODO: shall we attempt to fill our buffer or should we wait for our write-partner to finish?
736             }
737         }
738       else /* operation was either queued or failed*/
739         {
740           int err = GetLastError ();
741           if (ERROR_IO_PENDING == err)
742             { /* operation queued */
743               input_facility->facility_state = IOSTATE_QUEUED;
744             }
745           else
746             { /* error occurred, let the rest of the elements finish */
747               input_facility->path_open = FALSE;
748               input_facility->facility_state = IOSTATE_FAILED;
749               if (IOSTATE_WAITING == output_facility->facility_state)
750                 output_facility->path_open = FALSE;
751
752               fprintf (stderr, "Fatal: Read from handle failed, allowing write to finish!\n");
753             }
754         }
755     }
756     // We are queued and should check if the read has finished
757   else if (IOSTATE_QUEUED == input_facility->facility_state)
758     {
759       // there was an operation going on already, check if that has completed now.
760       input_facility->status = GetOverlappedResult (input_facility->handle,
761                                                     &input_facility->overlapped,
762                                                     &input_facility->buffer_size,
763                                                     FALSE);
764       if (input_facility->status)
765         {/* successful return for a queued operation */
766           if (!ResetEvent (input_facility->overlapped.hEvent))
767             return FALSE;
768
769           /* we successfully read something from the TAP and now need to
770            * send it our via STDOUT. Is that possible at the moment? */
771           if ((IOSTATE_READY == output_facility->facility_state ||
772                IOSTATE_WAITING == output_facility->facility_state)
773               && 0 < input_facility->buffer_size)
774             { /* hand over this buffers content */
775               memcpy (output_facility->buffer,
776                       input_facility->buffer,
777                       MAX_SIZE);
778               output_facility->buffer_size = input_facility->buffer_size;
779               output_facility->facility_state = IOSTATE_READY;
780               input_facility->facility_state = IOSTATE_READY;
781             }
782           else if (0 < input_facility->buffer_size)
783             { /* If we have have read our buffer, wait for our write-partner*/
784               input_facility->facility_state = IOSTATE_WAITING;
785               // TODO: shall we attempt to fill our buffer or should we wait for our write-partner to finish?
786             }
787         }
788       else
789         { /* operation still pending/queued or failed? */
790           int err = GetLastError ();
791           if (ERROR_IO_INCOMPLETE != err && ERROR_IO_PENDING != err)
792             { /* error occurred, let the rest of the elements finish */
793               input_facility->path_open = FALSE;
794               input_facility->facility_state = IOSTATE_FAILED;
795               if (IOSTATE_WAITING == output_facility->facility_state)
796                 output_facility->path_open = FALSE;
797               fprintf (stderr, "Fatal: Read from handle failed, allowing write to finish!\n");
798             }
799         }
800     }
801   return TRUE;
802 }
803
804 /**
805  * Attempts to write to an output facility (tap or named pipe) in overlapped mode.
806  *
807  * TODO: high level description
808  * 
809  * @param output_facility output pipe or file to hand over data to.
810  * @param input_facility input named pipe or file to work with.
811  * @return false if an event reset was impossible (OS error), else true
812  */
813 static boolean
814 attempt_write (struct io_facility * output_facility,
815                struct io_facility * input_facility)
816 {
817   if (IOSTATE_READY == output_facility->facility_state
818       && output_facility->buffer_size > 0)
819     {
820       if (!ResetEvent (output_facility->overlapped.hEvent))
821         {
822           return FALSE;
823         }
824
825       output_facility->status = WriteFile (output_facility->handle,
826                                            output_facility->buffer,
827                                            output_facility->buffer_size,
828                                            &output_facility->buffer_size_written,
829                                            &output_facility->overlapped);
830
831       /* Check how the task is handled */
832       if (output_facility->status &&
833           output_facility->buffer_size_written == output_facility->buffer_size)
834         {/* async event processed immediately*/
835
836           /* reset event manually*/
837           if (!SetEvent (output_facility->overlapped.hEvent))
838             return FALSE;
839
840           /* we are now waiting for our buffer to be filled*/
841           output_facility->facility_state = IOSTATE_WAITING;
842           output_facility->buffer_size = 0;
843           output_facility->buffer_size_written = 0;
844
845           /* we successfully wrote something and now need to reset our reader */
846           if (IOSTATE_WAITING == input_facility->facility_state)
847             input_facility->facility_state = IOSTATE_READY;
848           else if (IOSTATE_FAILED == input_facility->facility_state)
849             output_facility->path_open = FALSE;
850         }
851       else /* operation was either queued or failed*/
852         {
853           int err = GetLastError ();
854           if (ERROR_IO_PENDING == err)
855             { /* operation queued */
856               output_facility->facility_state = IOSTATE_QUEUED;
857             }
858           else
859             { /* error occurred, close this path */
860               output_facility->path_open = FALSE;
861               output_facility->facility_state = IOSTATE_FAILED;
862               fprintf (stderr, "Fatal: Write to handle failed, exiting!\n");
863             }
864         }
865
866     }
867   else if (IOSTATE_QUEUED == output_facility->facility_state)
868     {
869       // there was an operation going on already, check if that has completed now.
870       output_facility->status = GetOverlappedResult (output_facility->handle,
871                                                      &output_facility->overlapped,
872                                                      &output_facility->buffer_size_written,
873                                                      FALSE);
874       if (output_facility->status &&
875           output_facility->buffer_size_written == output_facility->buffer_size)
876         {/* successful return for a queued operation */
877           if (!ResetEvent (output_facility->overlapped.hEvent))
878             return FALSE;
879
880           /* we are now waiting for our buffer to be filled*/
881           output_facility->facility_state = IOSTATE_WAITING;
882           output_facility->buffer_size = 0;
883           output_facility->buffer_size_written = 0;
884
885           /* we successfully wrote something and now need to reset our reader */
886           if (IOSTATE_WAITING == input_facility->facility_state)
887             input_facility->facility_state = IOSTATE_READY;
888           else if (IOSTATE_FAILED == input_facility->facility_state)
889             output_facility->path_open = FALSE;
890         }
891       else
892         { /* operation still pending/queued or failed? */
893           int err = GetLastError ();
894           if (ERROR_IO_INCOMPLETE != err && ERROR_IO_PENDING != err)
895             { /* error occurred, close this path */
896               output_facility->path_open = FALSE;
897               output_facility->facility_state = IOSTATE_FAILED;
898               fprintf (stderr, "Fatal: Write to handle failed, exiting!\n");
899             }
900         }
901     }
902
903   return TRUE;
904 }
905
906 /**
907  * Initialize a overlapped structure
908  * 
909  * @param elem the element to initilize
910  * @param initial_state the initial state for this instance
911  * @param signaled if the hEvent created should default to signaled or not
912  * @return true on success, else false
913  */
914 static boolean
915 initialize_io_facility (struct io_facility * elem,
916                         BOOL initial_state,
917                         BOOL signaled)
918 {
919
920   elem->path_open = TRUE;
921   elem->status = initial_state;
922   elem->handle = INVALID_HANDLE_VALUE;
923   elem->facility_state = 0;
924   elem->buffer_size = 0;
925   elem->overlapped.hEvent = CreateEvent (NULL, TRUE, signaled, NULL);
926   if (NULL == elem->overlapped.hEvent)
927     return FALSE;
928
929   return TRUE;
930 }
931
932 /**
933  * Start forwarding to and from the tunnel.
934  *
935  * @param fd_tun tunnel FD
936  */
937 static void
938 run (HANDLE tap_handle)
939 {
940   /* IO-Facility for reading from our virtual interface */
941   struct io_facility tap_read;
942   /* IO-Facility for writing to our virtual interface */
943   struct io_facility tap_write;
944   /* IO-Facility for reading from stdin */
945   struct io_facility std_in;
946   /* IO-Facility for writing to stdout */
947   struct io_facility std_out;
948
949   HANDLE parent_std_in_handle = GetStdHandle (STD_INPUT_HANDLE);
950   HANDLE parent_std_out_handle = GetStdHandle (STD_OUTPUT_HANDLE);
951
952   /* tun up: */
953   /* we do this HERE and not beforehand (in init_tun()), in contrast to openvpn
954    * to remove the need to flush the arp cache, handle DHCP and wrong IPs.
955    *  
956    * DHCP and such are all features we will never use in gnunet afaik.
957    * But for openvpn those are essential.
958    */
959   if (!tun_up (tap_handle))
960     return;
961
962   /* Initialize our overlapped IO structures*/
963   if (!(initialize_io_facility (&tap_read, TRUE, FALSE)
964         && initialize_io_facility (&tap_write, FALSE, TRUE)
965         && initialize_io_facility (&std_in, TRUE, FALSE)
966         && initialize_io_facility (&std_out, FALSE, TRUE)))
967     goto teardown_final;
968
969   /* Handles for STDIN and STDOUT */
970   tap_read.handle = tap_handle;
971   tap_write.handle = tap_handle;
972
973   /* 
974    * Find out the types of our handles. 
975    * This part is a problem, because in windows we need to handle files, 
976    * pipes and the console differently.
977    */
978   if (FILE_TYPE_PIPE != GetFileType (parent_std_in_handle) ||
979       FILE_TYPE_PIPE != GetFileType (parent_std_out_handle))
980     {
981       fprintf (stderr, "Fatal: stdin/stdout must be named pipes!\n");
982       goto teardown;
983     }
984
985   std_in.handle = ReOpenFile (parent_std_in_handle,
986                               GENERIC_READ,
987                               FILE_SHARE_WRITE | FILE_SHARE_READ,
988                               FILE_FLAG_OVERLAPPED);
989
990   if (INVALID_HANDLE_VALUE == std_in.handle)
991     {
992       fprintf (stderr, "Fatal: Could not reopen stdin for in overlapped mode, has to be a named pipe!\n");
993       goto teardown;
994     }
995
996   std_out.handle = ReOpenFile (parent_std_out_handle,
997                                GENERIC_WRITE,
998                                FILE_SHARE_READ,
999                                FILE_FLAG_OVERLAPPED);
1000
1001   if (INVALID_HANDLE_VALUE == std_out.handle)
1002     {
1003       fprintf (stderr, "Fatal: Could not reopen stdout for in overlapped mode, has to be a named pipe!\n");
1004       goto teardown;
1005     }
1006
1007   while (std_out.path_open || tap_write.path_open)
1008     {
1009       /* perform READ from stdin if possible */
1010       if (std_in.path_open && tap_write.path_open && !attempt_read (&std_in, &tap_write))
1011         break;
1012
1013       /* perform READ from tap if possible */
1014       if (tap_read.path_open && std_out.path_open && !attempt_read (&tap_read, &std_out))
1015         break;
1016
1017       /* perform WRITE to tap if possible */
1018       if (tap_write.path_open && !attempt_write (&tap_write, &std_in))
1019         break;
1020
1021       /* perform WRITE to STDOUT if possible */
1022       if (std_out.path_open && !attempt_write (&std_out, &tap_read))
1023         break;
1024     }
1025
1026 teardown:
1027
1028   CancelIo (tap_handle);
1029   CancelIo (std_in.handle);
1030   CancelIo (std_out.handle);
1031
1032 teardown_final:
1033
1034   CloseHandle (tap_handle);
1035 }
1036
1037 /**
1038  * Open VPN tunnel interface.
1039  *
1040  * @param argc must be 6
1041  * @param argv 0: binary name (gnunet-helper-vpn)
1042  *             1: tunnel interface name (gnunet-vpn)
1043  *             2: IPv6 address (::1), "-" to disable
1044  *             3: IPv6 netmask length in bits (64), ignored if #2 is "-"
1045  *             4: IPv4 address (1.2.3.4), "-" to disable
1046  *             5: IPv4 netmask (255.255.0.0), ignored if #4 is "-"
1047  */
1048 int
1049 main (int argc, char **argv)
1050 {
1051   char hwid[LINE_LEN];
1052   HANDLE handle;
1053   int global_ret = 0;
1054
1055   if (6 != argc)
1056     {
1057       fprintf (stderr, "Fatal: must supply 5 arguments!\n");
1058       return 1;
1059     }
1060
1061   strncpy (hwid, argv[1], LINE_LEN);
1062   hwid[LINE_LEN - 1] = '\0';
1063
1064   /* 
1065    * We use our PID for finding/resolving the control-panel name of our virtual 
1066    * device. PIDs are (of course) unique at runtime, thus we can safely use it 
1067    * as additional hardware-id for our device.
1068    */
1069   snprintf (secondary_hwid, LINE_LEN / 2, "%s-%d",
1070             hwid,
1071             _getpid ());
1072
1073   if (INVALID_HANDLE_VALUE == (handle = init_tun ()))
1074     {
1075       fprintf (stderr, "Fatal: could not initialize virtual-interface %s with IPv6 %s/%s and IPv4 %s/%s\n",
1076                hwid,
1077                argv[2],
1078                argv[3],
1079                argv[4],
1080                argv[5]);
1081       global_ret = -1;
1082       goto cleanup;
1083     }
1084
1085   if (0 != strcmp (argv[2], "-"))
1086     {
1087       const char *address = argv[2];
1088       long prefix_len = atol (argv[3]);
1089
1090       if ((prefix_len < 1) || (prefix_len > 127))
1091         {
1092           fprintf (stderr, "Fatal: prefix_len out of range\n");
1093           global_ret = -1;
1094           goto cleanup;
1095         }
1096
1097       if (0 != (global_ret = set_address6 (address, prefix_len)))
1098         goto cleanup;
1099     }
1100
1101   if (0 != strcmp (argv[4], "-"))
1102     {
1103       const char *address = argv[4];
1104       const char *mask = argv[5];
1105
1106       if (0 != (global_ret = set_address4 (address, mask)))
1107         goto cleanup;
1108     }
1109
1110   run (handle);
1111   global_ret = 0;
1112 cleanup:
1113
1114   remove_interface ();
1115   return global_ret;
1116 }