//**************************************************************************** // // 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; HANDLE g_addressChangeEvent; HANDLE g_netEvent; HANDLE g_triggerEvent; HANDLE g_hUpdateThread; DWORD g_dwTraceID = (DWORD)-1; DWORD g_dwCurrentState; DWORD g_dwCheckPoint; DWORD g_dwWaitHint; #ifndef CHICAGO HMODULE g_hmodule; #endif #define INDEX_NETEVENT 0 #define INDEX_STOPEVENT (INDEX_NETEVENT + 1) #define INDEX_ADDRESSCHANGEEVENT (INDEX_STOPEVENT + 1) #define TOTAL_WAITEVENTS (INDEX_ADDRESSCHANGEEVENT + 1) //----------------------------------------------------------------------- // 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; DWORD dwLocalNet, dwLocalMask, dwNexthop; 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; } // // make sure that the nexthop is on a local net // // // In case of P2P connections, the subnet mask of the interface // is all ones. So do an additional check to make sure that we // don't end up rejecting routes received over a P2P connection. // dwNexthop = srcaddr.s_addr; dwLocalMask = lpaddr->dwNetmask; dwLocalNet = lpaddr->dwAddress & dwLocalMask; if ( ((dwNexthop & dwLocalMask) != dwLocalNet) && (dwLocalMask != 0xFFFFFFFF) ) { dbgprintf("Dropped route %s with next hop %s because " "NextHop is not on the same subnet as the " "interface on which the route was received", szAddress, szSrcaddr); 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) { WSADATA wsaData; HANDLE hWaitEvents[TOTAL_WAITEVENTS]; 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 DWORD dwCurrTime, dwLastReload, dwReloadIntr; dwLastReload = dwCurrTime = GetTickCount(); dwReloadIntr = IP_ADDRESS_RELOAD_INTR * 1000; #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(2, 0), &wsaData)) { dbgprintf("error %d initializing Windows Sockets.", WSAGetLastError()); RipLogError(RIPLOG_WSOCKINIT_FAILED, 0, NULL, WSAGetLastError()); RIPServiceStop(); return; } // confirm that Winsock dll supports 2.0 if ( LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0 ) { // The dll doesn't support Winsock 2.0. So exit. // We need 2.0 for WSAEventSelect and WSAEnumNetworkEvents dbgprintf("could not find winsock dll that supports version 2.0"); RipLogError(RIPLOG_WSOCKINIT_FAILED, 0, NULL, WSAVERNOTSUPPORTED); 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; } // load the IP local routes table 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; } // create network event. This event is passed to WSAEventSelect. // WSAEventSelect is posted on each socket in the LoadAddressSockets // function. We need to create this event before calling // InitializeAddressTable g_netEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if ( g_netEvent == NULL ) { dwErr = GetLastError(); dbgprintf("could not create Network event, error code %d", dwErr); RipLogError(RIPLOG_CREATEEVENT_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; } // Create service stop event g_stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if ( g_stopEvent == NULL ) { dwErr = GetLastError(); dbgprintf("could not create Service Stop event, error code %d", dwErr); RipLogError(RIPLOG_CREATEEVENT_FAILED, 0, NULL, dwErr); RIPServiceStop(); return; } // Create triggered update request event g_triggerEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if ( g_triggerEvent == NULL ) { dwErr = GetLastError(); dbgprintf("could not create Trigger event, error code %d", dwErr); RipLogError(RIPLOG_CREATEEVENT_FAILED, 0, NULL, dwErr); RIPServiceStop(); return; } // Open the event for DHCP address change notifications g_addressChangeEvent = DhcpOpenGlobalEvent(); // if we can't open this handle then we simple quit this thread if (g_addressChangeEvent == NULL) { dbgprintf("could not create address change notification event, " "error code %d", GetLastError()); RipLogError(RIPLOG_CREATEEVENT_FAILED, 0, NULL, GetLastError()); RIPServiceStop(); return; } #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 g_hUpdateThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)UpdateThread, NULL, 0, &dwThread); if (g_hUpdateThread == NULL) { dbgprintf("could not create route update thread, error code %lu", GetLastError()); RipLogError(RIPLOG_CREATETHREAD_FAILED, 0, NULL, GetLastError()); RIPServiceStop(); return; } #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); hWaitEvents[INDEX_NETEVENT] = g_netEvent; // Manual Reset: FALSE hWaitEvents[INDEX_STOPEVENT] = g_stopEvent; // Manual Reset: TRUE hWaitEvents[INDEX_ADDRESSCHANGEEVENT] = g_addressChangeEvent; // Manual Reset: TRUE // Event created by // DhcpOpenGlobalEvent // enter the main input processing loop while (TRUE) { INT length, size; IN_ADDR addr; DWORD dwSilentRIP; SOCKADDR_IN srcaddr; BOOL bLocalAddr; BOOL bPacketValid; BYTE buffer[RIP_MESSAGE_SIZE]; LPRIP_HEADER lpheader; LPRIP_ADDRESS lpaddr, lpend; DWORD dwResult, dwUpdateFreq, dwTrigger; DWORD dwWaitEndCode; WSANETWORKEVENTS wsaNetEvents; // this is where we wait for something to come down the wire #ifndef CHICAGO dwWaitEndCode = WaitForMultipleObjects( TOTAL_WAITEVENTS, hWaitEvents, FALSE, INFINITE); #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. // dwCurrTime = GetTickCount(); if ( (dwCurrTime > (dwLastReload + dwReloadIntr) ) || (dwCurrTime < dwLastReload) ) { dwWaitEndCode = WAIT_TIMEOUT; } else { dwWaitEndCode = WaitForMultipleObjects( TOTAL_WAITEVENTS, hWaitEvents, FALSE, dwReloadIntr); } #endif if (dwWaitEndCode != WAIT_OBJECT_0) { // check if g_stopEvent event was signalled if ((dwWaitEndCode - WAIT_OBJECT_0) == INDEX_STOPEVENT) { dbgprintf("service received stop request, shutting down"); WaitForSingleObject(g_hUpdateThread, INFINITE); RIPServiceStop(); return; } else if ( ((dwWaitEndCode - WAIT_OBJECT_0) == INDEX_ADDRESSCHANGEEVENT) #ifdef CHICAGO || ( dwWaitEndCode == WAIT_TIMEOUT ) #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); WaitForSingleObject(g_hUpdateThread, INFINITE); RIPServiceStop(); return; } #ifdef CHICAGO dwLastReload = GetTickCount(); #endif continue; } else { dbgprintf("ServiceMain: WaitForMultipleObjects failed. Error: %d", GetLastError()); 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){ dwErr = WSAEnumNetworkEvents( lpaddr->sock, NULL, &wsaNetEvents); if (dwErr == SOCKET_ERROR) { dbgprintf("error doing WSAEnumNetworkEvents on address %s, " "error code %d", inet_ntoa(addr), WSAGetLastError()); RipLogInformation(RIPLOG_WSAENUMNETWORKEVENTS_FAILED, 0, NULL, WSAGetLastError()); continue; } // see if there is something to read on this socket if ( !(wsaNetEvents.lNetworkEvents & FD_READ) ) { continue; } // 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) { dwErr = WSAGetLastError(); // Even though FD_READ is set, recvfrom can still fail with // WSAEWOULDBLOCK. // So, if recvfrom failed with WSAEWOULDBLOCK we should not // log it as an error. if ( length == SOCKET_ERROR && dwErr == WSAEWOULDBLOCK) { continue; } 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: 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: 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_netEvent != NULL) { CloseHandle(g_netEvent); g_netEvent = NULL; } if (g_addressChangeEvent != NULL) { CloseHandle(g_addressChangeEvent); g_addressChangeEvent = NULL; } if (g_stopEvent != NULL) { CloseHandle(g_stopEvent); g_stopEvent = NULL; } if (g_ripcfg.hTCPDriver != NULL) { CloseHandle(g_ripcfg.hTCPDriver); g_ripcfg.hTCPDriver = 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; // 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 #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