aboutsummaryrefslogtreecommitdiff
path: root/src/vpn
diff options
context:
space:
mode:
authorChristian Fuchs <christian.fuchs@cfuchs.net>2012-12-31 15:52:36 +0000
committerChristian Fuchs <christian.fuchs@cfuchs.net>2012-12-31 15:52:36 +0000
commitd4c657e337060285f560b1a9287dd6a51551d35e (patch)
treecc21c6411bb1419c563332299f9db2bd662e967b /src/vpn
parentf3eca31df25d50ebe32c5d38f31cc7a62e62914d (diff)
downloadgnunet-d4c657e337060285f560b1a9287dd6a51551d35e.tar.gz
gnunet-d4c657e337060285f560b1a9287dd6a51551d35e.zip
* added tap version checking logics. Many tap32 versions are broken,
Only version 9.8 and later support IPv6, 9.8 is broken with IPv4. Thus, we are using the same minium version as openvpn 2.3: tap32-9.9 * created our TAP/TUN handle-object (equivalent to the *nix init_tun() function), this still requires some more logics to be complete. * added logics to set the tun up (+a fixed sleep, to wait for it to come up) * we now also store the device's GUID, as we need it for creating the handle. * added the exports of tap32: src/include/tap_windows.h , for the sake of upgradability. This file contains version-specific defines for the driver. * happy new year!
Diffstat (limited to 'src/vpn')
-rw-r--r--src/vpn/gnunet-helper-vpn-windows.c305
1 files changed, 209 insertions, 96 deletions
diff --git a/src/vpn/gnunet-helper-vpn-windows.c b/src/vpn/gnunet-helper-vpn-windows.c
index bf5585204..2df5377c6 100644
--- a/src/vpn/gnunet-helper-vpn-windows.c
+++ b/src/vpn/gnunet-helper-vpn-windows.c
@@ -36,6 +36,7 @@
36#include <setupapi.h> 36#include <setupapi.h>
37#include <ddk/cfgmgr32.h> 37#include <ddk/cfgmgr32.h>
38#include "platform.h" 38#include "platform.h"
39#include "tap-windows.h"
39#include <Winsock2.h> 40#include <Winsock2.h>
40 41
41/** 42/**
@@ -72,6 +73,31 @@
72#define HARDWARE_ID "TAP0901" 73#define HARDWARE_ID "TAP0901"
73 74
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 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/**
75 * Location of the network interface list resides in registry. 101 * Location of the network interface list resides in registry.
76 * TODO: is this fixed on all version of windows? Checked with XP and 7 102 * TODO: is this fixed on all version of windows? Checked with XP and 7
77 */ 103 */
@@ -106,17 +132,10 @@ static HDEVINFO DeviceInfo = INVALID_HANDLE_VALUE;
106static SP_DEVINFO_DATA DeviceNode; 132static SP_DEVINFO_DATA DeviceNode;
107 133
108/** 134/**
109 * Class-tag of our virtual device
110 */
111static char class[128];
112
113/**
114 * GUID of our virtual device in the form of 135 * GUID of our virtual device in the form of
115 * {12345678-1234-1234-1234-123456789abc} - in hex 136 * {12345678-1234-1234-1234-123456789abc} - in hex
116 */ 137 */
117static GUID guid; 138static char device_guid[256];
118
119
120/** 139/**
121 * inet_pton() wrapper for WSAStringToAddress() 140 * inet_pton() wrapper for WSAStringToAddress()
122 * 141 *
@@ -131,6 +150,7 @@ static GUID guid;
131#if WINVER >= 0x0600 150#if WINVER >= 0x0600
132int inet_pton (int af, const char *src, void *dst); 151int inet_pton (int af, const char *src, void *dst);
133#else 152#else
153
134int 154int
135inet_pton (int af, const char *src, void *dst) 155inet_pton (int af, const char *src, void *dst)
136{ 156{
@@ -158,6 +178,7 @@ inet_pton (int af, const char *src, void *dst)
158 return 0; 178 return 0;
159} 179}
160#endif 180#endif
181
161/** 182/**
162 * Wrapper for executing a shellcommand in windows. 183 * Wrapper for executing a shellcommand in windows.
163 * 184 *
@@ -220,8 +241,8 @@ set_address6 (const char *address, unsigned long prefix_len)
220 * prepare the command 241 * prepare the command
221 */ 242 */
222 snprintf (command, LINE_LEN, 243 snprintf (command, LINE_LEN,
223 "netsh interface ipv6 add address \"%s\" %s/%d", 244 "netsh interface ipv6 add address \"%s\" %s/%d",
224 device_visible_name, address, prefix_len); 245 device_visible_name, address, prefix_len);
225 /* 246 /*
226 * Set the address 247 * Set the address
227 */ 248 */
@@ -265,8 +286,8 @@ set_address4 (const char *address, const char *mask)
265 * prepare the command 286 * prepare the command
266 */ 287 */
267 snprintf (command, LINE_LEN, 288 snprintf (command, LINE_LEN,
268 "netsh interface ipv4 add address \"%s\" %s %s", 289 "netsh interface ipv4 add address \"%s\" %s %s",
269 device_visible_name, address, mask); 290 device_visible_name, address, mask);
270 /* 291 /*
271 * Set the address 292 * Set the address
272 */ 293 */
@@ -296,10 +317,10 @@ setup_interface ()
296 */ 317 */
297 char inf_file_path[MAX_PATH]; 318 char inf_file_path[MAX_PATH];
298 char hwidlist[LINE_LEN + 4]; 319 char hwidlist[LINE_LEN + 4];
299 320 char class_name[128];
321 GUID class_guid;
300 int str_lenth = 0; 322 int str_lenth = 0;
301 323
302
303 /** 324 /**
304 * Set the device's hardware ID and add it to a list. 325 * Set the device's hardware ID and add it to a list.
305 * This information will later on identify this device in registry. 326 * This information will later on identify this device in registry.
@@ -330,35 +351,35 @@ setup_interface ()
330 * Bootstrap our device info using the drivers inf-file 351 * Bootstrap our device info using the drivers inf-file
331 */ 352 */
332 if (!SetupDiGetINFClassA (inf_file_path, 353 if (!SetupDiGetINFClassA (inf_file_path,
333 &guid, 354 &class_guid,
334 class, sizeof (class) / sizeof (char), 355 class_name, sizeof (class_name) / sizeof (char),
335 NULL)) 356 NULL))
336 return FALSE; 357 return FALSE;
337 358
338 /** 359 /**
339 * Collect all the other needed information... 360 * Collect all the other needed information...
340 * let the system fill our this form 361 * let the system fill our this form
341 */ 362 */
342 DeviceInfo = SetupDiCreateDeviceInfoList (&guid, NULL); 363 DeviceInfo = SetupDiCreateDeviceInfoList (&class_guid, NULL);
343 if (DeviceInfo == INVALID_HANDLE_VALUE) 364 if (DeviceInfo == INVALID_HANDLE_VALUE)
344 return FALSE; 365 return FALSE;
345 366
346 DeviceNode.cbSize = sizeof (SP_DEVINFO_DATA); 367 DeviceNode.cbSize = sizeof (SP_DEVINFO_DATA);
347 if (!SetupDiCreateDeviceInfoA (DeviceInfo, 368 if (!SetupDiCreateDeviceInfoA (DeviceInfo,
348 class, 369 class_name,
349 &guid, 370 &class_guid,
350 NULL, 371 NULL,
351 NULL, 372 NULL,
352 DICD_GENERATE_ID, 373 DICD_GENERATE_ID,
353 &DeviceNode)) 374 &DeviceNode))
354 return FALSE; 375 return FALSE;
355 376
356 /* Deploy all the information collected into the registry */ 377 /* Deploy all the information collected into the registry */
357 if (!SetupDiSetDeviceRegistryPropertyA (DeviceInfo, 378 if (!SetupDiSetDeviceRegistryPropertyA (DeviceInfo,
358 &DeviceNode, 379 &DeviceNode,
359 SPDRP_HARDWAREID, 380 SPDRP_HARDWAREID,
360 (LPBYTE) hwidlist, 381 (LPBYTE) hwidlist,
361 (strlen (hwidlist) + 2) * sizeof (char))) 382 (strlen (hwidlist) + 2) * sizeof (char)))
362 return FALSE; 383 return FALSE;
363 384
364 /* Install our new class(=device) into the system */ 385 /* Install our new class(=device) into the system */
@@ -393,9 +414,9 @@ remove_interface ()
393 * uninstall related information into the structure 414 * uninstall related information into the structure
394 */ 415 */
395 if (!SetupDiSetClassInstallParamsA (DeviceInfo, 416 if (!SetupDiSetClassInstallParamsA (DeviceInfo,
396 (PSP_DEVINFO_DATA) & DeviceNode, 417 (PSP_DEVINFO_DATA) & DeviceNode,
397 &remove.ClassInstallHeader, 418 &remove.ClassInstallHeader,
398 sizeof (remove))) 419 sizeof (remove)))
399 return FALSE; 420 return FALSE;
400 /* 421 /*
401 * 2. Uninstall the virtual interface using the class installer 422 * 2. Uninstall the virtual interface using the class installer
@@ -432,19 +453,19 @@ resolve_interface_name ()
432 /* We can obtain the PNP instance ID from our setupapi handle */ 453 /* We can obtain the PNP instance ID from our setupapi handle */
433 device_details.cbSize = sizeof (device_details); 454 device_details.cbSize = sizeof (device_details);
434 if (CR_SUCCESS != CM_Get_Device_ID_ExA (DeviceNode.DevInst, 455 if (CR_SUCCESS != CM_Get_Device_ID_ExA (DeviceNode.DevInst,
435 (PCHAR) pnp_instance_id, 456 (PCHAR) pnp_instance_id,
436 MAX_DEVICE_ID_LEN, 457 MAX_DEVICE_ID_LEN,
437 0, //must be 0 458 0, //must be 0
438 NULL)) //hMachine, we are local 459 NULL)) //hMachine, we are local
439 return FALSE; 460 return FALSE;
440 461
441 /* Now we can use this ID to locate the correct networks interface in registry */ 462 /* Now we can use this ID to locate the correct networks interface in registry */
442 if (ERROR_SUCCESS != RegOpenKeyExA ( 463 if (ERROR_SUCCESS != RegOpenKeyExA (
443 HKEY_LOCAL_MACHINE, 464 HKEY_LOCAL_MACHINE,
444 adapter, 465 adapter,
445 0, 466 0,
446 KEY_READ, 467 KEY_READ,
447 &adapter_key_handle)) 468 &adapter_key_handle))
448 return FALSE; 469 return FALSE;
449 470
450 /* Of course there is a multitude of entries here, with arbitrary names, 471 /* Of course there is a multitude of entries here, with arbitrary names,
@@ -463,14 +484,14 @@ resolve_interface_name ()
463 len = sizeof (adapter_key_handle); 484 len = sizeof (adapter_key_handle);
464 /* optain a subkey of {4D36E972-E325-11CE-BFC1-08002BE10318} */ 485 /* optain a subkey of {4D36E972-E325-11CE-BFC1-08002BE10318} */
465 status = RegEnumKeyExA ( 486 status = RegEnumKeyExA (
466 adapter_key_handle, 487 adapter_key_handle,
467 i, 488 i,
468 instance_key, 489 instance_key,
469 &len, 490 &len,
470 NULL, 491 NULL,
471 NULL, 492 NULL,
472 NULL, 493 NULL,
473 NULL); 494 NULL);
474 495
475 /* this may fail due to one of two reasons: 496 /* this may fail due to one of two reasons:
476 * we are at the end of the list*/ 497 * we are at the end of the list*/
@@ -482,16 +503,16 @@ resolve_interface_name ()
482 503
483 /* prepare our new query string: */ 504 /* prepare our new query string: */
484 snprintf (query_key, 256, "%s\\%s\\Connection", 505 snprintf (query_key, 256, "%s\\%s\\Connection",
485 INTERFACE_REGISTRY_LOCATION, 506 INTERFACE_REGISTRY_LOCATION,
486 instance_key); 507 instance_key);
487 508
488 /* look inside instance_key\\Connection */ 509 /* look inside instance_key\\Connection */
489 status = RegOpenKeyExA ( 510 status = RegOpenKeyExA (
490 HKEY_LOCAL_MACHINE, 511 HKEY_LOCAL_MACHINE,
491 query_key, 512 query_key,
492 0, 513 0,
493 KEY_READ, 514 KEY_READ,
494 &instance_key_handle); 515 &instance_key_handle);
495 516
496 if (status != ERROR_SUCCESS) 517 if (status != ERROR_SUCCESS)
497 continue; 518 continue;
@@ -499,33 +520,40 @@ resolve_interface_name ()
499 /* now, read our PnpInstanceID */ 520 /* now, read our PnpInstanceID */
500 len = sizeof (pnpinstanceid_value); 521 len = sizeof (pnpinstanceid_value);
501 status = RegQueryValueExA (instance_key_handle, 522 status = RegQueryValueExA (instance_key_handle,
502 pnpinstanceid_name, 523 pnpinstanceid_name,
503 NULL, //reserved, always NULL according to MSDN 524 NULL, //reserved, always NULL according to MSDN
504 &data_type, 525 &data_type,
505 (LPBYTE) pnpinstanceid_value, 526 (LPBYTE) pnpinstanceid_value,
506 &len); 527 &len);
507 528
508 if (status != ERROR_SUCCESS || data_type != REG_SZ) 529 if (status != ERROR_SUCCESS || data_type != REG_SZ)
509 goto cleanup; 530 goto cleanup;
510 531
511 /* compare the value we got to our devices PNPInstanceID*/ 532 /* compare the value we got to our devices PNPInstanceID*/
512 if (0 != strncmp (pnpinstanceid_value, pnp_instance_id, 533 if (0 != strncmp (pnpinstanceid_value, pnp_instance_id,
513 sizeof (pnpinstanceid_value) / sizeof (char))) 534 sizeof (pnpinstanceid_value) / sizeof (char)))
514 goto cleanup; 535 goto cleanup;
515 536
516 len = sizeof (device_visible_name); 537 len = sizeof (device_visible_name);
517 status = RegQueryValueExA ( 538 status = RegQueryValueExA (
518 instance_key_handle, 539 instance_key_handle,
519 adaptername_name, 540 adaptername_name,
520 NULL, //reserved, always NULL according to MSDN 541 NULL, //reserved, always NULL according to MSDN
521 &data_type, 542 &data_type,
522 (LPBYTE) device_visible_name, 543 (LPBYTE) device_visible_name,
523 &len); 544 &len);
524 545
525 if (status == ERROR_SUCCESS && data_type == REG_SZ) 546 if (status != ERROR_SUCCESS || data_type != REG_SZ)
526 { 547 goto cleanup;
527 retval = TRUE; 548
528 } 549 /*
550 * we have successfully found OUR instance,
551 * save the device GUID before exiting
552 */
553
554 strncpy (device_guid, instance_key, 256);
555 retval = TRUE;
556
529cleanup: 557cleanup:
530 RegCloseKey (instance_key_handle); 558 RegCloseKey (instance_key_handle);
531 559
@@ -537,36 +565,111 @@ cleanup:
537 return retval; 565 return retval;
538} 566}
539 567
568static boolean
569check_tapw32_version (HANDLE handle)
570{
571 {
572 ULONG version[3];
573 DWORD len;
574 memset (&(version), 0, sizeof (version));
575
576
577 if (DeviceIoControl (handle, TAP_WIN_IOCTL_GET_VERSION,
578 &version, sizeof (version),
579 &version, sizeof (version), &len, NULL))
580 {
581#ifdef TESTING
582 fprintf (stderr, "TAP-Windows Driver Version %d.%d %s",
583 (int) version[0],
584 (int) version[1],
585 (version[2] ? "(DEBUG)" : ""));
586#endif
587 }
588
589 if (version[0] != TAP_WIN_MIN_MAJOR || version[1] < TAP_WIN_MIN_MINOR)
590 {
591 fprintf (stderr, "ERROR: This version of gnunet requires a TAP-Windows driver that is at least version %d.%d!\n",
592 TAP_WIN_MIN_MAJOR,
593 TAP_WIN_MIN_MINOR);
594 return FALSE;
595 }
596 return TRUE;
597 }
598}
599
540/** 600/**
541 * Creates a tun-interface called dev; 601 * Creates a tun-interface called dev;
542 * 602 *
543 * @return the fd to the tun or -1 on error 603 * @return the fd to the tun or -1 on error
544 */ 604 */
545static int 605static HANDLE
546init_tun () 606init_tun ()
547{ 607{
548 int fd = -1; 608 char device_path[256];
609 HANDLE handle;
549 610
550 if (!setup_interface ()) 611 if (!setup_interface ())
551 { 612 {
552 errno = ENODEV; 613 errno = ENODEV;
553 return -1; 614 return INVALID_HANDLE_VALUE;
554 } 615 }
555 616
556 if (!resolve_interface_name ()) 617 if (!resolve_interface_name ())
557 { 618 {
558 errno = ENODEV; 619 errno = ENODEV;
559 return -1; 620 return INVALID_HANDLE_VALUE;
560 } 621 }
561 622
562 //openvpn 623 /* Open Windows TAP-Windows adapter */
563 /* get driver MTU */ 624 snprintf (device_path, sizeof (device_path), "%s%s%s",
564 // tun.c:2869 625 USERMODEDEVICEDIR,
565 626 device_guid,
566 /* tun up: */ 627 TAP_WIN_SUFFIX);
567 // tun.c: 3024 628
568 629 handle = CreateFile (
569 return fd; 630 device_path,
631 GENERIC_READ | GENERIC_WRITE,
632 0, /* was: FILE_SHARE_READ */
633 0,
634 OPEN_EXISTING,
635 FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
636 0
637 );
638
639 if (handle == INVALID_HANDLE_VALUE)
640 {
641 fprintf (stderr, "CreateFile failed on TAP device: %s\n", device_path);
642 return handle;
643 }
644
645 /* get driver version info */
646 if (!check_tapw32_version (handle))
647 {
648 CloseHandle (handle);
649 return INVALID_HANDLE_VALUE;
650 }
651
652 return handle;
653}
654
655static boolean
656tun_up (HANDLE handle)
657{
658 ULONG status = TRUE;
659 DWORD len;
660 if (DeviceIoControl (handle, TAP_WIN_IOCTL_SET_MEDIA_STATUS,
661 &status, sizeof (status),
662 &status, sizeof (status), &len, NULL))
663 {
664 fprintf (stderr, "The TAP-Windows driver ignored our request to set the interface UP (TAP_WIN_IOCTL_SET_MEDIA_STATUS DeviceIoControl call)!\n");
665 return FALSE;
666 }
667
668 /* Wait for the device to go UP, might take some time. */
669 Sleep ((TAP32_POSTUP_WAITTIME)*1000);
670
671 return TRUE;
672
570} 673}
571 674
572/** 675/**
@@ -575,7 +678,7 @@ init_tun ()
575 * @param fd_tun tunnel FD 678 * @param fd_tun tunnel FD
576 */ 679 */
577static void 680static void
578run (int fd_tun) 681run (HANDLE handle)
579{ 682{
580 /* 683 /*
581 * The buffer filled by reading from fd_tun 684 * The buffer filled by reading from fd_tun
@@ -591,19 +694,29 @@ run (int fd_tun)
591 ssize_t bufin_size = 0; 694 ssize_t bufin_size = 0;
592 ssize_t bufin_rpos = 0; 695 ssize_t bufin_rpos = 0;
593 unsigned char *bufin_read = NULL; 696 unsigned char *bufin_read = NULL;
594 /* Hello, I am a stub function! I did my job, yay me! */ 697
595
596 //openvpn 698 //openvpn
597 699 // Set Device to Subnet-Mode?
700 // do we really need tun.c:2925 ?
701 // Why do we also assign IPv4's there??? Foobar??
702
703 /* tun up: */
704 if (!tun_up (handle))
705 goto teardown;
706
707 // tun.c:3038
708
598 // mainloop: 709 // mainloop:
599 // tunnel_point_to_point 710 // tunnel_point_to_point
600 //openvpn.c:62 711 //openvpn.c:62
601 712
713 // init.c:3337
602 /* setup ansync IO */ 714 /* setup ansync IO */
603 //forward.c: 1515 715 //forward.c: 1515
604 716
605 717
606 //teardown: 718teardown:
719 ;
607 //init.c:3472 720 //init.c:3472
608} 721}
609 722
@@ -622,7 +735,7 @@ int
622main (int argc, char **argv) 735main (int argc, char **argv)
623{ 736{
624 char hwid[LINE_LEN]; 737 char hwid[LINE_LEN];
625 int fd_tun; 738 HANDLE handle;
626 int global_ret; 739 int global_ret;
627 740
628 if (6 != argc) 741 if (6 != argc)
@@ -640,10 +753,10 @@ main (int argc, char **argv)
640 * as additional hardware-id for our device. 753 * as additional hardware-id for our device.
641 */ 754 */
642 snprintf (secondary_hwid, LINE_LEN / 2, "%s-%d", 755 snprintf (secondary_hwid, LINE_LEN / 2, "%s-%d",
643 hwid, 756 hwid,
644 _getpid ()); 757 _getpid ());
645 758
646 if (-1 == (fd_tun = init_tun ())) 759 if (INVALID_HANDLE_VALUE == (handle = init_tun ()))
647 { 760 {
648 fprintf (stderr, "Fatal: could not initialize virtual-interface %s with IPv6 %s/%s and IPv4 %s/%s\n", 761 fprintf (stderr, "Fatal: could not initialize virtual-interface %s with IPv6 %s/%s and IPv4 %s/%s\n",
649 hwid, 762 hwid,
@@ -681,7 +794,7 @@ main (int argc, char **argv)
681 // tap_allow_nonadmin_access 794 // tap_allow_nonadmin_access
682 //tun.c:2023 795 //tun.c:2023
683 796
684 run (fd_tun); 797 run (handle);
685 global_ret = 0; 798 global_ret = 0;
686cleanup: 799cleanup:
687 remove_interface (); 800 remove_interface ();