diff options
author | Christian Fuchs <christian.fuchs@cfuchs.net> | 2013-01-17 14:23:24 +0000 |
---|---|---|
committer | Christian Fuchs <christian.fuchs@cfuchs.net> | 2013-01-17 14:23:24 +0000 |
commit | 98ff7cc0d495e235024467467c77409ac5359253 (patch) | |
tree | 1c939e8b12a5d166c87ec42477215026db407ee6 /src/vpn | |
parent | b2671f5cb4e45f6902b0cfe05147b18d36bb2788 (diff) | |
download | gnunet-98ff7cc0d495e235024467467c77409ac5359253.tar.gz gnunet-98ff7cc0d495e235024467467c77409ac5359253.zip |
* a little bit of bugfixing
* added functionality to remove ip addresses from our interfaces
* some formatting work
* added rety-loop for the interface-name resolver (retry up to 30
seconds)
* set new ipv4/v6 addresses to be forgotten on bootup (store=active)
* adjusted some debug output (added a few \n here and there)
Diffstat (limited to 'src/vpn')
-rw-r--r-- | src/vpn/gnunet-helper-vpn-windows.c | 600 |
1 files changed, 340 insertions, 260 deletions
diff --git a/src/vpn/gnunet-helper-vpn-windows.c b/src/vpn/gnunet-helper-vpn-windows.c index 5249bfd70..05a0aeeff 100644 --- a/src/vpn/gnunet-helper-vpn-windows.c +++ b/src/vpn/gnunet-helper-vpn-windows.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <ddk/cfgmgr32.h> | 37 | #include <ddk/cfgmgr32.h> |
38 | #include <ddk/newdev.h> | 38 | #include <ddk/newdev.h> |
39 | #include <Winsock2.h> | 39 | #include <Winsock2.h> |
40 | #include <time.h> | ||
40 | #include "platform.h" | 41 | #include "platform.h" |
41 | #include "tap-windows.h" | 42 | #include "tap-windows.h" |
42 | /** | 43 | /** |
@@ -184,6 +185,7 @@ execute_shellcommand (const char *command) | |||
184 | return EINVAL; | 185 | return EINVAL; |
185 | 186 | ||
186 | #ifdef TESTING | 187 | #ifdef TESTING |
188 | fprintf (stderr, "DEBUG: Command output: \n"); | ||
187 | char output[LINE_LEN]; | 189 | char output[LINE_LEN]; |
188 | while (NULL != fgets (output, sizeof (output), pipe)) | 190 | while (NULL != fgets (output, sizeof (output), pipe)) |
189 | fprintf (stderr, "%s", output); | 191 | fprintf (stderr, "%s", output); |
@@ -212,7 +214,7 @@ set_address6 (const char *address, unsigned long prefix_len) | |||
212 | sa6.sin6_family = AF_INET6; | 214 | sa6.sin6_family = AF_INET6; |
213 | if (1 != inet_pton (AF_INET6, address, &sa6.sin6_addr.s6_addr)) | 215 | if (1 != inet_pton (AF_INET6, address, &sa6.sin6_addr.s6_addr)) |
214 | { | 216 | { |
215 | fprintf (stderr, "Failed to parse address `%s': %s\n", address, | 217 | fprintf (stderr, "ERROR: Failed to parse address `%s': %s\n", address, |
216 | strerror (errno)); | 218 | strerror (errno)); |
217 | return -1; | 219 | return -1; |
218 | } | 220 | } |
@@ -221,7 +223,7 @@ set_address6 (const char *address, unsigned long prefix_len) | |||
221 | * prepare the command | 223 | * prepare the command |
222 | */ | 224 | */ |
223 | snprintf (command, LINE_LEN, | 225 | snprintf (command, LINE_LEN, |
224 | "netsh interface ipv6 add address \"%s\" %s/%d", | 226 | "netsh interface ipv6 add address \"%s\" %s/%d store=active", |
225 | device_visible_name, address, prefix_len); | 227 | device_visible_name, address, prefix_len); |
226 | /* | 228 | /* |
227 | * Set the address | 229 | * Set the address |
@@ -230,11 +232,42 @@ set_address6 (const char *address, unsigned long prefix_len) | |||
230 | 232 | ||
231 | /* Did it work?*/ | 233 | /* Did it work?*/ |
232 | if (0 != ret) | 234 | if (0 != ret) |
233 | fprintf (stderr, "Setting IPv6 address failed: %s\n", strerror (ret)); | 235 | fprintf (stderr, "FATAL: Setting IPv6 address failed: %s\n", strerror (ret)); |
234 | return ret; | 236 | return ret; |
235 | } | 237 | } |
236 | 238 | ||
237 | /** | 239 | /** |
240 | * @brief Removes the IPv6-Address given in address from the interface dev | ||
241 | * | ||
242 | * @param dev the interface to remove | ||
243 | * @param address the IPv4-Address | ||
244 | * @param mask the netmask | ||
245 | */ | ||
246 | static void | ||
247 | remove_address6 (const char *address) | ||
248 | { | ||
249 | char command[LINE_LEN]; | ||
250 | int ret = EINVAL; | ||
251 | |||
252 | // sanity checking was already done in set_address6 | ||
253 | /* | ||
254 | * prepare the command | ||
255 | */ | ||
256 | snprintf (command, LINE_LEN, | ||
257 | "netsh interface ipv6 delete address \"%s\" store=persistent", | ||
258 | device_visible_name, address); | ||
259 | /* | ||
260 | * Set the address | ||
261 | */ | ||
262 | ret = execute_shellcommand (command); | ||
263 | |||
264 | /* Did it work?*/ | ||
265 | if (0 != ret) | ||
266 | fprintf (stderr, "FATAL: removing IPv6 address failed: %s\n", strerror (ret)); | ||
267 | } | ||
268 | |||
269 | |||
270 | /** | ||
238 | * @brief Sets the IPv4-Address given in address on the interface dev | 271 | * @brief Sets the IPv4-Address given in address on the interface dev |
239 | * | 272 | * |
240 | * @param dev the interface to configure | 273 | * @param dev the interface to configure |
@@ -255,7 +288,7 @@ set_address4 (const char *address, const char *mask) | |||
255 | */ | 288 | */ |
256 | if (1 != inet_pton (AF_INET, address, &addr.sin_addr.s_addr)) | 289 | if (1 != inet_pton (AF_INET, address, &addr.sin_addr.s_addr)) |
257 | { | 290 | { |
258 | fprintf (stderr, "Failed to parse address `%s': %s\n", address, | 291 | fprintf (stderr, "ERROR: Failed to parse address `%s': %s\n", address, |
259 | strerror (errno)); | 292 | strerror (errno)); |
260 | return -1; | 293 | return -1; |
261 | } | 294 | } |
@@ -266,7 +299,7 @@ set_address4 (const char *address, const char *mask) | |||
266 | * prepare the command | 299 | * prepare the command |
267 | */ | 300 | */ |
268 | snprintf (command, LINE_LEN, | 301 | snprintf (command, LINE_LEN, |
269 | "netsh interface ipv4 add address \"%s\" %s %s", | 302 | "netsh interface ipv4 add address \"%s\" %s %s store=active", |
270 | device_visible_name, address, mask); | 303 | device_visible_name, address, mask); |
271 | /* | 304 | /* |
272 | * Set the address | 305 | * Set the address |
@@ -275,11 +308,42 @@ set_address4 (const char *address, const char *mask) | |||
275 | 308 | ||
276 | /* Did it work?*/ | 309 | /* Did it work?*/ |
277 | if (0 != ret) | 310 | if (0 != ret) |
278 | fprintf (stderr, "Setting IPv4 address failed: %s\n", strerror (ret)); | 311 | fprintf (stderr, "FATAL: Setting IPv4 address failed: %s\n", strerror (ret)); |
279 | return ret; | 312 | return ret; |
280 | } | 313 | } |
281 | 314 | ||
282 | /** | 315 | /** |
316 | * @brief Removes the IPv4-Address given in address from the interface dev | ||
317 | * | ||
318 | * @param dev the interface to remove | ||
319 | * @param address the IPv4-Address | ||
320 | * @param mask the netmask | ||
321 | */ | ||
322 | static void | ||
323 | remove_address4 (const char *address) | ||
324 | { | ||
325 | char command[LINE_LEN]; | ||
326 | int ret = EINVAL; | ||
327 | |||
328 | // sanity checking was already done in set_address4 | ||
329 | |||
330 | /* | ||
331 | * prepare the command | ||
332 | */ | ||
333 | snprintf (command, LINE_LEN, | ||
334 | "netsh interface ipv4 delete address \"%s\" gateway=all store=persistent", | ||
335 | device_visible_name, address); | ||
336 | /* | ||
337 | * Set the address | ||
338 | */ | ||
339 | ret = execute_shellcommand (command); | ||
340 | |||
341 | /* Did it work?*/ | ||
342 | if (0 != ret) | ||
343 | fprintf (stderr, "FATAL: removing IPv4 address failed: %s\n", strerror (ret)); | ||
344 | } | ||
345 | |||
346 | /** | ||
283 | * Setup a new virtual interface to use for tunneling. | 347 | * Setup a new virtual interface to use for tunneling. |
284 | * | 348 | * |
285 | * @return: TRUE if setup was successful, else FALSE | 349 | * @return: TRUE if setup was successful, else FALSE |
@@ -327,7 +391,7 @@ setup_interface () | |||
327 | /** | 391 | /** |
328 | * Bootstrap our device info using the drivers inf-file | 392 | * Bootstrap our device info using the drivers inf-file |
329 | */ | 393 | */ |
330 | if (!SetupDiGetINFClassA (inf_file_path, | 394 | if ( ! SetupDiGetINFClassA (inf_file_path, |
331 | &class_guid, | 395 | &class_guid, |
332 | class_name, sizeof (class_name) / sizeof (char), | 396 | class_name, sizeof (class_name) / sizeof (char), |
333 | NULL)) | 397 | NULL)) |
@@ -342,7 +406,7 @@ setup_interface () | |||
342 | return FALSE; | 406 | return FALSE; |
343 | 407 | ||
344 | DeviceNode.cbSize = sizeof (SP_DEVINFO_DATA); | 408 | DeviceNode.cbSize = sizeof (SP_DEVINFO_DATA); |
345 | if (!SetupDiCreateDeviceInfoA (DeviceInfo, | 409 | if ( ! SetupDiCreateDeviceInfoA (DeviceInfo, |
346 | class_name, | 410 | class_name, |
347 | &class_guid, | 411 | &class_guid, |
348 | NULL, | 412 | NULL, |
@@ -352,7 +416,7 @@ setup_interface () | |||
352 | return FALSE; | 416 | return FALSE; |
353 | 417 | ||
354 | /* Deploy all the information collected into the registry */ | 418 | /* Deploy all the information collected into the registry */ |
355 | if (!SetupDiSetDeviceRegistryPropertyA (DeviceInfo, | 419 | if ( ! SetupDiSetDeviceRegistryPropertyA (DeviceInfo, |
356 | &DeviceNode, | 420 | &DeviceNode, |
357 | SPDRP_HARDWAREID, | 421 | SPDRP_HARDWAREID, |
358 | (LPBYTE) hwidlist, | 422 | (LPBYTE) hwidlist, |
@@ -360,14 +424,14 @@ setup_interface () | |||
360 | return FALSE; | 424 | return FALSE; |
361 | 425 | ||
362 | /* Install our new class(=device) into the system */ | 426 | /* Install our new class(=device) into the system */ |
363 | if (!SetupDiCallClassInstaller (DIF_REGISTERDEVICE, | 427 | if ( ! SetupDiCallClassInstaller (DIF_REGISTERDEVICE, |
364 | DeviceInfo, | 428 | DeviceInfo, |
365 | &DeviceNode)) | 429 | &DeviceNode)) |
366 | return FALSE; | 430 | return FALSE; |
367 | 431 | ||
368 | /* This system call tends to take a while (several seconds!) on | 432 | /* This system call tends to take a while (several seconds!) on |
369 | "modern" Windoze systems */ | 433 | "modern" Windoze systems */ |
370 | if (!UpdateDriverForPlugAndPlayDevicesA (NULL, | 434 | if ( ! UpdateDriverForPlugAndPlayDevicesA (NULL, |
371 | secondary_hwid, | 435 | secondary_hwid, |
372 | inf_file_path, | 436 | inf_file_path, |
373 | INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE, | 437 | INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE, |
@@ -399,7 +463,7 @@ remove_interface () | |||
399 | * 1. Prepare our existing device information set, and place the | 463 | * 1. Prepare our existing device information set, and place the |
400 | * uninstall related information into the structure | 464 | * uninstall related information into the structure |
401 | */ | 465 | */ |
402 | if (!SetupDiSetClassInstallParamsA (DeviceInfo, | 466 | if ( ! SetupDiSetClassInstallParamsA (DeviceInfo, |
403 | (PSP_DEVINFO_DATA) & DeviceNode, | 467 | (PSP_DEVINFO_DATA) & DeviceNode, |
404 | &remove.ClassInstallHeader, | 468 | &remove.ClassInstallHeader, |
405 | sizeof (remove))) | 469 | sizeof (remove))) |
@@ -407,7 +471,7 @@ remove_interface () | |||
407 | /* | 471 | /* |
408 | * 2. Uninstall the virtual interface using the class installer | 472 | * 2. Uninstall the virtual interface using the class installer |
409 | */ | 473 | */ |
410 | if (!SetupDiCallClassInstaller (DIF_REMOVE, | 474 | if ( ! SetupDiCallClassInstaller (DIF_REMOVE, |
411 | DeviceInfo, | 475 | DeviceInfo, |
412 | (PSP_DEVINFO_DATA) & DeviceNode)) | 476 | (PSP_DEVINFO_DATA) & DeviceNode)) |
413 | return FALSE; | 477 | return FALSE; |
@@ -426,19 +490,16 @@ remove_interface () | |||
426 | static boolean | 490 | static boolean |
427 | resolve_interface_name () | 491 | resolve_interface_name () |
428 | { | 492 | { |
429 | |||
430 | SP_DEVINFO_LIST_DETAIL_DATA device_details; | 493 | SP_DEVINFO_LIST_DETAIL_DATA device_details; |
431 | char pnp_instance_id [MAX_DEVICE_ID_LEN]; | 494 | char pnp_instance_id [MAX_DEVICE_ID_LEN]; |
432 | HKEY adapter_key_handle; | 495 | HKEY adapter_key_handle; |
433 | LONG status; | 496 | LONG status; |
434 | DWORD len; | 497 | DWORD len; |
435 | int i = 0; | 498 | int i = 0; |
499 | int retrys; | ||
436 | boolean retval = FALSE; | 500 | boolean retval = FALSE; |
437 | char adapter[] = INTERFACE_REGISTRY_LOCATION; | 501 | char adapter[] = INTERFACE_REGISTRY_LOCATION; |
438 | 502 | ||
439 | /* Registry is incredibly slow, wait a few seconds for it to refresh */ | ||
440 | sleep (5); // FIXME: instead use sleep (1) in a retrying loop; maybe even nanosleep for 50-250ms instead | ||
441 | |||
442 | /* We can obtain the PNP instance ID from our setupapi handle */ | 503 | /* We can obtain the PNP instance ID from our setupapi handle */ |
443 | device_details.cbSize = sizeof (device_details); | 504 | device_details.cbSize = sizeof (device_details); |
444 | if (CR_SUCCESS != CM_Get_Device_ID_ExA (DeviceNode.DevInst, | 505 | if (CR_SUCCESS != CM_Get_Device_ID_ExA (DeviceNode.DevInst, |
@@ -448,142 +509,145 @@ resolve_interface_name () | |||
448 | NULL)) //hMachine, we are local | 509 | NULL)) //hMachine, we are local |
449 | return FALSE; | 510 | return FALSE; |
450 | 511 | ||
451 | /* Now we can use this ID to locate the correct networks interface in registry */ | 512 | /* Registry is incredibly slow, retry for up to 30 seconds to allow registry to refresh */ |
452 | if (ERROR_SUCCESS != RegOpenKeyExA ( | 513 | for (retrys = 0; retrys < 120 && !retval; retrys++) |
453 | HKEY_LOCAL_MACHINE, | ||
454 | adapter, | ||
455 | 0, | ||
456 | KEY_READ, | ||
457 | &adapter_key_handle)) | ||
458 | return FALSE; | ||
459 | |||
460 | /* Of course there is a multitude of entries here, with arbitrary names, | ||
461 | * thus we need to iterate through there. | ||
462 | */ | ||
463 | while (!retval) | ||
464 | { | 514 | { |
465 | char instance_key[256]; | 515 | /* sleep for 250ms*/ |
466 | char query_key [256]; | 516 | Sleep (250); |
467 | HKEY instance_key_handle; | 517 | |
468 | char pnpinstanceid_name[] = "PnpInstanceID"; | 518 | /* Now we can use this ID to locate the correct networks interface in registry */ |
469 | char pnpinstanceid_value[256]; | 519 | if (ERROR_SUCCESS != RegOpenKeyExA ( |
470 | char adaptername_name[] = "Name"; | 520 | HKEY_LOCAL_MACHINE, |
471 | DWORD data_type; | 521 | adapter, |
472 | 522 | 0, | |
473 | len = 256 * sizeof (char); | 523 | KEY_READ, |
474 | /* optain a subkey of {4D36E972-E325-11CE-BFC1-08002BE10318} */ | 524 | &adapter_key_handle)) |
475 | status = RegEnumKeyExA ( | 525 | return FALSE; |
476 | adapter_key_handle, | ||
477 | i, | ||
478 | instance_key, | ||
479 | &len, | ||
480 | NULL, | ||
481 | NULL, | ||
482 | NULL, | ||
483 | NULL); | ||
484 | |||
485 | /* this may fail due to one of two reasons: | ||
486 | * we are at the end of the list*/ | ||
487 | if (ERROR_NO_MORE_ITEMS == status) | ||
488 | break; | ||
489 | // * we found a broken registry key, continue with the next key. | ||
490 | if (ERROR_SUCCESS != status) | ||
491 | goto cleanup; | ||
492 | |||
493 | /* prepare our new query string: */ | ||
494 | snprintf (query_key, 256, "%s\\%s\\Connection", | ||
495 | adapter, | ||
496 | instance_key); | ||
497 | |||
498 | /* look inside instance_key\\Connection */ | ||
499 | status = RegOpenKeyExA ( | ||
500 | HKEY_LOCAL_MACHINE, | ||
501 | query_key, | ||
502 | 0, | ||
503 | KEY_READ, | ||
504 | &instance_key_handle); | ||
505 | |||
506 | if (status != ERROR_SUCCESS) | ||
507 | goto cleanup; | ||
508 | |||
509 | /* now, read our PnpInstanceID */ | ||
510 | len = sizeof (pnpinstanceid_value); | ||
511 | status = RegQueryValueExA (instance_key_handle, | ||
512 | pnpinstanceid_name, | ||
513 | NULL, //reserved, always NULL according to MSDN | ||
514 | &data_type, | ||
515 | (LPBYTE) pnpinstanceid_value, | ||
516 | &len); | ||
517 | |||
518 | if (status != ERROR_SUCCESS || data_type != REG_SZ) | ||
519 | goto cleanup; | ||
520 | |||
521 | /* compare the value we got to our devices PNPInstanceID*/ | ||
522 | if (0 != strncmp (pnpinstanceid_value, pnp_instance_id, | ||
523 | sizeof (pnpinstanceid_value) / sizeof (char))) | ||
524 | goto cleanup; | ||
525 | |||
526 | len = sizeof (device_visible_name); | ||
527 | status = RegQueryValueExA ( | ||
528 | instance_key_handle, | ||
529 | adaptername_name, | ||
530 | NULL, //reserved, always NULL according to MSDN | ||
531 | &data_type, | ||
532 | (LPBYTE) device_visible_name, | ||
533 | &len); | ||
534 | |||
535 | if (status != ERROR_SUCCESS || data_type != REG_SZ) | ||
536 | goto cleanup; | ||
537 | 526 | ||
538 | /* | 527 | /* Of course there is a multitude of entries here, with arbitrary names, |
539 | * we have successfully found OUR instance, | 528 | * thus we need to iterate through there. |
540 | * save the device GUID before exiting | ||
541 | */ | 529 | */ |
542 | 530 | while ( ! retval) | |
543 | strncpy (device_guid, instance_key, 256); | 531 | { |
544 | retval = TRUE; | 532 | char instance_key[256]; |
533 | char query_key [256]; | ||
534 | HKEY instance_key_handle; | ||
535 | char pnpinstanceid_name[] = "PnpInstanceID"; | ||
536 | char pnpinstanceid_value[256]; | ||
537 | char adaptername_name[] = "Name"; | ||
538 | DWORD data_type; | ||
539 | |||
540 | len = 256 * sizeof (char); | ||
541 | /* optain a subkey of {4D36E972-E325-11CE-BFC1-08002BE10318} */ | ||
542 | status = RegEnumKeyExA ( | ||
543 | adapter_key_handle, | ||
544 | i, | ||
545 | instance_key, | ||
546 | &len, | ||
547 | NULL, | ||
548 | NULL, | ||
549 | NULL, | ||
550 | NULL); | ||
551 | |||
552 | /* this may fail due to one of two reasons: | ||
553 | * we are at the end of the list*/ | ||
554 | if (ERROR_NO_MORE_ITEMS == status) | ||
555 | break; | ||
556 | // * we found a broken registry key, continue with the next key. | ||
557 | if (ERROR_SUCCESS != status) | ||
558 | goto cleanup; | ||
559 | |||
560 | /* prepare our new query string: */ | ||
561 | snprintf (query_key, 256, "%s\\%s\\Connection", | ||
562 | adapter, | ||
563 | instance_key); | ||
564 | |||
565 | /* look inside instance_key\\Connection */ | ||
566 | status = RegOpenKeyExA ( | ||
567 | HKEY_LOCAL_MACHINE, | ||
568 | query_key, | ||
569 | 0, | ||
570 | KEY_READ, | ||
571 | &instance_key_handle); | ||
572 | |||
573 | if (status != ERROR_SUCCESS) | ||
574 | goto cleanup; | ||
575 | |||
576 | /* now, read our PnpInstanceID */ | ||
577 | len = sizeof (pnpinstanceid_value); | ||
578 | status = RegQueryValueExA (instance_key_handle, | ||
579 | pnpinstanceid_name, | ||
580 | NULL, //reserved, always NULL according to MSDN | ||
581 | &data_type, | ||
582 | (LPBYTE) pnpinstanceid_value, | ||
583 | &len); | ||
584 | |||
585 | if (status != ERROR_SUCCESS || data_type != REG_SZ) | ||
586 | goto cleanup; | ||
587 | |||
588 | /* compare the value we got to our devices PNPInstanceID*/ | ||
589 | if (0 != strncmp (pnpinstanceid_value, pnp_instance_id, | ||
590 | sizeof (pnpinstanceid_value) / sizeof (char))) | ||
591 | goto cleanup; | ||
592 | |||
593 | len = sizeof (device_visible_name); | ||
594 | status = RegQueryValueExA ( | ||
595 | instance_key_handle, | ||
596 | adaptername_name, | ||
597 | NULL, //reserved, always NULL according to MSDN | ||
598 | &data_type, | ||
599 | (LPBYTE) device_visible_name, | ||
600 | &len); | ||
601 | |||
602 | if (status != ERROR_SUCCESS || data_type != REG_SZ) | ||
603 | goto cleanup; | ||
604 | |||
605 | /* | ||
606 | * we have successfully found OUR instance, | ||
607 | * save the device GUID before exiting | ||
608 | */ | ||
609 | |||
610 | strncpy (device_guid, instance_key, 256); | ||
611 | retval = TRUE; | ||
612 | fprintf (stderr, "DEBUG: Interface Name lookup succeeded on retry %d\n", retrys); | ||
545 | 613 | ||
546 | cleanup: | 614 | cleanup: |
547 | RegCloseKey (instance_key_handle); | 615 | RegCloseKey (instance_key_handle); |
548 | 616 | ||
549 | ++i; | 617 | ++i; |
550 | } | 618 | } |
551 | |||
552 | RegCloseKey (adapter_key_handle); | ||
553 | 619 | ||
620 | RegCloseKey (adapter_key_handle); | ||
621 | } | ||
554 | return retval; | 622 | return retval; |
555 | } | 623 | } |
556 | 624 | ||
557 | static boolean | 625 | static boolean |
558 | check_tapw32_version (HANDLE handle) | 626 | check_tapw32_version (HANDLE handle) |
559 | { | 627 | { |
560 | { | 628 | ULONG version[3]; |
561 | ULONG version[3]; | 629 | DWORD len; |
562 | DWORD len; | 630 | memset (&(version), 0, sizeof (version)); |
563 | memset (&(version), 0, sizeof (version)); | ||
564 | 631 | ||
565 | 632 | ||
566 | if (DeviceIoControl (handle, TAP_WIN_IOCTL_GET_VERSION, | 633 | if (DeviceIoControl (handle, TAP_WIN_IOCTL_GET_VERSION, |
567 | &version, sizeof (version), | 634 | &version, sizeof (version), |
568 | &version, sizeof (version), &len, NULL)) | 635 | &version, sizeof (version), &len, NULL)) |
569 | { | 636 | { |
570 | #ifdef TESTING | 637 | fprintf (stderr, "INFO: TAP-Windows Driver Version %d.%d %s\n", |
571 | fprintf (stderr, "TAP-Windows Driver Version %d.%d %s", | 638 | (int) version[0], |
572 | (int) version[0], | 639 | (int) version[1], |
573 | (int) version[1], | 640 | (version[2] ? "(DEBUG)" : "")); |
574 | (version[2] ? "(DEBUG)" : "")); | 641 | } |
575 | #endif | ||
576 | } | ||
577 | 642 | ||
578 | if (version[0] != TAP_WIN_MIN_MAJOR || version[1] < TAP_WIN_MIN_MINOR) | 643 | if (version[0] != TAP_WIN_MIN_MAJOR || version[1] < TAP_WIN_MIN_MINOR) |
579 | { | 644 | { |
580 | fprintf (stderr, "ERROR: This version of gnunet requires a TAP-Windows driver that is at least version %d.%d!\n", | 645 | fprintf (stderr, "FATAL: This version of gnunet requires a TAP-Windows driver that is at least version %d.%d!\n", |
581 | TAP_WIN_MIN_MAJOR, | 646 | TAP_WIN_MIN_MAJOR, |
582 | TAP_WIN_MIN_MINOR); | 647 | TAP_WIN_MIN_MINOR); |
583 | return FALSE; | 648 | return FALSE; |
584 | } | 649 | } |
585 | return TRUE; | 650 | return TRUE; |
586 | } | ||
587 | } | 651 | } |
588 | 652 | ||
589 | /** | 653 | /** |
@@ -597,13 +661,13 @@ init_tun () | |||
597 | char device_path[256]; | 661 | char device_path[256]; |
598 | HANDLE handle; | 662 | HANDLE handle; |
599 | 663 | ||
600 | if (!setup_interface ()) | 664 | if ( ! setup_interface ()) |
601 | { | 665 | { |
602 | errno = ENODEV; | 666 | errno = ENODEV; |
603 | return INVALID_HANDLE_VALUE; | 667 | return INVALID_HANDLE_VALUE; |
604 | } | 668 | } |
605 | 669 | ||
606 | if (!resolve_interface_name ()) | 670 | if ( ! resolve_interface_name ()) |
607 | { | 671 | { |
608 | errno = ENODEV; | 672 | errno = ENODEV; |
609 | return INVALID_HANDLE_VALUE; | 673 | return INVALID_HANDLE_VALUE; |
@@ -627,12 +691,12 @@ init_tun () | |||
627 | 691 | ||
628 | if (handle == INVALID_HANDLE_VALUE) | 692 | if (handle == INVALID_HANDLE_VALUE) |
629 | { | 693 | { |
630 | fprintf (stderr, "CreateFile failed on TAP device: %s\n", device_path); | 694 | fprintf (stderr, "FATAL: CreateFile failed on TAP device: %s\n", device_path); |
631 | return handle; | 695 | return handle; |
632 | } | 696 | } |
633 | 697 | ||
634 | /* get driver version info */ | 698 | /* get driver version info */ |
635 | if (!check_tapw32_version (handle)) | 699 | if ( ! check_tapw32_version (handle)) |
636 | { | 700 | { |
637 | CloseHandle (handle); | 701 | CloseHandle (handle); |
638 | return INVALID_HANDLE_VALUE; | 702 | return INVALID_HANDLE_VALUE; |
@@ -654,11 +718,11 @@ tun_up (HANDLE handle) | |||
654 | { | 718 | { |
655 | ULONG status = TRUE; | 719 | ULONG status = TRUE; |
656 | DWORD len; | 720 | DWORD len; |
657 | if (DeviceIoControl (handle, TAP_WIN_IOCTL_SET_MEDIA_STATUS, | 721 | if ( ! DeviceIoControl (handle, TAP_WIN_IOCTL_SET_MEDIA_STATUS, |
658 | &status, sizeof (status), | 722 | &status, sizeof (status), |
659 | &status, sizeof (status), &len, NULL)) | 723 | &status, sizeof (status), &len, NULL)) |
660 | { | 724 | { |
661 | fprintf (stderr, "The TAP-Windows driver ignored our request to set the interface UP (TAP_WIN_IOCTL_SET_MEDIA_STATUS DeviceIoControl call)!\n"); | 725 | fprintf (stderr, "FATAL: TAP driver ignored request to UP interface (DeviceIoControl call)!\n"); |
662 | return FALSE; | 726 | return FALSE; |
663 | } | 727 | } |
664 | 728 | ||
@@ -699,113 +763,113 @@ attempt_read (struct io_facility * input_facility, | |||
699 | struct io_facility * output_facility) | 763 | struct io_facility * output_facility) |
700 | { | 764 | { |
701 | switch (input_facility->facility_state) | 765 | switch (input_facility->facility_state) |
702 | { | ||
703 | case IOSTATE_READY: | ||
704 | { | 766 | { |
705 | if (!ResetEvent (input_facility->overlapped.hEvent)) | 767 | case IOSTATE_READY: |
706 | { | 768 | { |
707 | return FALSE; | 769 | if ( ! ResetEvent (input_facility->overlapped.hEvent)) |
708 | } | 770 | { |
709 | input_facility->status = ReadFile (input_facility->handle, | ||
710 | input_facility->buffer, | ||
711 | MAX_SIZE, | ||
712 | &input_facility->buffer_size, | ||
713 | &input_facility->overlapped); | ||
714 | |||
715 | /* Check how the task is handled */ | ||
716 | if (input_facility->status) | ||
717 | {/* async event processed immediately*/ | ||
718 | |||
719 | /* reset event manually*/ | ||
720 | if (!SetEvent (input_facility->overlapped.hEvent)) | ||
721 | return FALSE; | ||
722 | |||
723 | /* we successfully read something from the TAP and now need to | ||
724 | * send it our via STDOUT. Is that possible at the moment? */ | ||
725 | if ((IOSTATE_READY == output_facility->facility_state || | ||
726 | IOSTATE_WAITING == output_facility->facility_state) | ||
727 | && 0 < input_facility->buffer_size) | ||
728 | { /* hand over this buffers content */ | ||
729 | memcpy (output_facility->buffer, | ||
730 | input_facility->buffer, | ||
731 | MAX_SIZE); | ||
732 | output_facility->buffer_size = input_facility->buffer_size; | ||
733 | output_facility->facility_state = IOSTATE_READY; | ||
734 | } | ||
735 | else if (0 < input_facility->buffer_size) | ||
736 | { /* If we have have read our buffer, wait for our write-partner*/ | ||
737 | input_facility->facility_state = IOSTATE_WAITING; | ||
738 | // TODO: shall we attempt to fill our buffer or should we wait for our write-partner to finish? | ||
739 | } | ||
740 | } | ||
741 | else /* operation was either queued or failed*/ | ||
742 | { | ||
743 | int err = GetLastError (); | ||
744 | if (ERROR_IO_PENDING == err) | ||
745 | { /* operation queued */ | ||
746 | input_facility->facility_state = IOSTATE_QUEUED; | ||
747 | } | ||
748 | else | ||
749 | { /* error occurred, let the rest of the elements finish */ | ||
750 | input_facility->path_open = FALSE; | ||
751 | input_facility->facility_state = IOSTATE_FAILED; | ||
752 | if (IOSTATE_WAITING == output_facility->facility_state) | ||
753 | output_facility->path_open = FALSE; | ||
754 | |||
755 | fprintf (stderr, "Fatal: Read from handle failed, allowing write to finish!\n"); | ||
756 | } | ||
757 | } | ||
758 | } | ||
759 | return TRUE; | ||
760 | // We are queued and should check if the read has finished | ||
761 | case IOSTATE_QUEUED: | ||
762 | { | ||
763 | // there was an operation going on already, check if that has completed now. | ||
764 | input_facility->status = GetOverlappedResult (input_facility->handle, | ||
765 | &input_facility->overlapped, | ||
766 | &input_facility->buffer_size, | ||
767 | FALSE); | ||
768 | if (input_facility->status) | ||
769 | {/* successful return for a queued operation */ | ||
770 | if (!ResetEvent (input_facility->overlapped.hEvent)) | ||
771 | return FALSE; | 771 | return FALSE; |
772 | 772 | } | |
773 | /* we successfully read something from the TAP and now need to | 773 | input_facility->status = ReadFile (input_facility->handle, |
774 | * send it our via STDOUT. Is that possible at the moment? */ | 774 | input_facility->buffer, |
775 | if ((IOSTATE_READY == output_facility->facility_state || | 775 | MAX_SIZE, |
776 | IOSTATE_WAITING == output_facility->facility_state) | 776 | &input_facility->buffer_size, |
777 | && 0 < input_facility->buffer_size) | 777 | &input_facility->overlapped); |
778 | { /* hand over this buffers content */ | 778 | |
779 | memcpy (output_facility->buffer, | 779 | /* Check how the task is handled */ |
780 | input_facility->buffer, | 780 | if (input_facility->status) |
781 | MAX_SIZE); | 781 | {/* async event processed immediately*/ |
782 | output_facility->buffer_size = input_facility->buffer_size; | 782 | |
783 | output_facility->facility_state = IOSTATE_READY; | 783 | /* reset event manually*/ |
784 | input_facility->facility_state = IOSTATE_READY; | 784 | if ( ! SetEvent (input_facility->overlapped.hEvent)) |
785 | } | 785 | return FALSE; |
786 | else if (0 < input_facility->buffer_size) | 786 | |
787 | { /* If we have have read our buffer, wait for our write-partner*/ | 787 | /* we successfully read something from the TAP and now need to |
788 | input_facility->facility_state = IOSTATE_WAITING; | 788 | * send it our via STDOUT. Is that possible at the moment? */ |
789 | // TODO: shall we attempt to fill our buffer or should we wait for our write-partner to finish? | 789 | if ((IOSTATE_READY == output_facility->facility_state || |
790 | } | 790 | IOSTATE_WAITING == output_facility->facility_state) |
791 | } | 791 | && 0 < input_facility->buffer_size) |
792 | else | 792 | { /* hand over this buffers content */ |
793 | { /* operation still pending/queued or failed? */ | 793 | memcpy (output_facility->buffer, |
794 | int err = GetLastError (); | 794 | input_facility->buffer, |
795 | if (ERROR_IO_INCOMPLETE != err && ERROR_IO_PENDING != err) | 795 | MAX_SIZE); |
796 | { /* error occurred, let the rest of the elements finish */ | 796 | output_facility->buffer_size = input_facility->buffer_size; |
797 | input_facility->path_open = FALSE; | 797 | output_facility->facility_state = IOSTATE_READY; |
798 | input_facility->facility_state = IOSTATE_FAILED; | 798 | } |
799 | if (IOSTATE_WAITING == output_facility->facility_state) | 799 | else if (0 < input_facility->buffer_size) |
800 | output_facility->path_open = FALSE; | 800 | { /* If we have have read our buffer, wait for our write-partner*/ |
801 | fprintf (stderr, "Fatal: Read from handle failed, allowing write to finish!\n"); | 801 | input_facility->facility_state = IOSTATE_WAITING; |
802 | } | 802 | // TODO: shall we attempt to fill our buffer or should we wait for our write-partner to finish? |
803 | } | 803 | } |
804 | } | ||
805 | else /* operation was either queued or failed*/ | ||
806 | { | ||
807 | int err = GetLastError (); | ||
808 | if (ERROR_IO_PENDING == err) | ||
809 | { /* operation queued */ | ||
810 | input_facility->facility_state = IOSTATE_QUEUED; | ||
811 | } | ||
812 | else | ||
813 | { /* error occurred, let the rest of the elements finish */ | ||
814 | input_facility->path_open = FALSE; | ||
815 | input_facility->facility_state = IOSTATE_FAILED; | ||
816 | if (IOSTATE_WAITING == output_facility->facility_state) | ||
817 | output_facility->path_open = FALSE; | ||
818 | |||
819 | fprintf (stderr, "FATAL: Read from handle failed, allowing write to finish!\n"); | ||
820 | } | ||
821 | } | ||
822 | } | ||
823 | return TRUE; | ||
824 | // We are queued and should check if the read has finished | ||
825 | case IOSTATE_QUEUED: | ||
826 | { | ||
827 | // there was an operation going on already, check if that has completed now. | ||
828 | input_facility->status = GetOverlappedResult (input_facility->handle, | ||
829 | &input_facility->overlapped, | ||
830 | &input_facility->buffer_size, | ||
831 | FALSE); | ||
832 | if (input_facility->status) | ||
833 | {/* successful return for a queued operation */ | ||
834 | if ( ! ResetEvent (input_facility->overlapped.hEvent)) | ||
835 | return FALSE; | ||
836 | |||
837 | /* we successfully read something from the TAP and now need to | ||
838 | * send it our via STDOUT. Is that possible at the moment? */ | ||
839 | if ((IOSTATE_READY == output_facility->facility_state || | ||
840 | IOSTATE_WAITING == output_facility->facility_state) | ||
841 | && 0 < input_facility->buffer_size) | ||
842 | { /* hand over this buffers content */ | ||
843 | memcpy (output_facility->buffer, | ||
844 | input_facility->buffer, | ||
845 | MAX_SIZE); | ||
846 | output_facility->buffer_size = input_facility->buffer_size; | ||
847 | output_facility->facility_state = IOSTATE_READY; | ||
848 | input_facility->facility_state = IOSTATE_READY; | ||
849 | } | ||
850 | else if (0 < input_facility->buffer_size) | ||
851 | { /* If we have have read our buffer, wait for our write-partner*/ | ||
852 | input_facility->facility_state = IOSTATE_WAITING; | ||
853 | // TODO: shall we attempt to fill our buffer or should we wait for our write-partner to finish? | ||
854 | } | ||
855 | } | ||
856 | else | ||
857 | { /* operation still pending/queued or failed? */ | ||
858 | int err = GetLastError (); | ||
859 | if (ERROR_IO_INCOMPLETE != err && ERROR_IO_PENDING != err) | ||
860 | { /* error occurred, let the rest of the elements finish */ | ||
861 | input_facility->path_open = FALSE; | ||
862 | input_facility->facility_state = IOSTATE_FAILED; | ||
863 | if (IOSTATE_WAITING == output_facility->facility_state) | ||
864 | output_facility->path_open = FALSE; | ||
865 | fprintf (stderr, "FATAL: Read from handle failed, allowing write to finish!\n"); | ||
866 | } | ||
867 | } | ||
868 | } | ||
869 | return TRUE; | ||
870 | default: | ||
871 | return TRUE; | ||
804 | } | 872 | } |
805 | return TRUE; | ||
806 | default: | ||
807 | return TRUE; | ||
808 | } | ||
809 | } | 873 | } |
810 | 874 | ||
811 | /** | 875 | /** |
@@ -824,7 +888,7 @@ attempt_write (struct io_facility * output_facility, | |||
824 | if (IOSTATE_READY == output_facility->facility_state | 888 | if (IOSTATE_READY == output_facility->facility_state |
825 | && output_facility->buffer_size > 0) | 889 | && output_facility->buffer_size > 0) |
826 | { | 890 | { |
827 | if (!ResetEvent (output_facility->overlapped.hEvent)) | 891 | if ( ! ResetEvent (output_facility->overlapped.hEvent)) |
828 | { | 892 | { |
829 | return FALSE; | 893 | return FALSE; |
830 | } | 894 | } |
@@ -841,7 +905,7 @@ attempt_write (struct io_facility * output_facility, | |||
841 | {/* async event processed immediately*/ | 905 | {/* async event processed immediately*/ |
842 | 906 | ||
843 | /* reset event manually*/ | 907 | /* reset event manually*/ |
844 | if (!SetEvent (output_facility->overlapped.hEvent)) | 908 | if ( ! SetEvent (output_facility->overlapped.hEvent)) |
845 | return FALSE; | 909 | return FALSE; |
846 | 910 | ||
847 | /* we are now waiting for our buffer to be filled*/ | 911 | /* we are now waiting for our buffer to be filled*/ |
@@ -866,7 +930,7 @@ attempt_write (struct io_facility * output_facility, | |||
866 | { /* error occurred, close this path */ | 930 | { /* error occurred, close this path */ |
867 | output_facility->path_open = FALSE; | 931 | output_facility->path_open = FALSE; |
868 | output_facility->facility_state = IOSTATE_FAILED; | 932 | output_facility->facility_state = IOSTATE_FAILED; |
869 | fprintf (stderr, "Fatal: Write to handle failed, exiting!\n"); | 933 | fprintf (stderr, "FATAL: Write to handle failed, exiting!\n"); |
870 | } | 934 | } |
871 | } | 935 | } |
872 | 936 | ||
@@ -881,7 +945,7 @@ attempt_write (struct io_facility * output_facility, | |||
881 | if (output_facility->status && | 945 | if (output_facility->status && |
882 | output_facility->buffer_size_written == output_facility->buffer_size) | 946 | output_facility->buffer_size_written == output_facility->buffer_size) |
883 | {/* successful return for a queued operation */ | 947 | {/* successful return for a queued operation */ |
884 | if (!ResetEvent (output_facility->overlapped.hEvent)) | 948 | if ( ! ResetEvent (output_facility->overlapped.hEvent)) |
885 | return FALSE; | 949 | return FALSE; |
886 | 950 | ||
887 | /* we are now waiting for our buffer to be filled*/ | 951 | /* we are now waiting for our buffer to be filled*/ |
@@ -902,7 +966,7 @@ attempt_write (struct io_facility * output_facility, | |||
902 | { /* error occurred, close this path */ | 966 | { /* error occurred, close this path */ |
903 | output_facility->path_open = FALSE; | 967 | output_facility->path_open = FALSE; |
904 | output_facility->facility_state = IOSTATE_FAILED; | 968 | output_facility->facility_state = IOSTATE_FAILED; |
905 | fprintf (stderr, "Fatal: Write to handle failed, exiting!\n"); | 969 | fprintf (stderr, "FATAL: Write to handle failed, exiting!\n"); |
906 | } | 970 | } |
907 | } | 971 | } |
908 | } | 972 | } |
@@ -963,11 +1027,11 @@ run (HANDLE tap_handle) | |||
963 | * DHCP and such are all features we will never use in gnunet afaik. | 1027 | * DHCP and such are all features we will never use in gnunet afaik. |
964 | * But for openvpn those are essential. | 1028 | * But for openvpn those are essential. |
965 | */ | 1029 | */ |
966 | if (!tun_up (tap_handle)) | 1030 | if ( ! tun_up (tap_handle)) |
967 | return; | 1031 | return; |
968 | 1032 | ||
969 | /* Initialize our overlapped IO structures*/ | 1033 | /* Initialize our overlapped IO structures*/ |
970 | if (!(initialize_io_facility (&tap_read, TRUE, FALSE) | 1034 | if ( ! (initialize_io_facility (&tap_read, TRUE, FALSE) |
971 | && initialize_io_facility (&tap_write, FALSE, TRUE) | 1035 | && initialize_io_facility (&tap_write, FALSE, TRUE) |
972 | && initialize_io_facility (&std_in, TRUE, FALSE) | 1036 | && initialize_io_facility (&std_in, TRUE, FALSE) |
973 | && initialize_io_facility (&std_out, FALSE, TRUE))) | 1037 | && initialize_io_facility (&std_out, FALSE, TRUE))) |
@@ -985,7 +1049,9 @@ run (HANDLE tap_handle) | |||
985 | if (FILE_TYPE_PIPE != GetFileType (parent_std_in_handle) || | 1049 | if (FILE_TYPE_PIPE != GetFileType (parent_std_in_handle) || |
986 | FILE_TYPE_PIPE != GetFileType (parent_std_out_handle)) | 1050 | FILE_TYPE_PIPE != GetFileType (parent_std_out_handle)) |
987 | { | 1051 | { |
988 | fprintf (stderr, "Fatal: stdin/stdout must be named pipes!\n"); | 1052 | fprintf (stderr, "ERROR: stdin/stdout must be named pipes!\n"); |
1053 | printf("\nPress Enter to continue..."); | ||
1054 | getchar(); | ||
989 | goto teardown; | 1055 | goto teardown; |
990 | } | 1056 | } |
991 | 1057 | ||
@@ -996,7 +1062,7 @@ run (HANDLE tap_handle) | |||
996 | 1062 | ||
997 | if (INVALID_HANDLE_VALUE == std_in.handle) | 1063 | if (INVALID_HANDLE_VALUE == std_in.handle) |
998 | { | 1064 | { |
999 | fprintf (stderr, "Fatal: Could not reopen stdin for in overlapped mode, has to be a named pipe!\n"); | 1065 | fprintf (stderr, "FATAL: Could not reopen stdin for in overlapped mode, has to be a named pipe!\n"); |
1000 | goto teardown; | 1066 | goto teardown; |
1001 | } | 1067 | } |
1002 | 1068 | ||
@@ -1007,7 +1073,7 @@ run (HANDLE tap_handle) | |||
1007 | 1073 | ||
1008 | if (INVALID_HANDLE_VALUE == std_out.handle) | 1074 | if (INVALID_HANDLE_VALUE == std_out.handle) |
1009 | { | 1075 | { |
1010 | fprintf (stderr, "Fatal: Could not reopen stdout for in overlapped mode, has to be a named pipe!\n"); | 1076 | fprintf (stderr, "FATAL: Could not reopen stdout for in overlapped mode, has to be a named pipe!\n"); |
1011 | goto teardown; | 1077 | goto teardown; |
1012 | } | 1078 | } |
1013 | 1079 | ||
@@ -1058,10 +1124,12 @@ main (int argc, char **argv) | |||
1058 | char hwid[LINE_LEN]; | 1124 | char hwid[LINE_LEN]; |
1059 | HANDLE handle; | 1125 | HANDLE handle; |
1060 | int global_ret = 0; | 1126 | int global_ret = 0; |
1127 | boolean have_ip4=FALSE; | ||
1128 | boolean have_ip6=FALSE; | ||
1061 | 1129 | ||
1062 | if (6 != argc) | 1130 | if (6 != argc) |
1063 | { | 1131 | { |
1064 | fprintf (stderr, "Fatal: must supply 5 arguments!\n"); | 1132 | fprintf (stderr, "FATAL: must supply 5 arguments!\n"); |
1065 | return 1; | 1133 | return 1; |
1066 | } | 1134 | } |
1067 | 1135 | ||
@@ -1079,7 +1147,7 @@ main (int argc, char **argv) | |||
1079 | 1147 | ||
1080 | if (INVALID_HANDLE_VALUE == (handle = init_tun ())) | 1148 | if (INVALID_HANDLE_VALUE == (handle = init_tun ())) |
1081 | { | 1149 | { |
1082 | fprintf (stderr, "Fatal: could not initialize virtual-interface %s with IPv6 %s/%s and IPv4 %s/%s\n", | 1150 | fprintf (stderr, "FATAL: could not initialize virtual-interface %s with IPv6 %s/%s and IPv4 %s/%s\n", |
1083 | hwid, | 1151 | hwid, |
1084 | argv[2], | 1152 | argv[2], |
1085 | argv[3], | 1153 | argv[3], |
@@ -1096,13 +1164,15 @@ main (int argc, char **argv) | |||
1096 | 1164 | ||
1097 | if ((prefix_len < 1) || (prefix_len > 127)) | 1165 | if ((prefix_len < 1) || (prefix_len > 127)) |
1098 | { | 1166 | { |
1099 | fprintf (stderr, "Fatal: prefix_len out of range\n"); | 1167 | fprintf (stderr, "FATAL: prefix_len out of range\n"); |
1100 | global_ret = -1; | 1168 | global_ret = -1; |
1101 | goto cleanup; | 1169 | goto cleanup; |
1102 | } | 1170 | } |
1103 | 1171 | ||
1104 | if (0 != (global_ret = set_address6 (address, prefix_len))) | 1172 | if (0 != (global_ret = set_address6 (address, prefix_len))) |
1105 | goto cleanup; | 1173 | goto cleanup; |
1174 | |||
1175 | have_ip6 = TRUE; | ||
1106 | } | 1176 | } |
1107 | 1177 | ||
1108 | if (0 != strcmp (argv[4], "-")) | 1178 | if (0 != strcmp (argv[4], "-")) |
@@ -1112,12 +1182,22 @@ main (int argc, char **argv) | |||
1112 | 1182 | ||
1113 | if (0 != (global_ret = set_address4 (address, mask))) | 1183 | if (0 != (global_ret = set_address4 (address, mask))) |
1114 | goto cleanup; | 1184 | goto cleanup; |
1185 | |||
1186 | have_ip4 = TRUE; | ||
1115 | } | 1187 | } |
1116 | 1188 | ||
1117 | run (handle); | 1189 | run (handle); |
1118 | global_ret = 0; | 1190 | global_ret = 0; |
1119 | cleanup: | 1191 | cleanup: |
1120 | 1192 | ||
1193 | if (have_ip4){ | ||
1194 | const char *address = argv[4]; | ||
1195 | remove_address4(address); | ||
1196 | } | ||
1197 | if (have_ip6){ | ||
1198 | const char *address = argv[2]; | ||
1199 | remove_address6(address); | ||
1200 | } | ||
1121 | remove_interface (); | 1201 | remove_interface (); |
1122 | return global_ret; | 1202 | return global_ret; |
1123 | } | 1203 | } |