Compare commits

...
7 Commits
7 changed files with 155 additions and 100 deletions
+1
View File
@@ -70,6 +70,7 @@
ErrorControl="ignore" ErrorControl="ignore"
Interactive="no"> Interactive="no">
<ServiceConfig DelayedAutoStart="no" OnInstall="yes" OnReinstall="yes" ServiceSid="unrestricted"/> <ServiceConfig DelayedAutoStart="no" OnInstall="yes" OnReinstall="yes" ServiceSid="unrestricted"/>
<util:ServiceConfig FirstFailureActionType="restart" SecondFailureActionType="restart" ThirdFailureActionType="restart" ResetPeriodInDays="1" RestartServiceDelayInSeconds="10"/>
</ServiceInstall> </ServiceInstall>
<ServiceControl Id="StartService" Start="install" Stop="both" Remove="uninstall" Name="MISS" Wait="yes" /> <ServiceControl Id="StartService" Start="install" Stop="both" Remove="uninstall" Name="MISS" Wait="yes" />
</Component> </Component>
+27 -15
View File
@@ -39,6 +39,7 @@ bool PCPMapPort(PSOCKADDR_STORAGE localAddr, int localAddrLen, PSOCKADDR_STORAGE
#define POLLING_DELAY_SEC 120 #define POLLING_DELAY_SEC 120
#define PORT_MAPPING_DURATION_SEC 3600 #define PORT_MAPPING_DURATION_SEC 3600
#define UPNP_DISCOVERY_DELAY_MS 5000 #define UPNP_DISCOVERY_DELAY_MS 5000
#define GAA_INITIAL_SIZE 8192
static struct port_entry { static struct port_entry {
int proto; int proto;
@@ -233,10 +234,7 @@ bool UPnPMapPort(struct UPNPUrls* urls, struct IGDdatas* data, int proto, const
bool GetIP4OnLinkPrefixLength(char* lanAddressString, int* prefixLength) bool GetIP4OnLinkPrefixLength(char* lanAddressString, int* prefixLength)
{ {
union { PIP_ADAPTER_ADDRESSES addresses;
IP_ADAPTER_ADDRESSES addresses;
char buffer[8192];
};
ULONG error; ULONG error;
ULONG length; ULONG length;
PIP_ADAPTER_ADDRESSES currentAdapter; PIP_ADAPTER_ADDRESSES currentAdapter;
@@ -245,22 +243,34 @@ bool GetIP4OnLinkPrefixLength(char* lanAddressString, int* prefixLength)
inet_pton(AF_INET, lanAddressString, &targetAddress); inet_pton(AF_INET, lanAddressString, &targetAddress);
// Get a list of all interfaces with IPv4 addresses on the system addresses = NULL;
length = sizeof(buffer); length = GAA_INITIAL_SIZE;
error = GetAdaptersAddresses(AF_INET, do {
GAA_FLAG_SKIP_ANYCAST | free(addresses);
GAA_FLAG_SKIP_MULTICAST | addresses = (PIP_ADAPTER_ADDRESSES)malloc(length);
GAA_FLAG_SKIP_DNS_SERVER | if (addresses == NULL) {
GAA_FLAG_SKIP_FRIENDLY_NAME, printf("malloc(%u) failed" NL, length);
NULL, return false;
&addresses, }
&length);
// Get a list of all interfaces with IPv4 addresses on the system
error = GetAdaptersAddresses(AF_INET,
GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL,
addresses,
&length);
} while (error == ERROR_BUFFER_OVERFLOW);
if (error != ERROR_SUCCESS) { if (error != ERROR_SUCCESS) {
printf("GetAdaptersAddresses() failed: %d" NL, error); printf("GetAdaptersAddresses() failed: %d" NL, error);
free(addresses);
return false; return false;
} }
currentAdapter = &addresses; currentAdapter = addresses;
currentAddress = nullptr; currentAddress = nullptr;
while (currentAdapter != nullptr) { while (currentAdapter != nullptr) {
currentAddress = currentAdapter->FirstUnicastAddress; currentAddress = currentAdapter->FirstUnicastAddress;
@@ -271,6 +281,7 @@ bool GetIP4OnLinkPrefixLength(char* lanAddressString, int* prefixLength)
if (RtlEqualMemory(&currentAddrV4->sin_addr, &targetAddress, sizeof(targetAddress))) { if (RtlEqualMemory(&currentAddrV4->sin_addr, &targetAddress, sizeof(targetAddress))) {
*prefixLength = currentAddress->OnLinkPrefixLength; *prefixLength = currentAddress->OnLinkPrefixLength;
free(addresses);
return true; return true;
} }
@@ -281,6 +292,7 @@ bool GetIP4OnLinkPrefixLength(char* lanAddressString, int* prefixLength)
} }
printf("No adapter found with IPv4 address: %s" NL, lanAddressString); printf("No adapter found with IPv4 address: %s" NL, lanAddressString);
free(addresses);
return false; return false;
} }
+10 -6
View File
@@ -68,11 +68,13 @@ int StartUdpRelay(unsigned short Port)
SOCKADDR_IN addr; SOCKADDR_IN addr;
HANDLE thread; HANDLE thread;
PUDP_TUPLE tuple; PUDP_TUPLE tuple;
int error;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET) { if (sock == INVALID_SOCKET) {
printf("socket() failed: %d\n", WSAGetLastError()); error = WSAGetLastError();
return WSAGetLastError(); printf("socket() failed: %d\n", error);
return error;
} }
// Bind to the alternate port // Bind to the alternate port
@@ -80,9 +82,10 @@ int StartUdpRelay(unsigned short Port)
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_port = htons(Port + RELAY_PORT_OFFSET); addr.sin_port = htons(Port + RELAY_PORT_OFFSET);
if (bind(sock, (PSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR) { if (bind(sock, (PSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR) {
printf("bind() failed: %d\n", WSAGetLastError()); error = WSAGetLastError();
printf("bind() failed: %d\n", error);
closesocket(sock); closesocket(sock);
return WSAGetLastError(); return error;
} }
tuple = (PUDP_TUPLE)malloc(sizeof(*tuple)); tuple = (PUDP_TUPLE)malloc(sizeof(*tuple));
@@ -95,9 +98,10 @@ 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) {
printf("CreateThread() failed: %d\n", GetLastError()); error = GetLastError();
printf("CreateThread() failed: %d\n", error);
closesocket(sock); closesocket(sock);
return GetLastError(); return error;
} }
CloseHandle(thread); CloseHandle(thread);
+58 -36
View File
@@ -29,6 +29,8 @@
#define LOOPBACK_SERVER_PORT_OFFSET -10000 #define LOOPBACK_SERVER_PORT_OFFSET -10000
#define GAA_INITIAL_SIZE 8192
static struct port_entry { static struct port_entry {
int proto; int proto;
int port; int port;
@@ -864,31 +866,40 @@ bool FindLocalInterfaceIPAddress(int family, PSOCKADDR_STORAGE addr)
bool FindZeroTierInterfaceAddress(PSOCKADDR_STORAGE addr) bool FindZeroTierInterfaceAddress(PSOCKADDR_STORAGE addr)
{ {
union { PIP_ADAPTER_ADDRESSES addresses;
IP_ADAPTER_ADDRESSES addresses;
char buffer[8192];
};
ULONG error; ULONG error;
ULONG length; ULONG length;
PIP_ADAPTER_ADDRESSES currentAdapter; PIP_ADAPTER_ADDRESSES currentAdapter;
PIP_ADAPTER_UNICAST_ADDRESS currentAddress; PIP_ADAPTER_UNICAST_ADDRESS currentAddress;
// Get all IPv4 interfaces addresses = NULL;
length = sizeof(buffer); length = GAA_INITIAL_SIZE;
error = GetAdaptersAddresses(AF_INET, do {
GAA_FLAG_SKIP_ANYCAST | free(addresses);
GAA_FLAG_SKIP_MULTICAST | addresses = (PIP_ADAPTER_ADDRESSES)malloc(length);
GAA_FLAG_SKIP_DNS_SERVER | if (addresses == NULL) {
GAA_FLAG_SKIP_FRIENDLY_NAME, fprintf(LOG_OUT, "malloc(%u) failed\n", length);
NULL, return false;
&addresses, }
&length);
// Get all IPv4 interfaces
error = GetAdaptersAddresses(AF_INET,
GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL,
addresses,
&length);
} while (error == ERROR_BUFFER_OVERFLOW);
if (error != ERROR_SUCCESS) { if (error != ERROR_SUCCESS) {
fprintf(LOG_OUT, "GetAdaptersAddresses() failed: %d\n", error); fprintf(LOG_OUT, "GetAdaptersAddresses() failed: %d\n", error);
free(addresses);
return false; return false;
} }
currentAdapter = &addresses; currentAdapter = addresses;
while (currentAdapter != NULL) { while (currentAdapter != NULL) {
// Look for ones that correspond to a ZeroTier device // Look for ones that correspond to a ZeroTier device
if (wcsstr(currentAdapter->Description, L"ZeroTier")) { if (wcsstr(currentAdapter->Description, L"ZeroTier")) {
@@ -897,6 +908,7 @@ bool FindZeroTierInterfaceAddress(PSOCKADDR_STORAGE addr)
while (currentAddress != NULL) { while (currentAddress != NULL) {
if (currentAddress->Address.lpSockaddr->sa_family == AF_INET) { if (currentAddress->Address.lpSockaddr->sa_family == AF_INET) {
RtlCopyMemory(addr, currentAddress->Address.lpSockaddr, currentAddress->Address.iSockaddrLength); RtlCopyMemory(addr, currentAddress->Address.lpSockaddr, currentAddress->Address.iSockaddrLength);
free(addresses);
return true; return true;
} }
@@ -907,15 +919,13 @@ bool FindZeroTierInterfaceAddress(PSOCKADDR_STORAGE addr)
currentAdapter = currentAdapter->Next; currentAdapter = currentAdapter->Next;
} }
free(addresses);
return false; return false;
} }
bool FindDuplicateDefaultInterfaces(void) bool FindDuplicateDefaultInterfaces(void)
{ {
union { PIP_ADAPTER_ADDRESSES addresses;
IP_ADAPTER_ADDRESSES addresses;
char buffer[8192];
};
ULONG error; ULONG error;
ULONG length; ULONG length;
MIB_IPFORWARDROW defaultRoute; MIB_IPFORWARDROW defaultRoute;
@@ -928,24 +938,36 @@ bool FindDuplicateDefaultInterfaces(void)
return false; return false;
} }
// Get all IPv4 interfaces addresses = NULL;
length = sizeof(buffer); length = GAA_INITIAL_SIZE;
error = GetAdaptersAddresses(AF_INET, do {
GAA_FLAG_SKIP_UNICAST | free(addresses);
GAA_FLAG_SKIP_ANYCAST | addresses = (PIP_ADAPTER_ADDRESSES)malloc(length);
GAA_FLAG_SKIP_MULTICAST | if (addresses == NULL) {
GAA_FLAG_SKIP_DNS_SERVER | fprintf(LOG_OUT, "malloc(%u) failed\n", length);
GAA_FLAG_INCLUDE_GATEWAYS | return false;
GAA_FLAG_SKIP_FRIENDLY_NAME, }
NULL,
&addresses, // Get all IPv4 interfaces
&length); error = GetAdaptersAddresses(AF_INET,
GAA_FLAG_SKIP_UNICAST |
GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_INCLUDE_GATEWAYS |
GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL,
addresses,
&length);
} while (error == ERROR_BUFFER_OVERFLOW);
if (error != ERROR_SUCCESS) { if (error != ERROR_SUCCESS) {
fprintf(LOG_OUT, "GetAdaptersAddresses() failed: %d\n", error); fprintf(LOG_OUT, "GetAdaptersAddresses() failed: %d\n", error);
free(addresses);
return false; return false;
} }
currentAdapter = &addresses; currentAdapter = addresses;
while (currentAdapter != NULL) { while (currentAdapter != NULL) {
if (currentAdapter->OperStatus == IfOperStatusUp && if (currentAdapter->OperStatus == IfOperStatusUp &&
currentAdapter->FirstGatewayAddress != NULL && currentAdapter->FirstGatewayAddress != NULL &&
@@ -958,6 +980,7 @@ bool FindDuplicateDefaultInterfaces(void)
currentAdapter = currentAdapter->Next; currentAdapter = currentAdapter->Next;
} }
free(addresses);
return matchingInterfaces > 1; return matchingInterfaces > 1;
} }
@@ -1490,10 +1513,9 @@ int main(int argc, char* argv[])
return 0; return 0;
} }
} }
else {
// Tested against a working server and it failed // Tested against a IPv6 working server
break; break;
}
} }
} }
+56 -40
View File
@@ -45,15 +45,20 @@ bool getExternalAddressPortIP4(unsigned short localPort, PSOCKADDR_IN wanAddr)
int i; int i;
int bytesRead; int bytesRead;
int err; int err;
bool ret;
PSTUN_ATTRIBUTE_HEADER attribute; PSTUN_ATTRIBUTE_HEADER attribute;
PSTUN_MAPPED_IPV4_ADDRESS_ATTRIBUTE ipv4Attrib; PSTUN_MAPPED_IPV4_ADDRESS_ATTRIBUTE ipv4Attrib;
struct addrinfo* result; struct addrinfo* result;
struct addrinfo hints; struct addrinfo hints;
struct sockaddr_in bindAddr;
union { union {
STUN_MESSAGE hdr; STUN_MESSAGE hdr;
char buf[1024]; char buf[1024];
} resp; } resp;
sock = INVALID_SOCKET;
ret = false;
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET; hints.ai_family = AF_INET;
hints.ai_flags = AI_ADDRCONFIG; hints.ai_flags = AI_ADDRCONFIG;
@@ -68,18 +73,15 @@ bool getExternalAddressPortIP4(unsigned short localPort, PSOCKADDR_IN wanAddr)
sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol); sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol);
if (sock == INVALID_SOCKET) { if (sock == INVALID_SOCKET) {
fprintf(LOG_OUT, "socket() failed: %d\n", WSAGetLastError()); fprintf(LOG_OUT, "socket() failed: %d\n", WSAGetLastError());
freeaddrinfo(result); goto Exit;
return false;
} }
struct sockaddr_in bindAddr = {}; bindAddr = {};
bindAddr.sin_family = hints.ai_family; bindAddr.sin_family = hints.ai_family;
bindAddr.sin_port = htons(localPort); bindAddr.sin_port = htons(localPort);
if (bind(sock, (struct sockaddr*)&bindAddr, sizeof(bindAddr)) == SOCKET_ERROR) { if (bind(sock, (struct sockaddr*)&bindAddr, sizeof(bindAddr)) == SOCKET_ERROR) {
fprintf(LOG_OUT, "bind() failed: %d\n", WSAGetLastError()); fprintf(LOG_OUT, "bind() failed: %d\n", WSAGetLastError());
closesocket(sock); goto Exit;
freeaddrinfo(result);
return false;
} }
reqMsg.messageType = htons(STUN_MESSAGE_BINDING_REQUEST); reqMsg.messageType = htons(STUN_MESSAGE_BINDING_REQUEST);
@@ -98,57 +100,60 @@ bool getExternalAddressPortIP4(unsigned short localPort, PSOCKADDR_IN wanAddr)
} }
} }
fd_set fds; for (;;) {
FD_ZERO(&fds); fd_set fds;
FD_SET(sock, &fds); FD_ZERO(&fds);
FD_SET(sock, &fds);
struct timeval tv; struct timeval tv;
tv.tv_sec = 1; tv.tv_sec = 1;
tv.tv_usec = 0; tv.tv_usec = 0;
int selectRes = select(0, &fds, nullptr, nullptr, &tv); int selectRes = select(0, &fds, nullptr, nullptr, &tv);
if (selectRes == 0) { if (selectRes == 0) {
// Timeout - continue looping // Timeout - break to the enclosing loop
continue; break;
}
else if (selectRes == SOCKET_ERROR) {
fprintf(LOG_OUT, "select() failed: %d\n", WSAGetLastError());
goto Exit;
}
// recvfrom() will return WSAECONNRESET if the socket has received an ICMP Port Unreachable
// message from one of the IP addresses we've attempted communication with. The socket is still
// operable (and may even contain queued messages to receive). We should ignore that error and
// continue reading, otherwise exit the loop.
bytesRead = recvfrom(sock, resp.buf, sizeof(resp.buf), 0, NULL, NULL);
if (bytesRead != SOCKET_ERROR || WSAGetLastError() != WSAECONNRESET) {
goto RecvDone;
}
} }
else if (selectRes == SOCKET_ERROR) {
fprintf(LOG_OUT, "select() failed: %d\n", WSAGetLastError());
closesocket(sock);
freeaddrinfo(result);
return false;
}
// Error handling is below
bytesRead = recvfrom(sock, resp.buf, sizeof(resp.buf), 0, NULL, NULL);
break;
} }
freeaddrinfo(result); RecvDone:
closesocket(sock);
if (bytesRead == 0) { if (bytesRead == 0) {
fprintf(LOG_OUT, "No response from STUN server\n"); fprintf(LOG_OUT, "No response from STUN server\n");
return false; goto Exit;
} }
else if (bytesRead == SOCKET_ERROR) { else if (bytesRead == SOCKET_ERROR) {
fprintf(LOG_OUT, "Failed to read STUN binding response: %d\n", WSAGetLastError()); fprintf(LOG_OUT, "Failed to read STUN binding response: %d\n", WSAGetLastError());
return false; goto Exit;
} }
else if (bytesRead < sizeof(resp.hdr)) { else if (bytesRead < sizeof(resp.hdr)) {
fprintf(LOG_OUT, "STUN message truncated: %d\n", bytesRead); fprintf(LOG_OUT, "STUN message truncated: %d\n", bytesRead);
return false; goto Exit;
} }
else if (htonl(resp.hdr.magicCookie) != STUN_MESSAGE_COOKIE) { else if (htonl(resp.hdr.magicCookie) != STUN_MESSAGE_COOKIE) {
fprintf(LOG_OUT, "Bad STUN cookie value: %x\n", htonl(resp.hdr.magicCookie)); fprintf(LOG_OUT, "Bad STUN cookie value: %x\n", htonl(resp.hdr.magicCookie));
return false; goto Exit;
} }
else if (memcmp(reqMsg.transactionId, resp.hdr.transactionId, sizeof(reqMsg.transactionId))) { else if (memcmp(reqMsg.transactionId, resp.hdr.transactionId, sizeof(reqMsg.transactionId))) {
fprintf(LOG_OUT, "STUN transaction ID mismatch\n"); fprintf(LOG_OUT, "STUN transaction ID mismatch\n");
return false; goto Exit;
} }
else if (htons(resp.hdr.messageType) != STUN_MESSAGE_BINDING_SUCCESS) { else if (htons(resp.hdr.messageType) != STUN_MESSAGE_BINDING_SUCCESS) {
fprintf(LOG_OUT, "STUN message type mismatch: %x\n", htons(resp.hdr.messageType)); fprintf(LOG_OUT, "STUN message type mismatch: %x\n", htons(resp.hdr.messageType));
return false; goto Exit;
} }
attribute = (PSTUN_ATTRIBUTE_HEADER)(&resp.hdr + 1); attribute = (PSTUN_ATTRIBUTE_HEADER)(&resp.hdr + 1);
@@ -156,7 +161,7 @@ bool getExternalAddressPortIP4(unsigned short localPort, PSOCKADDR_IN wanAddr)
while (bytesRead > sizeof(*attribute)) { while (bytesRead > sizeof(*attribute)) {
if (bytesRead < sizeof(*attribute) + htons(attribute->length)) { if (bytesRead < sizeof(*attribute) + htons(attribute->length)) {
fprintf(LOG_OUT, "STUN attribute out of bounds: %d\n", htons(attribute->length)); fprintf(LOG_OUT, "STUN attribute out of bounds: %d\n", htons(attribute->length));
return false; goto Exit;
} }
// Mask off the comprehension bit // Mask off the comprehension bit
else if ((htons(attribute->type) & 0x7FFF) != STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS) { else if ((htons(attribute->type) & 0x7FFF) != STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS) {
@@ -169,11 +174,11 @@ bool getExternalAddressPortIP4(unsigned short localPort, PSOCKADDR_IN wanAddr)
ipv4Attrib = (PSTUN_MAPPED_IPV4_ADDRESS_ATTRIBUTE)attribute; ipv4Attrib = (PSTUN_MAPPED_IPV4_ADDRESS_ATTRIBUTE)attribute;
if (htons(ipv4Attrib->hdr.length) != 8) { if (htons(ipv4Attrib->hdr.length) != 8) {
fprintf(LOG_OUT, "STUN address length mismatch: %d\n", htons(ipv4Attrib->hdr.length)); fprintf(LOG_OUT, "STUN address length mismatch: %d\n", htons(ipv4Attrib->hdr.length));
return false; goto Exit;
} }
else if (ipv4Attrib->addressFamily != 1) { else if (ipv4Attrib->addressFamily != 1) {
fprintf(LOG_OUT, "STUN address family mismatch: %x\n", ipv4Attrib->addressFamily); fprintf(LOG_OUT, "STUN address family mismatch: %x\n", ipv4Attrib->addressFamily);
return false; goto Exit;
} }
*wanAddr = {}; *wanAddr = {};
@@ -183,9 +188,20 @@ bool getExternalAddressPortIP4(unsigned short localPort, PSOCKADDR_IN wanAddr)
wanAddr->sin_port = ipv4Attrib->port ^ (short)resp.hdr.magicCookie; wanAddr->sin_port = ipv4Attrib->port ^ (short)resp.hdr.magicCookie;
wanAddr->sin_addr.S_un.S_addr = ipv4Attrib->address ^ resp.hdr.magicCookie; wanAddr->sin_addr.S_un.S_addr = ipv4Attrib->address ^ resp.hdr.magicCookie;
return true; ret = true;
goto Exit;
} }
fprintf(LOG_OUT, "No XOR mapped address found in STUN response!\n"); fprintf(LOG_OUT, "No XOR mapped address found in STUN response!\n");
return false;
Exit:
if (sock != INVALID_SOCKET) {
closesocket(sock);
}
if (result != NULL) {
freeaddrinfo(result);
}
return ret;
} }
+2 -2
View File
@@ -1,7 +1,7 @@
#pragma once #pragma once
#define VER_VERSION 5,3,0,0 #define VER_VERSION 5,4,0,0
#define VER_VERSION_STR "5.3.0.0" #define VER_VERSION_STR "5.4.0.0"
#define VER_COMPANYNAME_STR "Moonlight Game Streaming Project" #define VER_COMPANYNAME_STR "Moonlight Game Streaming Project"
#define VER_PRODUCTNAME_STR "Moonlight Internet Hosting Tool" #define VER_PRODUCTNAME_STR "Moonlight Internet Hosting Tool"