Leaked source code of windows server 2003
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

///////////////////////////////////////////////////////////////////////////////
//
// 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;
}