Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2702 lines
81 KiB

  1. //****************************************************************************
  2. //
  3. // Microsoft Windows NT RIP
  4. //
  5. // Copyright 1995-96
  6. //
  7. //
  8. // Revision History
  9. //
  10. //
  11. // 2/26/95 Gurdeep Singh Pall Picked up from JBallard's team
  12. //
  13. // 7/09/99 Raghu Gatta - RIP Listener is now RIPv2 compliant
  14. //
  15. // Description: Main RIP Service Functions
  16. //
  17. //****************************************************************************
  18. #include "pchrip.h"
  19. #pragma hdrstop
  20. //-----------------------------------------------------------------------
  21. // global definitions
  22. //-----------------------------------------------------------------------
  23. RIP_PARAMETERS g_params;
  24. RIP_GLOBALS g_ripcfg;
  25. #ifdef ROUTE_FILTERS
  26. PRIP_FILTERS g_prfAnnounceFilters = NULL;
  27. PRIP_FILTERS g_prfAcceptFilters = NULL;
  28. CRITICAL_SECTION g_csAccFilters;
  29. CRITICAL_SECTION g_csAnnFilters;
  30. #endif
  31. CRITICAL_SECTION g_csRoutes;
  32. CRITICAL_SECTION g_csParameters;
  33. CRITICAL_SECTION g_csAddrtables;
  34. #ifndef CHICAGO
  35. SERVICE_STATUS_HANDLE g_hService;
  36. #endif
  37. HANDLE g_stopEvent;
  38. HANDLE g_addressChangeEvent;
  39. HANDLE g_netEvent;
  40. HANDLE g_triggerEvent;
  41. HANDLE g_hUpdateThread;
  42. DWORD g_dwTraceID = (DWORD)-1;
  43. DWORD g_dwCurrentState;
  44. DWORD g_dwCheckPoint;
  45. DWORD g_dwWaitHint;
  46. #ifndef CHICAGO
  47. HMODULE g_hmodule;
  48. #endif
  49. #define INDEX_NETEVENT 0
  50. #define INDEX_STOPEVENT (INDEX_NETEVENT + 1)
  51. #define INDEX_ADDRESSCHANGEEVENT (INDEX_STOPEVENT + 1)
  52. #define TOTAL_WAITEVENTS (INDEX_ADDRESSCHANGEEVENT + 1)
  53. //-----------------------------------------------------------------------
  54. // Function: NetclassMask
  55. //
  56. // returns the mask used to extract the network address from an
  57. // Internet address
  58. //-----------------------------------------------------------------------
  59. DWORD NetclassMask(DWORD dwAddress) {
  60. // net masks are returned in network byte order
  61. if (CLASSA_ADDR(dwAddress)) {
  62. return CLASSA_MASK;
  63. }
  64. else
  65. if (CLASSB_ADDR(dwAddress)) {
  66. return CLASSB_MASK;
  67. }
  68. else
  69. if (CLASSC_ADDR(dwAddress)) {
  70. return CLASSC_MASK;
  71. }
  72. else {
  73. return 0;
  74. }
  75. }
  76. //-----------------------------------------------------------------------
  77. // Function: SubnetMask
  78. //
  79. // Given an IP address, return the sub-network mask. This function
  80. // assumes the address table is already locked.
  81. //-----------------------------------------------------------------------
  82. DWORD SubnetMask(DWORD dwAddress) {
  83. DWORD dwNetmask;
  84. LPRIP_ADDRESS lpaddr, lpend;
  85. // subnet mask should be zero for default routes
  86. if (dwAddress == 0) { return 0; }
  87. // if its a broadcast address return all ones
  88. if (dwAddress == INADDR_BROADCAST) { return INADDR_BROADCAST; }
  89. //dwNetmask = NetclassMask(dwAddress);
  90. dwNetmask = NETCLASS_MASK(dwAddress);
  91. // if the network part is zero, return the network mask
  92. if ((dwAddress & ~dwNetmask) == 0) {
  93. return dwNetmask;
  94. }
  95. lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
  96. for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
  97. // if the address is found, return the subnet mask
  98. if ((dwAddress & dwNetmask) ==
  99. (lpaddr->dwAddress & NetclassMask(lpaddr->dwAddress))) {
  100. return lpaddr->dwNetmask;
  101. }
  102. }
  103. // address not found, return the network class mask
  104. return dwNetmask;
  105. }
  106. //-----------------------------------------------------------------------
  107. // Function: IsBroadcastAddress
  108. //
  109. // Returns TRUE if the given IP address is an all-ones bcast
  110. // or a class A, B, or C net broadcast. IP address is assumed to be
  111. // in network order (which is the reverse of Intel byte ordering.)
  112. //-----------------------------------------------------------------------
  113. BOOL IsBroadcastAddress(DWORD dwAddress) {
  114. if ((dwAddress == INADDR_BROADCAST) ||
  115. (CLASSA_ADDR(dwAddress) && ((dwAddress & ~CLASSA_MASK) ==
  116. ~CLASSA_MASK)) ||
  117. (CLASSB_ADDR(dwAddress) && ((dwAddress & ~CLASSB_MASK) ==
  118. ~CLASSB_MASK)) ||
  119. (CLASSC_ADDR(dwAddress) && ((dwAddress & ~CLASSC_MASK) ==
  120. ~CLASSC_MASK))) {
  121. return TRUE;
  122. }
  123. return FALSE;
  124. }
  125. //-----------------------------------------------------------------------
  126. // Function: IsLocalAddr
  127. //
  128. // Returns TRUE if the given IP address belongs to one of the interfaces
  129. // on the local host. Assumes that the IP address is in network order
  130. // and that the address table is already locked.
  131. //-----------------------------------------------------------------------
  132. BOOL IsLocalAddr(DWORD dwAddress) {
  133. LPRIP_ADDRESS lpaddr, lpend;
  134. lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
  135. for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
  136. if (dwAddress == lpaddr->dwAddress) {
  137. return TRUE;
  138. }
  139. }
  140. return FALSE;
  141. }
  142. BOOL IsDisabledLocalAddress(DWORD dwAddress) {
  143. LPRIP_ADDRESS lpaddr, lpend;
  144. lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
  145. for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
  146. if ((lpaddr->dwFlag & ADDRFLAG_DISABLED) != 0 &&
  147. (dwAddress == lpaddr->dwAddress)) {
  148. return TRUE;
  149. }
  150. }
  151. return FALSE;
  152. }
  153. //-----------------------------------------------------------------------
  154. // Function: IsHostAddress
  155. //
  156. // Returns TRUE if the given IP address has a non-zero host part.
  157. // Assumes that the IP address is in network order and that
  158. // the address table is already locked.
  159. //-----------------------------------------------------------------------
  160. BOOL IsHostAddress(DWORD dwAddress) {
  161. DWORD dwNetmask;
  162. // find most specific netmask we have for the address
  163. dwNetmask = SubnetMask(dwAddress);
  164. // if host part is non-zero, assume it is a host address
  165. if ((dwAddress & (~dwNetmask)) != 0) {
  166. return TRUE;
  167. }
  168. return FALSE;
  169. }
  170. //-----------------------------------------------------------------------
  171. // Function: ProcessRIPEntry
  172. //
  173. // This function examines a single entry in a RIP packet and
  174. // adds it to the hash table if necessary.
  175. //-----------------------------------------------------------------------
  176. DWORD ProcessRIPEntry(LPRIP_ADDRESS lpaddr, IN_ADDR srcaddr,
  177. LPRIP_ENTRY rip_entry, BYTE chVersion) {
  178. IN_ADDR addr;
  179. BOOL bIsHostAddr;
  180. CHAR szAddress[32] = {0};
  181. CHAR szSrcaddr[32] = {0};
  182. CHAR szMetric[12];
  183. LPSTR ppszArgs[3] = { szAddress, szSrcaddr, szMetric };
  184. LPHASH_TABLE_ENTRY rt_entry;
  185. DWORD rt_metric, rip_metric;
  186. DWORD dwHost, dwDefault, dwRouteTimeout;
  187. DWORD dwOverwriteStatic, dwGarbageTimeout;
  188. DWORD dwInd = 0;
  189. DWORD dwNetwork, dwNetmask, dwNetclassmask;
  190. DWORD dwLocalNet, dwLocalMask, dwNexthop;
  191. CHAR *pszTemp;
  192. addr.s_addr = rip_entry->dwAddress;
  193. pszTemp = inet_ntoa(addr);
  194. if (pszTemp != NULL) {
  195. strcpy(szAddress, pszTemp);
  196. }
  197. pszTemp = inet_ntoa(srcaddr);
  198. if (pszTemp != NULL) {
  199. strcpy(szSrcaddr, pszTemp);
  200. }
  201. // ignore metrics greater than infinity
  202. if (ntohl(rip_entry->dwMetric) > METRIC_INFINITE) {
  203. dbgprintf("metric > %d, ignoring route to %s with next hop of %s",
  204. METRIC_INFINITE, szAddress, szSrcaddr);
  205. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  206. return 0;
  207. }
  208. // ignore class D and E addresses
  209. if (CLASSD_ADDR(rip_entry->dwAddress) ||
  210. CLASSE_ADDR(rip_entry->dwAddress)) {
  211. dbgprintf("class D or E addresses are invalid, "
  212. "ignoring route to %s with next hop of %s",
  213. szAddress, szSrcaddr);
  214. RipLogWarning(RIPLOG_CLASS_INVALID, 2, ppszArgs, 0);
  215. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  216. return 0;
  217. }
  218. // ignore loopback routes
  219. if (IP_LOOPBACK_ADDR(rip_entry->dwAddress)) {
  220. dbgprintf("loopback addresses are invalid, "
  221. "ignoring route to %s with next hop of %s",
  222. szAddress, szSrcaddr);
  223. RipLogWarning(RIPLOG_LOOPBACK_INVALID, 2, ppszArgs, 0);
  224. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  225. return 0;
  226. }
  227. dwNetwork = rip_entry->dwAddress;
  228. //
  229. // calculate mask for all RIP versions
  230. //
  231. if (rip_entry->dwSubnetmask == 0) {
  232. // get the best subnetmask possible
  233. dwNetmask = SubnetMask(dwNetwork);
  234. // determine NetclassMask
  235. if (dwNetwork == 0) {
  236. dwNetclassmask = 0;
  237. }
  238. else if (dwNetwork == INADDR_BROADCAST) {
  239. dwNetclassmask = INADDR_BROADCAST;
  240. }
  241. else {
  242. dwNetclassmask = NETCLASS_MASK(rip_entry->dwAddress);
  243. }
  244. }
  245. else {
  246. dwNetmask = rip_entry->dwSubnetmask;
  247. //
  248. // double-check the netclass mask, to accomodate supernets
  249. //
  250. dwNetclassmask = NETCLASS_MASK(dwNetwork);
  251. if (dwNetclassmask > dwNetmask) {
  252. dwNetclassmask = dwNetmask;
  253. }
  254. }
  255. //
  256. // make sure route is not to a broadcast address;
  257. // double-check to make sure this isn't a host route,
  258. // which will look like a broadcast address since ~dwNetmask
  259. // will be 0 and thus (dwNetwork & ~dwNetmask) == ~dwNetmask
  260. //
  261. if ((dwNetwork & ~dwNetclassmask) == ~dwNetclassmask ||
  262. (~dwNetmask && (dwNetwork & ~dwNetmask) == ~dwNetmask)) {
  263. dbgprintf("broadcast addresses are invalid, "
  264. "ignoring route to %s with next hop of %s",
  265. szAddress, szSrcaddr);
  266. RipLogWarning(RIPLOG_BROADCAST_INVALID, 2, ppszArgs, 0);
  267. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  268. return 0;
  269. }
  270. //
  271. // make sure that the nexthop is on a local net
  272. //
  273. //
  274. // In case of P2P connections, the subnet mask of the interface
  275. // is all ones. So do an additional check to make sure that we
  276. // don't end up rejecting routes received over a P2P connection.
  277. //
  278. dwNexthop = srcaddr.s_addr;
  279. dwLocalMask = lpaddr->dwNetmask;
  280. dwLocalNet = lpaddr->dwAddress & dwLocalMask;
  281. if ( ((dwNexthop & dwLocalMask) != dwLocalNet) &&
  282. (dwLocalMask != 0xFFFFFFFF) ) {
  283. dbgprintf("Dropped route %s with next hop %s because "
  284. "NextHop is not on the same subnet as the "
  285. "interface on which the route was received",
  286. szAddress,
  287. szSrcaddr);
  288. return 0;
  289. }
  290. #ifdef ROUTE_FILTERS
  291. //
  292. // run the route thru' the accept filters
  293. //
  294. if ( g_prfAcceptFilters != NULL )
  295. {
  296. for ( dwInd = 0; dwInd < g_prfAcceptFilters-> dwCount; dwInd++ )
  297. {
  298. if ( g_prfAcceptFilters-> pdwFilter[ dwInd ] ==
  299. rip_entry-> dwAddress )
  300. {
  301. dbgprintf("Dropped route %s with next hop %s because"
  302. "of accept filter",
  303. szAddress, szSrcaddr);
  304. return 0;
  305. }
  306. }
  307. }
  308. #endif
  309. RIP_LOCK_PARAMS();
  310. dwHost = g_params.dwAcceptHost;
  311. dwDefault = g_params.dwAcceptDefault;
  312. dwRouteTimeout = g_params.dwRouteTimeout;
  313. dwGarbageTimeout = g_params.dwGarbageTimeout;
  314. dwOverwriteStatic = g_params.dwOverwriteStaticRoutes;
  315. RIP_UNLOCK_PARAMS();
  316. // ignore host routes unless configured otherwise
  317. if (bIsHostAddr = ((dwNetwork & ~dwNetmask) != 0)) {
  318. if (dwHost == 0) {
  319. dbgprintf("IPRIP is configured to discard host routes, "
  320. "ignoring route to %s with next hop of %s",
  321. szAddress, szSrcaddr);
  322. RipLogInformation(RIPLOG_HOST_INVALID, 2, ppszArgs, 0);
  323. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  324. return 0;
  325. }
  326. }
  327. // ignore default routes unless configured otherwise
  328. if (rip_entry->dwAddress == 0) {
  329. if (dwDefault == 0) {
  330. dbgprintf("IPRIP is configured to discard default routes, "
  331. "ignoring route to %s with next hop of %s",
  332. szAddress, szSrcaddr);
  333. RipLogInformation(RIPLOG_DEFAULT_INVALID, 2, ppszArgs, 0);
  334. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  335. return 0;
  336. }
  337. }
  338. rip_metric = ntohl(rip_entry->dwMetric);
  339. // do not add a new entry if its metric would be infinite
  340. if ((rip_metric + 1) >= METRIC_INFINITE &&
  341. !RouteTableEntryExists(lpaddr->dwIndex, rip_entry->dwAddress)) {
  342. dbgprintf("metric == %d, ignoring new route to %s with next hop of %s",
  343. METRIC_INFINITE, szAddress, szSrcaddr);
  344. return 0;
  345. }
  346. // find the entry, or create one if necessary
  347. rt_entry = GetRouteTableEntry(lpaddr->dwIndex, rip_entry->dwAddress,
  348. dwNetmask);
  349. if (rt_entry == NULL) {
  350. dbgprintf("could not allocate memory for new entry");
  351. RipLogError(RIPLOG_RT_ALLOC_FAILED, 0, NULL, ERROR_NOT_ENOUGH_MEMORY);
  352. return ERROR_NOT_ENOUGH_MEMORY;
  353. }
  354. // if this was a static route and RIP is not allowed
  355. // to overwrite static routes, return; exception is default routes,
  356. // which we overwrite if we are configured to accept default routes,
  357. // even if there is an existing static default route
  358. //
  359. if (rt_entry->dwFlag != NEW_ENTRY &&
  360. (rt_entry->dwProtocol == IRE_PROTO_LOCAL ||
  361. rt_entry->dwProtocol == IRE_PROTO_NETMGMT) &&
  362. rt_entry->dwDestaddr != 0) {
  363. if (dwOverwriteStatic == 0) {
  364. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  365. return 0;
  366. }
  367. }
  368. rt_metric = rt_entry->dwMetric;
  369. rip_metric = min(METRIC_INFINITE, rip_metric + 1);
  370. _ltoa(rip_metric, szMetric, 10);
  371. if (rt_entry->dwFlag == NEW_ENTRY) {
  372. dbgprintf("New route entry, destination == %s, "
  373. "next hop == %s, metric == %s",
  374. szAddress, szSrcaddr, szMetric);
  375. RipLogInformation(RIPLOG_NEW_LEARNT_ROUTE, 3, ppszArgs, 0);
  376. rt_entry->dwIndex = lpaddr->dwIndex;
  377. rt_entry->dwFlag = (TIMEOUT_TIMER | ROUTE_CHANGE);
  378. rt_entry->lTimeout = (LONG)dwRouteTimeout;
  379. rt_entry->dwDestaddr = rip_entry->dwAddress;
  380. rt_entry->dwNexthop = srcaddr.s_addr;
  381. rt_entry->dwProtocol = IRE_PROTO_RIP;
  382. rt_entry->dwMetric = rip_metric;
  383. if (bIsHostAddr) {
  384. rt_entry->dwFlag |= ROUTE_HOST;
  385. rt_entry->dwNetmask = HOSTADDR_MASK;
  386. }
  387. else {
  388. rt_entry->dwNetmask = dwNetmask;
  389. }
  390. }
  391. else
  392. if (rt_entry->dwNexthop == srcaddr.s_addr) {
  393. // this is from the next hop gateway for the existing entry
  394. // this may have been a local route before; now it is a RIP route
  395. rt_entry->dwProtocol = IRE_PROTO_RIP;
  396. rt_entry->dwIndex = lpaddr->dwIndex;
  397. // reset its timer if it is not pending garbage-collection
  398. if (rt_metric != METRIC_INFINITE &&
  399. (rt_entry->dwFlag & GARBAGE_TIMER) == 0) {
  400. rt_entry->lTimeout = (LONG)dwRouteTimeout;
  401. }
  402. // if the metric changed, or the metric has gone to METRIC_INFINITE,
  403. // update the route
  404. if (rt_metric != rip_metric ||
  405. (rt_metric == METRIC_INFINITE &&
  406. (rt_entry->dwFlag & GARBAGE_TIMER) == 0)) {
  407. dbgprintf("Metric change, destination == %s, "
  408. "next hop == %s, metric == %s",
  409. szAddress, szSrcaddr, szMetric);
  410. RipLogInformation(RIPLOG_METRIC_CHANGE, 3, ppszArgs, 0);
  411. // is the route going away?
  412. if (rip_metric == METRIC_INFINITE &&
  413. (rt_entry->dwFlag & GARBAGE_TIMER) == 0) {
  414. dbgprintf("METRIC IS UNREACHABLE");
  415. // we do not know about it
  416. rt_entry->dwFlag &= ~TIMEOUT_TIMER;
  417. rt_entry->dwFlag |= (GARBAGE_TIMER | ROUTE_CHANGE);
  418. if (bIsHostAddr) {
  419. rt_entry->dwFlag |= ROUTE_HOST;
  420. }
  421. rt_entry->lTimeout = (LONG)dwGarbageTimeout;
  422. rt_entry->dwMetric = METRIC_INFINITE;
  423. }
  424. else {
  425. // route isn't going away, metric just changed
  426. rt_entry->dwFlag &= ~GARBAGE_TIMER;
  427. rt_entry->dwFlag |= (TIMEOUT_TIMER | ROUTE_CHANGE);
  428. rt_entry->lTimeout = (LONG)dwRouteTimeout;
  429. rt_entry->dwDestaddr = rip_entry->dwAddress;
  430. if (bIsHostAddr) {
  431. rt_entry->dwFlag |= ROUTE_HOST;
  432. rt_entry->dwNetmask = HOSTADDR_MASK;
  433. }
  434. else {
  435. rt_entry->dwNetmask = dwNetmask;
  436. }
  437. rt_entry->dwNexthop = srcaddr.s_addr;
  438. rt_entry->dwMetric = rip_metric;
  439. }
  440. }
  441. }
  442. else
  443. if (rip_metric < rt_metric) {
  444. // not from original next hop for this route,
  445. // but this is a better route
  446. dbgprintf("New preferred route, destination == %s, "
  447. "next hop == %s, metric == %s",
  448. szAddress, szSrcaddr, szMetric);
  449. RipLogInformation(RIPLOG_ROUTE_REPLACED, 3, ppszArgs, 0);
  450. // if this route is pending garbage-collection,
  451. // remove the old entry before accepting a new next hop
  452. if (rt_entry->dwProtocol == IRE_PROTO_RIP &&
  453. (rt_entry->dwFlag & GARBAGE_TIMER) != 0) {
  454. UpdateSystemRouteTable(rt_entry, FALSE);
  455. }
  456. // this may have been a local route before; now it is a RIP route
  457. rt_entry->dwProtocol = IRE_PROTO_RIP;
  458. rt_entry->dwFlag &= ~GARBAGE_TIMER;
  459. rt_entry->dwFlag |= (TIMEOUT_TIMER | ROUTE_CHANGE);
  460. rt_entry->dwIndex = lpaddr->dwIndex;
  461. rt_entry->lTimeout = (LONG)dwRouteTimeout;
  462. rt_entry->dwDestaddr = rip_entry->dwAddress;
  463. if (bIsHostAddr) {
  464. rt_entry->dwFlag |= ROUTE_HOST;
  465. rt_entry->dwNetmask = HOSTADDR_MASK;
  466. }
  467. else {
  468. rt_entry->dwNetmask = dwNetmask;
  469. }
  470. rt_entry->dwNexthop = srcaddr.s_addr;
  471. rt_entry->dwMetric = rip_metric;
  472. }
  473. // we always update the route in the system table
  474. rt_entry->dwFlag |= ROUTE_UPDATE;
  475. InterlockedExchange(&g_ripcfg.dwRouteChanged, 1);
  476. #if 0
  477. DbgPrintf(
  478. "RIP entry : Protocol %x, Index %x, dest addr %x, dest mask %x\n",
  479. rt_entry->dwProtocol, rt_entry->dwIndex, rt_entry->dwDestaddr, rt_entry->dwNetmask
  480. );
  481. DbgPrintf(
  482. "Next Hop %x, Metric %x\n\n", rt_entry->dwNexthop, rt_entry->dwMetric
  483. );
  484. #endif
  485. return 0;
  486. }
  487. //-----------------------------------------------------------------------
  488. // Function: ProcessRIPQuery
  489. //
  490. // fills in a RIP packet entry with information from our routing table,
  491. // if we have a matching entry in our table.
  492. //-----------------------------------------------------------------------
  493. DWORD ProcessRIPQuery(LPRIP_ADDRESS lpaddr, LPRIP_ENTRY rip_entry) {
  494. LPHASH_TABLE_ENTRY rt_entry;
  495. #ifdef ROUTE_FILTERS
  496. DWORD dwInd = 0;
  497. //
  498. // run the route thru' the announce filters
  499. //
  500. if ( g_prfAnnounceFilters != NULL )
  501. {
  502. for ( dwInd = 0; dwInd < g_prfAnnounceFilters-> dwCount; dwInd++ )
  503. {
  504. if ( g_prfAnnounceFilters-> pdwFilter[ dwInd ] ==
  505. rip_entry-> dwAddress )
  506. {
  507. dbgprintf(
  508. "setting metric for route %s to infinite in RIP query",
  509. inet_ntoa(
  510. *( (struct in_addr*) &(rip_entry-> dwAddress ) )
  511. )
  512. );
  513. rip_entry-> dwMetric = htonl(METRIC_INFINITE);
  514. return 0;
  515. }
  516. }
  517. }
  518. #endif
  519. // RFC 1058 page 25
  520. // If routing table entry exists then pick up the metric.
  521. // Otherwise return a metric of METRIC_INFINITE.
  522. if (RouteTableEntryExists(lpaddr->dwIndex, rip_entry->dwAddress) &&
  523. (rt_entry = GetRouteTableEntry(lpaddr->dwIndex,
  524. rip_entry->dwAddress,
  525. rip_entry->dwSubnetmask)) != NULL) {
  526. rip_entry->dwMetric = htonl(rt_entry->dwMetric);
  527. }
  528. else {
  529. rip_entry->dwMetric = htonl(METRIC_INFINITE);
  530. }
  531. return 0;
  532. }
  533. //-----------------------------------------------------------------------
  534. // Function: ServiceMain
  535. //
  536. // This is the entry point of the service, and the function which
  537. // handles all network input processing.
  538. //-----------------------------------------------------------------------
  539. VOID FAR PASCAL ServiceMain(IN DWORD dwNumServicesArgs,
  540. IN LPSTR *lpServiceArgVectors) {
  541. WSADATA wsaData;
  542. HANDLE hWaitEvents[TOTAL_WAITEVENTS];
  543. DWORD dwErr, dwOption, dwThread;
  544. SERVICE_STATUS status = {SERVICE_WIN32, SERVICE_STOPPED,
  545. SERVICE_ACCEPT_STOP, NO_ERROR, 0, 0, 0};
  546. #ifndef CHICAGO
  547. CHAR achModule[MAX_PATH];
  548. #else
  549. DWORD dwCurrTime, dwLastReload, dwReloadIntr;
  550. dwLastReload = dwCurrTime = GetTickCount();
  551. dwReloadIntr = IP_ADDRESS_RELOAD_INTR * 1000;
  552. #endif
  553. // register with tracing DLL so errors can be reported below.
  554. g_dwTraceID = TraceRegister(RIP_SERVICE);
  555. if (g_dwTraceID == INVALID_TRACEID)
  556. {
  557. g_params.dwLoggingLevel = LOGLEVEL_ERROR;
  558. RipLogError(RIPLOG_SERVICE_INIT_FAILED, 0, NULL, GetLastError());
  559. return;
  560. }
  561. #ifndef CHICAGO
  562. // register the service and get a service status handle
  563. g_hService = RegisterServiceCtrlHandler(RIP_SERVICE,
  564. serviceHandlerFunction);
  565. if (g_hService == 0) {
  566. dbgprintf("IPRIP could not register as a service, error code %d",
  567. GetLastError());
  568. RipLogError(RIPLOG_REGISTER_FAILED, 0, NULL, GetLastError());
  569. return;
  570. }
  571. #endif
  572. dbgprintf("IPRIP is starting up...");
  573. // Prepare a status structure to pass to the service controller
  574. InterlockedExchange(&g_dwWaitHint, 60000);
  575. InterlockedExchange(&g_dwCheckPoint, 100);
  576. InterlockedExchange(&g_dwCurrentState, SERVICE_START_PENDING);
  577. status.dwControlsAccepted = 0;
  578. status.dwWaitHint = g_dwWaitHint;
  579. status.dwWin32ExitCode = NO_ERROR;
  580. status.dwCheckPoint = g_dwCheckPoint;
  581. status.dwServiceSpecificExitCode = 0;
  582. status.dwServiceType = SERVICE_WIN32;
  583. status.dwCurrentState = g_dwCurrentState;
  584. #ifndef CHICAGO
  585. if (!SetServiceStatus(g_hService, &status)) {
  586. dbgprintf("IPRIP could not report its status, error code %d",
  587. GetLastError());
  588. RipLogError(RIPLOG_SETSTATUS_FAILED, 0, NULL, GetLastError());
  589. return;
  590. }
  591. #endif
  592. RIP_CREATE_PARAMS_LOCK();
  593. RIP_CREATE_ADDRTABLE_LOCK();
  594. RIP_CREATE_ROUTETABLE_LOCK();
  595. #ifdef ROUTE_FILTERS
  596. RIP_CREATE_ANNOUNCE_FILTERS_LOCK();
  597. RIP_CREATE_ACCEPT_FILTERS_LOCK();
  598. #endif
  599. // first of all, start Winsock
  600. if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
  601. dbgprintf("error %d initializing Windows Sockets.", WSAGetLastError());
  602. RipLogError(RIPLOG_WSOCKINIT_FAILED, 0, NULL, WSAGetLastError());
  603. RIPServiceStop(); return;
  604. }
  605. // confirm that Winsock dll supports 2.0
  606. if ( LOBYTE(wsaData.wVersion) != 2 ||
  607. HIBYTE(wsaData.wVersion) != 0 ) {
  608. // The dll doesn't support Winsock 2.0. So exit.
  609. // We need 2.0 for WSAEventSelect and WSAEnumNetworkEvents
  610. dbgprintf("could not find winsock dll that supports version 2.0");
  611. RipLogError(RIPLOG_WSOCKINIT_FAILED, 0, NULL, WSAVERNOTSUPPORTED);
  612. RIPServiceStop(); return;
  613. }
  614. // load operating parameters from the registry
  615. dwErr = LoadParameters();
  616. if (dwErr != 0) {
  617. dbgprintf("could not load registry parameters, error code %d", dwErr);
  618. RipLogError(RIPLOG_REGINIT_FAILED, 0, NULL, dwErr);
  619. RIPServiceStop(); return;
  620. }
  621. // load the IP local routes table
  622. dwErr = InitializeRouteTable();
  623. if (dwErr != 0) {
  624. dbgprintf("could not initialize routing table, error code %d", dwErr);
  625. RipLogError(RIPLOG_RTAB_INIT_FAILED, 0, NULL, dwErr);
  626. RIPServiceStop(); return;
  627. }
  628. dwErr = InitializeStatsTable();
  629. if (dwErr != 0) {
  630. dbgprintf("could not initialize statistics, error code %d", dwErr);
  631. RipLogError(RIPLOG_STAT_INIT_FAILED, 0, NULL, dwErr);
  632. RIPServiceStop(); return;
  633. }
  634. // create network event. This event is passed to WSAEventSelect.
  635. // WSAEventSelect is posted on each socket in the LoadAddressSockets
  636. // function. We need to create this event before calling
  637. // InitializeAddressTable
  638. g_netEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  639. if ( g_netEvent == NULL ) {
  640. dwErr = GetLastError();
  641. dbgprintf("could not create Network event, error code %d", dwErr);
  642. RipLogError(RIPLOG_CREATEEVENT_FAILED, 0, NULL, dwErr);
  643. RIPServiceStop(); return;
  644. }
  645. // no other threads running, so no need for synchronization
  646. dwErr = InitializeAddressTable(TRUE);
  647. if (dwErr != 0) {
  648. dbgprintf("could not initialize sockets, error code %d", dwErr);
  649. RipLogError(RIPLOG_IFINIT_FAILED, 0, NULL, dwErr);
  650. RIPServiceStop(); return;
  651. }
  652. // Create service stop event
  653. g_stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  654. if ( g_stopEvent == NULL ) {
  655. dwErr = GetLastError();
  656. dbgprintf("could not create Service Stop event, error code %d", dwErr);
  657. RipLogError(RIPLOG_CREATEEVENT_FAILED, 0, NULL, dwErr);
  658. RIPServiceStop(); return;
  659. }
  660. // Create triggered update request event
  661. g_triggerEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  662. if ( g_triggerEvent == NULL ) {
  663. dwErr = GetLastError();
  664. dbgprintf("could not create Trigger event, error code %d", dwErr);
  665. RipLogError(RIPLOG_CREATEEVENT_FAILED, 0, NULL, dwErr);
  666. RIPServiceStop(); return;
  667. }
  668. // Open the event for DHCP address change notifications
  669. g_addressChangeEvent = DhcpOpenGlobalEvent();
  670. // if we can't open this handle then we simple quit this thread
  671. if (g_addressChangeEvent == NULL) {
  672. dbgprintf("could not create address change notification event, "
  673. "error code %d", GetLastError());
  674. RipLogError(RIPLOG_CREATEEVENT_FAILED, 0, NULL, GetLastError());
  675. RIPServiceStop();
  676. return;
  677. }
  678. #ifndef CHICAGO
  679. // In order to avoid having the DLL unloaded from underneath our threads,
  680. // we increment the DLL refcount as each thread is created.
  681. //
  682. // retrieve the module-name for this DLL.
  683. GetModuleFileName(g_hmodule, achModule, MAX_PATH);
  684. #endif
  685. // Create the thread which handles timed operations
  686. g_hUpdateThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)UpdateThread,
  687. NULL, 0, &dwThread);
  688. if (g_hUpdateThread == NULL) {
  689. dbgprintf("could not create route update thread, error code %lu",
  690. GetLastError());
  691. RipLogError(RIPLOG_CREATETHREAD_FAILED, 0, NULL, GetLastError());
  692. RIPServiceStop();
  693. return;
  694. }
  695. #ifndef CHICAGO
  696. // Increment the DLL refcount for the above thread
  697. LoadLibrary(achModule);
  698. #endif
  699. // broadcast the initial requests for full routing information
  700. // from all the neighboring routers
  701. BroadcastRouteTableRequests();
  702. // Everything initialized fine:
  703. // Prepare a status structure to pass to the service controller
  704. InterlockedExchange(&g_dwWaitHint, 0);
  705. InterlockedExchange(&g_dwCheckPoint, 0);
  706. InterlockedExchange(&g_dwCurrentState, SERVICE_RUNNING);
  707. status.dwWaitHint = g_dwWaitHint;
  708. status.dwCheckPoint = g_dwCheckPoint;
  709. status.dwCurrentState = g_dwCurrentState;
  710. status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
  711. #ifndef CHICAGO
  712. SetServiceStatus(g_hService, &status);
  713. #endif
  714. RipLogInformation(RIPLOG_SERVICE_STARTED, 0, NULL, 0);
  715. hWaitEvents[INDEX_NETEVENT] =
  716. g_netEvent; // Manual Reset: FALSE
  717. hWaitEvents[INDEX_STOPEVENT] =
  718. g_stopEvent; // Manual Reset: TRUE
  719. hWaitEvents[INDEX_ADDRESSCHANGEEVENT] =
  720. g_addressChangeEvent; // Manual Reset: TRUE
  721. // Event created by
  722. // DhcpOpenGlobalEvent
  723. // enter the main input processing loop
  724. while (TRUE) {
  725. INT length, size;
  726. IN_ADDR addr;
  727. DWORD dwSilentRIP;
  728. SOCKADDR_IN srcaddr;
  729. BOOL bLocalAddr;
  730. BOOL bPacketValid;
  731. BYTE buffer[RIP_MESSAGE_SIZE];
  732. LPRIP_HEADER lpheader;
  733. LPRIP_ADDRESS lpaddr, lpend;
  734. DWORD dwResult, dwUpdateFreq, dwTrigger;
  735. DWORD dwWaitEndCode;
  736. WSANETWORKEVENTS wsaNetEvents;
  737. // this is where we wait for something to come down the wire
  738. #ifndef CHICAGO
  739. dwWaitEndCode =
  740. WaitForMultipleObjects(
  741. TOTAL_WAITEVENTS,
  742. hWaitEvents,
  743. FALSE,
  744. INFINITE);
  745. #else
  746. //
  747. // hack for Win95 since there is no mechanism to wait
  748. // for DHCP address change notification.
  749. // set an interval after which the IP addresses will
  750. // be reloaded by the IPRIP.
  751. //
  752. dwCurrTime = GetTickCount();
  753. if ( (dwCurrTime > (dwLastReload + dwReloadIntr) ) ||
  754. (dwCurrTime < dwLastReload) )
  755. {
  756. dwWaitEndCode = WAIT_TIMEOUT;
  757. }
  758. else
  759. {
  760. dwWaitEndCode =
  761. WaitForMultipleObjects(
  762. TOTAL_WAITEVENTS,
  763. hWaitEvents,
  764. FALSE,
  765. dwReloadIntr);
  766. }
  767. #endif
  768. if (dwWaitEndCode != WAIT_OBJECT_0) {
  769. // check if g_stopEvent event was signalled
  770. if ((dwWaitEndCode - WAIT_OBJECT_0) == INDEX_STOPEVENT)
  771. {
  772. dbgprintf("service received stop request, shutting down");
  773. WaitForSingleObject(g_hUpdateThread, INFINITE);
  774. RIPServiceStop();
  775. return;
  776. }
  777. else
  778. if (
  779. ((dwWaitEndCode - WAIT_OBJECT_0) == INDEX_ADDRESSCHANGEEVENT)
  780. #ifdef CHICAGO
  781. || ( dwWaitEndCode == WAIT_TIMEOUT )
  782. #endif
  783. )
  784. {
  785. dbgprintf("service detected IP address change, reconfiguring");
  786. RipLogInformation(RIPLOG_ADDRESS_CHANGE, 0, NULL, 0);
  787. RIP_LOCK_ADDRTABLE();
  788. dwErr = InitializeAddressTable(FALSE);
  789. RIP_UNLOCK_ADDRTABLE();
  790. if (dwErr != 0 ||
  791. (dwErr = BroadcastRouteTableRequests()) != 0) {
  792. // re-init failed, log error and quit
  793. RipLogError(RIPLOG_REINIT_FAILED, 0, NULL, dwErr);
  794. SetEvent(g_stopEvent);
  795. WaitForSingleObject(g_hUpdateThread, INFINITE);
  796. RIPServiceStop();
  797. return;
  798. }
  799. #ifdef CHICAGO
  800. dwLastReload = GetTickCount();
  801. #endif
  802. continue;
  803. }
  804. else
  805. {
  806. dbgprintf("ServiceMain: WaitForMultipleObjects failed. Error: %d",
  807. GetLastError());
  808. continue;
  809. }
  810. }
  811. // neither stop request nor reconfig request, so some data
  812. // must have arrived. lock address table and go through
  813. // the sockets to see which ones are ready for reading
  814. RIP_LOCK_ADDRTABLE();
  815. lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
  816. for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
  817. if (lpaddr->sock != INVALID_SOCKET){
  818. dwErr = WSAEnumNetworkEvents(
  819. lpaddr->sock,
  820. NULL,
  821. &wsaNetEvents);
  822. if (dwErr == SOCKET_ERROR) {
  823. dbgprintf("error doing WSAEnumNetworkEvents on address %s, "
  824. "error code %d", inet_ntoa(addr),
  825. WSAGetLastError());
  826. RipLogInformation(RIPLOG_WSAENUMNETWORKEVENTS_FAILED, 0,
  827. NULL, WSAGetLastError());
  828. continue;
  829. }
  830. // see if there is something to read on this socket
  831. if ( !(wsaNetEvents.lNetworkEvents & FD_READ) ) {
  832. continue;
  833. }
  834. // read the incoming message
  835. size = sizeof(srcaddr);
  836. length = recvfrom(lpaddr->sock, buffer, RIP_MESSAGE_SIZE, 0,
  837. (SOCKADDR *)&srcaddr, &size);
  838. if (length == 0 || length == SOCKET_ERROR) {
  839. dwErr = WSAGetLastError();
  840. // Even though FD_READ is set, recvfrom can still fail with
  841. // WSAEWOULDBLOCK.
  842. // So, if recvfrom failed with WSAEWOULDBLOCK we should not
  843. // log it as an error.
  844. if ( length == SOCKET_ERROR && dwErr == WSAEWOULDBLOCK) {
  845. continue;
  846. }
  847. addr.s_addr = lpaddr->dwAddress;
  848. dbgprintf("error receiving data on local address %s, "
  849. "error code %d", inet_ntoa(addr),
  850. WSAGetLastError());
  851. InterlockedIncrement(&lpaddr->lpstats->dwReceiveFailures);
  852. if (WSAGetLastError() == WSAEMSGSIZE) {
  853. RipLogInformation(RIPLOG_RECVSIZE_TOO_GREAT, 0, NULL, 0);
  854. }
  855. else {
  856. RipLogInformation(RIPLOG_RECVFROM_FAILED, 0,
  857. NULL, WSAGetLastError());
  858. }
  859. continue;
  860. }
  861. #if 0
  862. DbgPrintf( "\n\n\nData received from %s on socket %d\n", inet_ntoa( srcaddr.sin_addr ), lpaddr-> sock );
  863. DbgPrintf( "socket bound to %s\n\n", inet_ntoa( *( (struct in_addr *) &(lpaddr-> dwAddress) ) ) );
  864. #endif
  865. // data received, so place a template over it
  866. lpheader = (LPRIP_HEADER)buffer;
  867. // validate the packet
  868. if (lpheader->chVersion == 0) {
  869. dbgprintf("version in RIP header is 0, "
  870. "discarding packet");
  871. InterlockedIncrement(&lpaddr->lpstats->dwBadPacketsReceived);
  872. RipLogInformation(RIPLOG_VERSION_ZERO, 0, NULL, 0);
  873. continue;
  874. }
  875. else
  876. if (lpheader->chVersion == 1 && lpheader->wReserved != 0) {
  877. dbgprintf("reserved field in RIPv1 header is non-zero, "
  878. "discarding packet");
  879. InterlockedIncrement(&lpaddr->lpstats->dwBadPacketsReceived);
  880. RipLogInformation(RIPLOG_FORMAT_ERROR, 0, NULL, 0);
  881. continue;
  882. }
  883. else
  884. if (lpheader->chVersion == 2 && lpheader->wReserved != 0) {
  885. dbgprintf("reserved field in RIPv2 header is non-zero, "
  886. "discarding packet");
  887. InterlockedIncrement(&lpaddr->lpstats->dwBadPacketsReceived);
  888. RipLogInformation(RIPLOG_FORMAT_ERROR, 0, NULL, 0);
  889. continue;
  890. }
  891. if (lpheader->chCommand == RIP_REQUEST) {
  892. ProcessRIPRequest(lpaddr, &srcaddr, buffer, length);
  893. }
  894. else
  895. if (lpheader->chCommand == RIP_RESPONSE) {
  896. ProcessRIPResponse(lpaddr, &srcaddr, buffer, length);
  897. // tell the update thread to process the changes just made
  898. // to the table;
  899. // this could include adding routes to the IP table
  900. // and/or sending out triggered updates
  901. if (g_ripcfg.dwRouteChanged != 0) {
  902. SetEvent(g_triggerEvent);
  903. }
  904. }
  905. }
  906. }
  907. RIP_UNLOCK_ADDRTABLE();
  908. }
  909. }
  910. //-----------------------------------------------------------------------
  911. // Function: ProcessRIPRequest
  912. //
  913. // Handles processing of requests. Validates packets, and sends
  914. // responses.
  915. //-----------------------------------------------------------------------
  916. VOID ProcessRIPRequest(LPRIP_ADDRESS lpaddr, LPSOCKADDR_IN lpsrcaddr,
  917. BYTE buffer[], int length) {
  918. INT iErr;
  919. IN_ADDR addr;
  920. BYTE chVersion;
  921. BOOL bValidated;
  922. DWORD dwSilentRIP;
  923. CHAR szAddress[32];
  924. LPRIP_HEADER lpheader;
  925. LPRIP_ENTRY lpentry, lpbufend;
  926. CHAR *pszTemp;
  927. RIP_LOCK_PARAMS();
  928. dwSilentRIP = g_params.dwSilentRIP;
  929. RIP_UNLOCK_PARAMS();
  930. // if this is a regular request and RIP is silent, do nothing
  931. if (dwSilentRIP != 0) { // && lpsrcaddr->sin_port == htons(RIP_PORT)) {
  932. return;
  933. }
  934. // ignore requests from our own interfaces
  935. if (IsLocalAddr(lpsrcaddr->sin_addr.s_addr)) {
  936. return;
  937. }
  938. InterlockedIncrement(&lpaddr->lpstats->dwRequestsReceived);
  939. // place a template over the first entry
  940. lpentry = (LPRIP_ENTRY)(buffer + sizeof(RIP_HEADER));
  941. lpbufend = (LPRIP_ENTRY)(buffer + length);
  942. lpheader = (LPRIP_HEADER)buffer;
  943. chVersion = lpheader->chVersion;
  944. // print a message
  945. addr.s_addr = lpaddr->dwAddress;
  946. pszTemp = inet_ntoa(addr);
  947. if (pszTemp != NULL) {
  948. strcpy(szAddress, pszTemp);
  949. }
  950. dbgprintf("received RIP v%d request from %s on address %s",
  951. chVersion, inet_ntoa(lpsrcaddr->sin_addr), szAddress);
  952. // if this is a request for the entire routing table, send it
  953. if (length == (sizeof(RIP_HEADER) + sizeof(RIP_ENTRY)) &&
  954. lpentry->wAddrFamily == 0 &&
  955. lpentry->dwMetric == htonl(METRIC_INFINITE)) {
  956. // transmit the entire routing table, subject
  957. // to split-horizon and poisoned reverse processing
  958. TransmitRouteTableContents(lpaddr, lpsrcaddr, FALSE);
  959. return;
  960. }
  961. #ifdef ROUTE_FILTERS
  962. RIP_LOCK_ANNOUNCE_FILTERS();
  963. #endif
  964. // this is a request for specific entries,
  965. // validate the entries first
  966. bValidated = TRUE;
  967. for ( ; (lpentry + 1) <= lpbufend; lpentry++) {
  968. // validate the entry first
  969. if (chVersion == 1 && (lpentry->wReserved != 0 ||
  970. lpentry->dwReserved1 != 0 ||
  971. lpentry->dwReserved2 != 0)) {
  972. bValidated = FALSE;
  973. break;
  974. }
  975. // now process it
  976. ProcessRIPQuery(lpaddr, lpentry);
  977. }
  978. #ifdef ROUTE_FILTERS
  979. RIP_UNLOCK_ANNOUNCE_FILTERS();
  980. #endif
  981. // if packet was validated and fields filled in, send it back
  982. if (bValidated) {
  983. // update the command field
  984. lpheader->chCommand = RIP_RESPONSE;
  985. iErr = sendto(lpaddr->sock, buffer, length, 0,
  986. (LPSOCKADDR)lpsrcaddr, sizeof(SOCKADDR_IN));
  987. if (iErr == SOCKET_ERROR) {
  988. dbgprintf("error sending response to %s from local interface %s",
  989. inet_ntoa(lpsrcaddr->sin_addr), szAddress);
  990. InterlockedIncrement(&lpaddr->lpstats->dwSendFailures);
  991. RipLogInformation(RIPLOG_SENDTO_FAILED, 0, NULL, WSAGetLastError());
  992. }
  993. else {
  994. InterlockedIncrement(&lpaddr->lpstats->dwResponsesSent);
  995. }
  996. }
  997. }
  998. //-----------------------------------------------------------------------
  999. // Function: ProcessRIPResponse
  1000. //
  1001. // Handles processing of response packets. Validates packets,
  1002. // and updates the tables if necessary.
  1003. //-----------------------------------------------------------------------
  1004. VOID ProcessRIPResponse(LPRIP_ADDRESS lpaddr, LPSOCKADDR_IN lpsrcaddr,
  1005. BYTE buffer[], int length) {
  1006. IN_ADDR addr;
  1007. BYTE chVersion;
  1008. CHAR szAddress[32];
  1009. LPRIP_HEADER lpheader;
  1010. LPRIP_ENTRY lpentry, lpbufend;
  1011. LPRIP_AUTHENT_ENTRY lpaentry;
  1012. CHAR *pszTemp;
  1013. // ignore responses from ports other than 520
  1014. if (lpsrcaddr->sin_port != htons(RIP_PORT)) {
  1015. dbgprintf("response is from invalid port (%d), discarding");
  1016. InterlockedIncrement(&lpaddr->lpstats->dwBadPacketsReceived);
  1017. RipLogWarning(RIPLOG_INVALIDPORT, 0, NULL, 0);
  1018. return;
  1019. }
  1020. // ignore responses from our own interfaces
  1021. if (IsLocalAddr(lpsrcaddr->sin_addr.s_addr)) {
  1022. return;
  1023. }
  1024. InterlockedIncrement(&lpaddr->lpstats->dwResponsesReceived);
  1025. // place templates over the buffer
  1026. lpentry = (LPRIP_ENTRY)(buffer + sizeof(RIP_HEADER));
  1027. lpbufend = (LPRIP_ENTRY)(buffer + length);
  1028. lpheader = (LPRIP_HEADER)buffer;
  1029. chVersion = lpheader->chVersion;
  1030. lpaentry = (LPRIP_AUTHENT_ENTRY) lpentry;
  1031. // seems OK, print a message
  1032. addr.s_addr = lpaddr->dwAddress;
  1033. pszTemp = inet_ntoa(addr);
  1034. if (pszTemp != NULL) {
  1035. strcpy(szAddress, pszTemp);
  1036. }
  1037. dbgprintf("received RIP v%d response from %s on address %s",
  1038. chVersion, inet_ntoa(lpsrcaddr->sin_addr), szAddress);
  1039. #ifdef ROUTE_FILTERS
  1040. RIP_LOCK_ACCEPT_FILTERS();
  1041. #endif
  1042. //
  1043. // take care of RIPv2 auth entry
  1044. // - ignoring auth entry till we decide on a way to allow this
  1045. // to be configurable
  1046. //
  1047. if (chVersion == 2) {
  1048. // if its an auth entry, ignore and continue
  1049. if (ntohs(lpaentry->wAddrFamily) == ADDRFAMILY_AUTHENT) {
  1050. lpentry++;
  1051. }
  1052. }
  1053. //
  1054. // validate each entry, then process it
  1055. //
  1056. for ( ; (lpentry + 1) <= lpbufend; lpentry++) {
  1057. //
  1058. // for non RIPv2 reserved fields must be checked
  1059. //
  1060. if (chVersion == 1) {
  1061. //
  1062. // check route entry fields
  1063. //
  1064. if (ntohs(lpentry->wAddrFamily) != AF_INET ||
  1065. lpentry->wReserved != 0 ||
  1066. lpentry->dwReserved1 != 0 ||
  1067. lpentry->dwReserved2 != 0) {
  1068. //
  1069. // update stats on ignored entries
  1070. //
  1071. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  1072. RipLogInformation(RIPLOG_FORMAT_ERROR, 0, NULL, 0);
  1073. continue;
  1074. }
  1075. // entry looks OK, so process it
  1076. ProcessRIPEntry(lpaddr, lpsrcaddr->sin_addr, lpentry, chVersion);
  1077. }
  1078. else
  1079. if (chVersion == 2) {
  1080. //
  1081. // check route entry fields
  1082. //
  1083. if (ntohs(lpentry->wAddrFamily) != AF_INET) {
  1084. //
  1085. // update stats on ignored entries
  1086. //
  1087. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  1088. RipLogInformation(RIPLOG_FORMAT_ERROR, 0, NULL, 0);
  1089. continue;
  1090. }
  1091. // entry looks OK, so process it
  1092. ProcessRIPEntry(lpaddr, lpsrcaddr->sin_addr, lpentry, chVersion);
  1093. }
  1094. else {
  1095. // following routing\ip\rip semantics
  1096. //
  1097. // this packet's version is greater than 2, so we ignore
  1098. // the contents of the reserved fields
  1099. //
  1100. //
  1101. // check route entry fields
  1102. //
  1103. if (ntohs(lpentry->wAddrFamily) != AF_INET) {
  1104. //
  1105. // update stats on ignored entries
  1106. //
  1107. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  1108. RipLogInformation(RIPLOG_FORMAT_ERROR, 0, NULL, 0);
  1109. continue;
  1110. }
  1111. //
  1112. // entry is alright, clear reserved fields and process
  1113. //
  1114. lpentry->wRoutetag = 0;
  1115. lpentry->dwSubnetmask = 0;
  1116. lpentry->dwNexthop = 0;
  1117. // entry looks OK, so process it
  1118. ProcessRIPEntry(lpaddr, lpsrcaddr->sin_addr, lpentry, chVersion);
  1119. }
  1120. }
  1121. #ifdef ROUTE_FILTERS
  1122. RIP_UNLOCK_ACCEPT_FILTERS();
  1123. #endif
  1124. }
  1125. //-----------------------------------------------------------------------
  1126. // Function: serviceHandlerFunction()
  1127. //
  1128. // Handles all service controller requests.
  1129. //-----------------------------------------------------------------------
  1130. VOID serviceHandlerFunction(DWORD dwControl) {
  1131. SERVICE_STATUS status;
  1132. dbgprintf("Service received control request %d", dwControl);
  1133. switch (dwControl) {
  1134. case SERVICE_CONTROL_INTERROGATE:
  1135. case SERVICE_CONTROL_PAUSE:
  1136. case SERVICE_CONTROL_CONTINUE:
  1137. // increment checkpoint if necessary
  1138. if (g_dwCheckPoint != 0) {
  1139. InterlockedExchange(&g_dwCheckPoint, g_dwCheckPoint + 100);
  1140. }
  1141. status.dwWaitHint = g_dwWaitHint;
  1142. status.dwWin32ExitCode = NO_ERROR;
  1143. status.dwServiceType = SERVICE_WIN32;
  1144. status.dwServiceSpecificExitCode = 0;
  1145. status.dwCheckPoint = g_dwCheckPoint;
  1146. status.dwCurrentState = g_dwCurrentState;
  1147. status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  1148. SERVICE_ACCEPT_SHUTDOWN;
  1149. #ifndef CHICAGO
  1150. SetServiceStatus (g_hService, &status);
  1151. #endif
  1152. break;
  1153. case SERVICE_CONTROL_STOP:
  1154. case SERVICE_CONTROL_SHUTDOWN:
  1155. SetEvent(g_stopEvent); // start cleanup
  1156. InterlockedExchange(&g_dwWaitHint, 120000);
  1157. InterlockedExchange(&g_dwCheckPoint, 100);
  1158. InterlockedExchange(&g_dwCurrentState, SERVICE_STOP_PENDING);
  1159. status.dwWaitHint = g_dwWaitHint;
  1160. status.dwWin32ExitCode = NO_ERROR;
  1161. status.dwCheckPoint = g_dwCheckPoint;
  1162. status.dwServiceType = SERVICE_WIN32;
  1163. status.dwServiceSpecificExitCode = 0;
  1164. status.dwCurrentState = g_dwCurrentState;
  1165. status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  1166. #ifndef CHICAGO
  1167. SetServiceStatus(g_hService, &status);
  1168. #endif
  1169. break;
  1170. }
  1171. }
  1172. //-----------------------------------------------------------------------
  1173. // Function: RIPServiceStop
  1174. //
  1175. // Handles freeing of resources, closing handles and sockets,
  1176. // and sending final status message to the service controller.
  1177. //-----------------------------------------------------------------------
  1178. void RIPServiceStop() {
  1179. LPRIP_ADDRESS lpaddr, lpend;
  1180. SERVICE_STATUS stopstatus = {SERVICE_WIN32, SERVICE_STOPPED, 0,
  1181. NO_ERROR, 0, 0, 0};
  1182. CleanupRouteTable();
  1183. CleanupStatsTable();
  1184. lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
  1185. for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
  1186. if (lpaddr->sock != INVALID_SOCKET) { closesocket(lpaddr->sock); }
  1187. }
  1188. WSACleanup();
  1189. if (g_triggerEvent != NULL) {
  1190. CloseHandle(g_triggerEvent); g_triggerEvent = NULL;
  1191. }
  1192. if (g_netEvent != NULL) {
  1193. CloseHandle(g_netEvent); g_netEvent = NULL;
  1194. }
  1195. if (g_addressChangeEvent != NULL) {
  1196. CloseHandle(g_addressChangeEvent); g_addressChangeEvent = NULL;
  1197. }
  1198. if (g_stopEvent != NULL) {
  1199. CloseHandle(g_stopEvent); g_stopEvent = NULL;
  1200. }
  1201. if (g_ripcfg.hTCPDriver != NULL) {
  1202. CloseHandle(g_ripcfg.hTCPDriver); g_ripcfg.hTCPDriver = NULL;
  1203. }
  1204. // need to log this before we destroy the locks
  1205. RipLogInformation(RIPLOG_SERVICE_STOPPED, 0, NULL, 0);
  1206. RIP_DESTROY_PARAMS_LOCK();
  1207. RIP_DESTROY_ADDRTABLE_LOCK();
  1208. RIP_DESTROY_ROUTETABLE_LOCK();
  1209. #ifdef ROUTE_FILTERS
  1210. RIP_DESTROY_ANNOUNCE_FILTERS_LOCK();
  1211. RIP_DESTROY_ACCEPT_FILTERS_LOCK();
  1212. #endif
  1213. dbgprintf("Main thread stopping.");
  1214. TraceDeregister(g_dwTraceID);
  1215. g_dwTraceID = (DWORD)-1;
  1216. #ifndef CHICAGO
  1217. SetServiceStatus(g_hService, &stopstatus);
  1218. #endif
  1219. }
  1220. #ifdef ROUTE_FILTERS
  1221. PRIP_FILTERS
  1222. LoadFilters(
  1223. IN HKEY hKeyParams,
  1224. IN LPSTR lpszKeyName
  1225. )
  1226. {
  1227. LPSTR pszFilter = NULL;
  1228. LPSTR pszIndex = NULL;
  1229. DWORD dwSize = 0, dwErr = NO_ERROR, dwType = 0, dwCount = 0, dwInd = 0;
  1230. PRIP_FILTERS prfFilter = NULL;
  1231. //
  1232. // route filters (added as a hotfix).
  1233. //
  1234. //
  1235. // Routes included in a RIP annoucement can be filtered.
  1236. //
  1237. // Route filters are configured by setting the value "AnnounceRouteFilters"
  1238. // or "AcceptRouteFilters"
  1239. // under the Parameters key. These are reg_multi_sz (or whatever it is
  1240. // formally called). Multiple filters can be set in each multistring.
  1241. // Each entry represents a network that will be filtered out when RIP
  1242. // announces/accepts routes.
  1243. //
  1244. do
  1245. {
  1246. dwSize = 0;
  1247. dwErr = RegQueryValueExA(
  1248. hKeyParams, lpszKeyName, NULL,
  1249. &dwType, (LPBYTE) NULL, &dwSize
  1250. );
  1251. if ( dwErr != ERROR_SUCCESS ||
  1252. dwType != REG_MULTI_SZ ||
  1253. dwSize <= 1 )
  1254. {
  1255. //
  1256. // either there is no key by this name or it is the
  1257. // wrong type. Nothing else to be done at this point
  1258. //
  1259. break;
  1260. }
  1261. //
  1262. // Appears to be a valid key with some data in it.
  1263. //
  1264. pszFilter = HeapAlloc(
  1265. GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize + 1
  1266. );
  1267. if ( pszFilter == NULL )
  1268. {
  1269. dbgprintf(
  1270. "Failed to allocate filter string : size = %d", dwSize
  1271. );
  1272. RipLogError(
  1273. RIPLOG_FILTER_ALLOC_FAILED, 0, NULL, ERROR_NOT_ENOUGH_MEMORY
  1274. );
  1275. break;
  1276. }
  1277. //
  1278. // retrieve key contents
  1279. //
  1280. dwErr = RegQueryValueExA(
  1281. hKeyParams, lpszKeyName, NULL,
  1282. &dwType, (LPBYTE) pszFilter, &dwSize
  1283. );
  1284. if ( dwErr != NO_ERROR || dwType != REG_MULTI_SZ || dwSize <= 1 )
  1285. {
  1286. dbgprintf(
  1287. "Failed to retrieve %s filters : error = %d", lpszKeyName,
  1288. dwErr
  1289. );
  1290. break;
  1291. }
  1292. //
  1293. // Convert the filter multi string to ip addresses
  1294. //
  1295. //
  1296. // count the number of filters
  1297. //
  1298. pszIndex = pszFilter;
  1299. while ( *pszIndex != '\0' )
  1300. {
  1301. dwCount++;
  1302. pszIndex += strlen( pszIndex ) + 1;
  1303. }
  1304. if ( dwCount == 0 )
  1305. {
  1306. dbgprintf( "No filters found" );
  1307. break;
  1308. }
  1309. //
  1310. // allocate filter structure
  1311. //
  1312. prfFilter = HeapAlloc(
  1313. GetProcessHeap(), HEAP_ZERO_MEMORY,
  1314. sizeof( RIP_FILTERS ) + ( dwCount - 1) * sizeof(
  1315. DWORD )
  1316. );
  1317. if ( prfFilter == NULL )
  1318. {
  1319. dbgprintf(
  1320. "Failed to allocate filter table : size = %d", dwSize
  1321. );
  1322. RipLogError(
  1323. RIPLOG_FILTER_ALLOC_FAILED, 0, NULL, ERROR_NOT_ENOUGH_MEMORY
  1324. );
  1325. break;
  1326. }
  1327. //
  1328. // fill it up
  1329. //
  1330. prfFilter-> dwCount = dwCount;
  1331. pszIndex = pszFilter;
  1332. for ( dwInd = 0; dwInd < dwCount; dwInd++ )
  1333. {
  1334. prfFilter-> pdwFilter[ dwInd ] = inet_addr( pszIndex );
  1335. pszIndex += strlen( pszIndex ) + 1;
  1336. }
  1337. } while ( FALSE );
  1338. if ( pszFilter != NULL )
  1339. {
  1340. HeapFree( GetProcessHeap(), 0, pszFilter );
  1341. }
  1342. if ( prfFilter != NULL )
  1343. {
  1344. //
  1345. // Print the list of configured filters
  1346. //
  1347. dbgprintf( "Number of filters : %d", prfFilter-> dwCount );
  1348. for ( dwInd = 0; dwInd < prfFilter-> dwCount; dwInd++ )
  1349. {
  1350. dbgprintf(
  1351. "Filter #%d : %x (%s)", dwInd,
  1352. prfFilter-> pdwFilter[ dwInd ],
  1353. inet_ntoa( *( (struct in_addr*)
  1354. &(prfFilter-> pdwFilter[ dwInd ] ) ) )
  1355. );
  1356. }
  1357. }
  1358. return prfFilter;
  1359. }
  1360. #endif
  1361. //-----------------------------------------------------------------------
  1362. //
  1363. //--------------------------- WINNT Specific ----------------------------
  1364. //
  1365. //-----------------------------------------------------------------------
  1366. #ifndef CHICAGO
  1367. //-----------------------------------------------------------------------
  1368. // Function: DllMain
  1369. //
  1370. // DLL entry-point; saves the module handle for later use.
  1371. //-----------------------------------------------------------------------
  1372. BOOL APIENTRY
  1373. DllMain(
  1374. HMODULE hmodule,
  1375. DWORD dwReason,
  1376. VOID* pReserved
  1377. ) {
  1378. if (dwReason == DLL_PROCESS_ATTACH) { g_hmodule = hmodule; }
  1379. return TRUE;
  1380. }
  1381. //-----------------------------------------------------------------------
  1382. // Function: LoadParameters
  1383. //
  1384. // Reads various configuration flags from the registry.
  1385. //-----------------------------------------------------------------------
  1386. DWORD LoadParameters() {
  1387. DWORD valuesize;
  1388. DWORD dwErr, dwType, dwIndex, dwValue;
  1389. HKEY hkeyParams;
  1390. DWORD dwRouteTimeout, dwGarbageTimeout;
  1391. DWORD dwLoggingLevel, dwUpdateFrequency;
  1392. DWORD dwMaxTriggerFrequency, dwOverwriteStaticRoutes;
  1393. DWORD dwSize = MAX_PATH;
  1394. HKEY hkey = NULL;
  1395. WCHAR Buffer[MAX_PATH+1];
  1396. RegCloseKey( hkey );
  1397. dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_RIP_PARAMS, &hkeyParams);
  1398. if (dwErr != ERROR_SUCCESS) {
  1399. return GetLastError();
  1400. }
  1401. #ifdef ROUTE_FILTERS
  1402. RIP_LOCK_ANNOUNCE_FILTERS();
  1403. if ( g_prfAnnounceFilters != NULL ) {
  1404. HeapFree( GetProcessHeap(), 0, g_prfAnnounceFilters );
  1405. }
  1406. g_prfAnnounceFilters = LoadFilters( hkeyParams, REGVAL_ANNOUCE_FILTERS );
  1407. RIP_UNLOCK_ANNOUNCE_FILTERS();
  1408. RIP_LOCK_ACCEPT_FILTERS();
  1409. if ( g_prfAcceptFilters != NULL ) {
  1410. HeapFree( GetProcessHeap(), 0, g_prfAcceptFilters );
  1411. }
  1412. g_prfAcceptFilters = LoadFilters( hkeyParams, REGVAL_ACCEPT_FILTERS );
  1413. RIP_UNLOCK_ACCEPT_FILTERS();
  1414. #endif
  1415. RIP_LOCK_PARAMS();
  1416. // always run in SilentRIP mode.
  1417. {
  1418. g_params.dwSilentRIP = 1;
  1419. }
  1420. // read the value for accepting host routes
  1421. valuesize = sizeof(DWORD);
  1422. dwErr = RegQueryValueEx(hkeyParams, REGVAL_ACCEPT_HOST, NULL,
  1423. &dwType, (LPBYTE)&dwValue, &valuesize);
  1424. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1425. g_params.dwAcceptHost = dwValue;
  1426. }
  1427. else {
  1428. g_params.dwAcceptHost = DEF_ACCEPT_HOST;
  1429. }
  1430. // read the value for announcing host routes
  1431. valuesize = sizeof(DWORD);
  1432. dwErr = RegQueryValueEx(hkeyParams, REGVAL_ANNOUNCE_HOST, NULL,
  1433. &dwType, (LPBYTE)&dwValue, &valuesize);
  1434. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1435. g_params.dwAnnounceHost = dwValue;
  1436. }
  1437. else {
  1438. g_params.dwAnnounceHost = DEF_ANNOUNCE_HOST;
  1439. }
  1440. // read the value for accepting default routes
  1441. valuesize = sizeof(DWORD);
  1442. dwErr = RegQueryValueEx(hkeyParams, REGVAL_ACCEPT_DEFAULT, NULL,
  1443. &dwType, (LPBYTE)&dwValue, &valuesize);
  1444. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1445. g_params.dwAcceptDefault = dwValue;
  1446. }
  1447. else {
  1448. g_params.dwAcceptDefault = DEF_ACCEPT_DEFAULT;
  1449. }
  1450. // read the value for announcing default routes
  1451. valuesize = sizeof(DWORD);
  1452. dwErr = RegQueryValueEx(hkeyParams, REGVAL_ANNOUNCE_DEFAULT, NULL,
  1453. &dwType, (LPBYTE)&dwValue, &valuesize);
  1454. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1455. g_params.dwAnnounceDefault = dwValue;
  1456. }
  1457. else {
  1458. g_params.dwAnnounceDefault = DEF_ANNOUNCE_DEFAULT;
  1459. }
  1460. // read value for split-horizon processing
  1461. valuesize = sizeof(DWORD);
  1462. dwErr = RegQueryValueEx(hkeyParams, REGVAL_SPLITHORIZON, NULL,
  1463. &dwType, (LPBYTE)&dwValue, &valuesize);
  1464. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1465. g_params.dwSplitHorizon = dwValue;
  1466. }
  1467. else {
  1468. g_params.dwSplitHorizon = DEF_SPLITHORIZON;
  1469. }
  1470. // read value for poisoned-reverse processing
  1471. valuesize = sizeof(DWORD);
  1472. dwErr = RegQueryValueEx(hkeyParams, REGVAL_POISONREVERSE, NULL,
  1473. &dwType, (LPBYTE)&dwValue, &valuesize);
  1474. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1475. g_params.dwPoisonReverse = dwValue;
  1476. }
  1477. else {
  1478. g_params.dwPoisonReverse = DEF_POISONREVERSE;
  1479. }
  1480. // read value for triggered update sending
  1481. valuesize = sizeof(DWORD);
  1482. dwErr = RegQueryValueEx(hkeyParams, REGVAL_TRIGGEREDUPDATES, NULL,
  1483. &dwType, (LPBYTE)&dwValue, &valuesize);
  1484. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1485. g_params.dwTriggeredUpdates = dwValue;
  1486. }
  1487. else {
  1488. g_params.dwTriggeredUpdates = DEF_TRIGGEREDUPDATES;
  1489. }
  1490. // read value for triggered update frequency
  1491. valuesize = sizeof(DWORD);
  1492. dwErr = RegQueryValueEx(hkeyParams, REGVAL_TRIGGERFREQUENCY, NULL,
  1493. &dwType, (LPBYTE)&dwValue, &valuesize);
  1494. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1495. dwMaxTriggerFrequency = dwValue * 1000;
  1496. }
  1497. else {
  1498. dwMaxTriggerFrequency = DEF_TRIGGERFREQUENCY;
  1499. }
  1500. // read value for route timeouts
  1501. valuesize = sizeof(DWORD);
  1502. dwErr = RegQueryValueEx(hkeyParams, REGVAL_ROUTETIMEOUT, NULL,
  1503. &dwType, (LPBYTE)&dwValue, &valuesize);
  1504. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1505. dwRouteTimeout = dwValue * 1000;
  1506. }
  1507. else {
  1508. dwRouteTimeout = DEF_ROUTETIMEOUT;
  1509. }
  1510. // read values for update frequency
  1511. valuesize = sizeof(DWORD);
  1512. dwErr = RegQueryValueEx(hkeyParams, REGVAL_UPDATEFREQUENCY, NULL,
  1513. &dwType, (LPBYTE)&dwValue, &valuesize);
  1514. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1515. dwUpdateFrequency = dwValue * 1000;
  1516. }
  1517. else {
  1518. dwUpdateFrequency = DEF_UPDATEFREQUENCY;
  1519. }
  1520. // read values for garbage timeouts
  1521. valuesize = sizeof(DWORD);
  1522. dwErr = RegQueryValueEx(hkeyParams, REGVAL_GARBAGETIMEOUT, NULL,
  1523. &dwType, (LPBYTE)&dwValue, &valuesize);
  1524. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1525. dwGarbageTimeout = dwValue * 1000;
  1526. }
  1527. else {
  1528. dwGarbageTimeout = DEF_GARBAGETIMEOUT;
  1529. }
  1530. // read values for logging level
  1531. valuesize = sizeof(DWORD);
  1532. dwErr = RegQueryValueEx(hkeyParams, REGVAL_OVERWRITESTATIC, NULL,
  1533. &dwType, (LPBYTE)&dwValue, &valuesize);
  1534. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1535. dwOverwriteStaticRoutes = dwValue;
  1536. }
  1537. else {
  1538. dwOverwriteStaticRoutes = DEF_OVERWRITESTATIC;
  1539. }
  1540. // read values for logging level
  1541. valuesize = sizeof(DWORD);
  1542. dwErr = RegQueryValueEx(hkeyParams, REGVAL_LOGGINGLEVEL, NULL,
  1543. &dwType, (LPBYTE)&dwValue, &valuesize);
  1544. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1545. dwLoggingLevel = dwValue;
  1546. }
  1547. else {
  1548. dwLoggingLevel = DEF_LOGGINGLEVEL;
  1549. }
  1550. // read value for MaxTimedOpsInterval
  1551. valuesize = sizeof(DWORD);
  1552. dwErr = RegQueryValueEx(hkeyParams, REGVAL_MAXTIMEDOPSINTERVAL, NULL,
  1553. &dwType, (LPBYTE)&dwValue, &valuesize);
  1554. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD && dwValue) {
  1555. g_params.dwMaxTimedOpsInterval = dwValue * 1000;
  1556. }
  1557. else {
  1558. g_params.dwMaxTimedOpsInterval = DEF_MAXTIMEDOPSINTERVAL;
  1559. }
  1560. RegCloseKey(hkeyParams);
  1561. // adjust values if out of acceptable range
  1562. if (dwRouteTimeout > MAX_ROUTETIMEOUT) {
  1563. dwRouteTimeout = MAX_ROUTETIMEOUT;
  1564. }
  1565. else
  1566. if (dwRouteTimeout < MIN_ROUTETIMEOUT) {
  1567. dwRouteTimeout = MIN_ROUTETIMEOUT;
  1568. }
  1569. if (dwGarbageTimeout > MAX_GARBAGETIMEOUT) {
  1570. dwGarbageTimeout = MAX_GARBAGETIMEOUT;
  1571. }
  1572. else
  1573. if (dwGarbageTimeout < MIN_GARBAGETIMEOUT) {
  1574. dwGarbageTimeout = MIN_GARBAGETIMEOUT;
  1575. }
  1576. if (dwUpdateFrequency > MAX_UPDATEFREQUENCY) {
  1577. dwUpdateFrequency = MAX_UPDATEFREQUENCY;
  1578. }
  1579. else
  1580. if (dwUpdateFrequency < MIN_UPDATEFREQUENCY) {
  1581. dwUpdateFrequency = MIN_UPDATEFREQUENCY;
  1582. }
  1583. if (dwMaxTriggerFrequency > MAX_TRIGGERFREQUENCY) {
  1584. dwMaxTriggerFrequency = MAX_TRIGGERFREQUENCY;
  1585. }
  1586. else
  1587. if (dwMaxTriggerFrequency < MIN_TRIGGERFREQUENCY) {
  1588. dwMaxTriggerFrequency = MIN_TRIGGERFREQUENCY;
  1589. }
  1590. g_params.dwRouteTimeout = dwRouteTimeout;
  1591. g_params.dwGarbageTimeout = dwGarbageTimeout;
  1592. g_params.dwUpdateFrequency = dwUpdateFrequency;
  1593. g_params.dwMaxTriggerFrequency = dwMaxTriggerFrequency;
  1594. g_params.dwLoggingLevel = dwLoggingLevel;
  1595. g_params.dwOverwriteStaticRoutes = dwOverwriteStaticRoutes;
  1596. dbgprintf("%s == %d", REGVAL_LOGGINGLEVEL, dwLoggingLevel);
  1597. dbgprintf("%s == %d", REGVAL_ROUTETIMEOUT, dwRouteTimeout / 1000);
  1598. dbgprintf("%s == %d", REGVAL_GARBAGETIMEOUT, dwGarbageTimeout / 1000);
  1599. dbgprintf("%s == %d", REGVAL_UPDATEFREQUENCY, dwUpdateFrequency / 1000);
  1600. dbgprintf("%s == %d", REGVAL_ACCEPT_HOST, g_params.dwAcceptHost);
  1601. dbgprintf("%s == %d", REGVAL_ANNOUNCE_HOST, g_params.dwAnnounceHost);
  1602. dbgprintf("%s == %d", REGVAL_ACCEPT_DEFAULT, g_params.dwAcceptDefault);
  1603. dbgprintf("%s == %d", REGVAL_ANNOUNCE_DEFAULT, g_params.dwAnnounceDefault);
  1604. dbgprintf("%s == %d", REGVAL_SPLITHORIZON, g_params.dwSplitHorizon);
  1605. dbgprintf("%s == %d", REGVAL_POISONREVERSE, g_params.dwPoisonReverse);
  1606. dbgprintf("%s == %d", REGVAL_TRIGGEREDUPDATES, g_params.dwTriggeredUpdates);
  1607. dbgprintf("%s == %d", REGVAL_OVERWRITESTATIC, dwOverwriteStaticRoutes);
  1608. dbgprintf("%s == %d", REGVAL_TRIGGERFREQUENCY,
  1609. g_params.dwMaxTriggerFrequency / 1000);
  1610. if (g_params.dwSilentRIP != 0) {
  1611. dbgprintf("IPRIP is configured to be silent.");
  1612. }
  1613. else {
  1614. dbgprintf("IPRIP is configured to be active.");
  1615. }
  1616. if (dwLoggingLevel >= LOGLEVEL_INFORMATION) {
  1617. // log the parameters IPRIP is using
  1618. //
  1619. CHAR szBuffer[2048], *lplpszArgs[] = { szBuffer };
  1620. sprintf(szBuffer,
  1621. "\r\n%s: %d"
  1622. "\r\n%s: %d"
  1623. "\r\n%s: %d"
  1624. "\r\n%s: %d"
  1625. "\r\n%s: %d"
  1626. "\r\n%s: %d"
  1627. "\r\n%s: %d"
  1628. "\r\n%s: %d"
  1629. "\r\n%s: %d"
  1630. "\r\n%s: %d"
  1631. "\r\n%s: %d"
  1632. "\r\n%s: %d"
  1633. "\r\n%s: %d"
  1634. "\r\n%s: %d",
  1635. REGVAL_LOGGINGLEVEL, dwLoggingLevel,
  1636. REGVAL_ROUTETIMEOUT, dwRouteTimeout / 1000,
  1637. REGVAL_GARBAGETIMEOUT, dwGarbageTimeout / 1000,
  1638. REGVAL_UPDATEFREQUENCY, dwUpdateFrequency / 1000,
  1639. REGVAL_ACCEPT_HOST, g_params.dwAcceptHost,
  1640. REGVAL_ANNOUNCE_HOST, g_params.dwAnnounceHost,
  1641. REGVAL_ACCEPT_DEFAULT, g_params.dwAcceptDefault,
  1642. REGVAL_ANNOUNCE_DEFAULT, g_params.dwAnnounceDefault,
  1643. REGVAL_SPLITHORIZON, g_params.dwSplitHorizon,
  1644. REGVAL_POISONREVERSE, g_params.dwPoisonReverse,
  1645. REGVAL_TRIGGEREDUPDATES, g_params.dwTriggeredUpdates,
  1646. REGVAL_OVERWRITESTATIC, dwOverwriteStaticRoutes,
  1647. REGVAL_TRIGGERFREQUENCY, g_params.dwMaxTriggerFrequency / 1000,
  1648. REGVAL_SILENTRIP, g_params.dwSilentRIP);
  1649. RipLogInformation(RIPLOG_REGISTRY_PARAMETERS, 1, lplpszArgs, 0);
  1650. }
  1651. RIP_UNLOCK_PARAMS();
  1652. return 0;
  1653. }
  1654. #else
  1655. //-----------------------------------------------------------------------
  1656. //
  1657. //--------------------------- Windows 95 Specific -----------------------
  1658. //
  1659. //-----------------------------------------------------------------------
  1660. //
  1661. // named event
  1662. //
  1663. #define RIP_LISTENER_EVENT TEXT( "RIP.Listener.Event" )
  1664. HINSTANCE hInst; // current instance
  1665. HWND hWnd; // Main window handle.
  1666. //
  1667. // resource strings
  1668. //
  1669. char szAppName[64]; // The name of this application
  1670. char szTitle[32]; // The title bar text
  1671. char szHelpStr[32]; // Help flag "Help"
  1672. char szQuestStr[32]; // Abriev. Help Flag "?"
  1673. char szCloseStr[32]; // Close flag "close"
  1674. char szDestroyStr[32]; // Destroy flag "destroy"
  1675. char szHelpText1[256]; // Help String
  1676. char szHelpText2[64]; // Help String
  1677. char szHelpText3[128]; // Help String
  1678. //
  1679. // local function prototypes
  1680. //
  1681. BOOL
  1682. InitApplication(
  1683. HINSTANCE hInstance
  1684. );
  1685. BOOL
  1686. InitInstance(
  1687. HINSTANCE hInstance,
  1688. int nCmdShow
  1689. );
  1690. BOOL
  1691. GetStrings(
  1692. HINSTANCE hInstance
  1693. );
  1694. LRESULT CALLBACK WndProc(
  1695. HWND hWnd, // window handle
  1696. UINT message, // type of message
  1697. WPARAM uParam, // additional information
  1698. LPARAM lParam // additional information
  1699. );
  1700. //-----------------------------------------------------------------------
  1701. // Function: GetStrings
  1702. //
  1703. // Retrieve resource strings
  1704. //-----------------------------------------------------------------------
  1705. BOOL GetStrings(HINSTANCE hInstance)
  1706. {
  1707. if (LoadString(hInstance, IDS_TITLE_BAR, szTitle, sizeof(szTitle)) == 0)
  1708. {
  1709. goto ErrorExit;
  1710. }
  1711. if (LoadString(hInstance, IDS_APP_NAME, szAppName, sizeof(szAppName)) == 0)
  1712. {
  1713. goto ErrorExit;
  1714. }
  1715. if (LoadString(hInstance, IDS_HELP_TEXT1, szHelpText1, sizeof(szHelpText1)) == 0)
  1716. {
  1717. goto ErrorExit;
  1718. }
  1719. if (LoadString(hInstance, IDS_HELP_TEXT2, szHelpText2, sizeof(szHelpText2)) == 0)
  1720. {
  1721. goto ErrorExit;
  1722. }
  1723. return TRUE;
  1724. ErrorExit:
  1725. return FALSE;
  1726. }
  1727. //-----------------------------------------------------------------------
  1728. // Functions : InitInstance
  1729. //
  1730. // save instance handle and create main window.
  1731. //-----------------------------------------------------------------------
  1732. BOOL
  1733. InitInstance(
  1734. HINSTANCE hInstance,
  1735. int nCmdShow
  1736. )
  1737. {
  1738. //
  1739. // Save the instance handle in static variable, which will be used in
  1740. // many subsequence calls from this application to Windows.
  1741. //
  1742. // Store instance handle in our global variable
  1743. //
  1744. hInst = hInstance;
  1745. //
  1746. // Create a main window for this application instance.
  1747. //
  1748. hWnd = CreateWindow(
  1749. szAppName,
  1750. szTitle,
  1751. WS_EX_TRANSPARENT, // Window style.
  1752. 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, // Use default positioning CW_USEDEAULT
  1753. NULL, // Overlapped windows have no parent.
  1754. NULL, // Use the window class menu.
  1755. hInstance, // This instance owns this window.
  1756. NULL // We don't use any data in our WM_CREATE
  1757. );
  1758. //
  1759. // If window could not be created, return "failure"
  1760. //
  1761. if (!hWnd)
  1762. {
  1763. dbgprintf( "Failed to create window" );
  1764. return (FALSE);
  1765. }
  1766. //
  1767. // Make the window visible; update its client area; and return "success"
  1768. //
  1769. ShowWindow(hWnd, nCmdShow); // Show the window
  1770. UpdateWindow(hWnd); // Sends WM_PAINT message
  1771. return (TRUE); // We succeeded...
  1772. }
  1773. //-----------------------------------------------------------------------------
  1774. // Function : InitApplication
  1775. //
  1776. // initialize window data and register window class
  1777. //-----------------------------------------------------------------------------
  1778. BOOL InitApplication(HINSTANCE hInstance)
  1779. {
  1780. WNDCLASS wc;
  1781. DWORD LastError;
  1782. //
  1783. // Fill in window class structure with parameters that
  1784. // describe the main window.
  1785. //
  1786. wc.style = CS_HREDRAW | CS_VREDRAW;// Class style(s).
  1787. wc.lpfnWndProc = WndProc; // Window Procedure
  1788. wc.cbClsExtra = 0; // No per-class extra data.
  1789. wc.cbWndExtra = 0; // No per-window extra data.
  1790. wc.hInstance = hInstance; // Owner of this class
  1791. wc.hIcon = NULL;
  1792. wc.hCursor = NULL;
  1793. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);// Default color
  1794. wc.lpszMenuName = szAppName; // Menu name from .RC
  1795. wc.lpszClassName = szAppName; // Name to register as
  1796. //
  1797. // Register the window class and return success/failure code.
  1798. //
  1799. if ( !RegisterClass(&wc) )
  1800. {
  1801. dbgprintf( "Failed to register class" );
  1802. return FALSE;
  1803. }
  1804. else
  1805. {
  1806. return TRUE;
  1807. }
  1808. }
  1809. //-----------------------------------------------------------------------------
  1810. // Function : WndProc
  1811. //
  1812. // process messages
  1813. //-----------------------------------------------------------------------------
  1814. LRESULT CALLBACK WndProc(
  1815. HWND hWnd, // window handle
  1816. UINT message, // type of message
  1817. WPARAM uParam, // additional information
  1818. LPARAM lParam // additional information
  1819. )
  1820. {
  1821. switch (message)
  1822. {
  1823. case WM_ENDSESSION:
  1824. case WM_QUERYENDSESSION:
  1825. if (lParam == 0)
  1826. {
  1827. dbgprintf ( "IPRIP : Received shutdown message\n" );
  1828. }
  1829. if (lParam == 1 ) //EWX_REALLYLOGOFF
  1830. {
  1831. dbgprintf ( "IPRIP : Received logoff message\n" );
  1832. }
  1833. return(1);
  1834. case WM_DESTROY: // message: window being destroyed
  1835. PostQuitMessage(0);
  1836. return(0);
  1837. default: // Pass it on if unproccessed
  1838. return (DefWindowProc(hWnd, message, uParam, lParam));
  1839. }
  1840. }
  1841. //-----------------------------------------------------------------------
  1842. // Function: LoadParameters
  1843. //
  1844. // Reads various configuration flags from the registry.
  1845. //-----------------------------------------------------------------------
  1846. DWORD LoadParameters()
  1847. {
  1848. RIP_LOCK_PARAMS();
  1849. g_params.dwSilentRIP = 1;
  1850. g_params.dwAcceptHost = DEF_ACCEPT_HOST;
  1851. g_params.dwAnnounceHost = DEF_ANNOUNCE_HOST;
  1852. g_params.dwAcceptDefault = DEF_ACCEPT_DEFAULT;
  1853. g_params.dwAnnounceDefault = DEF_ANNOUNCE_DEFAULT;
  1854. g_params.dwSplitHorizon = DEF_SPLITHORIZON;
  1855. g_params.dwPoisonReverse = DEF_POISONREVERSE;
  1856. g_params.dwTriggeredUpdates = DEF_TRIGGEREDUPDATES;
  1857. g_params.dwMaxTriggerFrequency = DEF_TRIGGERFREQUENCY;
  1858. g_params.dwRouteTimeout = DEF_ROUTETIMEOUT;
  1859. g_params.dwUpdateFrequency = DEF_UPDATEFREQUENCY;
  1860. g_params.dwGarbageTimeout = DEF_GARBAGETIMEOUT;
  1861. g_params.dwOverwriteStaticRoutes = DEF_OVERWRITESTATIC;
  1862. g_params.dwLoggingLevel = DEF_LOGGINGLEVEL;
  1863. dbgprintf("%s == %d", REGVAL_LOGGINGLEVEL, g_params.dwLoggingLevel);
  1864. dbgprintf("%s == %d", REGVAL_ROUTETIMEOUT, g_params.dwRouteTimeout / 1000);
  1865. dbgprintf("%s == %d", REGVAL_GARBAGETIMEOUT, g_params.dwGarbageTimeout / 1000);
  1866. dbgprintf("%s == %d", REGVAL_UPDATEFREQUENCY, g_params.dwUpdateFrequency / 1000);
  1867. dbgprintf("%s == %d", REGVAL_ACCEPT_HOST, g_params.dwAcceptHost);
  1868. dbgprintf("%s == %d", REGVAL_ANNOUNCE_HOST, g_params.dwAnnounceHost);
  1869. dbgprintf("%s == %d", REGVAL_ACCEPT_DEFAULT, g_params.dwAcceptDefault);
  1870. dbgprintf("%s == %d", REGVAL_ANNOUNCE_DEFAULT, g_params.dwAnnounceDefault);
  1871. dbgprintf("%s == %d", REGVAL_SPLITHORIZON, g_params.dwSplitHorizon);
  1872. dbgprintf("%s == %d", REGVAL_POISONREVERSE, g_params.dwPoisonReverse);
  1873. dbgprintf("%s == %d", REGVAL_TRIGGEREDUPDATES, g_params.dwTriggeredUpdates);
  1874. dbgprintf("%s == %d", REGVAL_OVERWRITESTATIC, g_params.dwOverwriteStaticRoutes);
  1875. dbgprintf("%s == %d", REGVAL_TRIGGERFREQUENCY,
  1876. g_params.dwMaxTriggerFrequency / 1000);
  1877. if (g_params.dwSilentRIP != 0)
  1878. {
  1879. dbgprintf("IPRIP is configured to be silent.");
  1880. }
  1881. else
  1882. {
  1883. dbgprintf("IPRIP is configured to be active.");
  1884. }
  1885. if (g_params.dwLoggingLevel >= LOGLEVEL_INFORMATION)
  1886. {
  1887. //
  1888. // log the parameters IPRIP is using
  1889. //
  1890. CHAR szBuffer[2048], *lplpszArgs[] = { szBuffer };
  1891. sprintf(szBuffer,
  1892. "\r\n%s: %d"
  1893. "\r\n%s: %d"
  1894. "\r\n%s: %d"
  1895. "\r\n%s: %d"
  1896. "\r\n%s: %d"
  1897. "\r\n%s: %d"
  1898. "\r\n%s: %d"
  1899. "\r\n%s: %d"
  1900. "\r\n%s: %d"
  1901. "\r\n%s: %d"
  1902. "\r\n%s: %d"
  1903. "\r\n%s: %d"
  1904. "\r\n%s: %d"
  1905. "\r\n%s: %d",
  1906. REGVAL_LOGGINGLEVEL, g_params.dwLoggingLevel,
  1907. REGVAL_ROUTETIMEOUT, g_params.dwRouteTimeout / 1000,
  1908. REGVAL_GARBAGETIMEOUT, g_params.dwGarbageTimeout / 1000,
  1909. REGVAL_UPDATEFREQUENCY, g_params.dwUpdateFrequency / 1000,
  1910. REGVAL_ACCEPT_HOST, g_params.dwAcceptHost,
  1911. REGVAL_ANNOUNCE_HOST, g_params.dwAnnounceHost,
  1912. REGVAL_ACCEPT_DEFAULT, g_params.dwAcceptDefault,
  1913. REGVAL_ANNOUNCE_DEFAULT, g_params.dwAnnounceDefault,
  1914. REGVAL_SPLITHORIZON, g_params.dwSplitHorizon,
  1915. REGVAL_POISONREVERSE, g_params.dwPoisonReverse,
  1916. REGVAL_TRIGGEREDUPDATES, g_params.dwTriggeredUpdates,
  1917. REGVAL_OVERWRITESTATIC, g_params.dwOverwriteStaticRoutes,
  1918. REGVAL_TRIGGERFREQUENCY, g_params.dwMaxTriggerFrequency / 1000,
  1919. REGVAL_SILENTRIP, g_params.dwSilentRIP);
  1920. RipLogInformation(RIPLOG_REGISTRY_PARAMETERS, 1, lplpszArgs, 0);
  1921. }
  1922. RIP_UNLOCK_PARAMS();
  1923. return 0;
  1924. }
  1925. //-----------------------------------------------------------------------
  1926. // Function: WinMain
  1927. //
  1928. // Launches the RIP service and waits for it to terminate
  1929. //-----------------------------------------------------------------------
  1930. INT APIENTRY
  1931. WinMain(
  1932. HINSTANCE hInstance,
  1933. HINSTANCE hPrevInstance,
  1934. LPSTR lpCmdLine,
  1935. int nCmdShow
  1936. )
  1937. {
  1938. MSG msg;
  1939. HANDLE RipListenerEvent, hThread, hKernel32 = NULL;
  1940. DWORD threadId, LastError;
  1941. BOOL fRegSrvcProc = FALSE;
  1942. FARPROC pRegSrvcProc;
  1943. LPCSTR event_name = RIP_LISTENER_EVENT;
  1944. DWORD err;
  1945. //
  1946. // Get entry point RegisterServiceProcess
  1947. //
  1948. /*
  1949. if ( (GetVersion() & 0x000000ff) == 0x04 )
  1950. {
  1951. if ((hKernel32 = GetModuleHandle("kernel32.dll")) == NULL)
  1952. {
  1953. //
  1954. // This should never happen but we'll try and
  1955. // load the library anyway
  1956. //
  1957. if ((hKernel32 = LoadLibrary("kernel32.dll")) == NULL)
  1958. {
  1959. fRegSrvcProc = FALSE;
  1960. }
  1961. }
  1962. if (hKernel32)
  1963. {
  1964. if ((pRegSrvcProc = GetProcAddress(hKernel32,"RegisterServiceProcess")) == NULL)
  1965. {
  1966. fRegSrvcProc = FALSE;
  1967. }
  1968. else
  1969. {
  1970. fRegSrvcProc = TRUE;
  1971. }
  1972. }
  1973. }
  1974. else
  1975. {
  1976. fRegSrvcProc = FALSE;
  1977. }
  1978. */
  1979. //
  1980. // Other instances of RIP listener running?
  1981. //
  1982. RipListenerEvent = OpenEvent( SYNCHRONIZE, FALSE, event_name ) ;
  1983. if ( RipListenerEvent == NULL)
  1984. {
  1985. if ( (RipListenerEvent = CreateEvent( NULL, FALSE, TRUE, event_name ) ) == NULL)
  1986. {
  1987. LastError = GetLastError();
  1988. dbgprintf(
  1989. "IPRIP Create Event failed, error code %d",
  1990. LastError
  1991. );
  1992. RipLogError( RIPLOG_CREATEEVENT_FAILED, 0, NULL, LastError );
  1993. return 1;
  1994. }
  1995. }
  1996. else
  1997. {
  1998. //
  1999. // another instance is running
  2000. //
  2001. HANDLE hParentWin;
  2002. dbgprintf( "IPRIP : Service already running\n" );
  2003. RipLogError( RIPLOG_SERVICE_AREADY_STARTED, 0, NULL, 0 );
  2004. return 1;
  2005. }
  2006. //
  2007. // retrieve resource strings
  2008. //
  2009. if ( !GetStrings(hInstance) )
  2010. {
  2011. dbgprintf( "IPRIP : Service failed to initialize\n" );
  2012. RipLogError( RIPLOG_SERVICE_INIT_FAILED, 0, NULL, 0 );
  2013. return 1;
  2014. }
  2015. //
  2016. // required initialization for windows apps.
  2017. //
  2018. if( !InitApplication( hInstance ) )
  2019. {
  2020. dbgprintf( "IPRIP : Service failed to initialize\n" );
  2021. RipLogError( RIPLOG_SERVICE_INIT_FAILED, 0, NULL, 0 );
  2022. return 1;
  2023. }
  2024. if (!InitInstance(hInstance, SW_HIDE))
  2025. {
  2026. dbgprintf( "IPRIP : Service failed to initialize\n" );
  2027. RipLogError( RIPLOG_SERVICE_INIT_FAILED, 0, NULL, 0 );
  2028. return 1;
  2029. }
  2030. //
  2031. // Launch main service controller thread
  2032. //
  2033. if ( ( hThread = CreateThread(
  2034. NULL,
  2035. 0,
  2036. (LPTHREAD_START_ROUTINE)ServiceMain,
  2037. NULL,
  2038. 0,
  2039. &threadId
  2040. )
  2041. ) == 0)
  2042. {
  2043. dbgprintf( "IPRIP : Failed thread creation\n" );
  2044. RipLogError( RIPLOG_CREATETHREAD_FAILED, 0, NULL, 0 );
  2045. return 1;
  2046. }
  2047. //
  2048. // Register service process
  2049. //
  2050. /*
  2051. if (fRegSrvcProc)
  2052. {
  2053. (*pRegSrvcProc)(GetCurrentProcessId(), RSP_SIMPLE_SERVICE);
  2054. }
  2055. */
  2056. //
  2057. // Acquire and dispatch messages until a WM_QUIT message is received.
  2058. //
  2059. while (GetMessage(&msg, NULL, 0, 0))
  2060. {
  2061. TranslateMessage(&msg); // Translates virtual key codes
  2062. DispatchMessage(&msg); // Dispatches message to window
  2063. }
  2064. //
  2065. // Un register service process
  2066. //
  2067. /*
  2068. if (fRegSrvcProc)
  2069. {
  2070. (*pRegSrvcProc)(GetCurrentProcessId(), RSP_UNREGISTER_SERVICE);
  2071. }
  2072. */
  2073. dbgprintf( "IPRIP : Service terminated\n" );
  2074. RipLogError( RIPLOG_SERVICE_STOPPED, 0, NULL, 0 );
  2075. return(0);
  2076. UNREFERENCED_PARAMETER(lpCmdLine);
  2077. }
  2078. // Name: Mohsin Ahmed
  2079. // Email: [email protected]
  2080. // Date: Mon Nov 04 13:53:46 1996
  2081. // File: s:/tcpcmd/common2/debug.c
  2082. // Synopsis: Win95 Woes, don't have ntdll.dll on win95.
  2083. #include <windows.h>
  2084. #define MAX_DEBUG_OUTPUT 1024
  2085. void DbgPrintf( char * format, ... )
  2086. {
  2087. va_list args;
  2088. char out[MAX_DEBUG_OUTPUT];
  2089. int cch=0;
  2090. // cch = wsprintf( out, MODULE_NAME ":" );
  2091. va_start( args, format );
  2092. wvsprintf( out + cch, format, args );
  2093. va_end( args );
  2094. OutputDebugString( out );
  2095. }
  2096. #endif