2726 lines
78 KiB
C
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
|
||
|
|
||
|
|