From f6adacf936890ffd298e67fe9ae78c0c5d060643 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 7 Oct 2019 11:15:45 +0100 Subject: [PATCH] Review fixes --- daemon/CMakeLists.txt | 33 ++- daemon/dns.cpp | 301 ------------------------- daemon/{rcutil.cpp => lokinetctl.cpp} | 2 +- docker/compose/compose-base.Dockerfile | 2 +- llarp/config/config.cpp | 4 +- win32-setup/lokinet-win32.iss | 116 +++++----- 6 files changed, 78 insertions(+), 380 deletions(-) delete mode 100644 daemon/dns.cpp rename daemon/{rcutil.cpp => lokinetctl.cpp} (99%) diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 8d6d915e4..987a4205d 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -1,5 +1,7 @@ set(EXE lokinet) set(EXE_SRC main.cpp) +set(CTL lokinetctl) +set(CTL_SRC lokinetctl.cpp) if(TRACY_ROOT) list(APPEND EXE_SRC ${TRACY_ROOT}/TracyClient.cpp) @@ -12,22 +14,19 @@ if(SHADOW) target_link_libraries(${LOKINET_SHADOW} ${LOKINET_SHADOW_LIBS}) target_include_directories(${LOKINET_SHADOW} PUBLIC ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/llarp ${PROJECT_SOURCE_DIR}/crypto/include) else() - if(NOT WIN32) - add_executable(${EXE} ${EXE_SRC}) - add_executable(lokinet-rcutil rcutil.cpp) - elseif(NOT MSVC_VERSION) - add_executable(${EXE} ${EXE_SRC} llarp/win32/version.rc) - add_executable(lokinet-rcutil rcutil.cpp llarp/win32/version.rc) - else() - add_executable(${EXE} ${EXE_SRC}) - add_executable(lokinet-rcutil rcutil.cpp) - endif(NOT WIN32) + if(WIN32 AND NOT MSVC_VERSION) + list(APPEND ${EXE_SRC} llarp/win32/version.rc) + list(APPEND ${CTL_SRC} llarp/win32/version.rc) + endif() + + add_executable(${EXE} ${EXE_SRC}) + add_executable(${CTL} ${CTL_SRC}) add_log_tag(${EXE}) - add_log_tag(lokinet-rcutil) + add_log_tag(${CTL}) install(TARGETS ${EXE} RUNTIME DESTINATION bin) - install(TARGETS lokinet-rcutil RUNTIME DESTINATION bin) + install(TARGETS ${CTL} RUNTIME DESTINATION bin) if(WIN32) install(PROGRAMS ${CMAKE_SOURCE_DIR}/lokinet-bootstrap.exe DESTINATION bin) else() @@ -38,17 +37,17 @@ else() install(CODE "execute_process(COMMAND setcap cap_net_admin,cap_net_bind_service=+eip ${CMAKE_INSTALL_PREFIX}/bin/lokinet)") elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") target_link_directories(${EXE} PRIVATE /usr/local/lib) - target_link_directories(lokinet-rcutil PRIVATE /usr/local/lib) + target_link_directories(${CTL} PRIVATE /usr/local/lib) endif() target_link_libraries(${EXE} PUBLIC ${EXE_LIBS} ${LIBS}) - target_link_libraries(lokinet-rcutil PUBLIC ${EXE_LIBS} ${LIBS}) + target_link_libraries(${CTL} PUBLIC ${EXE_LIBS} ${LIBS}) find_package(CURL) if(CURL_FOUND) - target_include_directories(lokinet-rcutil PRIVATE ${CURL_INCLUDE_DIRS}) - target_link_libraries(lokinet-rcutil PRIVATE ${CURL_LIBRARIES}) - target_compile_definitions(lokinet-rcutil PRIVATE -DWITH_CURL=1) + target_include_directories(${CTL} PRIVATE ${CURL_INCLUDE_DIRS}) + target_link_libraries(${CTL} PRIVATE ${CURL_LIBRARIES}) + target_compile_definitions(${CTL} PRIVATE -DWITH_CURL=1) endif(CURL_FOUND) endif(SHADOW) diff --git a/daemon/dns.cpp b/daemon/dns.cpp deleted file mode 100644 index 78503a2cd..000000000 --- a/daemon/dns.cpp +++ /dev/null @@ -1,301 +0,0 @@ -#include -#include -#include -#include -#include -#include // for multithreaded version (multiplatorm) - -#include // Linux needs this for SIGINT -#include - -#ifdef _WIN32 -#define uint UINT -#endif - -#if(__FreeBSD__) || (__OpenBSD__) || (__NetBSD__) -#include -#endif - -// CHECK: is multiprocess still a thing? -#ifndef TESTNET -#define TESTNET 0 -#endif - -struct llarp_main *ctx = 0; -bool done = false; - -void -handle_signal(int sig) -{ - printf("got SIGINT\n"); - done = true; - // if using router, signal it - if(ctx) - llarp_main_signal(ctx, sig); -} - -struct dns_relay_config -{ - std::string upstream_host; - uint16_t upstream_port; - - void - dns_iter_config(const char *section, const char *key, const char *val) - { - if(!strcmp(section, "dns")) - { - if(!strcmp(key, "upstream-server")) - { - upstream_host = strdup(val); - llarp::LogDebug("Config file setting dns server to ", upstream_host); - } - if(!strcmp(key, "upstream-port")) - { - upstream_port = atoi(val); - llarp::LogDebug("Config file setting dns server port to ", - upstream_port); - } - } - } -}; - -int -main(int argc, char *argv[]) -{ - int code = 1; - char cwd[1024]; - char *ptr = getcwd(cwd, sizeof(cwd)); - llarp::LogInfo("Starting up server at ", ptr); - - const char *conffname = handleBaseCmdLineArgs(argc, argv); - dns_relay_config dnsr_config; - dnsr_config.upstream_host = "8.8.8.8"; - dnsr_config.upstream_port = 53; - llarp::Config config_reader; - - if(config_reader.load(conffname)) - { - llarp::LogError("failed to load config file ", conffname); - return 0; - } - - using namespace std::placeholders; - config_reader.visit( - std::bind(&dns_relay_config::dns_iter_config, &dnsr_config, _1, _2, _3)); - llarp::LogInfo("config [", conffname, "] loaded"); - - const uint16_t server_port = 53; - - dns_iptracker_init(); - - // llarp::SetLogLevel(llarp::eLogDebug); - - bool enableDLL = false; - bool useLlarp = true; - - if(enableDLL) - { - // libev version w/router context - ctx = llarp_main_init(conffname, !TESTNET); - if(!ctx) - { - llarp::LogError("Cant set up context"); - return 0; - } - llarp_main_setup(ctx); - signal(SIGINT, handle_signal); - - // we can't programmatic force a client - // but we'll need to be one... - - /* - struct dnsd_context dnsd; - llarp::Addr dnsd_sockaddr(127, 0, 0, 1, 53); - llarp::Addr dnsc_sockaddr(dnsr_config.upstream_host, - dnsr_config.upstream_port); - // server_port, (const char *)dnsr_config.upstream_host.c_str(), - // dnsr_config.upstream_port - if(!llarp_main_init_dnsd(ctx, &dnsd, dnsd_sockaddr, dnsc_sockaddr)) - { - llarp::LogError("Couldnt init dns daemon"); - } - // Configure intercept - dnsd.intercept = &llarp_dotlokilookup_handler; - dotLokiLookup dll; - */ - // should be a function... - // dll.tunEndpoint = main_router_getFirstTunEndpoint(ctx); - // dll.ip_tracker = &g_dns_iptracker; - /* - llarp_main_init_dotLokiLookup(ctx, &dll); - dnsd.user = &dll; - - // check tun set up - llarp_tun_io *tun = main_router_getRange(ctx); - llarp::LogDebug("TunNetmask: ", tun->netmask); - llarp::LogDebug("TunIfAddr: ", tun->ifaddr); - - // configure dns_ip_tracker to use this - // well our routes table should already be set up - - // mark our TunIfAddr as used - if(tun) - { - dll.user = tun; - struct sockaddr_in addr; - addr.sin_addr.s_addr = inet_addr(tun->ifaddr); - addr.sin_family = AF_INET; - - llarp::Addr tunIp(addr); - llarp::LogDebug("llarp::TunIfAddr: ", tunIp); - dns_iptracker_setup_dotLokiLookup(&dll, tunIp); - dns_iptracker_setup(tunIp); - } - else - { - llarp::LogWarn("No tun interface, can't look up .loki"); - } - */ - - // run system and wait - llarp_main_run(ctx); - llarp_main_free(ctx); - } - else if(useLlarp) - { - // libev version - llarp_ev_loop *netloop = nullptr; - llarp_threadpool *worker = nullptr; - llarp::Logic *logic = nullptr; - - llarp_ev_loop_alloc(&netloop); // set up netio worker - worker = llarp_init_same_process_threadpool(); - logic = new llarp::Logic(worker); // set up logic worker - - // configure main netloop - struct dnsd_context dnsd; - llarp::Addr dnsd_sockaddr(127, 0, 0, 1, 53); - llarp::Addr dnsc_sockaddr(dnsr_config.upstream_host, - dnsr_config.upstream_port); - llarp::LogInfo("dnsd_sockaddr init: ", dnsd_sockaddr); - llarp::LogInfo("dnsc_sockaddr init: ", dnsc_sockaddr); - if(!llarp_dnsd_init(&dnsd, logic, netloop, dnsd_sockaddr, dnsc_sockaddr)) - { - // llarp::LogError("failed to initialize dns subsystem"); - llarp::LogError("Couldnt init dns daemon"); - return 0; - } - // Configure intercept - dnsd.intercept = &llarp_dotlokilookup_handler; - - llarp::LogInfo("singlethread start"); - llarp_ev_loop_run_single_process(netloop, worker, logic); - llarp::LogInfo("singlethread end"); - - llarp_ev_loop_free(&netloop); - } - else - { - // need this for timer stuff - llarp_threadpool *worker = llarp_init_same_process_threadpool(); - llarp::Logic *logic = new llarp::Logic(worker); - - // configure main netloop - struct dnsd_context dnsd; - llarp::Addr dnsd_sockaddr(127, 0, 0, 1, 53); - llarp::Addr dnsc_sockaddr(dnsr_config.upstream_host, - dnsr_config.upstream_port); - if(!llarp_dnsd_init(&dnsd, logic, nullptr, dnsd_sockaddr, dnsc_sockaddr)) - { - // llarp::LogError("failed to initialize dns subsystem"); - llarp::LogError("Couldnt init dns daemon"); - return 0; - } - // Configure intercept - dnsd.intercept = &llarp_dotlokilookup_handler; - - struct sockaddr_in m_address; - int m_sockfd; - -#ifndef _WIN32 - m_sockfd = socket(AF_INET, SOCK_DGRAM, 0); -#else - m_sockfd = - WSASocket(AF_INET, SOCK_DGRAM, 0, nullptr, 0, WSA_FLAG_OVERLAPPED); -#endif - m_address.sin_family = AF_INET; - m_address.sin_addr.s_addr = INADDR_ANY; - m_address.sin_port = htons(server_port); - int rbind = bind(m_sockfd, (struct sockaddr *)&m_address, - sizeof(struct sockaddr_in)); - - if(rbind != 0) - { - llarp::LogError("Could not bind: ", strerror(errno)); - return 0; - } - - const size_t BUFFER_SIZE = 1024; - char buffer[BUFFER_SIZE]; // 1024 is buffer size - struct sockaddr_in clientAddress; - socklen_t addrLen = sizeof(struct sockaddr_in); - - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 100 * 1000; // 1 sec -#ifndef _WIN32 - if(setsockopt(m_sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) -#else - if(setsockopt(m_sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, - sizeof(tv)) - < 0) -#endif - { - perror("Error"); - } - - signal(SIGINT, handle_signal); - while(!done) - { - // sigint quits after next packet - int nbytes = recvfrom(m_sockfd, buffer, BUFFER_SIZE, 0, - (struct sockaddr *)&clientAddress, &addrLen); - if(nbytes == -1) - continue; - llarp::LogInfo("Received Bytes ", nbytes); - - llarp_buffer_t lbuffer; - lbuffer.base = (byte_t *)buffer; - lbuffer.cur = lbuffer.base; - lbuffer.sz = nbytes; - - dns_msg_header hdr; - if(!decode_hdr(&lbuffer, &hdr)) - { - llarp::LogError("failed to decode dns header"); - continue; - } - - // if we sent this out, then there's an id - struct dns_tracker *tracker = (struct dns_tracker *)dnsd.client.tracker; - struct dnsc_answer_request *request = - tracker->client_request[hdr.id].get(); - - if(request) - { - request->packet.header = hdr; - generic_handle_dnsc_recvfrom(tracker->client_request[hdr.id].get(), - lbuffer, &hdr); - } - else - { - llarp::LogWarn("Ignoring multiple responses on ID #", hdr.id); - } - - // raw_handle_recvfrom(&m_sockfd, (const struct sockaddr *)&clientAddress, - // buffer, nbytes); - } - } - - return code; -} diff --git a/daemon/rcutil.cpp b/daemon/lokinetctl.cpp similarity index 99% rename from daemon/rcutil.cpp rename to daemon/lokinetctl.cpp index 0e8f2c61a..909c90a14 100644 --- a/daemon/rcutil.cpp +++ b/daemon/lokinetctl.cpp @@ -116,7 +116,7 @@ main(int argc, char* argv[]) // clang-format off cxxopts::Options options( - "lokinet-rcutil", + "lokinetctl", "LokiNET is a free, open source, private, decentralized, \"market based sybil resistant\" and IP based onion routing network" ); diff --git a/docker/compose/compose-base.Dockerfile b/docker/compose/compose-base.Dockerfile index 07caebd24..3211ae880 100644 --- a/docker/compose/compose-base.Dockerfile +++ b/docker/compose/compose-base.Dockerfile @@ -13,4 +13,4 @@ RUN make NINJA=ninja STATIC_LINK=ON BUILD_TYPE=Release FROM alpine:latest COPY --from=builder /src/build/daemon/lokinet / -COPY --from=builder /src/build/daemon/lokinet-rcutil / +COPY --from=builder /src/build/daemon/lokinet-ctl / diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index cab18e877..0ba2b968b 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -479,9 +479,9 @@ namespace llarp GetDefaultConfigDir() { #ifdef _WIN32 - fs::path homedir = fs::path(getenv("APPDATA")); + const fs::path homedir = fs::path(getenv("APPDATA")); #else - fs::path homedir = fs::path(getenv("HOME")); + const fs::path homedir = fs::path(getenv("HOME")); #endif return homedir / fs::path(".lokinet"); } diff --git a/win32-setup/lokinet-win32.iss b/win32-setup/lokinet-win32.iss index 544bffe4b..2b0f0299b 100644 --- a/win32-setup/lokinet-win32.iss +++ b/win32-setup/lokinet-win32.iss @@ -1,67 +1,67 @@ -; Script generated by the Inno Script Studio Wizard. -; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! - -#define MyAppName "Lokinet" -#define MyAppVersion "0.5.2" -#define MyAppPublisher "Loki Project" -#define MyAppURL "https://lokinet.org" -#define MyAppExeName "lokinetui.exe" +; Script generated by the Inno Script Studio Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +#define MyAppName "Lokinet" +#define MyAppVersion "0.5.2" +#define MyAppPublisher "Loki Project" +#define MyAppURL "https://lokinet.org" +#define MyAppExeName "lokinetui.exe" ; change this to avoid compiler errors -despair -#ifndef DevPath +#ifndef DevPath #define DevPath "D:\dev\external\llarp\" -#endif +#endif #include #include "version.txt" - + ; see ../LICENSE - -[Setup] -; NOTE: The value of AppId uniquely identifies this application. -; Do not use the same AppId value in installers for other applications. -; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) -AppId={{11335EAC-0385-4C78-A3AA-67731326B653}} -AppName={#MyAppName} -AppVersion={#MyAppVersion} + +[Setup] +; NOTE: The value of AppId uniquely identifies this application. +; Do not use the same AppId value in installers for other applications. +; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) +AppId={{11335EAC-0385-4C78-A3AA-67731326B653}} +AppName={#MyAppName} +AppVersion={#MyAppVersion} #ifndef RELEASE AppVerName={#MyAppName} {#MyAppVersion}-dev #else AppVerName={#MyAppName} {#MyAppVersion} -#endif -AppPublisher={#MyAppPublisher} -AppPublisherURL={#MyAppURL} -AppSupportURL={#MyAppURL} -AppUpdatesURL={#MyAppURL} -DefaultDirName={pf}\{#MyAppPublisher}\{#MyAppName} -DefaultGroupName={#MyAppName} -AllowNoIcons=yes -LicenseFile={#DevPath}LICENSE -OutputDir={#DevPath}win32-setup -OutputBaseFilename=lokinet-win32 -Compression=lzma2/ultra64 -SolidCompression=yes -VersionInfoVersion=0.5.2 -VersionInfoCompany=Loki Project -VersionInfoDescription=LokiNET for Microsoft® Windows® NT™ -#ifndef RELEASE +#endif +AppPublisher={#MyAppPublisher} +AppPublisherURL={#MyAppURL} +AppSupportURL={#MyAppURL} +AppUpdatesURL={#MyAppURL} +DefaultDirName={pf}\{#MyAppPublisher}\{#MyAppName} +DefaultGroupName={#MyAppName} +AllowNoIcons=yes +LicenseFile={#DevPath}LICENSE +OutputDir={#DevPath}win32-setup +OutputBaseFilename=lokinet-win32 +Compression=lzma2/ultra64 +SolidCompression=yes +VersionInfoVersion=0.5.2 +VersionInfoCompany=Loki Project +VersionInfoDescription=LokiNET for Microsoft� Windows� NT� +#ifndef RELEASE VersionInfoTextVersion=0.5.2-dev-{#VCSRev} VersionInfoProductTextVersion=0.5.2-dev-{#VCSRev} #else VersionInfoTextVersion=0.5.2 VersionInfoProductTextVersion=0.5.2 ({#Codename}) -#endif -VersionInfoProductName=LokiNET -VersionInfoProductVersion=0.5.2 +#endif +VersionInfoProductName=LokiNET +VersionInfoProductVersion=0.5.2 InternalCompressLevel=ultra64 -MinVersion=0,5.0 -ArchitecturesInstallIn64BitMode=x64 -VersionInfoCopyright=Copyright ©2018-2019 Loki Project - -[Languages] -Name: "english"; MessagesFile: "compiler:Default.isl" - -[Tasks] -Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked -Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1 +MinVersion=0,5.0 +ArchitecturesInstallIn64BitMode=x64 +VersionInfoCopyright=Copyright �2018-2019 Loki Project + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked +Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1 [Files] ; only one of these is installed @@ -89,7 +89,7 @@ Source: "{#DevPath}ui-win32\bin\release\lokinetui.pdb"; DestDir: "{app}"; Flags: #endif ; eh, might as well ship the 32-bit port of everything else Source: "{#DevPath}build\testAll.exe"; DestDir: "{app}"; Flags: ignoreversion -Source: "{#DevPath}build\lokinet-rcutil.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "{#DevPath}build\lokinetctl.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "LICENSE"; DestDir: "{app}"; Flags: ignoreversion Source: "lokinet-bootstrap.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "rootcerts.pem"; DestDir: "{app}"; Flags: ignoreversion @@ -144,7 +144,7 @@ Filename: "{app}\tap-windows-9.9.2\remove.bat"; WorkingDir: "{app}\tap-windows-9 Name: "{userappdata}\.lokinet" [Code] -var +var TapInstalled: Boolean; function reg_query_helper(): Integer; @@ -212,13 +212,13 @@ begin idpDownloadAfter(wpReady); end; -[Icons] -Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" -Name: "{group}\{cm:ProgramOnTheWeb,{#MyAppName}}"; Filename: "{#MyAppURL}" -Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" -Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon +[Icons] +Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" +Name: "{group}\{cm:ProgramOnTheWeb,{#MyAppName}}"; Filename: "{#MyAppURL}" +Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" +Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon; OnlyBelowVersion: 0, 6.1 -Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon; MinVersion: 0, 6.1 +Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon; MinVersion: 0, 6.1 [Run] Filename: "{app}\{#MyAppExeName}"; Flags: nowait postinstall skipifsilent; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}" @@ -233,4 +233,4 @@ Filename: "{app}\tap-windows-9.21.2\install.bat"; WorkingDir: "{app}\tap-windows ; install inet6 if not present. (I'd assume netsh displays something helpful if inet6 is already set up and configured.) ; if it doesn't exist, then the inet6 driver appears to be installed Filename: "{app}\inet6_driver\setup\hotfix.exe"; Parameters: "/m /z"; WorkingDir: "{app}\inet6_driver\setup\"; Flags: runascurrentuser waituntilterminated skipifdoesntexist; Description: "Install IPv6 driver"; StatusMsg: "Installing IPv6..."; OnlyBelowVersion: 0, 5.1; Check: not FileExists(ExpandConstant('{sys}\drivers\tcpip6.sys')) -Filename: "{sys}\netsh.exe"; Parameters: "int ipv6 install"; Flags: runascurrentuser waituntilterminated; Description: "install ipv6 on whistler"; StatusMsg: "Installing IPv6..."; MinVersion: 0,5.1; OnlyBelowVersion: 0,6.0 \ No newline at end of file +Filename: "{sys}\netsh.exe"; Parameters: "int ipv6 install"; Flags: runascurrentuser waituntilterminated; Description: "install ipv6 on whistler"; StatusMsg: "Installing IPv6..."; MinVersion: 0,5.1; OnlyBelowVersion: 0,6.0