https://git.reactos.org/?p=reactos.git;a=commitdiff;h=344f3672110c467cbb9705...
commit 344f3672110c467cbb97055b86cf798ff19ec211 Author: Ged Murphy gedmurphy@reactos.org AuthorDate: Tue Jan 2 09:43:14 2018 +0000
[TRACERT] Rewrite tracert
- Full rewrite. This commit replaces the old utility. - Use the new ICMP APIs instead of manually crafting ping requests using raw sockets. - Add support for additional languages (the previous utility was hardcoded) - Add support for IPv6 - Make the icmpapi header C++ compatible. (we don't appear to sync this with wine anymore.) - Now runs on Win10, is much more reliable, and brings the code somewhat into the 21st century. (It's currently missing source routing (-j), but as most routers disable this anyway, I'm not sure that it's worth adding) --- base/applications/network/tracert/CMakeLists.txt | 12 +- base/applications/network/tracert/lang/bg-BG.rc | 32 ++ base/applications/network/tracert/lang/cs-CZ.rc | 32 ++ base/applications/network/tracert/lang/de-DE.rc | 32 ++ base/applications/network/tracert/lang/en-US.rc | 32 ++ base/applications/network/tracert/lang/es-ES.rc | 32 ++ base/applications/network/tracert/lang/fr-FR.rc | 32 ++ base/applications/network/tracert/lang/it-IT.rc | 32 ++ base/applications/network/tracert/lang/pl-PL.rc | 32 ++ base/applications/network/tracert/lang/ro-RO.rc | 32 ++ base/applications/network/tracert/lang/ru-RU.rc | 32 ++ base/applications/network/tracert/lang/sq-AL.rc | 32 ++ base/applications/network/tracert/lang/sv-SE.rc | 32 ++ base/applications/network/tracert/lang/tr-TR.rc | 32 ++ base/applications/network/tracert/lang/uk-UA.rc | 32 ++ base/applications/network/tracert/lang/zh-CN.rc | 32 ++ base/applications/network/tracert/lang/zh-TW.rc | 32 ++ base/applications/network/tracert/resource.h | 16 + base/applications/network/tracert/tracert.c | 657 ----------------------- base/applications/network/tracert/tracert.cpp | 566 +++++++++++++++++++ base/applications/network/tracert/tracert.h | 81 --- base/applications/network/tracert/tracert.rc | 60 ++- sdk/include/psdk/icmpapi.h | 9 + 23 files changed, 1164 insertions(+), 749 deletions(-)
diff --git a/base/applications/network/tracert/CMakeLists.txt b/base/applications/network/tracert/CMakeLists.txt index ec605ed89a..132f7fc6de 100644 --- a/base/applications/network/tracert/CMakeLists.txt +++ b/base/applications/network/tracert/CMakeLists.txt @@ -1,11 +1,5 @@
-add_definitions(-D__USE_W32_SOCKETS) -add_executable(tracert tracert.c tracert.rc) -set_module_type(tracert win32cui) -add_importlibs(tracert ws2_32 msvcrt kernel32) - -if(MSVC) - add_importlibs(tracert ntdll) -endif() - +add_executable(tracert tracert.cpp tracert.rc) +set_module_type(tracert win32cui UNICODE) +add_importlibs(tracert ws2_32 iphlpapi user32 msvcrt kernel32 ntdll) add_cd_file(TARGET tracert DESTINATION reactos/system32 FOR all) diff --git a/base/applications/network/tracert/lang/bg-BG.rc b/base/applications/network/tracert/lang/bg-BG.rc new file mode 100644 index 0000000000..bf99e280f8 --- /dev/null +++ b/base/applications/network/tracert/lang/bg-BG.rc @@ -0,0 +1,32 @@ + +LANGUAGE LANG_BULGARIAN, SUBLANG_DEFAULT + +STRINGTABLE +BEGIN + IDS_USAGE "\r\n\ +Usage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name \r\n\r\n\ +Options:\r\n\ + -d Do not resolve addresses to hostnames.\r\n\ + -h maximum_hops Maximum number of hops to search for target.\r\n\ + -j host-list Loose source route along host-list.\r\n\ + -w timeout Wait timeout milliseconds for each reply.\r\n\ + -4 Force using IPv4.\r\n\ + -6 Force using IPv6.\r\n\ +\r\n" + + IDS_INVALID_OPTION "%1 is not a valid command option.\r\n" + IDS_TRACE_INFO "\r\nTracing route to %1 [%2]\r\nover a maximum of %3!u! hops:\r\n\r\n" + IDS_TRACE_COMPLETE "\r\nTrace complete.\r\n" + IDS_UNABLE_RESOLVE "Unable to resolve target system name %1.\r\n" + + IDS_GEN_FAILURE "General failure.\r\n" + + IDS_HOP_COUNT "%1!3lu! %0\r\n" + IDS_HOP_TIME "%1!4lu! ms %0\r\n" + IDS_HOP_ZERO, " <1 ms %0\r\n" + IDS_TIMEOUT " * %0\r\n" + IDS_HOP_RES_INFO "%1 [%2]\r\n" + IDS_HOP_IP_INFO "%1\r\n" + IDS_REQ_TIMED_OUT "Request timed out.\r\n" + +END diff --git a/base/applications/network/tracert/lang/cs-CZ.rc b/base/applications/network/tracert/lang/cs-CZ.rc new file mode 100644 index 0000000000..1c82fc5dc3 --- /dev/null +++ b/base/applications/network/tracert/lang/cs-CZ.rc @@ -0,0 +1,32 @@ + +LANGUAGE LANG_CZECH, SUBLANG_DEFAULT + +STRINGTABLE +BEGIN + IDS_USAGE "\r\n\ +Usage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name \r\n\r\n\ +Options:\r\n\ + -d Do not resolve addresses to hostnames.\r\n\ + -h maximum_hops Maximum number of hops to search for target.\r\n\ + -j host-list Loose source route along host-list.\r\n\ + -w timeout Wait timeout milliseconds for each reply.\r\n\ + -4 Force using IPv4.\r\n\ + -6 Force using IPv6.\r\n\ +\r\n" + + IDS_INVALID_OPTION "%1 is not a valid command option.\r\n" + IDS_TRACE_INFO "\r\nTracing route to %1 [%2]\r\nover a maximum of %3!u! hops:\r\n\r\n" + IDS_TRACE_COMPLETE "\r\nTrace complete.\r\n" + IDS_UNABLE_RESOLVE "Unable to resolve target system name %1.\r\n" + + IDS_GEN_FAILURE "General failure.\r\n" + + IDS_HOP_COUNT "%1!3lu! %0\r\n" + IDS_HOP_TIME "%1!4lu! ms %0\r\n" + IDS_HOP_ZERO, " <1 ms %0\r\n" + IDS_TIMEOUT " * %0\r\n" + IDS_HOP_RES_INFO "%1 [%2]\r\n" + IDS_HOP_IP_INFO "%1\r\n" + IDS_REQ_TIMED_OUT "Request timed out.\r\n" + +END diff --git a/base/applications/network/tracert/lang/de-DE.rc b/base/applications/network/tracert/lang/de-DE.rc new file mode 100644 index 0000000000..bbe5e4dbec --- /dev/null +++ b/base/applications/network/tracert/lang/de-DE.rc @@ -0,0 +1,32 @@ + +LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL + +STRINGTABLE +BEGIN + IDS_USAGE "\r\n\ +Usage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name \r\n\r\n\ +Options:\r\n\ + -d Do not resolve addresses to hostnames.\r\n\ + -h maximum_hops Maximum number of hops to search for target.\r\n\ + -j host-list Loose source route along host-list.\r\n\ + -w timeout Wait timeout milliseconds for each reply.\r\n\ + -4 Force using IPv4.\r\n\ + -6 Force using IPv6.\r\n\ +\r\n" + + IDS_INVALID_OPTION "%1 is not a valid command option.\r\n" + IDS_TRACE_INFO "\r\nTracing route to %1 [%2]\r\nover a maximum of %3!u! hops:\r\n\r\n" + IDS_TRACE_COMPLETE "\r\nTrace complete.\r\n" + IDS_UNABLE_RESOLVE "Unable to resolve target system name %1.\r\n" + + IDS_GEN_FAILURE "General failure.\r\n" + + IDS_HOP_COUNT "%1!3lu! %0\r\n" + IDS_HOP_TIME "%1!4lu! ms %0\r\n" + IDS_HOP_ZERO, " <1 ms %0\r\n" + IDS_TIMEOUT " * %0\r\n" + IDS_HOP_RES_INFO "%1 [%2]\r\n" + IDS_HOP_IP_INFO "%1\r\n" + IDS_REQ_TIMED_OUT "Request timed out.\r\n" + +END diff --git a/base/applications/network/tracert/lang/en-US.rc b/base/applications/network/tracert/lang/en-US.rc new file mode 100644 index 0000000000..27b5961ca9 --- /dev/null +++ b/base/applications/network/tracert/lang/en-US.rc @@ -0,0 +1,32 @@ + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +STRINGTABLE +BEGIN + IDS_USAGE "\r\n\ +Usage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name \r\n\r\n\ +Options:\r\n\ + -d Do not resolve addresses to hostnames.\r\n\ + -h maximum_hops Maximum number of hops to search for target.\r\n\ + -j host-list Loose source route along host-list.\r\n\ + -w timeout Wait timeout milliseconds for each reply.\r\n\ + -4 Force using IPv4.\r\n\ + -6 Force using IPv6.\r\n\ +\r\n" + + IDS_INVALID_OPTION "%1 is not a valid command option.\r\n" + IDS_TRACE_INFO "\r\nTracing route to %1 [%2]\r\nover a maximum of %3!u! hops:\r\n\r\n" + IDS_TRACE_COMPLETE "\r\nTrace complete.\r\n" + IDS_UNABLE_RESOLVE "Unable to resolve target system name %1.\r\n" + + IDS_GEN_FAILURE "General failure.\r\n" + + IDS_HOP_COUNT "%1!3lu! %0\r\n" + IDS_HOP_TIME "%1!4lu! ms %0\r\n" + IDS_HOP_ZERO, " <1 ms %0\r\n" + IDS_TIMEOUT " * %0\r\n" + IDS_HOP_RES_INFO "%1 [%2]\r\n" + IDS_HOP_IP_INFO "%1\r\n" + IDS_REQ_TIMED_OUT "Request timed out.\r\n" + +END diff --git a/base/applications/network/tracert/lang/es-ES.rc b/base/applications/network/tracert/lang/es-ES.rc new file mode 100644 index 0000000000..8c69db16ac --- /dev/null +++ b/base/applications/network/tracert/lang/es-ES.rc @@ -0,0 +1,32 @@ + +LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL + +STRINGTABLE +BEGIN + IDS_USAGE "\r\n\ +Usage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name \r\n\r\n\ +Options:\r\n\ + -d Do not resolve addresses to hostnames.\r\n\ + -h maximum_hops Maximum number of hops to search for target.\r\n\ + -j host-list Loose source route along host-list.\r\n\ + -w timeout Wait timeout milliseconds for each reply.\r\n\ + -4 Force using IPv4.\r\n\ + -6 Force using IPv6.\r\n\ +\r\n" + + IDS_INVALID_OPTION "%1 is not a valid command option.\r\n" + IDS_TRACE_INFO "\r\nTracing route to %1 [%2]\r\nover a maximum of %3!u! hops:\r\n\r\n" + IDS_TRACE_COMPLETE "\r\nTrace complete.\r\n" + IDS_UNABLE_RESOLVE "Unable to resolve target system name %1.\r\n" + + IDS_GEN_FAILURE "General failure.\r\n" + + IDS_HOP_COUNT "%1!3lu! %0\r\n" + IDS_HOP_TIME "%1!4lu! ms %0\r\n" + IDS_HOP_ZERO, " <1 ms %0\r\n" + IDS_TIMEOUT " * %0\r\n" + IDS_HOP_RES_INFO "%1 [%2]\r\n" + IDS_HOP_IP_INFO "%1\r\n" + IDS_REQ_TIMED_OUT "Request timed out.\r\n" + +END diff --git a/base/applications/network/tracert/lang/fr-FR.rc b/base/applications/network/tracert/lang/fr-FR.rc new file mode 100644 index 0000000000..611a56490d --- /dev/null +++ b/base/applications/network/tracert/lang/fr-FR.rc @@ -0,0 +1,32 @@ + +LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL + +STRINGTABLE +BEGIN + IDS_USAGE "\r\n\ +Usage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name \r\n\r\n\ +Options:\r\n\ + -d Do not resolve addresses to hostnames.\r\n\ + -h maximum_hops Maximum number of hops to search for target.\r\n\ + -j host-list Loose source route along host-list.\r\n\ + -w timeout Wait timeout milliseconds for each reply.\r\n\ + -4 Force using IPv4.\r\n\ + -6 Force using IPv6.\r\n\ +\r\n" + + IDS_INVALID_OPTION "%1 is not a valid command option.\r\n" + IDS_TRACE_INFO "\r\nTracing route to %1 [%2]\r\nover a maximum of %3!u! hops:\r\n\r\n" + IDS_TRACE_COMPLETE "\r\nTrace complete.\r\n" + IDS_UNABLE_RESOLVE "Unable to resolve target system name %1.\r\n" + + IDS_GEN_FAILURE "General failure.\r\n" + + IDS_HOP_COUNT "%1!3lu! %0\r\n" + IDS_HOP_TIME "%1!4lu! ms %0\r\n" + IDS_HOP_ZERO, " <1 ms %0\r\n" + IDS_TIMEOUT " * %0\r\n" + IDS_HOP_RES_INFO "%1 [%2]\r\n" + IDS_HOP_IP_INFO "%1\r\n" + IDS_REQ_TIMED_OUT "Request timed out.\r\n" + +END diff --git a/base/applications/network/tracert/lang/it-IT.rc b/base/applications/network/tracert/lang/it-IT.rc new file mode 100644 index 0000000000..15b0ba30bf --- /dev/null +++ b/base/applications/network/tracert/lang/it-IT.rc @@ -0,0 +1,32 @@ + +LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL + +STRINGTABLE +BEGIN + IDS_USAGE "\r\n\ +Usage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name \r\n\r\n\ +Options:\r\n\ + -d Do not resolve addresses to hostnames.\r\n\ + -h maximum_hops Maximum number of hops to search for target.\r\n\ + -j host-list Loose source route along host-list.\r\n\ + -w timeout Wait timeout milliseconds for each reply.\r\n\ + -4 Force using IPv4.\r\n\ + -6 Force using IPv6.\r\n\ +\r\n" + + IDS_INVALID_OPTION "%1 is not a valid command option.\r\n" + IDS_TRACE_INFO "\r\nTracing route to %1 [%2]\r\nover a maximum of %3!u! hops:\r\n\r\n" + IDS_TRACE_COMPLETE "\r\nTrace complete.\r\n" + IDS_UNABLE_RESOLVE "Unable to resolve target system name %1.\r\n" + + IDS_GEN_FAILURE "General failure.\r\n" + + IDS_HOP_COUNT "%1!3lu! %0\r\n" + IDS_HOP_TIME "%1!4lu! ms %0\r\n" + IDS_HOP_ZERO, " <1 ms %0\r\n" + IDS_TIMEOUT " * %0\r\n" + IDS_HOP_RES_INFO "%1 [%2]\r\n" + IDS_HOP_IP_INFO "%1\r\n" + IDS_REQ_TIMED_OUT "Request timed out.\r\n" + +END diff --git a/base/applications/network/tracert/lang/pl-PL.rc b/base/applications/network/tracert/lang/pl-PL.rc new file mode 100644 index 0000000000..94e5ba6ceb --- /dev/null +++ b/base/applications/network/tracert/lang/pl-PL.rc @@ -0,0 +1,32 @@ + +LANGUAGE LANG_POLISH, SUBLANG_DEFAULT + +STRINGTABLE +BEGIN + IDS_USAGE "\r\n\ +Usage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name \r\n\r\n\ +Options:\r\n\ + -d Do not resolve addresses to hostnames.\r\n\ + -h maximum_hops Maximum number of hops to search for target.\r\n\ + -j host-list Loose source route along host-list.\r\n\ + -w timeout Wait timeout milliseconds for each reply.\r\n\ + -4 Force using IPv4.\r\n\ + -6 Force using IPv6.\r\n\ +\r\n" + + IDS_INVALID_OPTION "%1 is not a valid command option.\r\n" + IDS_TRACE_INFO "\r\nTracing route to %1 [%2]\r\nover a maximum of %3!u! hops:\r\n\r\n" + IDS_TRACE_COMPLETE "\r\nTrace complete.\r\n" + IDS_UNABLE_RESOLVE "Unable to resolve target system name %1.\r\n" + + IDS_GEN_FAILURE "General failure.\r\n" + + IDS_HOP_COUNT "%1!3lu! %0\r\n" + IDS_HOP_TIME "%1!4lu! ms %0\r\n" + IDS_HOP_ZERO, " <1 ms %0\r\n" + IDS_TIMEOUT " * %0\r\n" + IDS_HOP_RES_INFO "%1 [%2]\r\n" + IDS_HOP_IP_INFO "%1\r\n" + IDS_REQ_TIMED_OUT "Request timed out.\r\n" + +END diff --git a/base/applications/network/tracert/lang/ro-RO.rc b/base/applications/network/tracert/lang/ro-RO.rc new file mode 100644 index 0000000000..d5f2a88910 --- /dev/null +++ b/base/applications/network/tracert/lang/ro-RO.rc @@ -0,0 +1,32 @@ + +LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL + +STRINGTABLE +BEGIN + IDS_USAGE "\r\n\ +Usage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name \r\n\r\n\ +Options:\r\n\ + -d Do not resolve addresses to hostnames.\r\n\ + -h maximum_hops Maximum number of hops to search for target.\r\n\ + -j host-list Loose source route along host-list.\r\n\ + -w timeout Wait timeout milliseconds for each reply.\r\n\ + -4 Force using IPv4.\r\n\ + -6 Force using IPv6.\r\n\ +\r\n" + + IDS_INVALID_OPTION "%1 is not a valid command option.\r\n" + IDS_TRACE_INFO "\r\nTracing route to %1 [%2]\r\nover a maximum of %3!u! hops:\r\n\r\n" + IDS_TRACE_COMPLETE "\r\nTrace complete.\r\n" + IDS_UNABLE_RESOLVE "Unable to resolve target system name %1.\r\n" + + IDS_GEN_FAILURE "General failure.\r\n" + + IDS_HOP_COUNT "%1!3lu! %0\r\n" + IDS_HOP_TIME "%1!4lu! ms %0\r\n" + IDS_HOP_ZERO, " <1 ms %0\r\n" + IDS_TIMEOUT " * %0\r\n" + IDS_HOP_RES_INFO "%1 [%2]\r\n" + IDS_HOP_IP_INFO "%1\r\n" + IDS_REQ_TIMED_OUT "Request timed out.\r\n" + +END diff --git a/base/applications/network/tracert/lang/ru-RU.rc b/base/applications/network/tracert/lang/ru-RU.rc new file mode 100644 index 0000000000..1a000627a1 --- /dev/null +++ b/base/applications/network/tracert/lang/ru-RU.rc @@ -0,0 +1,32 @@ + +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT + +STRINGTABLE +BEGIN + IDS_USAGE "\r\n\ +Usage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name \r\n\r\n\ +Options:\r\n\ + -d Do not resolve addresses to hostnames.\r\n\ + -h maximum_hops Maximum number of hops to search for target.\r\n\ + -j host-list Loose source route along host-list.\r\n\ + -w timeout Wait timeout milliseconds for each reply.\r\n\ + -4 Force using IPv4.\r\n\ + -6 Force using IPv6.\r\n\ +\r\n" + + IDS_INVALID_OPTION "%1 is not a valid command option.\r\n" + IDS_TRACE_INFO "\r\nTracing route to %1 [%2]\r\nover a maximum of %3!u! hops:\r\n\r\n" + IDS_TRACE_COMPLETE "\r\nTrace complete.\r\n" + IDS_UNABLE_RESOLVE "Unable to resolve target system name %1.\r\n" + + IDS_GEN_FAILURE "General failure.\r\n" + + IDS_HOP_COUNT "%1!3lu! %0\r\n" + IDS_HOP_TIME "%1!4lu! ms %0\r\n" + IDS_HOP_ZERO, " <1 ms %0\r\n" + IDS_TIMEOUT " * %0\r\n" + IDS_HOP_RES_INFO "%1 [%2]\r\n" + IDS_HOP_IP_INFO "%1\r\n" + IDS_REQ_TIMED_OUT "Request timed out.\r\n" + +END diff --git a/base/applications/network/tracert/lang/sq-AL.rc b/base/applications/network/tracert/lang/sq-AL.rc new file mode 100644 index 0000000000..d3dc494035 --- /dev/null +++ b/base/applications/network/tracert/lang/sq-AL.rc @@ -0,0 +1,32 @@ + +LANGUAGE LANG_ALBANIAN, SUBLANG_NEUTRAL + +STRINGTABLE +BEGIN + IDS_USAGE "\r\n\ +Usage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name \r\n\r\n\ +Options:\r\n\ + -d Do not resolve addresses to hostnames.\r\n\ + -h maximum_hops Maximum number of hops to search for target.\r\n\ + -j host-list Loose source route along host-list.\r\n\ + -w timeout Wait timeout milliseconds for each reply.\r\n\ + -4 Force using IPv4.\r\n\ + -6 Force using IPv6.\r\n\ +\r\n" + + IDS_INVALID_OPTION "%1 is not a valid command option.\r\n" + IDS_TRACE_INFO "\r\nTracing route to %1 [%2]\r\nover a maximum of %3!u! hops:\r\n\r\n" + IDS_TRACE_COMPLETE "\r\nTrace complete.\r\n" + IDS_UNABLE_RESOLVE "Unable to resolve target system name %1.\r\n" + + IDS_GEN_FAILURE "General failure.\r\n" + + IDS_HOP_COUNT "%1!3lu! %0\r\n" + IDS_HOP_TIME "%1!4lu! ms %0\r\n" + IDS_HOP_ZERO, " <1 ms %0\r\n" + IDS_TIMEOUT " * %0\r\n" + IDS_HOP_RES_INFO "%1 [%2]\r\n" + IDS_HOP_IP_INFO "%1\r\n" + IDS_REQ_TIMED_OUT "Request timed out.\r\n" + +END diff --git a/base/applications/network/tracert/lang/sv-SE.rc b/base/applications/network/tracert/lang/sv-SE.rc new file mode 100644 index 0000000000..6579325bdf --- /dev/null +++ b/base/applications/network/tracert/lang/sv-SE.rc @@ -0,0 +1,32 @@ + +LANGUAGE LANG_SWEDISH, SUBLANG_NEUTRAL + +STRINGTABLE +BEGIN + IDS_USAGE "\r\n\ +Usage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name \r\n\r\n\ +Options:\r\n\ + -d Do not resolve addresses to hostnames.\r\n\ + -h maximum_hops Maximum number of hops to search for target.\r\n\ + -j host-list Loose source route along host-list.\r\n\ + -w timeout Wait timeout milliseconds for each reply.\r\n\ + -4 Force using IPv4.\r\n\ + -6 Force using IPv6.\r\n\ +\r\n" + + IDS_INVALID_OPTION "%1 is not a valid command option.\r\n" + IDS_TRACE_INFO "\r\nTracing route to %1 [%2]\r\nover a maximum of %3!u! hops:\r\n\r\n" + IDS_TRACE_COMPLETE "\r\nTrace complete.\r\n" + IDS_UNABLE_RESOLVE "Unable to resolve target system name %1.\r\n" + + IDS_GEN_FAILURE "General failure.\r\n" + + IDS_HOP_COUNT "%1!3lu! %0\r\n" + IDS_HOP_TIME "%1!4lu! ms %0\r\n" + IDS_HOP_ZERO, " <1 ms %0\r\n" + IDS_TIMEOUT " * %0\r\n" + IDS_HOP_RES_INFO "%1 [%2]\r\n" + IDS_HOP_IP_INFO "%1\r\n" + IDS_REQ_TIMED_OUT "Request timed out.\r\n" + +END diff --git a/base/applications/network/tracert/lang/tr-TR.rc b/base/applications/network/tracert/lang/tr-TR.rc new file mode 100644 index 0000000000..0ee1a09845 --- /dev/null +++ b/base/applications/network/tracert/lang/tr-TR.rc @@ -0,0 +1,32 @@ + +LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT + +STRINGTABLE +BEGIN + IDS_USAGE "\r\n\ +Usage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name \r\n\r\n\ +Options:\r\n\ + -d Do not resolve addresses to hostnames.\r\n\ + -h maximum_hops Maximum number of hops to search for target.\r\n\ + -j host-list Loose source route along host-list.\r\n\ + -w timeout Wait timeout milliseconds for each reply.\r\n\ + -4 Force using IPv4.\r\n\ + -6 Force using IPv6.\r\n\ +\r\n" + + IDS_INVALID_OPTION "%1 is not a valid command option.\r\n" + IDS_TRACE_INFO "\r\nTracing route to %1 [%2]\r\nover a maximum of %3!u! hops:\r\n\r\n" + IDS_TRACE_COMPLETE "\r\nTrace complete.\r\n" + IDS_UNABLE_RESOLVE "Unable to resolve target system name %1.\r\n" + + IDS_GEN_FAILURE "General failure.\r\n" + + IDS_HOP_COUNT "%1!3lu! %0\r\n" + IDS_HOP_TIME "%1!4lu! ms %0\r\n" + IDS_HOP_ZERO, " <1 ms %0\r\n" + IDS_TIMEOUT " * %0\r\n" + IDS_HOP_RES_INFO "%1 [%2]\r\n" + IDS_HOP_IP_INFO "%1\r\n" + IDS_REQ_TIMED_OUT "Request timed out.\r\n" + +END diff --git a/base/applications/network/tracert/lang/uk-UA.rc b/base/applications/network/tracert/lang/uk-UA.rc new file mode 100644 index 0000000000..9a2903c251 --- /dev/null +++ b/base/applications/network/tracert/lang/uk-UA.rc @@ -0,0 +1,32 @@ + +LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT + +STRINGTABLE +BEGIN + IDS_USAGE "\r\n\ +Usage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name \r\n\r\n\ +Options:\r\n\ + -d Do not resolve addresses to hostnames.\r\n\ + -h maximum_hops Maximum number of hops to search for target.\r\n\ + -j host-list Loose source route along host-list.\r\n\ + -w timeout Wait timeout milliseconds for each reply.\r\n\ + -4 Force using IPv4.\r\n\ + -6 Force using IPv6.\r\n\ +\r\n" + + IDS_INVALID_OPTION "%1 is not a valid command option.\r\n" + IDS_TRACE_INFO "\r\nTracing route to %1 [%2]\r\nover a maximum of %3!u! hops:\r\n\r\n" + IDS_TRACE_COMPLETE "\r\nTrace complete.\r\n" + IDS_UNABLE_RESOLVE "Unable to resolve target system name %1.\r\n" + + IDS_GEN_FAILURE "General failure.\r\n" + + IDS_HOP_COUNT "%1!3lu! %0\r\n" + IDS_HOP_TIME "%1!4lu! ms %0\r\n" + IDS_HOP_ZERO, " <1 ms %0\r\n" + IDS_TIMEOUT " * %0\r\n" + IDS_HOP_RES_INFO "%1 [%2]\r\n" + IDS_HOP_IP_INFO "%1\r\n" + IDS_REQ_TIMED_OUT "Request timed out.\r\n" + +END diff --git a/base/applications/network/tracert/lang/zh-CN.rc b/base/applications/network/tracert/lang/zh-CN.rc new file mode 100644 index 0000000000..61966e02b8 --- /dev/null +++ b/base/applications/network/tracert/lang/zh-CN.rc @@ -0,0 +1,32 @@ + +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED + +STRINGTABLE +BEGIN + IDS_USAGE "\r\n\ +Usage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name \r\n\r\n\ +Options:\r\n\ + -d Do not resolve addresses to hostnames.\r\n\ + -h maximum_hops Maximum number of hops to search for target.\r\n\ + -j host-list Loose source route along host-list.\r\n\ + -w timeout Wait timeout milliseconds for each reply.\r\n\ + -4 Force using IPv4.\r\n\ + -6 Force using IPv6.\r\n\ +\r\n" + + IDS_INVALID_OPTION "%1 is not a valid command option.\r\n" + IDS_TRACE_INFO "\r\nTracing route to %1 [%2]\r\nover a maximum of %3!u! hops:\r\n\r\n" + IDS_TRACE_COMPLETE "\r\nTrace complete.\r\n" + IDS_UNABLE_RESOLVE "Unable to resolve target system name %1.\r\n" + + IDS_GEN_FAILURE "General failure.\r\n" + + IDS_HOP_COUNT "%1!3lu! %0\r\n" + IDS_HOP_TIME "%1!4lu! ms %0\r\n" + IDS_HOP_ZERO, " <1 ms %0\r\n" + IDS_TIMEOUT " * %0\r\n" + IDS_HOP_RES_INFO "%1 [%2]\r\n" + IDS_HOP_IP_INFO "%1\r\n" + IDS_REQ_TIMED_OUT "Request timed out.\r\n" + +END diff --git a/base/applications/network/tracert/lang/zh-TW.rc b/base/applications/network/tracert/lang/zh-TW.rc new file mode 100644 index 0000000000..86ecc1c9f8 --- /dev/null +++ b/base/applications/network/tracert/lang/zh-TW.rc @@ -0,0 +1,32 @@ + +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL + +STRINGTABLE +BEGIN + IDS_USAGE "\r\n\ +Usage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name \r\n\r\n\ +Options:\r\n\ + -d Do not resolve addresses to hostnames.\r\n\ + -h maximum_hops Maximum number of hops to search for target.\r\n\ + -j host-list Loose source route along host-list.\r\n\ + -w timeout Wait timeout milliseconds for each reply.\r\n\ + -4 Force using IPv4.\r\n\ + -6 Force using IPv6.\r\n\ +\r\n" + + IDS_INVALID_OPTION "%1 is not a valid command option.\r\n" + IDS_TRACE_INFO "\r\nTracing route to %1 [%2]\r\nover a maximum of %3!u! hops:\r\n\r\n" + IDS_TRACE_COMPLETE "\r\nTrace complete.\r\n" + IDS_UNABLE_RESOLVE "Unable to resolve target system name %1.\r\n" + + IDS_GEN_FAILURE "General failure.\r\n" + + IDS_HOP_COUNT "%1!3lu! %0\r\n" + IDS_HOP_TIME "%1!4lu! ms %0\r\n" + IDS_HOP_ZERO, " <1 ms %0\r\n" + IDS_TIMEOUT " * %0\r\n" + IDS_HOP_RES_INFO "%1 [%2]\r\n" + IDS_HOP_IP_INFO "%1\r\n" + IDS_REQ_TIMED_OUT "Request timed out.\r\n" + +END diff --git a/base/applications/network/tracert/resource.h b/base/applications/network/tracert/resource.h new file mode 100644 index 0000000000..5bb07ecd6e --- /dev/null +++ b/base/applications/network/tracert/resource.h @@ -0,0 +1,16 @@ +#pragma once + +#define IDS_USAGE 100 +#define IDS_INVALID_OPTION 101 +#define IDS_TRACE_INFO 102 +#define IDS_TRACE_COMPLETE 103 +#define IDS_UNABLE_RESOLVE 104 +#define IDS_GEN_FAILURE 105 + +#define IDS_HOP_COUNT 107 +#define IDS_HOP_TIME 108 +#define IDS_HOP_ZERO 109 +#define IDS_TIMEOUT 110 +#define IDS_HOP_RES_INFO 111 +#define IDS_HOP_IP_INFO 112 +#define IDS_REQ_TIMED_OUT 113 diff --git a/base/applications/network/tracert/tracert.c b/base/applications/network/tracert/tracert.c deleted file mode 100644 index 2a7fce0157..0000000000 --- a/base/applications/network/tracert/tracert.c +++ /dev/null @@ -1,657 +0,0 @@ - /* - * PROJECT: ReactOS trace route utility - * LICENSE: GPL - See COPYING in the top level directory - * FILE: base/applications/network/tracert/tracert.c - * PURPOSE: Trace network paths through networks - * COPYRIGHT: Copyright 2006 - 2007 Ged Murphy gedmurphy@reactos.org - * - */ - -#include "tracert.h" - -//#define TRACERT_DBG - -CHAR cHostname[256]; // target hostname -CHAR cDestIP[18]; // target IP - -static VOID -DebugPrint(LPTSTR lpString, ...) -{ -#ifdef TRACERT_DBG - va_list args; - va_start(args, lpString); - _vtprintf(lpString, args); - va_end(args); -#else - UNREFERENCED_PARAMETER(lpString); -#endif -} - -static VOID -Usage(VOID) -{ - _tprintf(_T("\nUsage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name\n\n" - "Options:\n" - " -d Do not resolve addresses to hostnames.\n" - " -h maximum_hops Maximum number of hops to search for target.\n" - " -j host-list Loose source route along host-list.\n" - " -w timeout Wait timeout milliseconds for each reply.\n\n")); - - _tprintf(_T("NOTES\n-----\n" - "- Setting TTL values is not currently supported in ReactOS, so the trace will\n" - " jump straight to the destination. This feature will be implemented soon.\n" - "- Host info is not currently available in ReactOS and will fail with strange\n" - " results. Use -d to force it not to resolve IP's.\n" - "- For testing purposes, all should work as normal in a Windows environment\n\n")); -} - -static BOOL -ParseCmdline(int argc, - LPCTSTR argv[], - PAPPINFO pInfo) -{ - INT i; - - if (argc < 2) - { - Usage(); - return FALSE; - } - else - { - for (i = 1; i < argc; i++) - { - if (argv[i][0] == _T('-')) - { - switch (argv[i][1]) - { - case _T('d'): - pInfo->bResolveAddresses = FALSE; - break; - - case _T('h'): - _stscanf(argv[i+1], _T("%d"), &pInfo->iMaxHops); - break; - - case _T('j'): - _tprintf(_T("-j is not yet implemented.\n")); - break; - - case _T('w'): - _stscanf(argv[i+1], _T("%d"), &pInfo->iTimeOut); - break; - - default: - { - _tprintf(_T("%s is not a valid option.\n"), argv[i]); - Usage(); - return FALSE; - } - } - } - else - /* copy target address */ - _tcsncpy(cHostname, argv[i], 255); - } - } - - return TRUE; -} - -static WORD -CheckSum(PUSHORT data, - UINT size) -{ - DWORD dwSum = 0; - - while (size > 1) - { - dwSum += *data++; - size -= sizeof(USHORT); - } - - if (size) - dwSum += *(UCHAR*)data; - - dwSum = (dwSum >> 16) + (dwSum & 0xFFFF); - dwSum += (dwSum >> 16); - - return (USHORT)(~dwSum); -} - -static VOID -SetupTimingMethod(PAPPINFO pInfo) -{ - LARGE_INTEGER PerformanceCounterFrequency; - - /* check if performance counters are available */ - pInfo->bUsePerformanceCounter = QueryPerformanceFrequency(&PerformanceCounterFrequency); - - if (pInfo->bUsePerformanceCounter) - { - /* restrict execution to first processor on SMP systems */ - if (SetThreadAffinityMask(GetCurrentThread(), 1) == 0) - pInfo->bUsePerformanceCounter = FALSE; - - pInfo->TicksPerMs.QuadPart = PerformanceCounterFrequency.QuadPart / 1000; - pInfo->TicksPerUs.QuadPart = PerformanceCounterFrequency.QuadPart / 1000000; - } - else - { - pInfo->TicksPerMs.QuadPart = 1; - pInfo->TicksPerUs.QuadPart = 1; - } -} - -static BOOL -ResolveHostname(PAPPINFO pInfo) -{ - HOSTENT *hp; - ULONG addr; - - ZeroMemory(&pInfo->dest, sizeof(pInfo->dest)); - - /* if address is not a dotted decimal */ - if ((addr = inet_addr(cHostname))== INADDR_NONE) - { - if ((hp = gethostbyname(cHostname)) != 0) - { - //CopyMemory(&pInfo->dest.sin_addr, hp->h_addr, hp->h_length); - pInfo->dest.sin_addr = *((struct in_addr *)hp->h_addr); - pInfo->dest.sin_family = hp->h_addrtype; - } - else - { - _tprintf(_T("Unable to resolve target system name %s.\n"), cHostname); - return FALSE; - } - } - else - { - pInfo->dest.sin_addr.s_addr = addr; - pInfo->dest.sin_family = AF_INET; - } - - _tcscpy(cDestIP, inet_ntoa(pInfo->dest.sin_addr)); - - return TRUE; -} - -static LONGLONG -GetTime(PAPPINFO pInfo) -{ - LARGE_INTEGER Time; - - /* Get the system time using performance counters if available */ - if (pInfo->bUsePerformanceCounter) - { - if (QueryPerformanceCounter(&Time)) - { - return Time.QuadPart; - } - } - - /* otherwise fall back to GetTickCount */ - Time.u.LowPart = (DWORD)GetTickCount(); - Time.u.HighPart = 0; - - return (LONGLONG)Time.u.LowPart; -} - -static BOOL -SetTTL(SOCKET sock, - INT iTTL) -{ - if (setsockopt(sock, - IPPROTO_IP, - IP_TTL, - (const char *)&iTTL, - sizeof(iTTL)) == SOCKET_ERROR) - { - DebugPrint(_T("TTL setsockopt failed : %d. \n"), WSAGetLastError()); - return FALSE; - } - - return TRUE; -} - -static BOOL -CreateSocket(PAPPINFO pInfo) -{ - pInfo->icmpSock = WSASocket(AF_INET, - SOCK_RAW, - IPPROTO_ICMP, - 0, - 0, - 0); - - if (pInfo->icmpSock == INVALID_SOCKET) - { - INT err = WSAGetLastError(); - DebugPrint(_T("Could not create socket : %d.\n"), err); - - if (err == WSAEACCES) - { - _tprintf(_T("\n\nYou must have access to raw sockets (admin) to run this program!\n\n")); - } - - return FALSE; - } - - return TRUE; -} - -static VOID -PreparePacket(PAPPINFO pInfo, - USHORT iSeqNum) -{ - /* assemble ICMP echo request packet */ - pInfo->SendPacket->icmpheader.type = ECHO_REQUEST; - pInfo->SendPacket->icmpheader.code = 0; - pInfo->SendPacket->icmpheader.checksum = 0; - pInfo->SendPacket->icmpheader.id = (USHORT)GetCurrentProcessId(); - pInfo->SendPacket->icmpheader.seq = htons((USHORT)iSeqNum); - - /* calculate checksum of packet */ - pInfo->SendPacket->icmpheader.checksum = CheckSum((PUSHORT)&pInfo->SendPacket->icmpheader, - sizeof(ICMP_HEADER) + PACKET_SIZE); -} - -static INT -SendPacket(PAPPINFO pInfo) -{ - INT iSockRet; - - DebugPrint(_T("\nsending packet of %d bytes... "), PACKET_SIZE); - - /* get time packet was sent */ - pInfo->lTimeStart = GetTime(pInfo); - - iSockRet = sendto(pInfo->icmpSock, //socket - (char *)&pInfo->SendPacket->icmpheader,//buffer - sizeof(ICMP_HEADER) + PACKET_SIZE,//size of buffer - 0, //flags - (SOCKADDR *)&pInfo->dest, //destination - sizeof(pInfo->dest)); //address length - - if (iSockRet == SOCKET_ERROR) - { - if (WSAGetLastError() == WSAEACCES) - { - /* FIXME: Is this correct? */ - _tprintf(_T("\n\nYou must be an administrator to run this program!\n\n")); - WSACleanup(); - HeapFree(GetProcessHeap(), 0, pInfo); - exit(-1); - } - else - { - DebugPrint(_T("sendto failed %d\n"), WSAGetLastError()); - } - } - else - { - DebugPrint(_T("sent %d bytes\n"), iSockRet); - } - - return iSockRet; -} - -static BOOL -ReceivePacket(PAPPINFO pInfo) -{ - TIMEVAL timeVal; - FD_SET readFDS; - INT iSockRet = 0, iSelRet; - INT iFromLen; - BOOL bRet = FALSE; - - iFromLen = sizeof(pInfo->source); - - DebugPrint(_T("Receiving packet. Available buffer, %d bytes... "), MAX_PING_PACKET_SIZE); - - /* monitor icmpSock for incoming connections */ - FD_ZERO(&readFDS); - FD_SET(pInfo->icmpSock, &readFDS); - - /* set timeout values */ - timeVal.tv_sec = pInfo->iTimeOut / 1000; - timeVal.tv_usec = pInfo->iTimeOut % 1000; - - iSelRet = select(0, - &readFDS, - NULL, - NULL, - &timeVal); - - if (iSelRet == SOCKET_ERROR) - { - DebugPrint(_T("select() failed in sendPacket() %d\n"), WSAGetLastError()); - } - else if (iSelRet == 0) /* if socket timed out */ - { - _tprintf(_T(" * ")); - } - else if ((iSelRet != SOCKET_ERROR) && (iSelRet != 0)) - { - iSockRet = recvfrom(pInfo->icmpSock, // socket - (char *)pInfo->RecvPacket, // buffer - MAX_PING_PACKET_SIZE, // size of buffer - 0, // flags - (SOCKADDR *)&pInfo->source, // source address - &iFromLen); // address length - - if (iSockRet != SOCKET_ERROR) - { - /* get time packet was received */ - pInfo->lTimeEnd = GetTime(pInfo); - DebugPrint(_T("received %d bytes\n"), iSockRet); - bRet = TRUE; - } - else - { - DebugPrint(_T("recvfrom failed: %d\n"), WSAGetLastError()); - } - } - - return bRet; -} - -static INT -DecodeResponse(PAPPINFO pInfo) -{ - unsigned short header_len = pInfo->RecvPacket->h_len * 4; - - /* cast the received packet into an ECHO reply and a TTL Exceed and check the ID*/ - ECHO_REPLY_HEADER *IcmpHdr = (ECHO_REPLY_HEADER *)((char*)pInfo->RecvPacket + header_len); - - /* Make sure the reply is ok */ - if (PACKET_SIZE < header_len + ICMP_MIN_SIZE) - { - DebugPrint(_T("too few bytes from %s\n"), inet_ntoa(pInfo->dest.sin_addr)); - return -2; - } - - switch (IcmpHdr->icmpheader.type) - { - case TTL_EXCEEDED : - _tprintf(_T("%3ld ms"), (ULONG)((pInfo->lTimeEnd - pInfo->lTimeStart) / pInfo->TicksPerMs.QuadPart)); - return 0; - - case ECHO_REPLY : - if (IcmpHdr->icmpheader.id != (USHORT)GetCurrentProcessId()) - { - /* FIXME: our network stack shouldn't allow this... */ - /* we've picked up a packet not related to this process probably from another local program. We ignore it */ - DebugPrint(_T("Rouge packet: header id %d, process id %d"), IcmpHdr->icmpheader.id, GetCurrentProcessId()); - return -1; - } - _tprintf(_T("%3ld ms"), (ULONG)((pInfo->lTimeEnd - pInfo->lTimeStart) / pInfo->TicksPerMs.QuadPart)); - return 1; - - case DEST_UNREACHABLE : - _tprintf(_T(" * ")); - return 2; - } - - return -3; -} - -static BOOL -AllocateBuffers(PAPPINFO pInfo) -{ - pInfo->SendPacket = (PECHO_REPLY_HEADER)HeapAlloc(GetProcessHeap(), - 0, - sizeof(ECHO_REPLY_HEADER) + PACKET_SIZE); - if (!pInfo->SendPacket) - return FALSE; - - pInfo->RecvPacket = (PIPv4_HEADER)HeapAlloc(GetProcessHeap(), - 0, - MAX_PING_PACKET_SIZE); - if (!pInfo->RecvPacket) - { - HeapFree(GetProcessHeap(), - 0, - pInfo->SendPacket); - - return FALSE; - } - - return TRUE; -} - -static INT -Driver(PAPPINFO pInfo) -{ - INT iHopCount = 1; // hop counter. default max is 30 - BOOL bFoundTarget = FALSE; // Have we reached our destination yet - INT iReceiveReturn; // ReceiveReturn return value - PECHO_REPLY_HEADER icmphdr; - INT iTTL = 1; - - INT ret = -1; - - //temps for getting host name - CHAR cHost[256]; - CHAR cServ[256]; - CHAR *ip; - - SetupTimingMethod(pInfo); - - if (AllocateBuffers(pInfo) && - ResolveHostname(pInfo) && - CreateSocket(pInfo)) - { - /* print tracing info to screen */ - _tprintf(_T("\nTracing route to %s [%s]\n"), cHostname, cDestIP); - _tprintf(_T("over a maximum of %d hop"), pInfo->iMaxHops); - pInfo->iMaxHops > 1 ? _tprintf(_T("s:\n\n")) : _tprintf(_T(":\n\n")); - - /* run until we hit either max hops, or find the target */ - while ((iHopCount <= pInfo->iMaxHops) && - (bFoundTarget == FALSE)) - { - USHORT iSeqNum = 0; - INT i; - - _tprintf(_T("%3d "), iHopCount); - - /* run 3 pings for each hop */ - for (i = 0; i < 3; i++) - { - if (SetTTL(pInfo->icmpSock, iTTL) == FALSE) - { - DebugPrint(_T("error in Setup()\n")); - return ret; - } - - PreparePacket(pInfo, iSeqNum); - - if (SendPacket(pInfo) != SOCKET_ERROR) - { - BOOL bAwaitPacket = FALSE; // indicates whether we have received a good packet - - do - { - /* Receive replies until we get a successful read, or a fatal error */ - if ((iReceiveReturn = ReceivePacket(pInfo)) < 0) - { - /* FIXME: consider moving this into ReceivePacket */ - /* check the seq num in the packet, if it's bad wait for another */ - WORD hdrLen = pInfo->RecvPacket->h_len * 4; - icmphdr = (ECHO_REPLY_HEADER *)((char*)&pInfo->RecvPacket + hdrLen); - if (icmphdr->icmpheader.seq != iSeqNum) - { - _tprintf(_T("bad sequence number!\n")); - continue; - } - } - - if (iReceiveReturn) - { - if (DecodeResponse(pInfo) < 0) - bAwaitPacket = TRUE; - } - - } while (bAwaitPacket); - } - - iSeqNum++; - _tprintf(_T(" ")); - } - - if(pInfo->bResolveAddresses) - { - INT iNameInfoRet; // getnameinfo return value - /* gethostbyaddr() and getnameinfo() are - * unimplemented in ROS at present. - * Alex has advised he will be implementing getnameinfo. - * I've used that for the time being for testing in Windows*/ - - //ip = inet_addr(inet_ntoa(source.sin_addr)); - //host = gethostbyaddr((char *)&ip, 4, 0); - - ip = inet_ntoa(pInfo->source.sin_addr); - - iNameInfoRet = getnameinfo((SOCKADDR *)&pInfo->source, - sizeof(SOCKADDR), - cHost, - 256, - cServ, - 256, - NI_NUMERICSERV); - if (iNameInfoRet == 0) - { - /* if IP address resolved to a hostname, - * print the IP address after it */ - if (lstrcmpA(cHost, ip) != 0) - _tprintf(_T("%s [%s]"), cHost, ip); - else - _tprintf(_T("%s"), cHost); - } - else - { - DebugPrint(_T("error: %d"), WSAGetLastError()); - DebugPrint(_T(" getnameinfo failed: %d"), iNameInfoRet); - _tprintf(_T("%s"), inet_ntoa(pInfo->source.sin_addr)); - } - - } - else - _tprintf(_T("%s"), inet_ntoa(pInfo->source.sin_addr)); - - _tprintf(_T("\n")); - - /* check if we've arrived at the target */ - if (strcmp(cDestIP, inet_ntoa(pInfo->source.sin_addr)) == 0) - bFoundTarget = TRUE; - else - { - iTTL++; - iHopCount++; - Sleep(500); - } - } - _tprintf(_T("\nTrace complete.\n")); - ret = 0; - } - - return ret; -} - -static VOID -Cleanup(PAPPINFO pInfo) -{ - if (pInfo->icmpSock) - closesocket(pInfo->icmpSock); - - WSACleanup(); - - if (pInfo->SendPacket) - HeapFree(GetProcessHeap(), - 0, - pInfo->SendPacket); - - if (pInfo->RecvPacket) - HeapFree(GetProcessHeap(), - 0, - pInfo->RecvPacket); -} - -#if defined(_UNICODE) && defined(__GNUC__) -static -#endif -int _tmain(int argc, LPCTSTR argv[]) -{ - PAPPINFO pInfo; - WSADATA wsaData; - int ret = -1; - - pInfo = (PAPPINFO)HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - sizeof(APPINFO)); - if (pInfo) - { - pInfo->bResolveAddresses = TRUE; - pInfo->iMaxHops = 30; - pInfo->iTimeOut = 1000; - - if (ParseCmdline(argc, argv, pInfo)) - { - if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) - { - DebugPrint(_T("WSAStartup failed.\n")); - } - else - { - ret = Driver(pInfo); - Cleanup(pInfo); - } - } - - HeapFree(GetProcessHeap(), - 0, - pInfo); - } - - return ret; -} - -#if defined(_UNICODE) && defined(__GNUC__) -/* HACK - MINGW HAS NO OFFICIAL SUPPORT FOR wmain()!!! */ -int main( int argc, char **argv ) -{ - WCHAR **argvW; - int i, j, Ret = 1; - - if ((argvW = malloc(argc * sizeof(WCHAR*)))) - { - /* convert the arguments */ - for (i = 0, j = 0; i < argc; i++) - { - if (!(argvW[i] = malloc((strlen(argv[i]) + 1) * sizeof(WCHAR)))) - { - j++; - } - swprintf(argvW[i], L"%hs", argv[i]); - } - - if (j == 0) - { - /* no error converting the parameters, call wmain() */ - Ret = wmain(argc, (LPCTSTR *)argvW); - } - - /* free the arguments */ - for (i = 0; i < argc; i++) - { - if (argvW[i]) - free(argvW[i]); - } - free(argvW); - } - - return Ret; -} -#endif diff --git a/base/applications/network/tracert/tracert.cpp b/base/applications/network/tracert/tracert.cpp new file mode 100644 index 0000000000..ca14cc5345 --- /dev/null +++ b/base/applications/network/tracert/tracert.cpp @@ -0,0 +1,566 @@ +/* + * PROJECT: ReactOS trace route utility + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/applications/network/tracert/tracert.cpp + * PURPOSE: Trace network paths through networks + * COPYRIGHT: Copyright 2018 Ged Murphy gedmurphy@reactos.org + * + */ + +#ifdef __REACTOS__ +#define WIN32_NO_STATUS +#include <stdarg.h> +#include <windef.h> +#include <winbase.h> +#include <winuser.h> +#define _INC_WINDOWS +#include <stdio.h> +#include <stdlib.h> +#include <winsock2.h> +#else +#include <winsock2.h> +#include <Windows.h> +#endif +#include <ws2tcpip.h> +#include <iphlpapi.h> +#include <icmpapi.h> +#include <strsafe.h> +#include "resource.h" + +#define SIZEOF_ICMP_ERROR 8 +#define SIZEOF_IO_STATUS_BLOCK 8 +#define PACKET_SIZE 32 +#define MAX_IPADDRESS 32 +#define NUM_OF_PINGS 3 + +struct TraceInfo +{ + bool ResolveAddresses; + ULONG MaxHops; + ULONG Timeout; + WCHAR HostName[NI_MAXHOST]; + WCHAR TargetIP[MAX_IPADDRESS]; + int Family; + + HANDLE hIcmpFile; + PADDRINFOW Target; + +} Info = { 0 }; + + + +#ifndef USE_CONUTILS +static +INT +LengthOfStrResource( + _In_ HINSTANCE hInst, + _In_ UINT uID +) +{ + HRSRC hrSrc; + HGLOBAL hRes; + LPWSTR lpName, lpStr; + + if (hInst == NULL) return -1; + + lpName = (LPWSTR)MAKEINTRESOURCE((uID >> 4) + 1); + + if ((hrSrc = FindResourceW(hInst, lpName, (LPWSTR)RT_STRING)) && + (hRes = LoadResource(hInst, hrSrc)) && + (lpStr = (WCHAR*)LockResource(hRes))) + { + UINT x; + uID &= 0xF; + for (x = 0; x < uID; x++) + { + lpStr += (*lpStr) + 1; + } + return (int)(*lpStr); + } + return -1; +} + +static +INT +AllocAndLoadString( + _In_ UINT uID, + _Out_ LPWSTR *lpTarget +) +{ + HMODULE hInst; + INT Length; + + hInst = GetModuleHandleW(NULL); + Length = LengthOfStrResource(hInst, uID); + if (Length++ > 0) + { + (*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED, + Length * sizeof(WCHAR)); + if ((*lpTarget) != NULL) + { + INT Ret; + if (!(Ret = LoadStringW(hInst, uID, *lpTarget, Length))) + { + LocalFree((HLOCAL)(*lpTarget)); + } + return Ret; + } + } + return 0; +} + +static +INT +OutputText( + _In_ UINT uID, + ...) +{ + LPWSTR Format; + DWORD Ret = 0; + va_list lArgs; + + if (AllocAndLoadString(uID, &Format) > 0) + { + va_start(lArgs, uID); + + LPWSTR Buffer; + Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, + Format, + 0, + 0, + (LPWSTR)&Buffer, + 0, + &lArgs); + va_end(lArgs); + + if (Ret) + { + wprintf(Buffer); + LocalFree(Buffer); + } + LocalFree((HLOCAL)Format); + } + + return Ret; +} +#else +#define OutputText(Id, ...) ConResPrintf(StdOut, Id, __VA_ARGS__) +#endif //USE_CONUTILS + +static +VOID +Usage() +{ + OutputText(IDS_USAGE); +} + +static ULONG +GetULONG( + _In_z_ LPWSTR String +) +{ + ULONG Length; + Length = wcslen(String); + + ULONG i = 0; + while ((i < Length) && ((String[i] < L'0') || (String[i] > L'9'))) i++; + if ((i >= Length) || ((String[i] < L'0') || (String[i] > L'9'))) + { + return (ULONG)-1; + } + + LPWSTR StopString; + return wcstoul(&String[i], &StopString, 10); +} + +static bool +ResolveTarget() +{ + ADDRINFOW Hints; + ZeroMemory(&Hints, sizeof(Hints)); + Hints.ai_family = Info.Family; + Hints.ai_flags = AI_CANONNAME; + + int Status; + Status = GetAddrInfoW(Info.HostName, + NULL, + &Hints, + &Info.Target); + if (Status != 0) + { + return false; + } + + Status = GetNameInfoW(Info.Target->ai_addr, + Info.Target->ai_addrlen, + Info.TargetIP, + MAX_IPADDRESS, + NULL, + 0, + NI_NUMERICHOST); + if (Status != 0) + { + return false; + } + + return true; +} + +static bool +PrintHopInfo(_In_ PVOID Buffer) +{ + SOCKADDR_IN6 SockAddrIn6 = { 0 }; + SOCKADDR_IN SockAddrIn = { 0 }; + PSOCKADDR SockAddr; + socklen_t Size; + + if (Info.Family == AF_INET6) + { + PIPV6_ADDRESS_EX Ipv6Addr = (PIPV6_ADDRESS_EX)Buffer; + SockAddrIn6.sin6_family = AF_INET6; + CopyMemory(SockAddrIn6.sin6_addr.u.Word, Ipv6Addr->sin6_addr, sizeof(SockAddrIn6.sin6_addr)); + //SockAddrIn6.sin6_addr = Ipv6Addr->sin6_addr; + SockAddr = (PSOCKADDR)&SockAddrIn6; + Size = sizeof(SOCKADDR_IN6); + + } + else + { + IPAddr *Address = (IPAddr *)Buffer; + SockAddrIn.sin_family = AF_INET; + SockAddrIn.sin_addr.S_un.S_addr = *Address; + SockAddr = (PSOCKADDR)&SockAddrIn; + Size = sizeof(SOCKADDR_IN); + } + + INT Status; + bool Resolved = false; + WCHAR HostName[NI_MAXHOST]; + if (Info.ResolveAddresses) + { + Status = GetNameInfoW(SockAddr, + Size, + HostName, + NI_MAXHOST, + NULL, + 0, + NI_NAMEREQD); + if (Status == 0) + { + Resolved = true; + } + } + + WCHAR IpAddress[MAX_IPADDRESS]; + Status = GetNameInfoW(SockAddr, + Size, + IpAddress, + NI_MAXHOST, + NULL, + 0, + NI_NUMERICHOST); + if (Status == 0) + { + if (Resolved) + { + OutputText(IDS_HOP_RES_INFO, HostName, IpAddress); + } + else + { + OutputText(IDS_HOP_IP_INFO, IpAddress); + } + } + + return (Status == 0); +} + +static bool +DecodeResponse( + _In_ PVOID ReplyBuffer, + _In_ bool OutputHopAddress, + _Out_ bool& FoundTarget +) +{ + ULONG RoundTripTime; + PVOID AddressInfo; + ULONG Status; + + if (Info.Family == AF_INET6) + { + PICMPV6_ECHO_REPLY EchoReplyV6; + EchoReplyV6 = (PICMPV6_ECHO_REPLY)ReplyBuffer; + Status = EchoReplyV6->Status; + RoundTripTime = EchoReplyV6->RoundTripTime; + AddressInfo = &EchoReplyV6->Address; + } + else + { + PICMP_ECHO_REPLY EchoReplyV4; + EchoReplyV4 = (PICMP_ECHO_REPLY)ReplyBuffer; + Status = EchoReplyV4->Status; + RoundTripTime = EchoReplyV4->RoundTripTime; + AddressInfo = &EchoReplyV4->Address; + } + + switch (Status) + { + case IP_SUCCESS: + case IP_TTL_EXPIRED_TRANSIT: + if (RoundTripTime) + { + OutputText(IDS_HOP_TIME, RoundTripTime); + } + else + { + OutputText(IDS_HOP_ZERO); + } + break; + + case IP_DEST_HOST_UNREACHABLE: + OutputText(IDS_TIMEOUT); + break; + + case IP_REQ_TIMED_OUT: + OutputText(IDS_TIMEOUT); + break; + + case IP_GENERAL_FAILURE: + OutputText(IDS_GEN_FAILURE); + return false; + + default: + return false; + } + + if (OutputHopAddress) + { + if (Status == IP_SUCCESS) + { + FoundTarget = true; + } + if (Status == IP_TTL_EXPIRED_TRANSIT || Status == IP_SUCCESS) + { + PrintHopInfo(AddressInfo); + } + else if (Status == IP_REQ_TIMED_OUT) + { + OutputText(IDS_REQ_TIMED_OUT); + } + } + + return true; +} + +static bool +RunTraceRoute() +{ + bool Success = false; + Success = ResolveTarget(); + if (!Success) + { + OutputText(IDS_UNABLE_RESOLVE, Info.HostName); + return false; + } + + BYTE SendBuffer[PACKET_SIZE]; + ICMPV6_ECHO_REPLY ReplyBufferv6; +#ifdef _WIN64 + ICMP_ECHO_REPLY32 ReplyBufferv432; +#else + ICMP_ECHO_REPLY ReplyBufferv4; +#endif + PVOID ReplyBuffer; + + DWORD ReplySize = PACKET_SIZE + SIZEOF_ICMP_ERROR + SIZEOF_IO_STATUS_BLOCK; + if (Info.Family == AF_INET6) + { + ReplyBuffer = &ReplyBufferv6; + ReplySize += sizeof(ICMPV6_ECHO_REPLY); + } + else + { +#ifdef _WIN64 + ReplyBuffer = &ReplyBufferv432; + ReplySize += sizeof(ICMP_ECHO_REPLY32); +#else + ReplyBuffer = &ReplyBufferv4; + ReplySize += sizeof(ICMP_ECHO_REPLY); +#endif + } + + if (Info.Family == AF_INET6) + { + Info.hIcmpFile = Icmp6CreateFile(); + } + else + { + Info.hIcmpFile = IcmpCreateFile(); + } + if (Info.hIcmpFile == INVALID_HANDLE_VALUE) + { + FreeAddrInfoW(Info.Target); + return false; + } + + OutputText(IDS_TRACE_INFO, Info.HostName, Info.TargetIP, Info.MaxHops); + + IP_OPTION_INFORMATION IpOptionInfo; + ZeroMemory(&IpOptionInfo, sizeof(IpOptionInfo)); + + bool Quit = false; + ULONG HopCount = 1; + bool FoundTarget = false; + while ((HopCount <= Info.MaxHops) && (FoundTarget == false) && (Quit == false)) + { + OutputText(IDS_HOP_COUNT, HopCount); + + for (int Ping = 1; Ping <= NUM_OF_PINGS; Ping++) + { + IpOptionInfo.Ttl = static_cast<UCHAR>(HopCount); + + if (Info.Family == AF_INET6) + { + struct sockaddr_in6 Source; + + ZeroMemory(&Source, sizeof(Source)); + Source.sin6_family = AF_INET6; + + (void)Icmp6SendEcho2(Info.hIcmpFile, + NULL, + NULL, + NULL, + &Source, + (struct sockaddr_in6 *)Info.Target->ai_addr, + SendBuffer, + (USHORT)PACKET_SIZE, + &IpOptionInfo, + ReplyBuffer, + ReplySize, + Info.Timeout); + } + else + { + (void)IcmpSendEcho2(Info.hIcmpFile, + NULL, + NULL, + NULL, + ((PSOCKADDR_IN)Info.Target->ai_addr)->sin_addr.s_addr, + SendBuffer, + (USHORT)PACKET_SIZE, + &IpOptionInfo, + ReplyBuffer, + ReplySize, + Info.Timeout); + } + + if (DecodeResponse(ReplyBuffer, (Ping == NUM_OF_PINGS), FoundTarget) == false) + { + Quit = true; + break; + } + + if (FoundTarget) + { + Success = true; + break; + } + } + + HopCount++; + Sleep(100); + } + + OutputText(IDS_TRACE_COMPLETE); + + FreeAddrInfoW(Info.Target); + if (Info.hIcmpFile) + { + IcmpCloseHandle(Info.hIcmpFile); + } + + return Success; +} + +static bool +ParseCmdline(int argc, wchar_t *argv[]) +{ + if (argc < 2) + { + Usage(); + return false; + } + + for (int i = 1; i < argc; i++) + { + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'd': + Info.ResolveAddresses = FALSE; + break; + + case 'h': + Info.MaxHops = GetULONG(argv[++i]); + break; + + case 'j': + printf("-j is not yet implemented.\n"); + return false; + + case 'w': + Info.Timeout = GetULONG(argv[++i]); + break; + + case '4': + Info.Family = AF_INET; + break; + + case '6': + Info.Family = AF_INET6; + break; + + default: + { + OutputText(IDS_INVALID_OPTION, argv[i]); + Usage(); + return false; + } + } + } + else + { + StringCchCopyW(Info.HostName, NI_MAXHOST, argv[i]); + break; + } + } + + return true; +} + +EXTERN_C +int wmain(int argc, wchar_t *argv[]) +{ + Info.ResolveAddresses = true; + Info.MaxHops = 30; + Info.Timeout = 4000; + Info.Family = AF_UNSPEC; + + if (!ParseCmdline(argc, argv)) + { + return 1; + } + + WSADATA WsaData; + if (WSAStartup(MAKEWORD(2, 2), &WsaData)) + { + return 1; + } + + bool Success; + Success = RunTraceRoute(); + + WSACleanup(); + + return Success ? 0 : 1; +} diff --git a/base/applications/network/tracert/tracert.h b/base/applications/network/tracert/tracert.h deleted file mode 100644 index 9026ae3a62..0000000000 --- a/base/applications/network/tracert/tracert.h +++ /dev/null @@ -1,81 +0,0 @@ -#define WIN32_NO_STATUS -#include <stdarg.h> -#include <windef.h> -#include <winbase.h> -#define _INC_WINDOWS -#include <winsock2.h> -#include <tchar.h> -#include <stdio.h> -#include <stdlib.h> -#include <ws2tcpip.h> - -#define ECHO_REPLY 0 -#define DEST_UNREACHABLE 3 -#define ECHO_REQUEST 8 -#define TTL_EXCEEDED 11 - -#define MAX_PING_PACKET_SIZE 1024 -#define MAX_PING_DATA_SIZE (MAX_PING_PACKET_SIZE + sizeof(IPv4Header)) -#define PACKET_SIZE 32 -#define ICMP_MIN_SIZE 8 - -/* we need this for packets which have the 'dont fragment' - * bit set, as they can get quite large otherwise */ -#define MAX_REC_SIZE 200 - -/* pack the structures */ -#include <pshpack1.h> - -/* IPv4 Header, 20 bytes */ -typedef struct IPv4Header -{ - BYTE h_len:4; - BYTE version:4; - BYTE tos; - USHORT length; - USHORT id; - USHORT flag_frag; - BYTE ttl; - BYTE proto; - USHORT checksum; - ULONG source; - ULONG dest; -} IPv4_HEADER, *PIPv4_HEADER; - -/* ICMP Header, 8 bytes */ -typedef struct ICMPHeader -{ - BYTE type; - BYTE code; - USHORT checksum; - USHORT id; // not used in time exceeded - USHORT seq; // not used in time exceeded -} ICMP_HEADER, *PICMP_HEADER; - -/* ICMP Echo Reply Header */ -typedef struct EchoReplyHeader -{ - struct ICMPHeader icmpheader; -} ECHO_REPLY_HEADER, *PECHO_REPLY_HEADER; - -#include <poppack.h> - -typedef struct _APPINFO -{ - SOCKET icmpSock; // socket descriptor - SOCKADDR_IN source, dest; // source and destination address info - PECHO_REPLY_HEADER SendPacket; // ICMP echo packet - PIPv4_HEADER RecvPacket; // return receive packet - - BOOL bUsePerformanceCounter; // whether to use the high res performance counter - LARGE_INTEGER TicksPerMs; // number of millisecs in relation to proc freq - LARGE_INTEGER TicksPerUs; // number of microsecs in relation to proc freq - LONGLONG lTimeStart; // send packet, timer start - LONGLONG lTimeEnd; // receive packet, timer end - - BOOL bResolveAddresses; // -d MS ping defaults to true. - INT iMaxHops; // -h Max number of hops before trace ends - INT iHostList; // -j Source route - INT iTimeOut; // -w time before packet times out - -} APPINFO, *PAPPINFO; diff --git a/base/applications/network/tracert/tracert.rc b/base/applications/network/tracert/tracert.rc index 96a08196b5..a39998756f 100644 --- a/base/applications/network/tracert/tracert.rc +++ b/base/applications/network/tracert/tracert.rc @@ -1,5 +1,61 @@ -#define REACTOS_STR_FILE_DESCRIPTION "ReactOS TCP/IPv4 Win32 Traceroute" +#include <windef.h> +#include "resource.h" + +#define REACTOS_STR_FILE_DESCRIPTION "ReactOS TCP/IP Traceroute" #define REACTOS_STR_INTERNAL_NAME "tracert" #define REACTOS_STR_ORIGINAL_FILENAME "tracert.exe" -#define REACTOS_STR_ORIGINAL_COPYRIGHT "Ged Murphy (gedmurphy@gmail.com)" +#define REACTOS_STR_ORIGINAL_COPYRIGHT "Ged Murphy (gedmurphy@reactos.org)" #include <reactos/version.rc> + + +/* UTF-8 */ +#pragma code_page(65001) + +#ifdef LANGUAGE_BG_BG + #include "lang/bg-BG.rc" +#endif +#ifdef LANGUAGE_CS_CZ + #include "lang/cs-CZ.rc" +#endif +#ifdef LANGUAGE_DE_DE + #include "lang/de-DE.rc" +#endif +#ifdef LANGUAGE_EN_US + #include "lang/en-US.rc" +#endif +#ifdef LANGUAGE_ES_ES + #include "lang/es-ES.rc" +#endif +#ifdef LANGUAGE_FR_FR + #include "lang/fr-FR.rc" +#endif +#ifdef LANGUAGE_IT_IT + #include "lang/it-IT.rc" +#endif +#ifdef LANGUAGE_PL_PL + #include "lang/pl-PL.rc" +#endif +#ifdef LANGUAGE_RO_RO + #include "lang/ro-RO.rc" +#endif +#ifdef LANGUAGE_RU_RU + #include "lang/ru-RU.rc" +#endif +#ifdef LANGUAGE_SV_SE + #include "lang/sv-SE.rc" +#endif +#ifdef LANGUAGE_SQ_AL + #include "lang/sq-AL.rc" +#endif +#ifdef LANGUAGE_TR_TR + #include "lang/tr-TR.rc" +#endif +#ifdef LANGUAGE_UK_UA + #include "lang/uk-UA.rc" +#endif +#ifdef LANGUAGE_ZH_CN + #include "lang/zh-CN.rc" +#endif +#ifdef LANGUAGE_ZH_TW + #include "lang/zh-TW.rc" +#endif diff --git a/sdk/include/psdk/icmpapi.h b/sdk/include/psdk/icmpapi.h index c8aae44aa3..8c6bcbd92a 100644 --- a/sdk/include/psdk/icmpapi.h +++ b/sdk/include/psdk/icmpapi.h @@ -21,6 +21,10 @@ #ifndef __WINE_ICMPAPI_H #define __WINE_ICMPAPI_H
+#ifdef __cplusplus +extern "C" { +#endif + HANDLE WINAPI IcmpCreateFile( VOID ); @@ -91,4 +95,9 @@ Icmp6ParseReplies( DWORD ReplySize );
+#ifdef __cplusplus +} +#endif + + #endif /* __WINE_ICMPAPI_H */