Add logging to disk

This commit is contained in:
Cameron Gutman 2019-07-13 14:24:35 -07:00
parent fbd19d716a
commit 53c017974d
3 changed files with 93 additions and 38 deletions

View File

@ -1,3 +1,5 @@
#define _CRT_SECURE_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <Windows.h>
@ -20,6 +22,8 @@
#include <miniupnpc/upnpcommands.h> #include <miniupnpc/upnpcommands.h>
#include <miniupnpc/upnperrors.h> #include <miniupnpc/upnperrors.h>
#include "../version.h"
#define SERVICE_NAME L"GSv6FwdSvc" #define SERVICE_NAME L"GSv6FwdSvc"
LPFN_WSARECVMSG WSARecvMsg; LPFN_WSARECVMSG WSARecvMsg;
@ -145,7 +149,7 @@ FindLocalAddressBySocket(SOCKET s, PIN_ADDR targetAddress)
// Get local address of the accepted socket so we can find the interface // Get local address of the accepted socket so we can find the interface
localSockAddrLen = sizeof(localSockAddr); localSockAddrLen = sizeof(localSockAddr);
if (getsockname(s, (PSOCKADDR)&localSockAddr, &localSockAddrLen) == SOCKET_ERROR) { if (getsockname(s, (PSOCKADDR)&localSockAddr, &localSockAddrLen) == SOCKET_ERROR) {
fprintf(stderr, "getsockname() failed: %d\n", WSAGetLastError()); printf("getsockname() failed: %d\n", WSAGetLastError());
return WSAGetLastError(); return WSAGetLastError();
} }
@ -160,7 +164,7 @@ FindLocalAddressBySocket(SOCKET s, PIN_ADDR targetAddress)
&addresses, &addresses,
&length); &length);
if (error != ERROR_SUCCESS) { if (error != ERROR_SUCCESS) {
fprintf(stderr, "GetAdaptersAddresses() failed: %d\n", error); printf("GetAdaptersAddresses() failed: %d\n", error);
return error; return error;
} }
@ -191,7 +195,7 @@ FindLocalAddressBySocket(SOCKET s, PIN_ADDR targetAddress)
// Check if we found the incoming interface // Check if we found the incoming interface
if (currentAdapter == NULL) { if (currentAdapter == NULL) {
// Hopefully the error is caused by transient interface reconfiguration // Hopefully the error is caused by transient interface reconfiguration
fprintf(stderr, "Unable to find incoming interface\n"); printf("Unable to find incoming interface\n");
return WSAENETDOWN; return WSAENETDOWN;
} }
@ -212,7 +216,7 @@ FindLocalAddressBySocket(SOCKET s, PIN_ADDR targetAddress)
// has no IPv4 connectivity. In this case, we can preserve most // has no IPv4 connectivity. In this case, we can preserve most
// functionality by forwarding via localhost. WoL won't work but // functionality by forwarding via localhost. WoL won't work but
// the basic stuff will. // the basic stuff will.
fprintf(stderr, "WARNING: No IPv4 connectivity on incoming interface\n"); printf("WARNING: No IPv4 connectivity on incoming interface\n");
targetAddress->S_un.S_addr = htonl(INADDR_LOOPBACK); targetAddress->S_un.S_addr = htonl(INADDR_LOOPBACK);
return 0; return 0;
} }
@ -232,13 +236,13 @@ TcpListenerThreadProc(LPVOID Context)
for (;;) { for (;;) {
acceptedSocket = accept(tuple->listener, NULL, 0); acceptedSocket = accept(tuple->listener, NULL, 0);
if (acceptedSocket == INVALID_SOCKET) { if (acceptedSocket == INVALID_SOCKET) {
fprintf(stderr, "accept() failed: %d\n", WSAGetLastError()); printf("accept() failed: %d\n", WSAGetLastError());
break; break;
} }
targetSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); targetSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (targetSocket == INVALID_SOCKET) { if (targetSocket == INVALID_SOCKET) {
fprintf(stderr, "socket() failed: %d\n", WSAGetLastError()); printf("socket() failed: %d\n", WSAGetLastError());
closesocket(acceptedSocket); closesocket(acceptedSocket);
continue; continue;
} }
@ -253,7 +257,7 @@ TcpListenerThreadProc(LPVOID Context)
} }
if (connect(targetSocket, (PSOCKADDR)&targetAddress, sizeof(targetAddress)) == SOCKET_ERROR) { if (connect(targetSocket, (PSOCKADDR)&targetAddress, sizeof(targetAddress)) == SOCKET_ERROR) {
fprintf(stderr, "connect() failed: %d\n", WSAGetLastError()); printf("connect() failed: %d\n", WSAGetLastError());
closesocket(acceptedSocket); closesocket(acceptedSocket);
closesocket(targetSocket); closesocket(targetSocket);
continue; continue;
@ -271,7 +275,7 @@ TcpListenerThreadProc(LPVOID Context)
thread = CreateThread(NULL, 0, TcpRelayThreadProc, relayTuple, 0, NULL); thread = CreateThread(NULL, 0, TcpRelayThreadProc, relayTuple, 0, NULL);
if (thread == NULL) { if (thread == NULL) {
fprintf(stderr, "CreateThread() failed: %d\n", GetLastError()); printf("CreateThread() failed: %d\n", GetLastError());
closesocket(acceptedSocket); closesocket(acceptedSocket);
closesocket(targetSocket); closesocket(targetSocket);
free(relayTuple); free(relayTuple);
@ -295,7 +299,7 @@ int StartTcpRelay(unsigned short Port)
listeningSocket = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); listeningSocket = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (listeningSocket == INVALID_SOCKET) { if (listeningSocket == INVALID_SOCKET) {
fprintf(stderr, "socket() failed: %d\n", WSAGetLastError()); printf("socket() failed: %d\n", WSAGetLastError());
return WSAGetLastError(); return WSAGetLastError();
} }
@ -303,12 +307,12 @@ int StartTcpRelay(unsigned short Port)
addr6.sin6_family = AF_INET6; addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(Port); addr6.sin6_port = htons(Port);
if (bind(listeningSocket, (PSOCKADDR)&addr6, sizeof(addr6)) == SOCKET_ERROR) { if (bind(listeningSocket, (PSOCKADDR)&addr6, sizeof(addr6)) == SOCKET_ERROR) {
fprintf(stderr, "bind() failed: %d\n", WSAGetLastError()); printf("bind() failed: %d\n", WSAGetLastError());
return WSAGetLastError(); return WSAGetLastError();
} }
if (listen(listeningSocket, SOMAXCONN) == SOCKET_ERROR) { if (listen(listeningSocket, SOMAXCONN) == SOCKET_ERROR) {
fprintf(stderr, "listen() failed: %d\n", WSAGetLastError()); printf("listen() failed: %d\n", WSAGetLastError());
return WSAGetLastError(); return WSAGetLastError();
} }
@ -322,7 +326,7 @@ int StartTcpRelay(unsigned short Port)
thread = CreateThread(NULL, 0, TcpListenerThreadProc, tuple, 0, NULL); thread = CreateThread(NULL, 0, TcpListenerThreadProc, tuple, 0, NULL);
if (thread == NULL) { if (thread == NULL) {
fprintf(stderr, "CreateThread() failed: %d\n", GetLastError()); printf("CreateThread() failed: %d\n", GetLastError());
return GetLastError(); return GetLastError();
} }
@ -351,7 +355,7 @@ ForwardUdpPacketV4toV6(PUDP_TUPLE tuple,
msg.Control.len = 0; msg.Control.len = 0;
msg.dwFlags = 0; msg.dwFlags = 0;
if (WSARecvMsg(tuple->ipv4Socket, &msg, &len, NULL, NULL) == SOCKET_ERROR) { if (WSARecvMsg(tuple->ipv4Socket, &msg, &len, NULL, NULL) == SOCKET_ERROR) {
fprintf(stderr, "WSARecvMsg() failed: %d\n", WSAGetLastError()); printf("WSARecvMsg() failed: %d\n", WSAGetLastError());
return WSAGetLastError(); return WSAGetLastError();
} }
@ -361,7 +365,7 @@ ForwardUdpPacketV4toV6(PUDP_TUPLE tuple,
msg.Control = *sourceInfoControlBuffer; msg.Control = *sourceInfoControlBuffer;
msg.dwFlags = 0; msg.dwFlags = 0;
if (WSASendMsg(tuple->ipv6Socket, &msg, 0, &len, NULL, NULL) == SOCKET_ERROR) { if (WSASendMsg(tuple->ipv6Socket, &msg, 0, &len, NULL, NULL) == SOCKET_ERROR) {
fprintf(stderr, "WSASendMsg() failed: %d\n", WSAGetLastError()); printf("WSASendMsg() failed: %d\n", WSAGetLastError());
return WSAGetLastError(); return WSAGetLastError();
} }
@ -389,7 +393,7 @@ ForwardUdpPacketV6toV4(PUDP_TUPLE tuple,
msg.Control = *destInfoControlBuffer; msg.Control = *destInfoControlBuffer;
msg.dwFlags = 0; msg.dwFlags = 0;
if (WSARecvMsg(tuple->ipv6Socket, &msg, &len, NULL, NULL) == SOCKET_ERROR) { if (WSARecvMsg(tuple->ipv6Socket, &msg, &len, NULL, NULL) == SOCKET_ERROR) {
fprintf(stderr, "WSARecvMsg() failed: %d\n", WSAGetLastError()); printf("WSARecvMsg() failed: %d\n", WSAGetLastError());
return WSAGetLastError(); return WSAGetLastError();
} }
@ -407,7 +411,7 @@ ForwardUdpPacketV6toV4(PUDP_TUPLE tuple,
msg.Control.len = 0; msg.Control.len = 0;
msg.dwFlags = 0; msg.dwFlags = 0;
if (WSASendMsg(tuple->ipv4Socket, &msg, 0, &len, NULL, NULL) == SOCKET_ERROR) { if (WSASendMsg(tuple->ipv4Socket, &msg, 0, &len, NULL, NULL) == SOCKET_ERROR) {
fprintf(stderr, "WSASendMsg() failed: %d\n", WSAGetLastError()); printf("WSASendMsg() failed: %d\n", WSAGetLastError());
return WSAGetLastError(); return WSAGetLastError();
} }
@ -490,13 +494,13 @@ int StartUdpRelay(unsigned short Port)
ipv6Socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); ipv6Socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (ipv6Socket == INVALID_SOCKET) { if (ipv6Socket == INVALID_SOCKET) {
fprintf(stderr, "socket() failed: %d\n", WSAGetLastError()); printf("socket() failed: %d\n", WSAGetLastError());
return WSAGetLastError(); return WSAGetLastError();
} }
if (WSAIoctl(ipv6Socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &wsaRecvMsgGuid, sizeof(wsaRecvMsgGuid), if (WSAIoctl(ipv6Socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &wsaRecvMsgGuid, sizeof(wsaRecvMsgGuid),
&WSARecvMsg, sizeof(WSARecvMsg), &bytesReturned, NULL, NULL) == SOCKET_ERROR) { &WSARecvMsg, sizeof(WSARecvMsg), &bytesReturned, NULL, NULL) == SOCKET_ERROR) {
fprintf(stderr, "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, WSARecvMsg) failed: %d\n", WSAGetLastError()); printf("WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, WSARecvMsg) failed: %d\n", WSAGetLastError());
return WSAGetLastError(); return WSAGetLastError();
} }
@ -505,7 +509,7 @@ int StartUdpRelay(unsigned short Port)
// outgoing NIC/address will get dropped by the remote party. // outgoing NIC/address will get dropped by the remote party.
val = TRUE; val = TRUE;
if (setsockopt(ipv6Socket, IPPROTO_IPV6, IPV6_PKTINFO, (char*)&val, sizeof(val)) == SOCKET_ERROR) { if (setsockopt(ipv6Socket, IPPROTO_IPV6, IPV6_PKTINFO, (char*)&val, sizeof(val)) == SOCKET_ERROR) {
fprintf(stderr, "setsockopt(IPV6_PKTINFO) failed: %d\n", WSAGetLastError()); printf("setsockopt(IPV6_PKTINFO) failed: %d\n", WSAGetLastError());
return WSAGetLastError(); return WSAGetLastError();
} }
@ -513,13 +517,13 @@ int StartUdpRelay(unsigned short Port)
addr6.sin6_family = AF_INET6; addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(Port); addr6.sin6_port = htons(Port);
if (bind(ipv6Socket, (PSOCKADDR)&addr6, sizeof(addr6)) == SOCKET_ERROR) { if (bind(ipv6Socket, (PSOCKADDR)&addr6, sizeof(addr6)) == SOCKET_ERROR) {
fprintf(stderr, "bind() failed: %d\n", WSAGetLastError()); printf("bind() failed: %d\n", WSAGetLastError());
return WSAGetLastError(); return WSAGetLastError();
} }
ipv4Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); ipv4Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ipv4Socket == INVALID_SOCKET) { if (ipv4Socket == INVALID_SOCKET) {
fprintf(stderr, "socket() failed: %d\n", WSAGetLastError()); printf("socket() failed: %d\n", WSAGetLastError());
return WSAGetLastError(); return WSAGetLastError();
} }
@ -527,7 +531,7 @@ int StartUdpRelay(unsigned short Port)
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = htonl(INADDR_LOOPBACK); addr.sin_addr.S_un.S_addr = htonl(INADDR_LOOPBACK);
if (bind(ipv4Socket, (PSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR) { if (bind(ipv4Socket, (PSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR) {
fprintf(stderr, "bind() failed: %d\n", WSAGetLastError()); printf("bind() failed: %d\n", WSAGetLastError());
return WSAGetLastError(); return WSAGetLastError();
} }
@ -542,7 +546,7 @@ int StartUdpRelay(unsigned short Port)
thread = CreateThread(NULL, 0, UdpRelayThreadProc, tuple, 0, NULL); thread = CreateThread(NULL, 0, UdpRelayThreadProc, tuple, 0, NULL);
if (thread == NULL) { if (thread == NULL) {
fprintf(stderr, "CreateThread() failed: %d\n", GetLastError()); printf("CreateThread() failed: %d\n", GetLastError());
return GetLastError(); return GetLastError();
} }
@ -749,7 +753,7 @@ void UpdatePcpPinholes()
&addresses, &addresses,
&length); &length);
if (error != ERROR_SUCCESS) { if (error != ERROR_SUCCESS) {
fprintf(stderr, "GetAdaptersAddresses() failed: %d\n", error); printf("GetAdaptersAddresses() failed: %d\n", error);
return; return;
} }
@ -811,16 +815,47 @@ void UpdatePcpPinholes()
} }
} }
void ResetLogFile()
{
char oldLogFilePath[MAX_PATH + 1];
char currentLogFilePath[MAX_PATH + 1];
char timeString[MAX_PATH + 1] = {};
SYSTEMTIME time;
ExpandEnvironmentStringsA("%ProgramData%\\MISS\\GSv6Fwd-old.log", oldLogFilePath, sizeof(oldLogFilePath));
ExpandEnvironmentStringsA("%ProgramData%\\MISS\\GSv6Fwd-current.log", currentLogFilePath, sizeof(currentLogFilePath));
// Close the existing stdout handle. This is important because otherwise
// it may still be open as stdout when we try to MoveFileEx below.
fclose(stdout);
// Rotate the current to the old log file
MoveFileExA(currentLogFilePath, oldLogFilePath, MOVEFILE_REPLACE_EXISTING);
// Redirect stdout to this new file
freopen(currentLogFilePath, "w", stdout);
// Print a log header
printf("IPv6 Forwarder for GameStream v" VER_VERSION_STR "\n");
// Print the current time
GetSystemTime(&time);
GetTimeFormatA(LOCALE_SYSTEM_DEFAULT, 0, &time, "hh':'mm':'ss tt", timeString, ARRAYSIZE(timeString));
printf("The current UTC time is: %s\n", timeString);
}
int Run(void) int Run(void)
{ {
int err; int err;
WSADATA data; WSADATA data;
ResetLogFile();
HANDLE ifaceChangeEvent = CreateEvent(nullptr, true, false, nullptr); HANDLE ifaceChangeEvent = CreateEvent(nullptr, true, false, nullptr);
err = WSAStartup(MAKEWORD(2, 0), &data); err = WSAStartup(MAKEWORD(2, 0), &data);
if (err == SOCKET_ERROR) { if (err == SOCKET_ERROR) {
fprintf(stderr, "WSAStartup() failed: %d\n", err); printf("WSAStartup() failed: %d\n", err);
return err; return err;
} }
@ -834,7 +869,7 @@ int Run(void)
for (int i = 0; i < ARRAYSIZE(TCP_PORTS); i++) { for (int i = 0; i < ARRAYSIZE(TCP_PORTS); i++) {
err = StartTcpRelay(TCP_PORTS[i]); err = StartTcpRelay(TCP_PORTS[i]);
if (err != 0) { if (err != 0) {
fprintf(stderr, "Failed to start relay on TCP %d: %d\n", TCP_PORTS[i], err); printf("Failed to start relay on TCP %d: %d\n", TCP_PORTS[i], err);
return err; return err;
} }
} }
@ -842,16 +877,25 @@ int Run(void)
for (int i = 0; i < ARRAYSIZE(UDP_PORTS); i++) { for (int i = 0; i < ARRAYSIZE(UDP_PORTS); i++) {
err = StartUdpRelay(UDP_PORTS[i]); err = StartUdpRelay(UDP_PORTS[i]);
if (err != 0) { if (err != 0) {
fprintf(stderr, "Failed to start relay on UDP %d: %d\n", UDP_PORTS[i], err); printf("Failed to start relay on UDP %d: %d\n", UDP_PORTS[i], err);
return err; return err;
} }
} }
do { for (;;) {
ResetEvent(ifaceChangeEvent); ResetEvent(ifaceChangeEvent);
UpdatePcpPinholes(); UpdatePcpPinholes();
UpdateUpnpPinholes(); UpdateUpnpPinholes();
} while (WaitForSingleObject(ifaceChangeEvent, 120 * 1000) != WAIT_FAILED);
printf("Going to sleep...\n");
fflush(stdout);
if (WaitForSingleObject(ifaceChangeEvent, 120 * 1000) == WAIT_FAILED) {
break;
}
ResetLogFile();
}
return 0; return 0;
} }
@ -886,7 +930,7 @@ ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
ServiceStatusHandle = RegisterServiceCtrlHandlerEx(SERVICE_NAME, HandlerEx, NULL); ServiceStatusHandle = RegisterServiceCtrlHandlerEx(SERVICE_NAME, HandlerEx, NULL);
if (ServiceStatusHandle == NULL) { if (ServiceStatusHandle == NULL) {
fprintf(stderr, "RegisterServiceCtrlHandlerEx() failed: %d\n", GetLastError()); printf("RegisterServiceCtrlHandlerEx() failed: %d\n", GetLastError());
return; return;
} }

View File

@ -40,18 +40,22 @@
<HintPath>$(WixExtDir)\WixUIExtension.dll</HintPath> <HintPath>$(WixExtDir)\WixUIExtension.dll</HintPath>
<Name>WixUIExtension</Name> <Name>WixUIExtension</Name>
</WixExtension> </WixExtension>
<WixExtension Include="WixUtilExtension">
<HintPath>$(WixExtDir)\WixUtilExtension.dll</HintPath>
<Name>WixUtilExtension</Name>
</WixExtension>
</ItemGroup> </ItemGroup>
<Import Project="$(WixTargetsPath)" Condition=" '$(WixTargetsPath)' != '' " /> <Import Project="$(WixTargetsPath)" Condition=" '$(WixTargetsPath)' != '' " />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets" Condition=" '$(WixTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets') " /> <Import Project="$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets" Condition=" '$(WixTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets') " />
<Target Name="EnsureWixToolsetInstalled" Condition=" '$(WixTargetsImported)' != 'true' "> <Target Name="EnsureWixToolsetInstalled" Condition=" '$(WixTargetsImported)' != 'true' ">
<Error Text="The WiX Toolset v3.11 (or newer) build tools must be installed to build this project. To download the WiX Toolset, see http://wixtoolset.org/releases/" /> <Error Text="The WiX Toolset v3.11 (or newer) build tools must be installed to build this project. To download the WiX Toolset, see http://wixtoolset.org/releases/" />
</Target> </Target>
<!-- <!--
To modify your build process, add your task inside one of the targets below and uncomment it. To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Wix.targets. Other similar extension points exist, see Wix.targets.
<Target Name="BeforeBuild"> <Target Name="BeforeBuild">
</Target> </Target>
<Target Name="AfterBuild"> <Target Name="AfterBuild">
</Target> </Target>
--> -->
</Project> </Project>

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:fire="http://schemas.microsoft.com/wix/FirewallExtension"> xmlns:fire="http://schemas.microsoft.com/wix/FirewallExtension"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Product Id="*" Name="IPv6 Forwarder for GameStream" Language="1033" Version="!(bind.fileVersion.GSv6FwdExe)" <Product Id="*" Name="IPv6 Forwarder for GameStream" Language="1033" Version="!(bind.fileVersion.GSv6FwdExe)"
Manufacturer="Moonlight Game Streaming Project" UpgradeCode="cae27153-26ed-4da2-8dd5-8cddc7126a05"> Manufacturer="Moonlight Game Streaming Project" UpgradeCode="cae27153-26ed-4da2-8dd5-8cddc7126a05">
<Package InstallerVersion="500" Compressed="yes" InstallScope="perMachine" /> <Package InstallerVersion="500" Compressed="yes" InstallScope="perMachine" />
@ -21,6 +22,9 @@
<Directory Id="ProgramFilesFolder"> <Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="IPv6 Forwarder for GameStream" /> <Directory Id="INSTALLFOLDER" Name="IPv6 Forwarder for GameStream" />
</Directory> </Directory>
<Directory Id="CommonAppDataFolder">
<Directory Name="MISS" Id="MISSLogFolder" />
</Directory>
</Directory> </Directory>
</Fragment> </Fragment>
@ -32,6 +36,9 @@
Scope="any" Scope="any"
Name="IPv6 Forwarder for GS Protocol"/> Name="IPv6 Forwarder for GS Protocol"/>
</File> </File>
<CreateFolder Directory="MISSLogFolder">
<util:PermissionEx User="NT SERVICE\GSv6FwdSvc" GenericAll="yes" />
</CreateFolder>
<ServiceInstall Type="ownProcess" <ServiceInstall Type="ownProcess"
Name="GSv6FwdSvc" Name="GSv6FwdSvc"
DisplayName="IPv6 Forwarder for GS Protocol" DisplayName="IPv6 Forwarder for GS Protocol"