/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) Microsoft Corporation // // SYNOPSIS // // Defines the class CPorts. // /////////////////////////////////////////////////////////////////////////////// #include "radcommon.h" #include "ports.h" #include "portparser.h" #include #include 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(&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(&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(&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; }