windows-nt/Source/XPSP1/NT/net/tcpip/services/rip/rip.c
2020-09-26 16:20:57 +08:00

2726 lines
78 KiB
C

//****************************************************************************
//
// Microsoft Windows NT RIP
//
// Copyright 1995-96
//
//
// Revision History
//
//
// 2/26/95 Gurdeep Singh Pall Picked up from JBallard's team
//
// 7/09/99 Raghu Gatta - RIP Listener is now RIPv2 compliant
//
// Description: Main RIP Service Functions
//
//****************************************************************************
#include "pchrip.h"
#pragma hdrstop
//-----------------------------------------------------------------------
// global definitions
//-----------------------------------------------------------------------
RIP_PARAMETERS g_params;
RIP_GLOBALS g_ripcfg;
#ifdef ROUTE_FILTERS
PRIP_FILTERS g_prfAnnounceFilters = NULL;
PRIP_FILTERS g_prfAcceptFilters = NULL;
CRITICAL_SECTION g_csAccFilters;
CRITICAL_SECTION g_csAnnFilters;
#endif
CRITICAL_SECTION g_csRoutes;
CRITICAL_SECTION g_csParameters;
CRITICAL_SECTION g_csAddrtables;
#ifndef CHICAGO
SERVICE_STATUS_HANDLE g_hService;
#endif
HANDLE g_stopEvent;
SOCKET g_stopSocket;
DWORD g_stopReason = (DWORD) -1;
HANDLE g_triggerEvent;
HANDLE g_updateDoneEvent;
HANDLE g_changeNotifyDoneEvent;
DWORD g_dwTraceID = (DWORD)-1;
DWORD g_dwCurrentState;
DWORD g_dwCheckPoint;
DWORD g_dwWaitHint;
#ifndef CHICAGO
HMODULE g_hmodule;
#endif
//-----------------------------------------------------------------------
// Function: NetclassMask
//
// returns the mask used to extract the network address from an
// Internet address
//-----------------------------------------------------------------------
DWORD NetclassMask(DWORD dwAddress) {
// net masks are returned in network byte order
if (CLASSA_ADDR(dwAddress)) {
return CLASSA_MASK;
}
else
if (CLASSB_ADDR(dwAddress)) {
return CLASSB_MASK;
}
else
if (CLASSC_ADDR(dwAddress)) {
return CLASSC_MASK;
}
else {
return 0;
}
}
//-----------------------------------------------------------------------
// Function: SubnetMask
//
// Given an IP address, return the sub-network mask. This function
// assumes the address table is already locked.
//-----------------------------------------------------------------------
DWORD SubnetMask(DWORD dwAddress) {
DWORD dwNetmask;
LPRIP_ADDRESS lpaddr, lpend;
// subnet mask should be zero for default routes
if (dwAddress == 0) { return 0; }
// if its a broadcast address return all ones
if (dwAddress == INADDR_BROADCAST) { return INADDR_BROADCAST; }
//dwNetmask = NetclassMask(dwAddress);
dwNetmask = NETCLASS_MASK(dwAddress);
// if the network part is zero, return the network mask
if ((dwAddress & ~dwNetmask) == 0) {
return dwNetmask;
}
lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
// if the address is found, return the subnet mask
if ((dwAddress & dwNetmask) ==
(lpaddr->dwAddress & NetclassMask(lpaddr->dwAddress))) {
return lpaddr->dwNetmask;
}
}
// address not found, return the network class mask
return dwNetmask;
}
//-----------------------------------------------------------------------
// Function: IsBroadcastAddress
//
// Returns TRUE if the given IP address is an all-ones bcast
// or a class A, B, or C net broadcast. IP address is assumed to be
// in network order (which is the reverse of Intel byte ordering.)
//-----------------------------------------------------------------------
BOOL IsBroadcastAddress(DWORD dwAddress) {
if ((dwAddress == INADDR_BROADCAST) ||
(CLASSA_ADDR(dwAddress) && ((dwAddress & ~CLASSA_MASK) ==
~CLASSA_MASK)) ||
(CLASSB_ADDR(dwAddress) && ((dwAddress & ~CLASSB_MASK) ==
~CLASSB_MASK)) ||
(CLASSC_ADDR(dwAddress) && ((dwAddress & ~CLASSC_MASK) ==
~CLASSC_MASK))) {
return TRUE;
}
return FALSE;
}
//-----------------------------------------------------------------------
// Function: IsLocalAddr
//
// Returns TRUE if the given IP address belongs to one of the interfaces
// on the local host. Assumes that the IP address is in network order
// and that the address table is already locked.
//-----------------------------------------------------------------------
BOOL IsLocalAddr(DWORD dwAddress) {
LPRIP_ADDRESS lpaddr, lpend;
lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
if (dwAddress == lpaddr->dwAddress) {
return TRUE;
}
}
return FALSE;
}
BOOL IsDisabledLocalAddress(DWORD dwAddress) {
LPRIP_ADDRESS lpaddr, lpend;
lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
if ((lpaddr->dwFlag & ADDRFLAG_DISABLED) != 0 &&
(dwAddress == lpaddr->dwAddress)) {
return TRUE;
}
}
return FALSE;
}
//-----------------------------------------------------------------------
// Function: IsHostAddress
//
// Returns TRUE if the given IP address has a non-zero host part.
// Assumes that the IP address is in network order and that
// the address table is already locked.
//-----------------------------------------------------------------------
BOOL IsHostAddress(DWORD dwAddress) {
DWORD dwNetmask;
// find most specific netmask we have for the address
dwNetmask = SubnetMask(dwAddress);
// if host part is non-zero, assume it is a host address
if ((dwAddress & (~dwNetmask)) != 0) {
return TRUE;
}
return FALSE;
}
//-----------------------------------------------------------------------
// Function: ProcessRIPEntry
//
// This function examines a single entry in a RIP packet and
// adds it to the hash table if necessary.
//-----------------------------------------------------------------------
DWORD ProcessRIPEntry(LPRIP_ADDRESS lpaddr, IN_ADDR srcaddr,
LPRIP_ENTRY rip_entry, BYTE chVersion) {
IN_ADDR addr;
BOOL bIsHostAddr;
CHAR szAddress[32] = {0};
CHAR szSrcaddr[32] = {0};
CHAR szMetric[12];
LPSTR ppszArgs[3] = { szAddress, szSrcaddr, szMetric };
LPHASH_TABLE_ENTRY rt_entry;
DWORD rt_metric, rip_metric;
DWORD dwHost, dwDefault, dwRouteTimeout;
DWORD dwOverwriteStatic, dwGarbageTimeout;
DWORD dwInd = 0;
DWORD dwNetwork, dwNetmask, dwNetclassmask;
CHAR *pszTemp;
addr.s_addr = rip_entry->dwAddress;
pszTemp = inet_ntoa(addr);
if (pszTemp != NULL) {
strcpy(szAddress, pszTemp);
}
pszTemp = inet_ntoa(srcaddr);
if (pszTemp != NULL) {
strcpy(szSrcaddr, pszTemp);
}
// ignore metrics greater than infinity
if (ntohl(rip_entry->dwMetric) > METRIC_INFINITE) {
dbgprintf("metric > %d, ignoring route to %s with next hop of %s",
METRIC_INFINITE, szAddress, szSrcaddr);
InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
return 0;
}
// ignore class D and E addresses
if (CLASSD_ADDR(rip_entry->dwAddress) ||
CLASSE_ADDR(rip_entry->dwAddress)) {
dbgprintf("class D or E addresses are invalid, "
"ignoring route to %s with next hop of %s",
szAddress, szSrcaddr);
RipLogWarning(RIPLOG_CLASS_INVALID, 2, ppszArgs, 0);
InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
return 0;
}
// ignore loopback routes
if (IP_LOOPBACK_ADDR(rip_entry->dwAddress)) {
dbgprintf("loopback addresses are invalid, "
"ignoring route to %s with next hop of %s",
szAddress, szSrcaddr);
RipLogWarning(RIPLOG_LOOPBACK_INVALID, 2, ppszArgs, 0);
InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
return 0;
}
dwNetwork = rip_entry->dwAddress;
//
// calculate mask for all RIP versions
//
if (rip_entry->dwSubnetmask == 0) {
// get the best subnetmask possible
dwNetmask = SubnetMask(dwNetwork);
// determine NetclassMask
if (dwNetwork == 0) {
dwNetclassmask = 0;
}
else if (dwNetwork == INADDR_BROADCAST) {
dwNetclassmask = INADDR_BROADCAST;
}
else {
dwNetclassmask = NETCLASS_MASK(rip_entry->dwAddress);
}
}
else {
dwNetmask = rip_entry->dwSubnetmask;
//
// double-check the netclass mask, to accomodate supernets
//
dwNetclassmask = NETCLASS_MASK(dwNetwork);
if (dwNetclassmask > dwNetmask) {
dwNetclassmask = dwNetmask;
}
}
//
// make sure route is not to a broadcast address;
// double-check to make sure this isn't a host route,
// which will look like a broadcast address since ~dwNetmask
// will be 0 and thus (dwNetwork & ~dwNetmask) == ~dwNetmask
//
if ((dwNetwork & ~dwNetclassmask) == ~dwNetclassmask ||
(~dwNetmask && (dwNetwork & ~dwNetmask) == ~dwNetmask)) {
dbgprintf("broadcast addresses are invalid, "
"ignoring route to %s with next hop of %s",
szAddress, szSrcaddr);
RipLogWarning(RIPLOG_BROADCAST_INVALID, 2, ppszArgs, 0);
InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
return 0;
}
#ifdef ROUTE_FILTERS
//
// run the route thru' the accept filters
//
if ( g_prfAcceptFilters != NULL )
{
for ( dwInd = 0; dwInd < g_prfAcceptFilters-> dwCount; dwInd++ )
{
if ( g_prfAcceptFilters-> pdwFilter[ dwInd ] ==
rip_entry-> dwAddress )
{
dbgprintf("Dropped route %s with next hop %s because"
"of accept filter",
szAddress, szSrcaddr);
return 0;
}
}
}
#endif
RIP_LOCK_PARAMS();
dwHost = g_params.dwAcceptHost;
dwDefault = g_params.dwAcceptDefault;
dwRouteTimeout = g_params.dwRouteTimeout;
dwGarbageTimeout = g_params.dwGarbageTimeout;
dwOverwriteStatic = g_params.dwOverwriteStaticRoutes;
RIP_UNLOCK_PARAMS();
// ignore host routes unless configured otherwise
if (bIsHostAddr = ((dwNetwork & ~dwNetmask) != 0)) {
if (dwHost == 0) {
dbgprintf("IPRIP is configured to discard host routes, "
"ignoring route to %s with next hop of %s",
szAddress, szSrcaddr);
RipLogInformation(RIPLOG_HOST_INVALID, 2, ppszArgs, 0);
InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
return 0;
}
}
// ignore default routes unless configured otherwise
if (rip_entry->dwAddress == 0) {
if (dwDefault == 0) {
dbgprintf("IPRIP is configured to discard default routes, "
"ignoring route to %s with next hop of %s",
szAddress, szSrcaddr);
RipLogInformation(RIPLOG_DEFAULT_INVALID, 2, ppszArgs, 0);
InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
return 0;
}
}
rip_metric = ntohl(rip_entry->dwMetric);
// do not add a new entry if its metric would be infinite
if ((rip_metric + 1) >= METRIC_INFINITE &&
!RouteTableEntryExists(lpaddr->dwIndex, rip_entry->dwAddress)) {
dbgprintf("metric == %d, ignoring new route to %s with next hop of %s",
METRIC_INFINITE, szAddress, szSrcaddr);
return 0;
}
// find the entry, or create one if necessary
rt_entry = GetRouteTableEntry(lpaddr->dwIndex, rip_entry->dwAddress,
dwNetmask);
if (rt_entry == NULL) {
dbgprintf("could not allocate memory for new entry");
RipLogError(RIPLOG_RT_ALLOC_FAILED, 0, NULL, ERROR_NOT_ENOUGH_MEMORY);
return ERROR_NOT_ENOUGH_MEMORY;
}
// if this was a static route and RIP is not allowed
// to overwrite static routes, return; exception is default routes,
// which we overwrite if we are configured to accept default routes,
// even if there is an existing static default route
//
if (rt_entry->dwFlag != NEW_ENTRY &&
(rt_entry->dwProtocol == IRE_PROTO_LOCAL ||
rt_entry->dwProtocol == IRE_PROTO_NETMGMT) &&
rt_entry->dwDestaddr != 0) {
if (dwOverwriteStatic == 0) {
InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
return 0;
}
}
rt_metric = rt_entry->dwMetric;
rip_metric = min(METRIC_INFINITE, rip_metric + 1);
_ltoa(rip_metric, szMetric, 10);
if (rt_entry->dwFlag == NEW_ENTRY) {
dbgprintf("New route entry, destination == %s, "
"next hop == %s, metric == %s",
szAddress, szSrcaddr, szMetric);
RipLogInformation(RIPLOG_NEW_LEARNT_ROUTE, 3, ppszArgs, 0);
rt_entry->dwIndex = lpaddr->dwIndex;
rt_entry->dwFlag = (TIMEOUT_TIMER | ROUTE_CHANGE);
rt_entry->lTimeout = (LONG)dwRouteTimeout;
rt_entry->dwDestaddr = rip_entry->dwAddress;
rt_entry->dwNexthop = srcaddr.s_addr;
rt_entry->dwProtocol = IRE_PROTO_RIP;
rt_entry->dwMetric = rip_metric;
if (bIsHostAddr) {
rt_entry->dwFlag |= ROUTE_HOST;
rt_entry->dwNetmask = HOSTADDR_MASK;
}
else {
rt_entry->dwNetmask = dwNetmask;
}
}
else
if (rt_entry->dwNexthop == srcaddr.s_addr) {
// this is from the next hop gateway for the existing entry
// this may have been a local route before; now it is a RIP route
rt_entry->dwProtocol = IRE_PROTO_RIP;
rt_entry->dwIndex = lpaddr->dwIndex;
// reset its timer if it is not pending garbage-collection
if (rt_metric != METRIC_INFINITE &&
(rt_entry->dwFlag & GARBAGE_TIMER) == 0) {
rt_entry->lTimeout = (LONG)dwRouteTimeout;
}
// if the metric changed, or the metric has gone to METRIC_INFINITE,
// update the route
if (rt_metric != rip_metric ||
(rt_metric == METRIC_INFINITE &&
(rt_entry->dwFlag & GARBAGE_TIMER) == 0)) {
dbgprintf("Metric change, destination == %s, "
"next hop == %s, metric == %s",
szAddress, szSrcaddr, szMetric);
RipLogInformation(RIPLOG_METRIC_CHANGE, 3, ppszArgs, 0);
// is the route going away?
if (rip_metric == METRIC_INFINITE &&
(rt_entry->dwFlag & GARBAGE_TIMER) == 0) {
dbgprintf("METRIC IS UNREACHABLE");
// we do not know about it
rt_entry->dwFlag &= ~TIMEOUT_TIMER;
rt_entry->dwFlag |= (GARBAGE_TIMER | ROUTE_CHANGE);
if (bIsHostAddr) {
rt_entry->dwFlag |= ROUTE_HOST;
}
rt_entry->lTimeout = (LONG)dwGarbageTimeout;
rt_entry->dwMetric = METRIC_INFINITE;
}
else {
// route isn't going away, metric just changed
rt_entry->dwFlag &= ~GARBAGE_TIMER;
rt_entry->dwFlag |= (TIMEOUT_TIMER | ROUTE_CHANGE);
rt_entry->lTimeout = (LONG)dwRouteTimeout;
rt_entry->dwDestaddr = rip_entry->dwAddress;
if (bIsHostAddr) {
rt_entry->dwFlag |= ROUTE_HOST;
rt_entry->dwNetmask = HOSTADDR_MASK;
}
else {
rt_entry->dwNetmask = dwNetmask;
}
rt_entry->dwNexthop = srcaddr.s_addr;
rt_entry->dwMetric = rip_metric;
}
}
}
else
if (rip_metric < rt_metric) {
// not from original next hop for this route,
// but this is a better route
dbgprintf("New preferred route, destination == %s, "
"next hop == %s, metric == %s",
szAddress, szSrcaddr, szMetric);
RipLogInformation(RIPLOG_ROUTE_REPLACED, 3, ppszArgs, 0);
// if this route is pending garbage-collection,
// remove the old entry before accepting a new next hop
if (rt_entry->dwProtocol == IRE_PROTO_RIP &&
(rt_entry->dwFlag & GARBAGE_TIMER) != 0) {
UpdateSystemRouteTable(rt_entry, FALSE);
}
// this may have been a local route before; now it is a RIP route
rt_entry->dwProtocol = IRE_PROTO_RIP;
rt_entry->dwFlag &= ~GARBAGE_TIMER;
rt_entry->dwFlag |= (TIMEOUT_TIMER | ROUTE_CHANGE);
rt_entry->dwIndex = lpaddr->dwIndex;
rt_entry->lTimeout = (LONG)dwRouteTimeout;
rt_entry->dwDestaddr = rip_entry->dwAddress;
if (bIsHostAddr) {
rt_entry->dwFlag |= ROUTE_HOST;
rt_entry->dwNetmask = HOSTADDR_MASK;
}
else {
rt_entry->dwNetmask = dwNetmask;
}
rt_entry->dwNexthop = srcaddr.s_addr;
rt_entry->dwMetric = rip_metric;
}
// we always update the route in the system table
rt_entry->dwFlag |= ROUTE_UPDATE;
InterlockedExchange(&g_ripcfg.dwRouteChanged, 1);
#if 0
DbgPrintf(
"RIP entry : Protocol %x, Index %x, dest addr %x, dest mask %x\n",
rt_entry->dwProtocol, rt_entry->dwIndex, rt_entry->dwDestaddr, rt_entry->dwNetmask
);
DbgPrintf(
"Next Hop %x, Metric %x\n\n", rt_entry->dwNexthop, rt_entry->dwMetric
);
#endif
return 0;
}
//-----------------------------------------------------------------------
// Function: ProcessRIPQuery
//
// fills in a RIP packet entry with information from our routing table,
// if we have a matching entry in our table.
//-----------------------------------------------------------------------
DWORD ProcessRIPQuery(LPRIP_ADDRESS lpaddr, LPRIP_ENTRY rip_entry) {
LPHASH_TABLE_ENTRY rt_entry;
#ifdef ROUTE_FILTERS
DWORD dwInd = 0;
//
// run the route thru' the announce filters
//
if ( g_prfAnnounceFilters != NULL )
{
for ( dwInd = 0; dwInd < g_prfAnnounceFilters-> dwCount; dwInd++ )
{
if ( g_prfAnnounceFilters-> pdwFilter[ dwInd ] ==
rip_entry-> dwAddress )
{
dbgprintf(
"setting metric for route %s to infinite in RIP query",
inet_ntoa(
*( (struct in_addr*) &(rip_entry-> dwAddress ) )
)
);
rip_entry-> dwMetric = htonl(METRIC_INFINITE);
return 0;
}
}
}
#endif
// RFC 1058 page 25
// If routing table entry exists then pick up the metric.
// Otherwise return a metric of METRIC_INFINITE.
if (RouteTableEntryExists(lpaddr->dwIndex, rip_entry->dwAddress) &&
(rt_entry = GetRouteTableEntry(lpaddr->dwIndex,
rip_entry->dwAddress,
rip_entry->dwSubnetmask)) != NULL) {
rip_entry->dwMetric = htonl(rt_entry->dwMetric);
}
else {
rip_entry->dwMetric = htonl(METRIC_INFINITE);
}
return 0;
}
//-----------------------------------------------------------------------
// Function: ServiceMain
//
// This is the entry point of the service, and the function which
// handles all network input processing.
//-----------------------------------------------------------------------
VOID FAR PASCAL ServiceMain(IN DWORD dwNumServicesArgs,
IN LPSTR *lpServiceArgVectors) {
HANDLE hThread;
WSADATA wsaData;
HANDLE DoneEvents[2];
DWORD dwErr, dwOption, dwThread;
SERVICE_STATUS status = {SERVICE_WIN32, SERVICE_STOPPED,
SERVICE_ACCEPT_STOP, NO_ERROR, 0, 0, 0};
#ifndef CHICAGO
CHAR achModule[MAX_PATH];
#else
time_t tLastReload, tCurrTime;
struct timeval tvReloadIntr;
tvReloadIntr.tv_sec = IP_ADDRESS_RELOAD_INTR;
tvReloadIntr.tv_usec = 0;
time( &tLastReload );
time( &tCurrTime );
#endif
// register with tracing DLL so errors can be reported below.
g_dwTraceID = TraceRegister(RIP_SERVICE);
if (g_dwTraceID == INVALID_TRACEID)
{
g_params.dwLoggingLevel = LOGLEVEL_ERROR;
RipLogError(RIPLOG_SERVICE_INIT_FAILED, 0, NULL, GetLastError());
return;
}
#ifndef CHICAGO
// register the service and get a service status handle
g_hService = RegisterServiceCtrlHandler(RIP_SERVICE,
serviceHandlerFunction);
if (g_hService == 0) {
dbgprintf("IPRIP could not register as a service, error code %d",
GetLastError());
RipLogError(RIPLOG_REGISTER_FAILED, 0, NULL, GetLastError());
return;
}
#endif
dbgprintf("IPRIP is starting up...");
// Prepare a status structure to pass to the service controller
InterlockedExchange(&g_dwWaitHint, 60000);
InterlockedExchange(&g_dwCheckPoint, 100);
InterlockedExchange(&g_dwCurrentState, SERVICE_START_PENDING);
status.dwControlsAccepted = 0;
status.dwWaitHint = g_dwWaitHint;
status.dwWin32ExitCode = NO_ERROR;
status.dwCheckPoint = g_dwCheckPoint;
status.dwServiceSpecificExitCode = 0;
status.dwServiceType = SERVICE_WIN32;
status.dwCurrentState = g_dwCurrentState;
#ifndef CHICAGO
if (!SetServiceStatus(g_hService, &status)) {
dbgprintf("IPRIP could not report its status, error code %d",
GetLastError());
RipLogError(RIPLOG_SETSTATUS_FAILED, 0, NULL, GetLastError());
return;
}
#endif
RIP_CREATE_PARAMS_LOCK();
RIP_CREATE_ADDRTABLE_LOCK();
RIP_CREATE_ROUTETABLE_LOCK();
#ifdef ROUTE_FILTERS
RIP_CREATE_ANNOUNCE_FILTERS_LOCK();
RIP_CREATE_ACCEPT_FILTERS_LOCK();
#endif
// first of all, start Winsock
if (WSAStartup(MAKEWORD(1, 1), &wsaData)) {
dbgprintf("error %d initializing Windows Sockets.", WSAGetLastError());
RipLogError(RIPLOG_WSOCKINIT_FAILED, 0, NULL, WSAGetLastError());
RIPServiceStop(); return;
}
// load operating parameters from the registry
dwErr = LoadParameters();
if (dwErr != 0) {
dbgprintf("could not load registry parameters, error code %d", dwErr);
RipLogError(RIPLOG_REGINIT_FAILED, 0, NULL, dwErr);
RIPServiceStop(); return;
}
dwErr = InitializeRouteTable();
if (dwErr != 0) {
dbgprintf("could not initialize routing table, error code %d", dwErr);
RipLogError(RIPLOG_RTAB_INIT_FAILED, 0, NULL, dwErr);
RIPServiceStop(); return;
}
dwErr = InitializeStatsTable();
if (dwErr != 0) {
dbgprintf("could not initialize statistics, error code %d", dwErr);
RipLogError(RIPLOG_STAT_INIT_FAILED, 0, NULL, dwErr);
RIPServiceStop(); return;
}
// no other threads running, so no need for synchronization
dwErr = InitializeAddressTable(TRUE);
if (dwErr != 0) {
dbgprintf("could not initialize sockets, error code %d", dwErr);
RipLogError(RIPLOG_IFINIT_FAILED, 0, NULL, dwErr);
RIPServiceStop(); return;
}
// load the IP local routes table
// create socket which will be closed to interrupt select
g_stopSocket = socket(AF_INET, SOCK_DGRAM, 0);
// Create service stop event
g_stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
// Create triggered update request event
g_triggerEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
// create events on which we wait for the other threads
DoneEvents[0] =
g_updateDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
DoneEvents[1] =
g_changeNotifyDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
#ifndef CHICAGO
// In order to avoid having the DLL unloaded from underneath our threads,
// we increment the DLL refcount as each thread is created.
//
// retrieve the module-name for this DLL.
GetModuleFileName(g_hmodule, achModule, MAX_PATH);
#endif
// Create the thread which handles timed operations
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)UpdateThread,
NULL, 0, &dwThread);
if (hThread == NULL) {
dbgprintf("could not create route update thread, error code %lu",
GetLastError());
RipLogError(RIPLOG_CREATETHREAD_FAILED, 0, NULL, GetLastError());
closesocket(g_stopSocket);
RIPServiceStop(); return;
}
CloseHandle(hThread);
#ifndef CHICAGO
// Increment the DLL refcount for the above thread
LoadLibrary(achModule);
#endif
// Create the thread which waits for address changes
hThread =
CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE)AddressChangeNotificationThread,
(LPVOID)NULL, 0, &dwThread);
if (hThread == NULL ) {
dbgprintf("could not create address change notification thread, "
"error code = %lu", GetLastError());
RipLogError(RIPLOG_CREATETHREAD_FAILED, 0, NULL, GetLastError());
SetEvent(g_stopEvent);
WaitForSingleObject(g_updateDoneEvent, INFINITE);
closesocket(g_stopSocket);
RIPServiceStop(); return;
}
CloseHandle (hThread);
#ifndef CHICAGO
// Increment the DLL refcount for the above thread
LoadLibrary(achModule);
#endif
// broadcast the initial requests for full routing information
// from all the neighboring routers
BroadcastRouteTableRequests();
// Everything initialized fine:
// Prepare a status structure to pass to the service controller
InterlockedExchange(&g_dwWaitHint, 0);
InterlockedExchange(&g_dwCheckPoint, 0);
InterlockedExchange(&g_dwCurrentState, SERVICE_RUNNING);
status.dwWaitHint = g_dwWaitHint;
status.dwCheckPoint = g_dwCheckPoint;
status.dwCurrentState = g_dwCurrentState;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
#ifndef CHICAGO
SetServiceStatus(g_hService, &status);
#endif
RipLogInformation(RIPLOG_SERVICE_STARTED, 0, NULL, 0);
// enter the main input processing loop
while (TRUE) {
INT length, size;
IN_ADDR addr;
DWORD dwSilentRIP;
SOCKADDR_IN srcaddr;
INT numReady;
fd_set readfds;
BOOL bLocalAddr;
BOOL bPacketValid;
BYTE buffer[RIP_MESSAGE_SIZE];
LPRIP_HEADER lpheader;
LPRIP_ADDRESS lpaddr, lpend;
DWORD dwResult, dwUpdateFreq, dwTrigger;
FD_ZERO(&readfds);
RIP_LOCK_ADDRTABLE();
lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
if (lpaddr->sock != INVALID_SOCKET) {
FD_SET(lpaddr->sock, &readfds);
}
}
RIP_UNLOCK_ADDRTABLE();
FD_SET(g_stopSocket, &readfds);
// this is where we wait for something to come down the wire
#ifndef CHICAGO
numReady = select(0, &readfds, NULL, NULL, NULL);
#else
//
// hack for Win95 since there is no mechanism to wait
// for DHCP address change notification.
// set an interval after which the IP addresses will
// be reloaded by the IPRIP.
//
time( &tCurrTime );
if ( ( tCurrTime - tLastReload ) > IP_ADDRESS_RELOAD_INTR )
{
numReady = 0;
}
else
{
numReady = select( 0, &readfds, NULL, NULL,
(struct timeval FAR *) &tvReloadIntr);
}
#endif
if (
(numReady == SOCKET_ERROR &&
WSAGetLastError() == WSAENOTSOCK)
#ifdef CHICAGO
|| ( numReady == 0 )
#endif
) {
// socket g_stopSocket was closed, find out why
if (g_stopReason == STOP_REASON_QUIT) {
dbgprintf("service received stop request, shutting down");
SetEvent(g_stopEvent);
WaitForMultipleObjects(2, DoneEvents, TRUE, INFINITE);
RIPServiceStop(); return;
}
else
if (
(g_stopReason == STOP_REASON_ADDRCHANGE)
#ifdef CHICAGO
|| ( numReady == 0 )
#endif
) {
dbgprintf("service detected IP address change, reconfiguring");
RipLogInformation(RIPLOG_ADDRESS_CHANGE, 0, NULL, 0);
RIP_LOCK_ADDRTABLE();
dwErr = InitializeAddressTable(FALSE);
RIP_UNLOCK_ADDRTABLE();
if (dwErr != 0 ||
(dwErr = BroadcastRouteTableRequests()) != 0) {
// re-init failed, log error and quit
RipLogError(RIPLOG_REINIT_FAILED, 0, NULL, dwErr);
SetEvent(g_stopEvent);
WaitForMultipleObjects(2, DoneEvents, TRUE, INFINITE);
RIPServiceStop(); return;
}
#ifndef CHICAGO
// create socket which will be closed to interrupt select
g_stopSocket = socket(AF_INET, SOCK_DGRAM, 0);
#else
time( &tLastReload );
#endif
continue;
}
}
// neither stop request nor reconfig request, so some data
// must have arrived. lock address table and go through
// the sockets to see which ones are ready for reading
RIP_LOCK_ADDRTABLE();
lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
if (lpaddr->sock != INVALID_SOCKET &&
FD_ISSET(lpaddr->sock, &readfds)) {
// read the incoming message
size = sizeof(srcaddr);
length = recvfrom(lpaddr->sock, buffer, RIP_MESSAGE_SIZE, 0,
(SOCKADDR *)&srcaddr, &size);
if (length == 0 || length == SOCKET_ERROR) {
addr.s_addr = lpaddr->dwAddress;
dbgprintf("error receiving data on local address %s, "
"error code %d", inet_ntoa(addr),
WSAGetLastError());
InterlockedIncrement(&lpaddr->lpstats->dwReceiveFailures);
if (WSAGetLastError() == WSAEMSGSIZE) {
RipLogInformation(RIPLOG_RECVSIZE_TOO_GREAT, 0, NULL, 0);
}
else {
RipLogInformation(RIPLOG_RECVFROM_FAILED, 0,
NULL, WSAGetLastError());
}
continue;
}
#if 0
DbgPrintf( "\n\n\nData received from %s on socket %d\n", inet_ntoa( srcaddr.sin_addr ), lpaddr-> sock );
DbgPrintf( "socket bound to %s\n\n", inet_ntoa( *( (struct in_addr *) &(lpaddr-> dwAddress) ) ) );
#endif
// data received, so place a template over it
lpheader = (LPRIP_HEADER)buffer;
// validate the packet
if (lpheader->chVersion == 0) {
dbgprintf("version in RIP header is 0, "
"discarding packet");
InterlockedIncrement(&lpaddr->lpstats->dwBadPacketsReceived);
RipLogInformation(RIPLOG_VERSION_ZERO, 0, NULL, 0);
continue;
}
else
if (lpheader->chVersion == 1 && lpheader->wReserved != 0) {
dbgprintf("reserved field in RIPv1 header is non-zero, "
"discarding packet");
InterlockedIncrement(&lpaddr->lpstats->dwBadPacketsReceived);
RipLogInformation(RIPLOG_FORMAT_ERROR, 0, NULL, 0);
continue;
}
else
if (lpheader->chVersion == 2 && lpheader->wReserved != 0) {
dbgprintf("reserved field in RIPv2 header is non-zero, "
"discarding packet");
InterlockedIncrement(&lpaddr->lpstats->dwBadPacketsReceived);
RipLogInformation(RIPLOG_FORMAT_ERROR, 0, NULL, 0);
continue;
}
if (lpheader->chCommand == RIP_REQUEST) {
ProcessRIPRequest(lpaddr, &srcaddr, buffer, length);
}
else
if (lpheader->chCommand == RIP_RESPONSE) {
ProcessRIPResponse(lpaddr, &srcaddr, buffer, length);
// tell the update thread to process the changes just made
// to the table;
// this could include adding routes to the IP table
// and/or sending out triggered updates
if (g_ripcfg.dwRouteChanged != 0) {
SetEvent(g_triggerEvent);
}
}
}
}
RIP_UNLOCK_ADDRTABLE();
}
}
//-----------------------------------------------------------------------
// Function: ProcessRIPRequest
//
// Handles processing of requests. Validates packets, and sends
// responses.
//-----------------------------------------------------------------------
VOID ProcessRIPRequest(LPRIP_ADDRESS lpaddr, LPSOCKADDR_IN lpsrcaddr,
BYTE buffer[], int length) {
INT iErr;
IN_ADDR addr;
BYTE chVersion;
BOOL bValidated;
DWORD dwSilentRIP;
CHAR szAddress[32];
LPRIP_HEADER lpheader;
LPRIP_ENTRY lpentry, lpbufend;
CHAR *pszTemp;
RIP_LOCK_PARAMS();
dwSilentRIP = g_params.dwSilentRIP;
RIP_UNLOCK_PARAMS();
// if this is a regular request and RIP is silent, do nothing
if (dwSilentRIP != 0) { // && lpsrcaddr->sin_port == htons(RIP_PORT)) {
return;
}
// ignore requests from our own interfaces
if (IsLocalAddr(lpsrcaddr->sin_addr.s_addr)) {
return;
}
InterlockedIncrement(&lpaddr->lpstats->dwRequestsReceived);
// place a template over the first entry
lpentry = (LPRIP_ENTRY)(buffer + sizeof(RIP_HEADER));
lpbufend = (LPRIP_ENTRY)(buffer + length);
lpheader = (LPRIP_HEADER)buffer;
chVersion = lpheader->chVersion;
// print a message
addr.s_addr = lpaddr->dwAddress;
pszTemp = inet_ntoa(addr);
if (pszTemp != NULL) {
strcpy(szAddress, pszTemp);
}
dbgprintf("received RIP v%d request from %s on address %s",
chVersion, inet_ntoa(lpsrcaddr->sin_addr), szAddress);
// if this is a request for the entire routing table, send it
if (length == (sizeof(RIP_HEADER) + sizeof(RIP_ENTRY)) &&
lpentry->wAddrFamily == 0 &&
lpentry->dwMetric == htonl(METRIC_INFINITE)) {
// transmit the entire routing table, subject
// to split-horizon and poisoned reverse processing
TransmitRouteTableContents(lpaddr, lpsrcaddr, FALSE);
return;
}
#ifdef ROUTE_FILTERS
RIP_LOCK_ANNOUNCE_FILTERS();
#endif
// this is a request for specific entries,
// validate the entries first
bValidated = TRUE;
for ( ; (lpentry + 1) <= lpbufend; lpentry++) {
// validate the entry first
if (chVersion == 1 && (lpentry->wReserved != 0 ||
lpentry->dwReserved1 != 0 ||
lpentry->dwReserved2 != 0)) {
bValidated = FALSE;
break;
}
// now process it
ProcessRIPQuery(lpaddr, lpentry);
}
#ifdef ROUTE_FILTERS
RIP_UNLOCK_ANNOUNCE_FILTERS();
#endif
// if packet was validated and fields filled in, send it back
if (bValidated) {
// update the command field
lpheader->chCommand = RIP_RESPONSE;
iErr = sendto(lpaddr->sock, buffer, length, 0,
(LPSOCKADDR)lpsrcaddr, sizeof(SOCKADDR_IN));
if (iErr == SOCKET_ERROR) {
dbgprintf("error sending response to %s from local interface %s",
inet_ntoa(lpsrcaddr->sin_addr), szAddress);
InterlockedIncrement(&lpaddr->lpstats->dwSendFailures);
RipLogInformation(RIPLOG_SENDTO_FAILED, 0, NULL, WSAGetLastError());
}
else {
InterlockedIncrement(&lpaddr->lpstats->dwResponsesSent);
}
}
}
//-----------------------------------------------------------------------
// Function: ProcessRIPResponse
//
// Handles processing of response packets. Validates packets,
// and updates the tables if necessary.
//-----------------------------------------------------------------------
VOID ProcessRIPResponse(LPRIP_ADDRESS lpaddr, LPSOCKADDR_IN lpsrcaddr,
BYTE buffer[], int length) {
IN_ADDR addr;
BYTE chVersion;
CHAR szAddress[32];
LPRIP_HEADER lpheader;
LPRIP_ENTRY lpentry, lpbufend;
LPRIP_AUTHENT_ENTRY lpaentry;
CHAR *pszTemp;
// ignore responses from ports other than 520
if (lpsrcaddr->sin_port != htons(RIP_PORT)) {
dbgprintf("response is from invalid port (%d), discarding");
InterlockedIncrement(&lpaddr->lpstats->dwBadPacketsReceived);
RipLogWarning(RIPLOG_INVALIDPORT, 0, NULL, 0);
return;
}
// ignore responses from our own interfaces
if (IsLocalAddr(lpsrcaddr->sin_addr.s_addr)) {
return;
}
InterlockedIncrement(&lpaddr->lpstats->dwResponsesReceived);
// place templates over the buffer
lpentry = (LPRIP_ENTRY)(buffer + sizeof(RIP_HEADER));
lpbufend = (LPRIP_ENTRY)(buffer + length);
lpheader = (LPRIP_HEADER)buffer;
chVersion = lpheader->chVersion;
lpaentry = (LPRIP_AUTHENT_ENTRY) lpentry;
// seems OK, print a message
addr.s_addr = lpaddr->dwAddress;
pszTemp = inet_ntoa(addr);
if (pszTemp != NULL) {
strcpy(szAddress, pszTemp);
}
dbgprintf("received RIP v%d response from %s on address %s",
chVersion, inet_ntoa(lpsrcaddr->sin_addr), szAddress);
#ifdef ROUTE_FILTERS
RIP_LOCK_ACCEPT_FILTERS();
#endif
//
// take care of RIPv2 auth entry
// - ignoring auth entry till we decide on a way to allow this
// to be configurable
//
if (chVersion == 2) {
// if its an auth entry, ignore and continue
if (ntohs(lpaentry->wAddrFamily) == ADDRFAMILY_AUTHENT) {
lpentry++;
}
}
//
// validate each entry, then process it
//
for ( ; (lpentry + 1) <= lpbufend; lpentry++) {
//
// for non RIPv2 reserved fields must be checked
//
if (chVersion == 1) {
//
// check route entry fields
//
if (ntohs(lpentry->wAddrFamily) != AF_INET ||
lpentry->wReserved != 0 ||
lpentry->dwReserved1 != 0 ||
lpentry->dwReserved2 != 0) {
//
// update stats on ignored entries
//
InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
RipLogInformation(RIPLOG_FORMAT_ERROR, 0, NULL, 0);
continue;
}
// entry looks OK, so process it
ProcessRIPEntry(lpaddr, lpsrcaddr->sin_addr, lpentry, chVersion);
}
else
if (chVersion == 2) {
//
// check route entry fields
//
if (ntohs(lpentry->wAddrFamily) != AF_INET) {
//
// update stats on ignored entries
//
InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
RipLogInformation(RIPLOG_FORMAT_ERROR, 0, NULL, 0);
continue;
}
// entry looks OK, so process it
ProcessRIPEntry(lpaddr, lpsrcaddr->sin_addr, lpentry, chVersion);
}
else {
// following routing\ip\rip semantics
//
// this packet's version is greater than 2, so we ignore
// the contents of the reserved fields
//
//
// check route entry fields
//
if (ntohs(lpentry->wAddrFamily) != AF_INET) {
//
// update stats on ignored entries
//
InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
RipLogInformation(RIPLOG_FORMAT_ERROR, 0, NULL, 0);
continue;
}
//
// entry is alright, clear reserved fields and process
//
lpentry->wRoutetag = 0;
lpentry->dwSubnetmask = 0;
lpentry->dwNexthop = 0;
// entry looks OK, so process it
ProcessRIPEntry(lpaddr, lpsrcaddr->sin_addr, lpentry, chVersion);
}
}
#ifdef ROUTE_FILTERS
RIP_UNLOCK_ACCEPT_FILTERS();
#endif
}
//-----------------------------------------------------------------------
// Function: AddressChangeNotificationThread
//
// Used to wait on a DHCP triggered event that tells whenever there is
// a config change. At that point we go re-read the IP config information
// and build the interface table again.
//
// This thread also waits on the shutdown event to clean up route tables.
//-----------------------------------------------------------------------
DWORD AddressChangeNotificationThread(LPVOID param) {
DWORD dwErr;
HANDLE hEvents[2];
HANDLE hDHCPEvent;
#if (WINVER >= 0x500)
hDHCPEvent = DhcpOpenGlobalEvent();
#else
SECURITY_ATTRIBUTES saAttr;
SECURITY_DESCRIPTOR sdDesc;
//
// Try to create this event in case DHCP service or DHCP API
// has not created it; use the security attributes struct
// because DHCP will, and omitting this code will cause DHCP
// to fail to open the event if the interfaces are statically
// configured (in which case the DHCP client would not be running)
saAttr.nLength = sizeof(saAttr);
saAttr.bInheritHandle = FALSE;
InitializeSecurityDescriptor(&sdDesc, SECURITY_DESCRIPTOR_REVISION);
if (SetSecurityDescriptorDacl(&sdDesc, TRUE, NULL, FALSE)) {
saAttr.lpSecurityDescriptor = &sdDesc;
}
else {
saAttr.lpSecurityDescriptor = NULL;
}
hDHCPEvent = CreateEvent(&saAttr, TRUE, FALSE, DHCP_ADDR_CHANGE_EVENT);
#endif
// if we can't open this handle then we simple quit this thread
// this does mean that we will not be able to pick up
// any new changes to the config.
if (hDHCPEvent == NULL) {
dbgprintf("could not create address change notification event, "
"error code %d", GetLastError());
RipLogError(RIPLOG_CREATEEVENT_FAILED, 0, NULL, GetLastError());
SetEvent(g_changeNotifyDoneEvent);
#ifndef CHICAGO
FreeLibraryAndExitThread(g_hmodule, 0);
#endif
return 0;
}
hEvents[0] = hDHCPEvent;
hEvents[1] = g_stopEvent;
// loop waiting for an address to change or for the service to stop
for ( ; ; ) {
dwErr = WaitForMultipleObjects(2, (LPHANDLE)hEvents,
FALSE, INFINITE);
if (dwErr == WAIT_OBJECT_0) {
// IP config changed - re-read the config info
dbgprintf("IP address table changed, signalling input thread");
// set the reason for interruption
InterlockedExchange(&g_stopReason, STOP_REASON_ADDRCHANGE);
// close the socket to tell main thread it should stop
closesocket(g_stopSocket);
}
else
if (dwErr == WAIT_OBJECT_0 + 1) {
break;
}
}
dbgprintf("address change notification thread is stopping.");
CloseHandle(hDHCPEvent);
SetEvent(g_changeNotifyDoneEvent);
#ifndef CHICAGO
FreeLibraryAndExitThread(g_hmodule, 0);
#endif
return 0;
}
//-----------------------------------------------------------------------
// Function: serviceHandlerFunction()
//
// Handles all service controller requests.
//-----------------------------------------------------------------------
VOID serviceHandlerFunction(DWORD dwControl) {
SERVICE_STATUS status;
dbgprintf("Service received control request %d", dwControl);
switch (dwControl) {
case SERVICE_CONTROL_INTERROGATE:
case SERVICE_CONTROL_PAUSE:
case SERVICE_CONTROL_CONTINUE:
// increment checkpoint if necessary
if (g_dwCheckPoint != 0) {
InterlockedExchange(&g_dwCheckPoint, g_dwCheckPoint + 100);
}
status.dwWaitHint = g_dwWaitHint;
status.dwWin32ExitCode = NO_ERROR;
status.dwServiceType = SERVICE_WIN32;
status.dwServiceSpecificExitCode = 0;
status.dwCheckPoint = g_dwCheckPoint;
status.dwCurrentState = g_dwCurrentState;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_SHUTDOWN;
#ifndef CHICAGO
SetServiceStatus (g_hService, &status);
#endif
break;
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
InterlockedExchange(&g_stopReason, STOP_REASON_QUIT);
closesocket(g_stopSocket);
SetEvent(g_stopEvent); // start cleanup
InterlockedExchange(&g_dwWaitHint, 120000);
InterlockedExchange(&g_dwCheckPoint, 100);
InterlockedExchange(&g_dwCurrentState, SERVICE_STOP_PENDING);
status.dwWaitHint = g_dwWaitHint;
status.dwWin32ExitCode = NO_ERROR;
status.dwCheckPoint = g_dwCheckPoint;
status.dwServiceType = SERVICE_WIN32;
status.dwServiceSpecificExitCode = 0;
status.dwCurrentState = g_dwCurrentState;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
#ifndef CHICAGO
SetServiceStatus(g_hService, &status);
#endif
break;
}
}
//-----------------------------------------------------------------------
// Function: RIPServiceStop
//
// Handles freeing of resources, closing handles and sockets,
// and sending final status message to the service controller.
//-----------------------------------------------------------------------
void RIPServiceStop() {
LPRIP_ADDRESS lpaddr, lpend;
SERVICE_STATUS stopstatus = {SERVICE_WIN32, SERVICE_STOPPED, 0,
NO_ERROR, 0, 0, 0};
CleanupRouteTable();
CleanupStatsTable();
lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
if (lpaddr->sock != INVALID_SOCKET) { closesocket(lpaddr->sock); }
}
WSACleanup();
if (g_triggerEvent != NULL) {
CloseHandle(g_triggerEvent); g_triggerEvent = NULL;
}
if (g_updateDoneEvent != NULL) {
CloseHandle(g_updateDoneEvent); g_updateDoneEvent = NULL;
}
if (g_changeNotifyDoneEvent != NULL) {
CloseHandle(g_changeNotifyDoneEvent); g_changeNotifyDoneEvent = NULL;
}
if (g_ripcfg.hTCPDriver != NULL) {
CloseHandle(g_ripcfg.hTCPDriver); g_ripcfg.hTCPDriver = NULL;
}
if (g_stopEvent != NULL) {
CloseHandle(g_stopEvent); g_stopEvent = NULL;
}
// need to log this before we destroy the locks
RipLogInformation(RIPLOG_SERVICE_STOPPED, 0, NULL, 0);
RIP_DESTROY_PARAMS_LOCK();
RIP_DESTROY_ADDRTABLE_LOCK();
RIP_DESTROY_ROUTETABLE_LOCK();
#ifdef ROUTE_FILTERS
RIP_DESTROY_ANNOUNCE_FILTERS_LOCK();
RIP_DESTROY_ACCEPT_FILTERS_LOCK();
#endif
dbgprintf("Main thread stopping.");
TraceDeregister(g_dwTraceID);
g_dwTraceID = (DWORD)-1;
#ifndef CHICAGO
SetServiceStatus(g_hService, &stopstatus);
#endif
}
#ifdef ROUTE_FILTERS
PRIP_FILTERS
LoadFilters(
IN HKEY hKeyParams,
IN LPSTR lpszKeyName
)
{
LPSTR pszFilter = NULL;
LPSTR pszIndex = NULL;
DWORD dwSize = 0, dwErr = NO_ERROR, dwType = 0, dwCount = 0, dwInd = 0;
PRIP_FILTERS prfFilter = NULL;
//
// route filters (added as a hotfix).
//
//
// Routes included in a RIP annoucement can be filtered.
//
// Route filters are configured by setting the value "AnnounceRouteFilters"
// or "AcceptRouteFilters"
// under the Parameters key. These are reg_multi_sz (or whatever it is
// formally called). Multiple filters can be set in each multistring.
// Each entry represents a network that will be filtered out when RIP
// announces/accepts routes.
//
do
{
dwSize = 0;
dwErr = RegQueryValueExA(
hKeyParams, lpszKeyName, NULL,
&dwType, (LPBYTE) NULL, &dwSize
);
if ( dwErr != ERROR_SUCCESS ||
dwType != REG_MULTI_SZ ||
dwSize <= 1 )
{
//
// either there is no key by this name or it is the
// wrong type. Nothing else to be done at this point
//
break;
}
//
// Appears to be a valid key with some data in it.
//
pszFilter = HeapAlloc(
GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize + 1
);
if ( pszFilter == NULL )
{
dbgprintf(
"Failed to allocate filter string : size = %d", dwSize
);
RipLogError(
RIPLOG_FILTER_ALLOC_FAILED, 0, NULL, ERROR_NOT_ENOUGH_MEMORY
);
break;
}
//
// retrieve key contents
//
dwErr = RegQueryValueExA(
hKeyParams, lpszKeyName, NULL,
&dwType, (LPBYTE) pszFilter, &dwSize
);
if ( dwErr != NO_ERROR || dwType != REG_MULTI_SZ || dwSize <= 1 )
{
dbgprintf(
"Failed to retrieve %s filters : error = %d", lpszKeyName,
dwErr
);
break;
}
//
// Convert the filter multi string to ip addresses
//
//
// count the number of filters
//
pszIndex = pszFilter;
while ( *pszIndex != '\0' )
{
dwCount++;
pszIndex += strlen( pszIndex ) + 1;
}
if ( dwCount == 0 )
{
dbgprintf( "No filters found" );
break;
}
//
// allocate filter structure
//
prfFilter = HeapAlloc(
GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof( RIP_FILTERS ) + ( dwCount - 1) * sizeof(
DWORD )
);
if ( prfFilter == NULL )
{
dbgprintf(
"Failed to allocate filter table : size = %d", dwSize
);
RipLogError(
RIPLOG_FILTER_ALLOC_FAILED, 0, NULL, ERROR_NOT_ENOUGH_MEMORY
);
break;
}
//
// fill it up
//
prfFilter-> dwCount = dwCount;
pszIndex = pszFilter;
for ( dwInd = 0; dwInd < dwCount; dwInd++ )
{
prfFilter-> pdwFilter[ dwInd ] = inet_addr( pszIndex );
pszIndex += strlen( pszIndex ) + 1;
}
} while ( FALSE );
if ( pszFilter != NULL )
{
HeapFree( GetProcessHeap(), 0, pszFilter );
}
if ( prfFilter != NULL )
{
//
// Print the list of configured filters
//
dbgprintf( "Number of filters : %d", prfFilter-> dwCount );
for ( dwInd = 0; dwInd < prfFilter-> dwCount; dwInd++ )
{
dbgprintf(
"Filter #%d : %x (%s)", dwInd,
prfFilter-> pdwFilter[ dwInd ],
inet_ntoa( *( (struct in_addr*)
&(prfFilter-> pdwFilter[ dwInd ] ) ) )
);
}
}
return prfFilter;
}
#endif
//-----------------------------------------------------------------------
//
//--------------------------- WINNT Specific ----------------------------
//
//-----------------------------------------------------------------------
#ifndef CHICAGO
//-----------------------------------------------------------------------
// Function: DllMain
//
// DLL entry-point; saves the module handle for later use.
//-----------------------------------------------------------------------
BOOL APIENTRY
DllMain(
HMODULE hmodule,
DWORD dwReason,
VOID* pReserved
) {
if (dwReason == DLL_PROCESS_ATTACH) { g_hmodule = hmodule; }
return TRUE;
}
//-----------------------------------------------------------------------
// Function: LoadParameters
//
// Reads various configuration flags from the registry.
//-----------------------------------------------------------------------
DWORD LoadParameters() {
DWORD valuesize;
DWORD dwErr, dwType, dwIndex, dwValue;
HKEY hkeyParams;
DWORD dwRouteTimeout, dwGarbageTimeout;
DWORD dwLoggingLevel, dwUpdateFrequency;
DWORD dwMaxTriggerFrequency, dwOverwriteStaticRoutes;
DWORD dwSize = MAX_PATH;
HKEY hkey = NULL;
WCHAR Buffer[MAX_PATH+1];
RegCloseKey( hkey );
dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_RIP_PARAMS, &hkeyParams);
if (dwErr != ERROR_SUCCESS) {
return GetLastError();
}
#ifdef ROUTE_FILTERS
RIP_LOCK_ANNOUNCE_FILTERS();
if ( g_prfAnnounceFilters != NULL ) {
HeapFree( GetProcessHeap(), 0, g_prfAnnounceFilters );
}
g_prfAnnounceFilters = LoadFilters( hkeyParams, REGVAL_ANNOUCE_FILTERS );
RIP_UNLOCK_ANNOUNCE_FILTERS();
RIP_LOCK_ACCEPT_FILTERS();
if ( g_prfAcceptFilters != NULL ) {
HeapFree( GetProcessHeap(), 0, g_prfAcceptFilters );
}
g_prfAcceptFilters = LoadFilters( hkeyParams, REGVAL_ACCEPT_FILTERS );
RIP_UNLOCK_ACCEPT_FILTERS();
#endif
RIP_LOCK_PARAMS();
// always run in SilentRIP mode.
{
g_params.dwSilentRIP = 1;
}
// read the value for accepting host routes
valuesize = sizeof(DWORD);
dwErr = RegQueryValueEx(hkeyParams, REGVAL_ACCEPT_HOST, NULL,
&dwType, (LPBYTE)&dwValue, &valuesize);
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
g_params.dwAcceptHost = dwValue;
}
else {
g_params.dwAcceptHost = DEF_ACCEPT_HOST;
}
// read the value for announcing host routes
valuesize = sizeof(DWORD);
dwErr = RegQueryValueEx(hkeyParams, REGVAL_ANNOUNCE_HOST, NULL,
&dwType, (LPBYTE)&dwValue, &valuesize);
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
g_params.dwAnnounceHost = dwValue;
}
else {
g_params.dwAnnounceHost = DEF_ANNOUNCE_HOST;
}
// read the value for accepting default routes
valuesize = sizeof(DWORD);
dwErr = RegQueryValueEx(hkeyParams, REGVAL_ACCEPT_DEFAULT, NULL,
&dwType, (LPBYTE)&dwValue, &valuesize);
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
g_params.dwAcceptDefault = dwValue;
}
else {
g_params.dwAcceptDefault = DEF_ACCEPT_DEFAULT;
}
// read the value for announcing default routes
valuesize = sizeof(DWORD);
dwErr = RegQueryValueEx(hkeyParams, REGVAL_ANNOUNCE_DEFAULT, NULL,
&dwType, (LPBYTE)&dwValue, &valuesize);
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
g_params.dwAnnounceDefault = dwValue;
}
else {
g_params.dwAnnounceDefault = DEF_ANNOUNCE_DEFAULT;
}
// read value for split-horizon processing
valuesize = sizeof(DWORD);
dwErr = RegQueryValueEx(hkeyParams, REGVAL_SPLITHORIZON, NULL,
&dwType, (LPBYTE)&dwValue, &valuesize);
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
g_params.dwSplitHorizon = dwValue;
}
else {
g_params.dwSplitHorizon = DEF_SPLITHORIZON;
}
// read value for poisoned-reverse processing
valuesize = sizeof(DWORD);
dwErr = RegQueryValueEx(hkeyParams, REGVAL_POISONREVERSE, NULL,
&dwType, (LPBYTE)&dwValue, &valuesize);
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
g_params.dwPoisonReverse = dwValue;
}
else {
g_params.dwPoisonReverse = DEF_POISONREVERSE;
}
// read value for triggered update sending
valuesize = sizeof(DWORD);
dwErr = RegQueryValueEx(hkeyParams, REGVAL_TRIGGEREDUPDATES, NULL,
&dwType, (LPBYTE)&dwValue, &valuesize);
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
g_params.dwTriggeredUpdates = dwValue;
}
else {
g_params.dwTriggeredUpdates = DEF_TRIGGEREDUPDATES;
}
// read value for triggered update frequency
valuesize = sizeof(DWORD);
dwErr = RegQueryValueEx(hkeyParams, REGVAL_TRIGGERFREQUENCY, NULL,
&dwType, (LPBYTE)&dwValue, &valuesize);
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
dwMaxTriggerFrequency = dwValue * 1000;
}
else {
dwMaxTriggerFrequency = DEF_TRIGGERFREQUENCY;
}
// read value for route timeouts
valuesize = sizeof(DWORD);
dwErr = RegQueryValueEx(hkeyParams, REGVAL_ROUTETIMEOUT, NULL,
&dwType, (LPBYTE)&dwValue, &valuesize);
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
dwRouteTimeout = dwValue * 1000;
}
else {
dwRouteTimeout = DEF_ROUTETIMEOUT;
}
// read values for update frequency
valuesize = sizeof(DWORD);
dwErr = RegQueryValueEx(hkeyParams, REGVAL_UPDATEFREQUENCY, NULL,
&dwType, (LPBYTE)&dwValue, &valuesize);
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
dwUpdateFrequency = dwValue * 1000;
}
else {
dwUpdateFrequency = DEF_UPDATEFREQUENCY;
}
// read values for garbage timeouts
valuesize = sizeof(DWORD);
dwErr = RegQueryValueEx(hkeyParams, REGVAL_GARBAGETIMEOUT, NULL,
&dwType, (LPBYTE)&dwValue, &valuesize);
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
dwGarbageTimeout = dwValue * 1000;
}
else {
dwGarbageTimeout = DEF_GARBAGETIMEOUT;
}
// read values for logging level
valuesize = sizeof(DWORD);
dwErr = RegQueryValueEx(hkeyParams, REGVAL_OVERWRITESTATIC, NULL,
&dwType, (LPBYTE)&dwValue, &valuesize);
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
dwOverwriteStaticRoutes = dwValue;
}
else {
dwOverwriteStaticRoutes = DEF_OVERWRITESTATIC;
}
// read values for logging level
valuesize = sizeof(DWORD);
dwErr = RegQueryValueEx(hkeyParams, REGVAL_LOGGINGLEVEL, NULL,
&dwType, (LPBYTE)&dwValue, &valuesize);
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
dwLoggingLevel = dwValue;
}
else {
dwLoggingLevel = DEF_LOGGINGLEVEL;
}
// read value for MaxTimedOpsInterval
valuesize = sizeof(DWORD);
dwErr = RegQueryValueEx(hkeyParams, REGVAL_MAXTIMEDOPSINTERVAL, NULL,
&dwType, (LPBYTE)&dwValue, &valuesize);
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD && dwValue) {
g_params.dwMaxTimedOpsInterval = dwValue * 1000;
}
else {
g_params.dwMaxTimedOpsInterval = DEF_MAXTIMEDOPSINTERVAL;
}
RegCloseKey(hkeyParams);
// adjust values if out of acceptable range
if (dwRouteTimeout > MAX_ROUTETIMEOUT) {
dwRouteTimeout = MAX_ROUTETIMEOUT;
}
else
if (dwRouteTimeout < MIN_ROUTETIMEOUT) {
dwRouteTimeout = MIN_ROUTETIMEOUT;
}
if (dwGarbageTimeout > MAX_GARBAGETIMEOUT) {
dwGarbageTimeout = MAX_GARBAGETIMEOUT;
}
else
if (dwGarbageTimeout < MIN_GARBAGETIMEOUT) {
dwGarbageTimeout = MIN_GARBAGETIMEOUT;
}
if (dwUpdateFrequency > MAX_UPDATEFREQUENCY) {
dwUpdateFrequency = MAX_UPDATEFREQUENCY;
}
else
if (dwUpdateFrequency < MIN_UPDATEFREQUENCY) {
dwUpdateFrequency = MIN_UPDATEFREQUENCY;
}
if (dwMaxTriggerFrequency > MAX_TRIGGERFREQUENCY) {
dwMaxTriggerFrequency = MAX_TRIGGERFREQUENCY;
}
else
if (dwMaxTriggerFrequency < MIN_TRIGGERFREQUENCY) {
dwMaxTriggerFrequency = MIN_TRIGGERFREQUENCY;
}
g_params.dwRouteTimeout = dwRouteTimeout;
g_params.dwGarbageTimeout = dwGarbageTimeout;
g_params.dwUpdateFrequency = dwUpdateFrequency;
g_params.dwMaxTriggerFrequency = dwMaxTriggerFrequency;
g_params.dwLoggingLevel = dwLoggingLevel;
g_params.dwOverwriteStaticRoutes = dwOverwriteStaticRoutes;
dbgprintf("%s == %d", REGVAL_LOGGINGLEVEL, dwLoggingLevel);
dbgprintf("%s == %d", REGVAL_ROUTETIMEOUT, dwRouteTimeout / 1000);
dbgprintf("%s == %d", REGVAL_GARBAGETIMEOUT, dwGarbageTimeout / 1000);
dbgprintf("%s == %d", REGVAL_UPDATEFREQUENCY, dwUpdateFrequency / 1000);
dbgprintf("%s == %d", REGVAL_ACCEPT_HOST, g_params.dwAcceptHost);
dbgprintf("%s == %d", REGVAL_ANNOUNCE_HOST, g_params.dwAnnounceHost);
dbgprintf("%s == %d", REGVAL_ACCEPT_DEFAULT, g_params.dwAcceptDefault);
dbgprintf("%s == %d", REGVAL_ANNOUNCE_DEFAULT, g_params.dwAnnounceDefault);
dbgprintf("%s == %d", REGVAL_SPLITHORIZON, g_params.dwSplitHorizon);
dbgprintf("%s == %d", REGVAL_POISONREVERSE, g_params.dwPoisonReverse);
dbgprintf("%s == %d", REGVAL_TRIGGEREDUPDATES, g_params.dwTriggeredUpdates);
dbgprintf("%s == %d", REGVAL_OVERWRITESTATIC, dwOverwriteStaticRoutes);
dbgprintf("%s == %d", REGVAL_TRIGGERFREQUENCY,
g_params.dwMaxTriggerFrequency / 1000);
if (g_params.dwSilentRIP != 0) {
dbgprintf("IPRIP is configured to be silent.");
}
else {
dbgprintf("IPRIP is configured to be active.");
}
if (dwLoggingLevel >= LOGLEVEL_INFORMATION) {
// log the parameters IPRIP is using
//
CHAR szBuffer[2048], *lplpszArgs[] = { szBuffer };
sprintf(szBuffer,
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d",
REGVAL_LOGGINGLEVEL, dwLoggingLevel,
REGVAL_ROUTETIMEOUT, dwRouteTimeout / 1000,
REGVAL_GARBAGETIMEOUT, dwGarbageTimeout / 1000,
REGVAL_UPDATEFREQUENCY, dwUpdateFrequency / 1000,
REGVAL_ACCEPT_HOST, g_params.dwAcceptHost,
REGVAL_ANNOUNCE_HOST, g_params.dwAnnounceHost,
REGVAL_ACCEPT_DEFAULT, g_params.dwAcceptDefault,
REGVAL_ANNOUNCE_DEFAULT, g_params.dwAnnounceDefault,
REGVAL_SPLITHORIZON, g_params.dwSplitHorizon,
REGVAL_POISONREVERSE, g_params.dwPoisonReverse,
REGVAL_TRIGGEREDUPDATES, g_params.dwTriggeredUpdates,
REGVAL_OVERWRITESTATIC, dwOverwriteStaticRoutes,
REGVAL_TRIGGERFREQUENCY, g_params.dwMaxTriggerFrequency / 1000,
REGVAL_SILENTRIP, g_params.dwSilentRIP);
RipLogInformation(RIPLOG_REGISTRY_PARAMETERS, 1, lplpszArgs, 0);
}
RIP_UNLOCK_PARAMS();
return 0;
}
#else
//-----------------------------------------------------------------------
//
//--------------------------- Windows 95 Specific -----------------------
//
//-----------------------------------------------------------------------
//
// named event
//
#define RIP_LISTENER_EVENT TEXT( "RIP.Listener.Event" )
HINSTANCE hInst; // current instance
HWND hWnd; // Main window handle.
//
// resource strings
//
char szAppName[64]; // The name of this application
char szTitle[32]; // The title bar text
char szHelpStr[32]; // Help flag "Help"
char szQuestStr[32]; // Abriev. Help Flag "?"
char szCloseStr[32]; // Close flag "close"
char szDestroyStr[32]; // Destroy flag "destroy"
char szHelpText1[256]; // Help String
char szHelpText2[64]; // Help String
char szHelpText3[128]; // Help String
//
// local function prototypes
//
BOOL
InitApplication(
HINSTANCE hInstance
);
BOOL
InitInstance(
HINSTANCE hInstance,
int nCmdShow
);
BOOL
GetStrings(
HINSTANCE hInstance
);
LRESULT CALLBACK WndProc(
HWND hWnd, // window handle
UINT message, // type of message
WPARAM uParam, // additional information
LPARAM lParam // additional information
);
//-----------------------------------------------------------------------
// Function: GetStrings
//
// Retrieve resource strings
//-----------------------------------------------------------------------
BOOL GetStrings(HINSTANCE hInstance)
{
if (LoadString(hInstance, IDS_TITLE_BAR, szTitle, sizeof(szTitle)) == 0)
{
goto ErrorExit;
}
if (LoadString(hInstance, IDS_APP_NAME, szAppName, sizeof(szAppName)) == 0)
{
goto ErrorExit;
}
if (LoadString(hInstance, IDS_HELP_TEXT1, szHelpText1, sizeof(szHelpText1)) == 0)
{
goto ErrorExit;
}
if (LoadString(hInstance, IDS_HELP_TEXT2, szHelpText2, sizeof(szHelpText2)) == 0)
{
goto ErrorExit;
}
return TRUE;
ErrorExit:
return FALSE;
}
//-----------------------------------------------------------------------
// Functions : InitInstance
//
// save instance handle and create main window.
//-----------------------------------------------------------------------
BOOL
InitInstance(
HINSTANCE hInstance,
int nCmdShow
)
{
//
// Save the instance handle in static variable, which will be used in
// many subsequence calls from this application to Windows.
//
// Store instance handle in our global variable
//
hInst = hInstance;
//
// Create a main window for this application instance.
//
hWnd = CreateWindow(
szAppName,
szTitle,
WS_EX_TRANSPARENT, // Window style.
0, 0, CW_USEDEFAULT, CW_USEDEFAULT, // Use default positioning CW_USEDEAULT
NULL, // Overlapped windows have no parent.
NULL, // Use the window class menu.
hInstance, // This instance owns this window.
NULL // We don't use any data in our WM_CREATE
);
//
// If window could not be created, return "failure"
//
if (!hWnd)
{
dbgprintf( "Failed to create window" );
return (FALSE);
}
//
// Make the window visible; update its client area; and return "success"
//
ShowWindow(hWnd, nCmdShow); // Show the window
UpdateWindow(hWnd); // Sends WM_PAINT message
return (TRUE); // We succeeded...
}
//-----------------------------------------------------------------------------
// Function : InitApplication
//
// initialize window data and register window class
//-----------------------------------------------------------------------------
BOOL InitApplication(HINSTANCE hInstance)
{
WNDCLASS wc;
DWORD LastError;
//
// Fill in window class structure with parameters that
// describe the main window.
//
wc.style = CS_HREDRAW | CS_VREDRAW;// Class style(s).
wc.lpfnWndProc = (WNDPROC)WndProc; // Window Procedure
wc.cbClsExtra = 0; // No per-class extra data.
wc.cbWndExtra = 0; // No per-window extra data.
wc.hInstance = hInstance; // Owner of this class
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);// Default color
wc.lpszMenuName = szAppName; // Menu name from .RC
wc.lpszClassName = szAppName; // Name to register as
//
// Register the window class and return success/failure code.
//
if ( !RegisterClass(&wc) )
{
dbgprintf( "Failed to register class" );
return FALSE;
}
else
{
return TRUE;
}
}
//-----------------------------------------------------------------------------
// Function : WndProc
//
// process messages
//-----------------------------------------------------------------------------
LRESULT CALLBACK WndProc(
HWND hWnd, // window handle
UINT message, // type of message
WPARAM uParam, // additional information
LPARAM lParam // additional information
)
{
switch (message)
{
case WM_ENDSESSION:
case WM_QUERYENDSESSION:
if (lParam == 0)
{
dbgprintf ( "IPRIP : Received shutdown message\n" );
}
if (lParam == 1 ) //EWX_REALLYLOGOFF
{
dbgprintf ( "IPRIP : Received logoff message\n" );
}
return(1);
case WM_DESTROY: // message: window being destroyed
PostQuitMessage(0);
return(0);
default: // Pass it on if unproccessed
return (DefWindowProc(hWnd, message, uParam, lParam));
}
}
//-----------------------------------------------------------------------
// Function: LoadParameters
//
// Reads various configuration flags from the registry.
//-----------------------------------------------------------------------
DWORD LoadParameters()
{
RIP_LOCK_PARAMS();
g_params.dwSilentRIP = 1;
g_params.dwAcceptHost = DEF_ACCEPT_HOST;
g_params.dwAnnounceHost = DEF_ANNOUNCE_HOST;
g_params.dwAcceptDefault = DEF_ACCEPT_DEFAULT;
g_params.dwAnnounceDefault = DEF_ANNOUNCE_DEFAULT;
g_params.dwSplitHorizon = DEF_SPLITHORIZON;
g_params.dwPoisonReverse = DEF_POISONREVERSE;
g_params.dwTriggeredUpdates = DEF_TRIGGEREDUPDATES;
g_params.dwMaxTriggerFrequency = DEF_TRIGGERFREQUENCY;
g_params.dwRouteTimeout = DEF_ROUTETIMEOUT;
g_params.dwUpdateFrequency = DEF_UPDATEFREQUENCY;
g_params.dwGarbageTimeout = DEF_GARBAGETIMEOUT;
g_params.dwOverwriteStaticRoutes = DEF_OVERWRITESTATIC;
g_params.dwLoggingLevel = DEF_LOGGINGLEVEL;
dbgprintf("%s == %d", REGVAL_LOGGINGLEVEL, g_params.dwLoggingLevel);
dbgprintf("%s == %d", REGVAL_ROUTETIMEOUT, g_params.dwRouteTimeout / 1000);
dbgprintf("%s == %d", REGVAL_GARBAGETIMEOUT, g_params.dwGarbageTimeout / 1000);
dbgprintf("%s == %d", REGVAL_UPDATEFREQUENCY, g_params.dwUpdateFrequency / 1000);
dbgprintf("%s == %d", REGVAL_ACCEPT_HOST, g_params.dwAcceptHost);
dbgprintf("%s == %d", REGVAL_ANNOUNCE_HOST, g_params.dwAnnounceHost);
dbgprintf("%s == %d", REGVAL_ACCEPT_DEFAULT, g_params.dwAcceptDefault);
dbgprintf("%s == %d", REGVAL_ANNOUNCE_DEFAULT, g_params.dwAnnounceDefault);
dbgprintf("%s == %d", REGVAL_SPLITHORIZON, g_params.dwSplitHorizon);
dbgprintf("%s == %d", REGVAL_POISONREVERSE, g_params.dwPoisonReverse);
dbgprintf("%s == %d", REGVAL_TRIGGEREDUPDATES, g_params.dwTriggeredUpdates);
dbgprintf("%s == %d", REGVAL_OVERWRITESTATIC, g_params.dwOverwriteStaticRoutes);
dbgprintf("%s == %d", REGVAL_TRIGGERFREQUENCY,
g_params.dwMaxTriggerFrequency / 1000);
if (g_params.dwSilentRIP != 0)
{
dbgprintf("IPRIP is configured to be silent.");
}
else
{
dbgprintf("IPRIP is configured to be active.");
}
if (g_params.dwLoggingLevel >= LOGLEVEL_INFORMATION)
{
//
// log the parameters IPRIP is using
//
CHAR szBuffer[2048], *lplpszArgs[] = { szBuffer };
sprintf(szBuffer,
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d"
"\r\n%s: %d",
REGVAL_LOGGINGLEVEL, g_params.dwLoggingLevel,
REGVAL_ROUTETIMEOUT, g_params.dwRouteTimeout / 1000,
REGVAL_GARBAGETIMEOUT, g_params.dwGarbageTimeout / 1000,
REGVAL_UPDATEFREQUENCY, g_params.dwUpdateFrequency / 1000,
REGVAL_ACCEPT_HOST, g_params.dwAcceptHost,
REGVAL_ANNOUNCE_HOST, g_params.dwAnnounceHost,
REGVAL_ACCEPT_DEFAULT, g_params.dwAcceptDefault,
REGVAL_ANNOUNCE_DEFAULT, g_params.dwAnnounceDefault,
REGVAL_SPLITHORIZON, g_params.dwSplitHorizon,
REGVAL_POISONREVERSE, g_params.dwPoisonReverse,
REGVAL_TRIGGEREDUPDATES, g_params.dwTriggeredUpdates,
REGVAL_OVERWRITESTATIC, g_params.dwOverwriteStaticRoutes,
REGVAL_TRIGGERFREQUENCY, g_params.dwMaxTriggerFrequency / 1000,
REGVAL_SILENTRIP, g_params.dwSilentRIP);
RipLogInformation(RIPLOG_REGISTRY_PARAMETERS, 1, lplpszArgs, 0);
}
RIP_UNLOCK_PARAMS();
return 0;
}
//-----------------------------------------------------------------------
// Function: WinMain
//
// Launches the RIP service and waits for it to terminate
//-----------------------------------------------------------------------
INT APIENTRY
WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
MSG msg;
HANDLE RipListenerEvent, hThread, hKernel32 = NULL;
DWORD threadId, LastError;
BOOL fRegSrvcProc = FALSE;
FARPROC pRegSrvcProc;
LPCSTR event_name = RIP_LISTENER_EVENT;
DWORD err;
//
// Get entry point RegisterServiceProcess
//
/*
if ( (GetVersion() & 0x000000ff) == 0x04 )
{
if ((hKernel32 = GetModuleHandle("kernel32.dll")) == NULL)
{
//
// This should never happen but we'll try and
// load the library anyway
//
if ((hKernel32 = LoadLibrary("kernel32.dll")) == NULL)
{
fRegSrvcProc = FALSE;
}
}
if (hKernel32)
{
if ((pRegSrvcProc = GetProcAddress(hKernel32,"RegisterServiceProcess")) == NULL)
{
fRegSrvcProc = FALSE;
}
else
{
fRegSrvcProc = TRUE;
}
}
}
else
{
fRegSrvcProc = FALSE;
}
*/
//
// Other instances of RIP listener running?
//
RipListenerEvent = OpenEvent( SYNCHRONIZE, FALSE, event_name ) ;
if ( RipListenerEvent == NULL)
{
if ( (RipListenerEvent = CreateEvent( NULL, FALSE, TRUE, event_name ) ) == NULL)
{
LastError = GetLastError();
dbgprintf(
"IPRIP Create Event failed, error code %d",
LastError
);
RipLogError( RIPLOG_CREATEEVENT_FAILED, 0, NULL, LastError );
return 1;
}
}
else
{
//
// another instance is running
//
HANDLE hParentWin;
dbgprintf( "IPRIP : Service already running\n" );
RipLogError( RIPLOG_SERVICE_AREADY_STARTED, 0, NULL, 0 );
return 1;
}
//
// retrieve resource strings
//
if ( !GetStrings(hInstance) )
{
dbgprintf( "IPRIP : Service failed to initialize\n" );
RipLogError( RIPLOG_SERVICE_INIT_FAILED, 0, NULL, 0 );
return 1;
}
//
// required initialization for windows apps.
//
if( !InitApplication( hInstance ) )
{
dbgprintf( "IPRIP : Service failed to initialize\n" );
RipLogError( RIPLOG_SERVICE_INIT_FAILED, 0, NULL, 0 );
return 1;
}
if (!InitInstance(hInstance, SW_HIDE))
{
dbgprintf( "IPRIP : Service failed to initialize\n" );
RipLogError( RIPLOG_SERVICE_INIT_FAILED, 0, NULL, 0 );
return 1;
}
//
// Launch main service controller thread
//
if ( ( hThread = CreateThread(
NULL,
0,
(LPTHREAD_START_ROUTINE)ServiceMain,
NULL,
0,
&threadId
)
) == 0)
{
dbgprintf( "IPRIP : Failed thread creation\n" );
RipLogError( RIPLOG_CREATETHREAD_FAILED, 0, NULL, 0 );
return 1;
}
//
// Register service process
//
/*
if (fRegSrvcProc)
{
(*pRegSrvcProc)(GetCurrentProcessId(), RSP_SIMPLE_SERVICE);
}
*/
//
// Acquire and dispatch messages until a WM_QUIT message is received.
//
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg); // Translates virtual key codes
DispatchMessage(&msg); // Dispatches message to window
}
//
// Un register service process
//
/*
if (fRegSrvcProc)
{
(*pRegSrvcProc)(GetCurrentProcessId(), RSP_UNREGISTER_SERVICE);
}
*/
dbgprintf( "IPRIP : Service terminated\n" );
RipLogError( RIPLOG_SERVICE_STOPPED, 0, NULL, 0 );
return(0);
UNREFERENCED_PARAMETER(lpCmdLine);
}
// Name: Mohsin Ahmed
// Email: MohsinA@microsoft.com
// Date: Mon Nov 04 13:53:46 1996
// File: s:/tcpcmd/common2/debug.c
// Synopsis: Win95 Woes, don't have ntdll.dll on win95.
#include <windows.h>
#define MAX_DEBUG_OUTPUT 1024
void DbgPrintf( char * format, ... )
{
va_list args;
char out[MAX_DEBUG_OUTPUT];
int cch=0;
// cch = wsprintf( out, MODULE_NAME ":" );
va_start( args, format );
wvsprintf( out + cch, format, args );
va_end( args );
OutputDebugString( out );
}
#endif