-feedback on style
[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 "platform.h"
38
39 //#include <tchar.h>
40 //#include <stdlib.h>
41 //#include <regstr.h>
42 //#include <string.h>
43 //#include <malloc.h>
44 //#include <objbase.h>
45
46 /**
47  * Need 'struct GNUNET_MessageHeader'.
48  */
49 #include "gnunet_common.h"
50
51 /**
52  * Need VPN message types.
53  */
54 #include "gnunet_protocols.h"
55
56 /**
57  * Should we print (interesting|debug) messages that can happen during
58  * normal operation?
59  */
60 #define DEBUG GNUNET_NO
61
62 /**
63  * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE)
64  */
65 #define MAX_SIZE 65536
66
67 /** 
68  * This is our own local instance of a virtual network interface
69  * It is (somewhat) equivalent to using tun/tap in unixoid systems
70  * 
71  * Upon initialization, we create such an device node.
72  * Upon termination, we remove it again.
73  * 
74  * If we crash this device might stay around.
75  */
76 static HDEVINFO DeviceInfo = INVALID_HANDLE_VALUE;
77
78 /**
79  * FIXME
80  */
81 static SP_DEVINFO_DATA DeviceNode;
82
83 /**
84  * FIXME
85  */
86 static TCHAR class[128];
87
88 /**
89  * FIXME
90  */
91 static GUID guid;
92
93
94 /**
95  * Creates a tun-interface called dev;
96  *
97  * @param dev is asumed to point to a char[IFNAMSIZ]
98  *        if *dev == '\\0', uses the name supplied by the kernel;
99  * @return the fd to the tun or -1 on error
100  */
101 static int
102 init_tun (char *dev)
103 {
104   int fd;
105
106   if (NULL == dev)
107     {
108       errno = EINVAL;
109       return -1;
110     }
111
112   /* Hello, I am a stub function! I did my job, yay me! */
113
114   return fd;
115 }
116
117
118 /**
119  * @brief Sets the IPv6-Address given in address on the interface dev
120  *
121  * @param dev the interface to configure
122  * @param address the IPv6-Address
123  * @param prefix_len the length of the network-prefix
124  */
125 static void
126 set_address6 (const char *dev, const char *address, unsigned long prefix_len)
127 {
128   int fd = -1;
129
130   /*
131    * parse the new address
132    */
133
134   /*
135    * Get the index of the if
136    */
137
138   /*
139    * Set the address
140    */
141
142   /*
143    * Get the flags
144    */
145
146
147   /*
148    * Add the UP and RUNNING flags
149    */
150
151
152   if (0 != close (fd))
153     {
154       fprintf (stderr, "close failed: %s\n", strerror (errno));
155       exit (1);
156     }
157 }
158
159 /**
160  * @brief Sets the IPv4-Address given in address on the interface dev
161  *
162  * @param dev the interface to configure
163  * @param address the IPv4-Address
164  * @param mask the netmask
165  */
166 static void
167 set_address4 (const char *dev, const char *address, const char *mask)
168 {
169   int fd = -1;
170
171   /*
172    * Parse the address
173    */
174
175   /*
176    * Set the address
177    */
178
179   /*
180    * Parse the netmask
181    */
182
183
184   /*
185    * Set the netmask
186    */
187
188
189   /*
190    * Get the flags
191    */
192
193
194   /*
195    * Add the UP and RUNNING flags
196    */
197
198
199   if (0 != close (fd))
200     {
201       fprintf (stderr, "close failed: %s\n", strerror (errno));
202       (void) close (fd);
203       exit (1);
204     }
205 }
206
207
208 /**
209  * FIXME.
210  */
211 static boolean
212 setup_interface ()
213 {
214   /*
215    * where to find our inf-file. (+ the "full" path, after windows found")
216    * 
217    * We do not directly input all the props here, because openvpn will update
218    * these details over time.
219    */
220   TCHAR InfFile[] = _T("tapw32.inf"); // FIXME: inline or #define, no 'variable'
221   TCHAR hwid[] = _T("TAP0901");
222   TCHAR InfFilePath[MAX_PATH];
223   TCHAR hwIdList[LINE_LEN + 4];
224
225 #if DEAD
226   /** 
227    * Locate the inf-file, we need to store it somewhere where the system can
228    * find it. A good choice would be CWD/PDW or %WINDIR$\system32\
229    * 
230    * TODO: Finde a more sane way to do this!
231    */
232
233   if (NULL == (InfFilePath = calloc (MAX_PATH, sizeof (TCHAR))))
234       return FALSE;
235 #endif
236   GetFullPathName (InfFile, MAX_PATH, InfFilePath, NULL);
237
238 #if DEAD
239   /** 
240    * Set the device's hardware ID and add it to a list.
241    * This information will later on identify this device in registry. 
242    * 
243    * TODO: Currently we just use TAP0901 as HWID, 
244    * but we might want to add additional information
245    */
246   hwIdList = calloc (LINE_LEN + 4, sizeof (TCHAR));
247   if (hwIdList == NULL)
248     {
249       goto cleanup1;
250     }
251 #endif
252   strncpy (hwIdList, hwid, LINE_LEN);
253
254   /** 
255    * Bootstrap our device info using the drivers inf-file
256    */
257   if (!SetupDiGetINFClass (InfFilePath,
258                            &guid,
259                            class, sizeof (class) / sizeof (TCHAR),
260                            NULL))
261     {
262       goto cleanup2;
263     }
264
265   /** 
266    * Collect all the other needed information... 
267    * let the system fill our this form 
268    */
269   DeviceInfo = SetupDiCreateDeviceInfoList (&guid, NULL);
270   if (DeviceInfo == INVALID_HANDLE_VALUE)
271     {
272       goto cleanup3;
273     }
274   DeviceNode.cbSize = sizeof (SP_DEVINFO_DATA);
275   if (!SetupDiCreateDeviceInfo (DeviceInfo,
276                                 class,
277                                 &guid,
278                                 NULL,
279                                 NULL,
280                                 DICD_GENERATE_ID,
281                                 &DeviceNode))
282     {
283       goto cleanup3;
284     }
285
286   /* Deploy all the information collected into the registry */
287   if (!SetupDiSetDeviceRegistryProperty (DeviceInfo,
288                                          &DeviceNode,
289                                          SPDRP_HARDWAREID,
290                                          (LPBYTE) hwIdList,
291                                          (lstrlen (hwIdList) + 2) * sizeof (TCHAR)))
292     {
293       goto cleanup3;
294     }
295   /* Install our new class(=device) into the system */
296   if (SetupDiCallClassInstaller (DIF_REGISTERDEVICE,
297                                  DeviceInfo,
298                                  &DeviceNode))
299     {
300       return TRUE;
301     }
302
303   //disabled for debug-reasons...
304 cleanup3:
305   //GNUNET_free(DeviceInfo);
306   ;
307 cleanup2:
308   //GNUNET_free(hwIdList);
309   ;
310 cleanup1:
311   //GNUNET_free(InfFilePath);
312   ;
313   return FALSE;
314
315 }
316
317
318 static boolean
319 remove_interface ()
320 {
321   SP_REMOVEDEVICE_PARAMS remove;
322
323   remove.ClassInstallHeader.cbSize = sizeof (SP_CLASSINSTALL_HEADER);
324   remove.HwProfile = 0;
325   remove.Scope = DI_REMOVEDEVICE_GLOBAL;
326   remove.ClassInstallHeader.InstallFunction = DIF_REMOVE;
327   if (! SetupDiSetClassInstallParams (DeviceInfo,
328                                       (PSP_DEVINFO_DATA) &DeviceNode,
329                                       &remove.ClassInstallHeader,
330                                       sizeof (remove)))
331     return FALSE;
332   if (! SetupDiCallClassInstaller (DIF_REMOVE, 
333                                    DeviceInfo, 
334                                    (PSP_DEVINFO_DATA) &DeviceNode))
335     return FALSE;
336   return TRUE;
337 }
338
339
340 /**
341  * Start forwarding to and from the tunnel.
342  *
343  * @param fd_tun tunnel FD
344  */
345 static void
346 run (int fd_tun)
347 {
348   /*
349    * The buffer filled by reading from fd_tun
350    */
351   unsigned char buftun[MAX_SIZE];
352   ssize_t buftun_size = 0;
353   unsigned char *buftun_read = NULL;
354
355   /*
356    * The buffer filled by reading from stdin
357    */
358   unsigned char bufin[MAX_SIZE];
359   ssize_t bufin_size = 0;
360   size_t bufin_rpos = 0;
361   unsigned char *bufin_read = NULL;
362   /* Hello, I am a stub function! I did my job, yay me! */
363
364 }
365
366
367 /**
368  * Open VPN tunnel interface.
369  *
370  * @param argc must be 6
371  * @param argv 0: binary name (gnunet-helper-vpn)
372  *             1: tunnel interface name (gnunet-vpn)
373  *             2: IPv6 address (::1), "-" to disable
374  *             3: IPv6 netmask length in bits (64), ignored if #2 is "-"
375  *             4: IPv4 address (1.2.3.4), "-" to disable
376  *             5: IPv4 netmask (255.255.0.0), ignored if #4 is "-"
377  */
378 int
379 main (int argc, char **argv)
380 {
381   //char dev[IFNAMSIZ];
382   int fd_tun;
383   int global_ret;
384
385   if (6 != argc)
386     {
387       fprintf (stderr, "Fatal: must supply 5 arguments!\n");
388       return 1;
389     }
390
391   /*
392    * strncpy (dev, argv[1], IFNAMSIZ);
393    * dev[IFNAMSIZ - 1] = '\0';
394    */
395   /*  if (-1 == (fd_tun = init_tun (dev)))
396     {
397       fprintf (stderr, "Fatal: could not initialize tun-interface  with IPv6 %s/%s and IPv4 %s/%s\n",
398                dev,
399                argv[2],
400                argv[3],
401                argv[4],
402                argv[5]);
403       return 1;
404     }
405    */
406
407   if (0 != strcmp (argv[2], "-"))
408     {
409       const char *address = argv[2];
410       long prefix_len = atol (argv[3]);
411
412       if ((prefix_len < 1) || (prefix_len > 127))
413         {
414           fprintf (stderr, "Fatal: prefix_len out of range\n");
415           return 1;
416         }
417
418       //set_address6 (dev, address, prefix_len);
419     }
420
421   if (0 != strcmp (argv[4], "-"))
422     {
423       const char *address = argv[4];
424       const char *mask = argv[5];
425
426       set_address4 (NULL, address, mask);
427     }
428
429   if (setup_interface ())
430     {
431       ;
432     }
433
434   /*
435   uid_t uid = getuid ();
436   if (0 != setresuid (uid, uid, uid))
437   {
438     fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
439     global_ret = 2;
440     goto cleanup;
441   }
442    */
443
444   /*if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
445   {
446     fprintf (stderr, "Failed to protect against SIGPIPE: %s\n",
447              strerror (errno));
448     // no exit, we might as well die with SIGPIPE should it ever happen 
449   }
450    */
451   //run (fd_tun);
452   global_ret = 0;
453 cleanup:
454   //close (fd_tun);
455   return global_ret;
456 }