You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
238 lines
5.5 KiB
238 lines
5.5 KiB
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) Microsoft Corporation
|
|
//
|
|
// SYNOPSIS
|
|
//
|
|
// Defines the class CPorts.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "radcommon.h"
|
|
#include "ports.h"
|
|
#include "portparser.h"
|
|
#include <new>
|
|
#include <ws2tcpip.h>
|
|
|
|
CPorts::CPorts() throw ()
|
|
: ports(0),
|
|
numPorts(0)
|
|
{
|
|
FD_ZERO(&fdSet);
|
|
}
|
|
|
|
|
|
CPorts::~CPorts() throw ()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
|
|
HRESULT CPorts::SetConfig(const wchar_t* config) throw ()
|
|
{
|
|
// We can only be configured once.
|
|
if (ports != 0)
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
size_t maxPorts = CPortParser::CountPorts(config);
|
|
if (maxPorts == 0)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ports = new (std::nothrow) Port[maxPorts];
|
|
if (ports == 0)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
CPortParser parser(config);
|
|
|
|
DWORD ipAddress;
|
|
while (parser.GetIPAddress(&ipAddress) == S_OK)
|
|
{
|
|
WORD ipPort;
|
|
while (parser.GetNextPort(&ipPort) == S_OK)
|
|
{
|
|
InsertPort(ipAddress, ipPort);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CPorts::OpenSockets() throw ()
|
|
{
|
|
HRESULT result = S_OK;
|
|
|
|
for (size_t i = 0; i < numPorts; ++i)
|
|
{
|
|
if (ports[i].socket != INVALID_SOCKET)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
SOCKADDR_IN sin;
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = htons(ports[i].ipPort);
|
|
sin.sin_addr.s_addr = ports[i].ipAddress;
|
|
|
|
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (sock == INVALID_SOCKET)
|
|
{
|
|
int error = WSAGetLastError();
|
|
IASTracePrintf(
|
|
"Create socket failed for %s:%hu; error = %lu",
|
|
inet_ntoa(sin.sin_addr),
|
|
ports[i].ipPort,
|
|
error
|
|
);
|
|
result = HRESULT_FROM_WIN32(error);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Bind the socket for exclusive access to keep other apps from
|
|
// snooping.
|
|
int optval = 1;
|
|
if (setsockopt(
|
|
sock,
|
|
SOL_SOCKET,
|
|
SO_EXCLUSIVEADDRUSE,
|
|
reinterpret_cast<const char*>(&optval),
|
|
sizeof(optval)
|
|
) == SOCKET_ERROR)
|
|
{
|
|
int error = WSAGetLastError();
|
|
IASTracePrintf(
|
|
"Set socket option SO_EXCLUSIVEADDRUSE failed for %s:%hu; error = %lu",
|
|
inet_ntoa(sin.sin_addr),
|
|
ports[i].ipPort,
|
|
error
|
|
);
|
|
result = HRESULT_FROM_WIN32(error);
|
|
closesocket(sock);
|
|
break;
|
|
}
|
|
|
|
// Block receiving broadcast traffic (for security)
|
|
optval = 0; // FALSE
|
|
if (setsockopt(
|
|
sock,
|
|
IPPROTO_IP,
|
|
IP_RECEIVE_BROADCAST,
|
|
reinterpret_cast<const char*>(&optval),
|
|
sizeof(optval)
|
|
) == SOCKET_ERROR)
|
|
{
|
|
int error = WSAGetLastError();
|
|
IASTracePrintf(
|
|
"Set IP option IP_RECEIVE_BROADCAST failed for %s:%hu; error = %lu",
|
|
inet_ntoa(sin.sin_addr),
|
|
ports[i].ipPort,
|
|
error
|
|
);
|
|
result = HRESULT_FROM_WIN32(error);
|
|
closesocket(sock);
|
|
break;
|
|
}
|
|
|
|
int bindResult = bind(
|
|
sock,
|
|
reinterpret_cast<const SOCKADDR*>(&sin),
|
|
sizeof(SOCKADDR_IN)
|
|
);
|
|
if (bindResult == SOCKET_ERROR)
|
|
{
|
|
int error = WSAGetLastError();
|
|
IASTracePrintf(
|
|
"Bind failed for %s:%hu; error = %lu",
|
|
inet_ntoa(sin.sin_addr),
|
|
ports[i].ipPort,
|
|
error
|
|
);
|
|
|
|
result = HRESULT_FROM_WIN32(error);
|
|
closesocket (sock);
|
|
}
|
|
else
|
|
{
|
|
IASTracePrintf(
|
|
"RADIUS Server starting to listen on %s:%hu",
|
|
inet_ntoa(sin.sin_addr),
|
|
ports[i].ipPort
|
|
);
|
|
|
|
ports[i].socket = sock;
|
|
FD_SET(sock, &fdSet);
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
void CPorts::CloseSockets() throw ()
|
|
{
|
|
for (size_t i = 0; i < numPorts; ++i)
|
|
{
|
|
if (ports[i].socket != INVALID_SOCKET)
|
|
{
|
|
closesocket(ports[i].socket);
|
|
ports[i].socket = INVALID_SOCKET;
|
|
}
|
|
}
|
|
|
|
FD_ZERO(&fdSet);
|
|
}
|
|
|
|
|
|
void CPorts::Clear() throw ()
|
|
{
|
|
CloseSockets();
|
|
|
|
delete[] ports;
|
|
ports = 0;
|
|
|
|
numPorts = 0;
|
|
}
|
|
|
|
|
|
void CPorts::InsertPort(DWORD ipAddress, WORD ipPort) throw ()
|
|
{
|
|
for (size_t i = 0; i < numPorts; )
|
|
{
|
|
if (ipPort == ports[i].ipPort)
|
|
{
|
|
if (ipAddress == INADDR_ANY)
|
|
{
|
|
// Remove the existing entry.
|
|
--numPorts;
|
|
ports[i] = ports[numPorts];
|
|
|
|
// Don't increment the loop variable because we just put a new port
|
|
// into this array element.
|
|
continue;
|
|
}
|
|
else if ((ipAddress == ports[i].ipAddress) ||
|
|
(ports[i].ipAddress == INADDR_ANY))
|
|
{
|
|
// The new port is already covered by an existing entry.
|
|
return;
|
|
}
|
|
}
|
|
|
|
++i;
|
|
}
|
|
|
|
// Add the port to the array.
|
|
ports[numPorts].ipAddress = ipAddress;
|
|
ports[numPorts].ipPort = ipPort;
|
|
ports[numPorts].socket = INVALID_SOCKET;
|
|
|
|
++numPorts;
|
|
}
|