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.

1334 lines
44 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. //
  14. // Description: RIP Tables Manipulation Functions
  15. //
  16. //****************************************************************************
  17. #include "pchrip.h"
  18. #pragma hdrstop
  19. //-----------------------------------------------------------------------------
  20. // Function: InitializeRouteTable
  21. //
  22. // Initializes hash table
  23. //-----------------------------------------------------------------------------
  24. DWORD InitializeRouteTable() {
  25. LPHASH_TABLE_ENTRY *lplpentry, *lplpend;
  26. lplpend = g_ripcfg.lpRouteTable + HASH_TABLE_SIZE;
  27. for (lplpentry = g_ripcfg.lpRouteTable; lplpentry < lplpend; lplpentry++) {
  28. *lplpentry = NULL;
  29. }
  30. return 0;
  31. }
  32. //-----------------------------------------------------------------------------
  33. // Function: GetRouteTableEntry
  34. //
  35. // Looks for an entry with the specified address and mask, learnt using the
  36. // specified interface. If the entry is not found, one is created.
  37. //-----------------------------------------------------------------------------
  38. LPHASH_TABLE_ENTRY GetRouteTableEntry(DWORD dwIndex, DWORD dwAddress,
  39. DWORD dwNetmask) {
  40. INT hashval;
  41. IN_ADDR addr;
  42. LPHASH_TABLE_ENTRY rt_entry;
  43. LPHASH_TABLE_ENTRY prev_rt_entry;
  44. hashval = HASH_VALUE(dwAddress);
  45. ASSERT(hashval < HASH_TABLE_SIZE);
  46. RIP_LOCK_ROUTETABLE();
  47. prev_rt_entry = rt_entry = g_ripcfg.lpRouteTable[hashval];
  48. while (rt_entry != NULL) {
  49. if ((rt_entry->dwDestaddr == dwAddress) &&
  50. (rt_entry->dwNetmask == dwNetmask)) {
  51. break;
  52. }
  53. prev_rt_entry = rt_entry;
  54. rt_entry = rt_entry->next;
  55. }
  56. if (rt_entry == NULL) {
  57. // entry was not found, so allocate a new one
  58. rt_entry = malloc(sizeof(HASH_TABLE_ENTRY));
  59. if (rt_entry == NULL) {
  60. dbgprintf("could not allocate memory for routing-table entry");
  61. }
  62. else {
  63. rt_entry->next = NULL;
  64. rt_entry->dwFlag = NEW_ENTRY;
  65. rt_entry->dwIndex = dwIndex;
  66. rt_entry->dwProtocol = IRE_PROTO_RIP;
  67. rt_entry->dwDestaddr = dwAddress;
  68. if (prev_rt_entry != NULL) {
  69. rt_entry->prev = prev_rt_entry;
  70. prev_rt_entry->next = rt_entry;
  71. }
  72. else {
  73. rt_entry->prev = NULL;
  74. g_ripcfg.lpRouteTable[hashval] = rt_entry;
  75. }
  76. InterlockedIncrement(&g_ripcfg.lpStatsTable->dwRouteCount);
  77. }
  78. }
  79. RIP_UNLOCK_ROUTETABLE();
  80. // check_rt_entries();
  81. return rt_entry;
  82. }
  83. //-----------------------------------------------------------------------------
  84. // Function: RouteTableEntryExists
  85. //
  86. // This function returns TRUE if an entry to the specified address
  87. // exists with the specified index.
  88. //-----------------------------------------------------------------------------
  89. BOOL RouteTableEntryExists(DWORD dwIndex, DWORD dwAddress) {
  90. INT hashval;
  91. LPHASH_TABLE_ENTRY rt_entry;
  92. hashval = HASH_VALUE(dwAddress);
  93. RIP_LOCK_ROUTETABLE();
  94. rt_entry = g_ripcfg.lpRouteTable[hashval];
  95. while (rt_entry != NULL) {
  96. if (rt_entry->dwDestaddr == dwAddress) {
  97. break;
  98. }
  99. rt_entry = rt_entry->next;
  100. }
  101. RIP_UNLOCK_ROUTETABLE();
  102. return (rt_entry == NULL ? FALSE : TRUE);
  103. }
  104. //-----------------------------------------------------------------------------
  105. // Function: AddZombieRouteTableEntry
  106. //
  107. // This function adds a special route-table entry known as a Zombie
  108. // route entry. In the case of border gateways which summarize attached
  109. // subnets and send a single entry for the network, and in the case
  110. // of routers whose interfaces have different subnet masks, the destination
  111. // that RIP will send will be different from the destination in RIP's table.
  112. // This makes it possible for the destination to get bounced back at RIP by
  113. // some other router; RIP would then add an entry for the bogus route, and
  114. // advertise the route back again, and a count to infinity would commence.
  115. //
  116. // Zombie entries exist to prevent this from happening:
  117. // they have metrics of zero, so they will not be replaced
  118. // by RIP-learnt routes (all of which have a metric of at least 1);
  119. // they are excluded from updates sent
  120. // they are excluded from updates written to the system routing table
  121. // they can be timed-out
  122. // The above conditions ensure that zombies do not interfere with the working
  123. // of RIP, EXCEPT in the case where they prevent RIP from adding a normal entry
  124. // for a route which was summarized in a previous update and which is therefore
  125. // not really a RIP route at all.
  126. //-----------------------------------------------------------------------------
  127. DWORD AddZombieRouteTableEntry(LPRIP_ADDRESS lpaddr, DWORD dwNetwork,
  128. DWORD dwNetmask) {
  129. LPHASH_TABLE_ENTRY rt_entry;
  130. rt_entry = GetRouteTableEntry(lpaddr->dwIndex, dwNetwork, dwNetmask);
  131. if (rt_entry == NULL) {
  132. dbgprintf("could not make entry for network in routing table");
  133. return ERROR_NOT_ENOUGH_MEMORY;
  134. }
  135. // don't want to overwrite an existing entry, if there is one
  136. if ((rt_entry->dwFlag & NEW_ENTRY) == 0 &&
  137. (rt_entry->dwFlag & ROUTE_ZOMBIE) == 0) {
  138. return 0;
  139. }
  140. // since the only reason this entry exists is because a
  141. // subnet we are sending is being summarized or truncated, we have to
  142. // set up values to make sure this entry is not considered in
  143. // normal processing; (e.g. metric of 0 to make sure it is not
  144. // replaced by a RIP-learnt route)
  145. // however, we do allow it to be timed out
  146. rt_entry->dwIndex = (DWORD)~0;
  147. rt_entry->dwFlag = (GARBAGE_TIMER | ROUTE_ZOMBIE);
  148. rt_entry->lTimeout = (LONG)DEF_GARBAGETIMEOUT;
  149. rt_entry->dwDestaddr = dwNetwork;
  150. rt_entry->dwNetmask = dwNetmask;
  151. rt_entry->dwNexthop = 0;
  152. rt_entry->dwProtocol = IRE_PROTO_OTHER;
  153. rt_entry->dwMetric = 0;
  154. return 0;
  155. }
  156. //-----------------------------------------------------------------------------
  157. // Function: DeleteRouteTableEntry
  158. //
  159. // This function removes a route from the route table. Assumes
  160. // that the route table is already locked
  161. //-----------------------------------------------------------------------------
  162. VOID DeleteRouteTableEntry(int pos, LPHASH_TABLE_ENTRY rt_entry) {
  163. IN_ADDR addr;
  164. CHAR szDest[32] = {0};
  165. CHAR* pszTemp;
  166. if (rt_entry == NULL) { return; }
  167. addr.s_addr = rt_entry->dwDestaddr;
  168. pszTemp = inet_ntoa(addr);
  169. if (pszTemp != NULL) {
  170. strcpy(szDest, pszTemp);
  171. }
  172. dbgprintf("Removing entry %d with destination IP address %s "
  173. "from interface %d in RIP routing table",
  174. pos, szDest, rt_entry->dwIndex);
  175. if (rt_entry->prev != NULL) {
  176. rt_entry->prev->next = rt_entry->next;
  177. if (rt_entry->next != NULL) {
  178. rt_entry->next->prev = rt_entry->prev;
  179. }
  180. }
  181. else {
  182. g_ripcfg.lpRouteTable[pos] = rt_entry->next;
  183. if (rt_entry->next != NULL) {
  184. rt_entry->next->prev = NULL;
  185. }
  186. }
  187. InterlockedDecrement(&g_ripcfg.lpStatsTable->dwRouteCount);
  188. // delete the route from the IP table as well
  189. if ((rt_entry->dwFlag & ROUTE_ZOMBIE) == 0) {
  190. UpdateSystemRouteTable(rt_entry, FALSE);
  191. }
  192. free(rt_entry);
  193. return;
  194. }
  195. void check_rt_entries() {
  196. int pos;
  197. LPHASH_TABLE_ENTRY rt_entry;
  198. LPHASH_TABLE_ENTRY prev_rt_entry = NULL ;
  199. RIP_LOCK_ROUTETABLE();
  200. for (pos = 0; pos < HASH_TABLE_SIZE; pos++) {
  201. rt_entry = g_ripcfg.lpRouteTable[pos];
  202. while (rt_entry != NULL) {
  203. if (rt_entry == rt_entry->next) {
  204. DebugBreak();
  205. }
  206. if (rt_entry == rt_entry->prev) {
  207. DebugBreak();
  208. }
  209. if (rt_entry->prev != NULL) {
  210. if (rt_entry->prev != prev_rt_entry) {
  211. DebugBreak();
  212. }
  213. }
  214. prev_rt_entry = rt_entry;
  215. rt_entry = rt_entry->next;
  216. }
  217. }
  218. RIP_UNLOCK_ROUTETABLE();
  219. return;
  220. }
  221. //-----------------------------------------------------------------------------
  222. // Function: ProcessRouteTableChanges
  223. //
  224. // Process the changes, updating metrics for routes. If necessary,
  225. // this function will trigger an update.
  226. // Assumes address table is locked.
  227. //-----------------------------------------------------------------------------
  228. void ProcessRouteTableChanges(BOOL bTriggered) {
  229. int pos;
  230. BOOL bNeedTriggeredUpdate;
  231. LPHASH_TABLE_ENTRY rt_entry;
  232. DWORD dwLastTrigger, dwMsecsTillUpdate;
  233. DWORD dwSystime, dwSilentRIP, dwTrigger, dwTriggerFrequency;
  234. // check_rt_entries();
  235. RIP_LOCK_PARAMS();
  236. dwSilentRIP = g_params.dwSilentRIP;
  237. dwTrigger = g_params.dwTriggeredUpdates;
  238. dwTriggerFrequency = g_params.dwMaxTriggerFrequency;
  239. RIP_UNLOCK_PARAMS();
  240. RIP_LOCK_ROUTETABLE();
  241. bNeedTriggeredUpdate = FALSE;
  242. for (pos = 0; pos < HASH_TABLE_SIZE; pos++) {
  243. rt_entry = g_ripcfg.lpRouteTable[pos];
  244. while (rt_entry != NULL) {
  245. if ((rt_entry->dwFlag & ROUTE_CHANGE) == 0 &&
  246. (rt_entry->dwFlag & ROUTE_UPDATE) == 0) {
  247. rt_entry = rt_entry->next;
  248. continue;
  249. }
  250. if ((rt_entry->dwFlag & ROUTE_CHANGE) != 0) {
  251. bNeedTriggeredUpdate = TRUE;
  252. }
  253. // update if this is a RIP-learnt route
  254. if (rt_entry->dwProtocol == IRE_PROTO_RIP) {
  255. UpdateSystemRouteTable(rt_entry, TRUE);
  256. }
  257. // clear the update flag, now that the route
  258. // has been updated in the system table
  259. rt_entry->dwFlag &= ~ROUTE_UPDATE;
  260. rt_entry = rt_entry->next;
  261. }
  262. }
  263. dwSystime = GetTickCount();
  264. dwLastTrigger = g_ripcfg.dwLastTriggeredUpdate;
  265. dwMsecsTillUpdate = g_ripcfg.dwMillisecsTillFullUpdate;
  266. // adjust the times if the clock has wrapped around past zero
  267. if (dwSystime < dwLastTrigger) {
  268. dwSystime += (DWORD)~0 - dwLastTrigger;
  269. dwLastTrigger = 0;
  270. }
  271. // we generate a triggered update iff:
  272. // 1. this call was made because of a response received
  273. // 2. we are not in silent RIP mode
  274. // 3. triggered updates are not disabled
  275. // 4. the minimum configured interval between triggered updates
  276. // has elapsed
  277. // 5. the time till the next regular update is greater than the
  278. // configured minimum interval between triggered updates
  279. // if the system clock has wrapped around to zero, skip the condition 4;
  280. // we know the clock has wrapped around if dwSystime is less than
  281. // the last triggered update time
  282. if (bTriggered && bNeedTriggeredUpdate &&
  283. dwSilentRIP == 0 &&
  284. dwTrigger != 0 &&
  285. (dwSystime - dwLastTrigger) >= dwTriggerFrequency &&
  286. dwMsecsTillUpdate >= dwTriggerFrequency) {
  287. // update the last triggered update time
  288. InterlockedExchange(&g_ripcfg.dwLastTriggeredUpdate, GetTickCount());
  289. // send out the routing table, but only include changes
  290. BroadcastRouteTableContents(bTriggered, TRUE);
  291. }
  292. ClearChangeFlags();
  293. InterlockedExchange(&g_ripcfg.dwRouteChanged, 0);
  294. RIP_UNLOCK_ROUTETABLE();
  295. return;
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Function: ClearChangeFlags
  299. //
  300. // This function clears all the change flags in the table after an update.
  301. // Assumes that the routing table is locked.
  302. //-----------------------------------------------------------------------------
  303. VOID ClearChangeFlags() {
  304. int pos;
  305. LPHASH_TABLE_ENTRY rt_entry;
  306. for (pos = 0; pos < HASH_TABLE_SIZE; pos++) {
  307. rt_entry = g_ripcfg.lpRouteTable[pos];
  308. while (rt_entry != NULL) {
  309. rt_entry->dwFlag &= ~ROUTE_CHANGE;
  310. rt_entry = rt_entry->next;
  311. }
  312. }
  313. }
  314. //-----------------------------------------------------------------------------
  315. // Function: DoTimedOperations()
  316. //
  317. // This function updates the routing table entries' timers periodically,
  318. // and handles deletion of timed-out routes.
  319. //-----------------------------------------------------------------------------
  320. VOID DoTimedOperations(DWORD dwMillisecsSinceLastCall) {
  321. int pos;
  322. IN_ADDR addr;
  323. DWORD dwGarbageTimeout;
  324. HASH_TABLE_ENTRY *rt_entry;
  325. HASH_TABLE_ENTRY *rt_entry_next;
  326. char szDest[32] = {0};
  327. char szNexthop[32] = {0};
  328. char* pszTemp;
  329. // read the garbage timeout and adjust for number of times
  330. // this routine will be called over the interval
  331. RIP_LOCK_PARAMS();
  332. dwGarbageTimeout = g_params.dwGarbageTimeout;
  333. RIP_UNLOCK_PARAMS();
  334. RIP_LOCK_ROUTETABLE();
  335. for (pos = 0; pos < HASH_TABLE_SIZE; pos++) {
  336. rt_entry = g_ripcfg.lpRouteTable[pos];
  337. while (rt_entry != NULL) {
  338. rt_entry_next = rt_entry->next;
  339. if (rt_entry->lTimeout > (LONG)dwMillisecsSinceLastCall) {
  340. rt_entry->lTimeout -= dwMillisecsSinceLastCall;
  341. }
  342. else {
  343. // timeout is all the way down
  344. addr.s_addr = rt_entry->dwDestaddr;
  345. pszTemp = inet_ntoa(addr);
  346. if (pszTemp != NULL) {
  347. strcpy(szDest, pszTemp);
  348. }
  349. addr.s_addr = rt_entry->dwNexthop;
  350. pszTemp = inet_ntoa(addr);
  351. if (pszTemp != NULL) {
  352. strcpy(szNexthop, pszTemp);
  353. }
  354. if (rt_entry->dwFlag & TIMEOUT_TIMER) {
  355. dbgprintf("Timing out route to %s over netcard %d, "
  356. "with next hop of %s",
  357. szDest, rt_entry->dwIndex, szNexthop);
  358. rt_entry->lTimeout = (LONG)dwGarbageTimeout;
  359. rt_entry->dwFlag &= ~TIMEOUT_TIMER;
  360. rt_entry->dwFlag |= (GARBAGE_TIMER | ROUTE_CHANGE);
  361. rt_entry->dwMetric = METRIC_INFINITE;
  362. InterlockedExchange(&g_ripcfg.dwRouteChanged, 1);
  363. }
  364. else
  365. if (rt_entry->dwFlag & GARBAGE_TIMER) {
  366. // time to delete this
  367. addr.s_addr = rt_entry->dwDestaddr;
  368. pszTemp = inet_ntoa(addr);
  369. if (pszTemp != NULL) {
  370. strcpy(szDest, pszTemp);
  371. }
  372. dbgprintf("Deleting route to %s over netcard %d "
  373. "with next hop of %s",
  374. szDest, rt_entry->dwIndex, szNexthop);
  375. DeleteRouteTableEntry(pos, rt_entry);
  376. }
  377. }
  378. rt_entry = rt_entry_next;
  379. }
  380. }
  381. RIP_UNLOCK_ROUTETABLE();
  382. return;
  383. }
  384. DWORD BroadcastRouteTableRequests() {
  385. INT iErr;
  386. DWORD dwSize;
  387. LPRIP_ENTRY lpentry;
  388. SOCKADDR_IN destaddr;
  389. LPRIP_HEADER lpheader;
  390. BYTE buffer[RIP_MESSAGE_SIZE];
  391. LPRIP_ADDRESS lpaddr, lpend;
  392. RIP_LOCK_ADDRTABLE();
  393. if (g_ripcfg.dwAddrCount > 0) {
  394. destaddr.sin_family = AF_INET;
  395. destaddr.sin_port = htons(RIP_PORT);
  396. lpheader = (LPRIP_HEADER)buffer;
  397. lpheader->chCommand = RIP_REQUEST;
  398. lpheader->wReserved = 0;
  399. lpentry = (LPRIP_ENTRY)(buffer + sizeof(RIP_HEADER));
  400. lpentry->dwAddress = 0;
  401. lpentry->wReserved = 0;
  402. lpentry->wAddrFamily = 0;
  403. lpentry->dwReserved1 = 0;
  404. lpentry->dwReserved2 = 0;
  405. lpentry->dwMetric = htonl(METRIC_INFINITE);
  406. dwSize = sizeof(RIP_HEADER) + sizeof(RIP_ENTRY);
  407. lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
  408. for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
  409. // skip disabled interfaces
  410. if (lpaddr->sock == INVALID_SOCKET) {
  411. continue;
  412. }
  413. // send out broadcast requests as RIPv1 packets
  414. lpheader->chVersion = 1;
  415. // set the destination to the broadcast address on this subnet
  416. destaddr.sin_addr.s_addr = (lpaddr->dwAddress |
  417. ~lpaddr->dwNetmask);
  418. iErr = sendto(lpaddr->sock, buffer, dwSize, 0,
  419. (LPSOCKADDR)&destaddr, sizeof(SOCKADDR_IN));
  420. if (iErr == SOCKET_ERROR) {
  421. dbgprintf("error %d occurred broadcasting route table request "
  422. "on netcard %d using IP address %s",
  423. WSAGetLastError(), lpaddr->dwIndex,
  424. inet_ntoa(destaddr.sin_addr));
  425. InterlockedIncrement(&lpaddr->lpstats->dwSendFailures);
  426. RipLogInformation(RIPLOG_SENDTO_FAILED, 0, NULL, WSAGetLastError());
  427. }
  428. else {
  429. InterlockedIncrement(&lpaddr->lpstats->dwRequestsSent);
  430. }
  431. // send out multicast requests as RIPv2 packets
  432. lpheader->chVersion = 2;
  433. // set the destination to the RIP multicast address on this net
  434. destaddr.sin_addr.s_addr = RIP_MULTIADDR;
  435. iErr = sendto(lpaddr->sock, buffer, dwSize, 0,
  436. (LPSOCKADDR)&destaddr, sizeof(SOCKADDR_IN));
  437. if (iErr == SOCKET_ERROR) {
  438. dbgprintf("error %d occurred multicasting route table request "
  439. "on netcard %d using IP address %s",
  440. WSAGetLastError(), lpaddr->dwIndex,
  441. inet_ntoa(destaddr.sin_addr));
  442. InterlockedIncrement(&lpaddr->lpstats->dwSendFailures);
  443. RipLogInformation(RIPLOG_SENDTO_FAILED, 0, NULL, WSAGetLastError());
  444. }
  445. else {
  446. InterlockedIncrement(&lpaddr->lpstats->dwRequestsSent);
  447. }
  448. }
  449. }
  450. RIP_UNLOCK_ADDRTABLE();
  451. return 0;
  452. }
  453. VOID InitUpdateBuffer(BYTE buffer[], LPRIP_ENTRY *lplpentry, LPDWORD lpdwSize) {
  454. LPRIP_HEADER lpheader;
  455. lpheader = (LPRIP_HEADER)buffer;
  456. lpheader->chCommand = RIP_RESPONSE;
  457. lpheader->chVersion = 1;
  458. lpheader->wReserved = 0;
  459. *lplpentry = (LPRIP_ENTRY)(buffer + sizeof(RIP_HEADER));
  460. *lpdwSize= sizeof(RIP_HEADER);
  461. }
  462. VOID AddUpdateEntry(BYTE buffer[], LPRIP_ENTRY *lplpentry, LPDWORD lpdwSize,
  463. LPRIP_ADDRESS lpaddr, LPSOCKADDR_IN lpdestaddr,
  464. DWORD dwAddress, DWORD dwMetric) {
  465. DWORD length;
  466. LPRIP_ENTRY lpentry;
  467. #ifdef ROUTE_FILTERS
  468. DWORD dwInd = 0;
  469. //
  470. // run the route thru' the announce filters
  471. //
  472. if ( g_prfAnnounceFilters != NULL )
  473. {
  474. for ( dwInd = 0; dwInd < g_prfAnnounceFilters-> dwCount; dwInd++ )
  475. {
  476. if ( g_prfAnnounceFilters-> pdwFilter[ dwInd ] == dwAddress )
  477. {
  478. dbgprintf(
  479. "Skipped route %s with next hop %s because"
  480. "of announce filter",
  481. inet_ntoa( *( (struct in_addr*)
  482. &( g_prfAnnounceFilters-> pdwFilter[ dwInd ] ) ))
  483. );
  484. return;
  485. }
  486. }
  487. }
  488. #endif
  489. if ((*lpdwSize + sizeof(RIP_ENTRY)) > RIP_MESSAGE_SIZE) {
  490. length = sendto(lpaddr->sock, buffer, *lpdwSize, 0,
  491. (LPSOCKADDR)lpdestaddr, sizeof(SOCKADDR_IN));
  492. if (length == SOCKET_ERROR || length < *lpdwSize) {
  493. dbgprintf("error %d sending update", WSAGetLastError());
  494. InterlockedIncrement(&lpaddr->lpstats->dwSendFailures);
  495. RipLogInformation(RIPLOG_SENDTO_FAILED, 0, NULL, 0);
  496. }
  497. else {
  498. InterlockedIncrement(&lpaddr->lpstats->dwResponsesSent);
  499. }
  500. // reinitialize the buffer that was passed in
  501. InitUpdateBuffer(buffer, lplpentry, lpdwSize);
  502. }
  503. lpentry = *lplpentry;
  504. lpentry->wReserved = 0;
  505. lpentry->wAddrFamily = htons(AF_INET);
  506. lpentry->dwAddress = dwAddress;
  507. lpentry->dwReserved1 = 0;
  508. lpentry->dwReserved2 = 0;
  509. lpentry->dwMetric = htonl(dwMetric);
  510. *lpdwSize += sizeof(RIP_ENTRY);
  511. ++(*lplpentry);
  512. }
  513. VOID FinishUpdateBuffer(BYTE buffer[], LPDWORD lpdwSize,
  514. LPRIP_ADDRESS lpaddr, LPSOCKADDR_IN lpdestaddr) {
  515. DWORD length;
  516. // do nothing if no entries were added
  517. if (*lpdwSize <= sizeof(RIP_HEADER)) {
  518. return;
  519. }
  520. length = sendto(lpaddr->sock, buffer, *lpdwSize, 0,
  521. (LPSOCKADDR)lpdestaddr, sizeof(SOCKADDR_IN));
  522. if (length == SOCKET_ERROR || length < *lpdwSize) {
  523. dbgprintf("error %d sending update", GetLastError());
  524. InterlockedIncrement(&lpaddr->lpstats->dwSendFailures);
  525. RipLogInformation(RIPLOG_SENDTO_FAILED, 0, NULL, 0);
  526. }
  527. else {
  528. InterlockedIncrement(&lpaddr->lpstats->dwResponsesSent);
  529. }
  530. }
  531. //-------------------------------------------------------------------------
  532. // the following struct and three functions are used
  533. // to implement subnet hiding. when a subnet is summarized,
  534. // the network which is its summary is added to a list using the
  535. // function AddToAddressList. When another subnet of the same network
  536. // needs to be summarized, it is first searched for using the function
  537. // IsInAddressList, and if it is found, it is not re-advertised.
  538. // After the update is over, the list is freed.
  539. //-------------------------------------------------------------------------
  540. typedef struct _ADDRESS_LIST {
  541. struct _ADDRESS_LIST *next;
  542. DWORD dwAddress;
  543. DWORD dwNetmask;
  544. } ADDRESS_LIST, *LPADDRESS_LIST;
  545. DWORD AddToAddressList(LPADDRESS_LIST *lplpList, DWORD dwAddress,
  546. DWORD dwNetmask) {
  547. LPADDRESS_LIST lpal;
  548. lpal = HeapAlloc(GetProcessHeap(), 0, sizeof(ADDRESS_LIST));
  549. if (lpal == NULL) { return ERROR_NOT_ENOUGH_MEMORY; }
  550. lpal->dwAddress = dwAddress;
  551. lpal->dwNetmask = dwNetmask;
  552. lpal->next = *lplpList;
  553. *lplpList = lpal;
  554. return 0;
  555. }
  556. BOOL IsInAddressList(LPADDRESS_LIST lpList, DWORD dwAddress) {
  557. LPADDRESS_LIST lpal;
  558. for (lpal = lpList; lpal != NULL; lpal = lpal->next) {
  559. if (lpal->dwAddress == dwAddress) {
  560. return TRUE;
  561. }
  562. }
  563. return FALSE;
  564. }
  565. VOID FreeAddressList(LPADDRESS_LIST lpList) {
  566. LPADDRESS_LIST lpal, lpnext;
  567. for (lpal = lpList; lpal != NULL; lpal = lpnext) {
  568. lpnext = lpal->next;
  569. HeapFree(GetProcessHeap(), 0, lpal);
  570. }
  571. }
  572. //-----------------------------------------------------------------------------
  573. // Function: TransmitRouteTableContents
  574. //
  575. // Sends the route tables contents, either as unicast or broadcast
  576. // depending on the destination address specified. This function assumes
  577. // that the address table is locked.
  578. //-----------------------------------------------------------------------------
  579. VOID TransmitRouteTableContents(LPRIP_ADDRESS lpaddr,
  580. LPSOCKADDR_IN lpdestaddr,
  581. BOOL bChangesOnly) {
  582. INT pos;
  583. DWORD dwSize;
  584. LPADDRESS_LIST lpnet, lpSummaries;
  585. LPRIP_ENTRY lpentry;
  586. LPHASH_TABLE_ENTRY rt_entry;
  587. BYTE buffer[RIP_MESSAGE_SIZE];
  588. DWORD dwNexthopNetaddr, dwDestNetaddr;
  589. DWORD dwSplit, dwPoison, dwHost, dwDefault;
  590. DWORD dwDestNetclassMask, dwEntryNetclassMask;
  591. DWORD dwEntryAddr, dwDestNetclassAddr, dwEntryNetclassAddr;
  592. dwDestNetaddr = (lpdestaddr->sin_addr.s_addr &
  593. SubnetMask(lpdestaddr->sin_addr.s_addr));
  594. dwDestNetclassMask = NetclassMask(lpdestaddr->sin_addr.s_addr);
  595. dwDestNetclassAddr = (lpdestaddr->sin_addr.s_addr & dwDestNetclassMask);
  596. RIP_LOCK_PARAMS();
  597. dwHost = g_params.dwAnnounceHost;
  598. dwSplit = g_params.dwSplitHorizon;
  599. dwPoison = g_params.dwPoisonReverse;
  600. dwDefault = g_params.dwAnnounceDefault;
  601. RIP_UNLOCK_PARAMS();
  602. InitUpdateBuffer(buffer, &lpentry, &dwSize);
  603. // start out with an empty list of summarized networks
  604. lpSummaries = NULL;
  605. RIP_LOCK_ROUTETABLE();
  606. #ifdef ROUTE_FILTERS
  607. RIP_LOCK_ANNOUNCE_FILTERS();
  608. #endif
  609. for (pos = 0; pos < HASH_TABLE_SIZE; pos++) {
  610. rt_entry = g_ripcfg.lpRouteTable[pos];
  611. while (rt_entry != NULL) {
  612. // if we're supposed to only send changes
  613. // and this entry hasn't changed, skip it
  614. if (bChangesOnly &&
  615. (rt_entry->dwFlag & ROUTE_CHANGE) == 0) {
  616. rt_entry = rt_entry->next;
  617. continue;
  618. }
  619. // ignore network summary entries
  620. if ((rt_entry->dwFlag & ROUTE_ZOMBIE) != 0) {
  621. rt_entry = rt_entry->next;
  622. continue;
  623. }
  624. // copy the destination to be advertised
  625. dwEntryAddr = rt_entry->dwDestaddr;
  626. // if this is the route to the network for the outgoing interface
  627. // don't send it
  628. //
  629. if (dwEntryAddr == dwDestNetaddr) {
  630. rt_entry = rt_entry->next;
  631. continue;
  632. }
  633. // if host route announcements are disabled,
  634. // and this is a host route, don't add this entry
  635. if (dwHost == 0 &&
  636. (rt_entry->dwFlag & ROUTE_HOST) != 0) {
  637. rt_entry = rt_entry->next;
  638. continue;
  639. }
  640. // if default route announcements are disabled
  641. // and this is a default route, don't add this entry
  642. if (dwDefault == 0 &&
  643. dwEntryAddr == 0) {
  644. rt_entry = rt_entry->next;
  645. continue;
  646. }
  647. // if this update is being sent to a network different
  648. // from the network of the destination in the route entry,
  649. // or if the destination was truncated due to different
  650. // subnetmask lengths, summarize the route entry's destination,
  651. // also, if the entry is network route, we need
  652. // to remember it so we don't re-advertise it when
  653. // summarizing subnets
  654. dwEntryNetclassMask = NetclassMask(dwEntryAddr);
  655. dwEntryNetclassAddr = (dwEntryAddr & dwEntryNetclassMask);
  656. // special case exception is default route
  657. if (dwEntryAddr != 0 &&
  658. (dwDestNetclassAddr != dwEntryNetclassAddr ||
  659. dwEntryAddr == dwEntryNetclassAddr)) {
  660. // if the network for the entry has already been
  661. // advertised, don't advertise it again
  662. if (IsInAddressList(lpSummaries, dwEntryNetclassAddr)) {
  663. rt_entry = rt_entry->next;
  664. continue;
  665. }
  666. // add an entry for the network to the list
  667. // of networks used as summaries so far
  668. AddToAddressList(&lpSummaries, dwEntryNetclassAddr,
  669. dwEntryNetclassMask);
  670. // now we will advertise the NETWORK, not the original address
  671. dwEntryAddr = dwEntryNetclassAddr;
  672. }
  673. else
  674. if (dwEntryAddr != 0 &&
  675. (rt_entry->dwFlag & ROUTE_HOST) == 0 &&
  676. lpaddr->dwNetmask < rt_entry->dwNetmask) {
  677. // this is neither a host route nor a default route
  678. // and the subnet mask on the outgoing interface
  679. // is shorter than the one for the entry, so the entry
  680. // must be truncated so it is not considered a host route
  681. // by the routers who will receive this update
  682. // the comparison assumes netmasks are in network byte order
  683. dwEntryAddr &= lpaddr->dwNetmask;
  684. // skip the entry if the truncated destination
  685. // turns out to have been advertised already
  686. if (IsInAddressList(lpSummaries, dwEntryAddr)) {
  687. rt_entry = rt_entry->next;
  688. continue;
  689. }
  690. AddToAddressList(&lpSummaries, dwEntryAddr, lpaddr->dwNetmask);
  691. }
  692. // we only do poisoned-reverse/split-horizon on RIP routes
  693. //
  694. if (dwSplit == 0 ||
  695. rt_entry->dwProtocol != IRE_PROTO_RIP) {
  696. // always add the entry in this case;
  697. // we increment the metric for a static route
  698. // when sending it on interfaces other than
  699. // the interface to which the route is attached
  700. if (lpaddr->dwIndex == rt_entry->dwIndex) {
  701. AddUpdateEntry(buffer, &lpentry, &dwSize, lpaddr,
  702. lpdestaddr, dwEntryAddr,
  703. rt_entry->dwMetric);
  704. }
  705. else {
  706. AddUpdateEntry(buffer, &lpentry, &dwSize, lpaddr,
  707. lpdestaddr, dwEntryAddr,
  708. rt_entry->dwMetric + 1);
  709. }
  710. }
  711. else
  712. if (dwSplit != 0 && dwPoison == 0) {
  713. // don't advertise the route if this update is
  714. // being sent to the network from which we learnt
  715. // the route; we can tell by looking at the nexthop,
  716. // and comparing its subnet number to the subnet number
  717. // of the destination network
  718. dwNexthopNetaddr = (rt_entry->dwNexthop &
  719. SubnetMask(rt_entry->dwNexthop));
  720. if (dwNexthopNetaddr != dwDestNetaddr) {
  721. AddUpdateEntry(buffer, &lpentry, &dwSize, lpaddr,
  722. lpdestaddr, dwEntryAddr,
  723. rt_entry->dwMetric);
  724. }
  725. }
  726. else
  727. if (dwSplit != 0 && dwPoison != 0) {
  728. // if the update is being sent to the network from which
  729. // the route was learnt to begin with, poison any routing loops
  730. // by saying the metric is infinite
  731. dwNexthopNetaddr = (rt_entry->dwNexthop &
  732. SubnetMask(rt_entry->dwNexthop));
  733. if (dwNexthopNetaddr == dwDestNetaddr) {
  734. // this is the case which calls for poison reverse
  735. AddUpdateEntry(buffer, &lpentry, &dwSize, lpaddr,
  736. lpdestaddr, dwEntryAddr,
  737. METRIC_INFINITE);
  738. }
  739. else {
  740. AddUpdateEntry(buffer, &lpentry, &dwSize, lpaddr,
  741. lpdestaddr, dwEntryAddr,
  742. rt_entry->dwMetric);
  743. }
  744. }
  745. rt_entry = rt_entry->next;
  746. }
  747. }
  748. // remember the summarized networks in case some router
  749. // broadcasts them back at us
  750. for (lpnet = lpSummaries; lpnet != NULL; lpnet = lpnet->next) {
  751. AddZombieRouteTableEntry(lpaddr, lpnet->dwAddress, lpnet->dwNetmask);
  752. }
  753. #ifdef ROUTE_FILTERS
  754. RIP_UNLOCK_ANNOUNCE_FILTERS();
  755. #endif
  756. RIP_UNLOCK_ROUTETABLE();
  757. // done with the list of summarized networks
  758. FreeAddressList(lpSummaries);
  759. FinishUpdateBuffer(buffer, &dwSize, lpaddr, lpdestaddr);
  760. }
  761. //-----------------------------------------------------------------------------
  762. // Function: BroadcastRouteTableContents
  763. //
  764. // This function handles both triggered updates and regular updates.
  765. // Depending on the value of bChangesOnly, it may exclude unchanged routes
  766. // from the update.
  767. // Assumes the address table is locked.
  768. //-----------------------------------------------------------------------------
  769. DWORD BroadcastRouteTableContents(BOOL bTriggered, BOOL bChangesOnly) {
  770. SOCKADDR_IN destaddr;
  771. LPRIP_ADDRESS lpaddr, lpend;
  772. destaddr.sin_family = AF_INET;
  773. destaddr.sin_port = htons(RIP_PORT);
  774. lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
  775. for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
  776. if (lpaddr->sock == INVALID_SOCKET) {
  777. continue;
  778. }
  779. destaddr.sin_addr.s_addr = (lpaddr->dwAddress | ~lpaddr->dwNetmask);
  780. TransmitRouteTableContents(lpaddr, &destaddr, bChangesOnly);
  781. if (bTriggered) {
  782. InterlockedIncrement(&lpaddr->lpstats->dwTriggeredUpdatesSent);
  783. }
  784. }
  785. return 0;
  786. }
  787. #ifndef CHICAGO
  788. #define POS_REGEVENT 0
  789. #define POS_TRIGEVENT 1
  790. #define POS_STOPEVENT 2
  791. #define POS_LASTEVENT 3
  792. #else
  793. #define POS_TRIGEVENT 0
  794. #define POS_STOPEVENT 1
  795. #define POS_LASTEVENT 2
  796. #endif
  797. #define DEF_TIMEOUT (10 * 1000)
  798. DWORD UpdateThread(LPVOID Param) {
  799. DWORD dwErr;
  800. HKEY hkeyParams;
  801. HANDLE hEvents[POS_LASTEVENT];
  802. LONG lMillisecsTillFullUpdate, lMillisecsTillRouteRefresh;
  803. DWORD dwWaitTimeout, dwGlobalTimeout;
  804. DWORD dwTickCount, dwTickCountBeforeWait, dwTickCountAfterWait;
  805. DWORD dwUpdateFrequency, dwSilentRIP, dwMillisecsSinceTimedOpsDone;
  806. #ifndef CHICAGO
  807. dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_RIP_PARAMS, &hkeyParams);
  808. if (dwErr == ERROR_SUCCESS) {
  809. hEvents[POS_REGEVENT] = CreateEvent(NULL,FALSE,FALSE,NULL);
  810. if (hEvents[POS_REGEVENT] != NULL) {
  811. dwErr = RegNotifyChangeKeyValue(hkeyParams, FALSE,
  812. REG_NOTIFY_CHANGE_LAST_SET |
  813. REG_NOTIFY_CHANGE_ATTRIBUTES |
  814. REG_NOTIFY_CHANGE_NAME,
  815. hEvents[POS_REGEVENT], TRUE);
  816. }
  817. }
  818. #endif
  819. hEvents[POS_STOPEVENT] = g_stopEvent;
  820. hEvents[POS_TRIGEVENT] = g_triggerEvent;
  821. // get the update frequency, in seconds
  822. RIP_LOCK_PARAMS();
  823. dwSilentRIP = g_params.dwSilentRIP;
  824. dwUpdateFrequency = g_params.dwUpdateFrequency;
  825. dwGlobalTimeout = g_params.dwMaxTimedOpsInterval;
  826. RIP_UNLOCK_PARAMS();
  827. lMillisecsTillFullUpdate = (LONG)dwUpdateFrequency;
  828. lMillisecsTillRouteRefresh = DEF_GETROUTEFREQUENCY;
  829. dwMillisecsSinceTimedOpsDone = 0;
  830. while (1) {
  831. // set the time till the next full update
  832. InterlockedExchange(&g_ripcfg.dwMillisecsTillFullUpdate,
  833. (DWORD)lMillisecsTillFullUpdate);
  834. // set the time we need the next wait to last;
  835. // it has to be the minimum of the times till there is work to do;
  836. // uses a two-comparison sort to find the smallest of three items
  837. dwWaitTimeout = dwGlobalTimeout;
  838. if (dwWaitTimeout > (DWORD)lMillisecsTillFullUpdate) {
  839. dwWaitTimeout = lMillisecsTillFullUpdate;
  840. }
  841. if (dwWaitTimeout > (DWORD)lMillisecsTillRouteRefresh) {
  842. dwWaitTimeout = lMillisecsTillRouteRefresh;
  843. }
  844. // get the time before entering the wait
  845. dwTickCountBeforeWait = GetTickCount();
  846. // enter the wait
  847. //---------------
  848. dwErr = WaitForMultipleObjects(POS_LASTEVENT, hEvents, FALSE,
  849. dwWaitTimeout) ;
  850. dwTickCountAfterWait = GetTickCount();
  851. // we have to find out how long the wait lasted, taking care
  852. // in case the system timer wrapped around to zero
  853. if (dwTickCountAfterWait < dwTickCountBeforeWait) {
  854. dwTickCountAfterWait += (DWORD)~0 - dwTickCountBeforeWait;
  855. dwTickCountBeforeWait = 0;
  856. }
  857. dwTickCount = dwTickCountAfterWait - dwTickCountBeforeWait;
  858. dwMillisecsSinceTimedOpsDone += dwTickCount;
  859. // wait returned, now see why
  860. //---------------------------
  861. if (dwErr == WAIT_TIMEOUT) {
  862. // every minute we read local routes again -
  863. // this is to deal with somebody adding
  864. // static routes. note that deleted static routes
  865. // get deleted every 90 seconds.
  866. lMillisecsTillRouteRefresh -= dwWaitTimeout;
  867. if (lMillisecsTillRouteRefresh <= 0) {
  868. lMillisecsTillRouteRefresh = DEF_GETROUTEFREQUENCY;
  869. }
  870. // ProcessRouteTableChanges and BroadcastRouteTableContents
  871. // both assume the address table is locked; lock it before
  872. // doing timed operations, too, for good measure
  873. RIP_LOCK_ADDRTABLE();
  874. // update timers, passing the number of milliseconds
  875. // since we last called DoTimedOperations
  876. DoTimedOperations(dwMillisecsSinceTimedOpsDone);
  877. dwMillisecsSinceTimedOpsDone = 0;
  878. // if anything changed, process the changes
  879. // but tell the function not to send update packets
  880. if (g_ripcfg.dwRouteChanged != 0) {
  881. ProcessRouteTableChanges(FALSE);
  882. }
  883. // update the time till the next update,
  884. // and send the update if it is due
  885. lMillisecsTillFullUpdate -= dwWaitTimeout;
  886. if (lMillisecsTillFullUpdate <= 0) {
  887. lMillisecsTillFullUpdate = dwUpdateFrequency;
  888. // send out the periodic update
  889. if (dwSilentRIP == 0) {
  890. // this is not triggered, and we need to broadcast
  891. // the entire table, instead of just the changes
  892. BroadcastRouteTableContents(FALSE, FALSE);
  893. }
  894. }
  895. RIP_UNLOCK_ADDRTABLE();
  896. // this continue is here because there is some processing
  897. // done below for the cases where the wait is interrupted
  898. // before it could timeout; this skips that code
  899. //----------------------------------------------
  900. continue;
  901. }
  902. else
  903. #ifndef CHICAGO
  904. if (dwErr == WAIT_OBJECT_0 + POS_REGEVENT) {
  905. // registry was changed
  906. LoadParameters();
  907. // get the update frequency, converted to milliseconds
  908. RIP_LOCK_PARAMS();
  909. dwSilentRIP = g_params.dwSilentRIP;
  910. dwUpdateFrequency = g_params.dwUpdateFrequency;
  911. dwGlobalTimeout = g_params.dwMaxTimedOpsInterval;
  912. RIP_UNLOCK_PARAMS();
  913. RegNotifyChangeKeyValue(hkeyParams, FALSE,
  914. REG_NOTIFY_CHANGE_LAST_SET |
  915. REG_NOTIFY_CHANGE_ATTRIBUTES |
  916. REG_NOTIFY_CHANGE_NAME,
  917. hEvents[POS_REGEVENT], TRUE);
  918. }
  919. else
  920. #endif
  921. if (dwErr == WAIT_OBJECT_0 + POS_TRIGEVENT) {
  922. RIP_LOCK_ADDRTABLE();
  923. ProcessRouteTableChanges(TRUE);
  924. RIP_UNLOCK_ADDRTABLE();
  925. }
  926. else
  927. if (dwErr == WAIT_OBJECT_0 + POS_STOPEVENT) {
  928. // perform graceful shutdown
  929. //
  930. // first, set all metrics to METRIC_INFINITE - 1
  931. // next, send out four full updates at intervals
  932. // of between 2 and 4 seconds
  933. int pos;
  934. LPHASH_TABLE_ENTRY rt_entry;
  935. RIP_LOCK_ADDRTABLE();
  936. RIP_LOCK_ROUTETABLE();
  937. dbgprintf("sending out final updates.");
  938. // setting metrics to 15
  939. for (pos = 0; pos < HASH_TABLE_SIZE; pos++) {
  940. rt_entry = g_ripcfg.lpRouteTable[pos];
  941. while (rt_entry != NULL) {
  942. if (rt_entry->dwMetric != METRIC_INFINITE) {
  943. rt_entry->dwMetric = METRIC_INFINITE - 1;
  944. }
  945. rt_entry = rt_entry->next;
  946. }
  947. }
  948. // sending out final full updates
  949. if (dwSilentRIP == 0) {
  950. srand((unsigned)time(NULL));
  951. for (pos = 0; pos < 4; pos++) {
  952. BroadcastRouteTableContents(FALSE, FALSE);
  953. Sleep(2000 + (int)((double)rand() / RAND_MAX * 2000.0));
  954. }
  955. }
  956. RIP_UNLOCK_ROUTETABLE();
  957. RIP_UNLOCK_ADDRTABLE();
  958. // break out of the infinite loop
  959. #ifndef CHICAGO
  960. CloseHandle(hEvents[POS_REGEVENT]);
  961. #endif
  962. break;
  963. }
  964. // these are only executed if the wait ended
  965. // for some reason other than a timeout;
  966. //--------------------------------------
  967. lMillisecsTillFullUpdate -= min(lMillisecsTillFullUpdate,
  968. (LONG)dwTickCount);
  969. lMillisecsTillRouteRefresh -= min(lMillisecsTillRouteRefresh,
  970. (LONG)dwTickCount);
  971. //
  972. // Make sure DoTimedOperations() runs at least every
  973. // MaxTimedOpsInterval seconds.
  974. // We grab the address table lock for good measure.
  975. //
  976. if (dwMillisecsSinceTimedOpsDone >= g_params.dwMaxTimedOpsInterval) {
  977. RIP_LOCK_ADDRTABLE();
  978. DoTimedOperations(dwMillisecsSinceTimedOpsDone);
  979. dwMillisecsSinceTimedOpsDone = 0;
  980. // if anything changed, process the changes
  981. // but tell the function not to send update packets
  982. if (g_ripcfg.dwRouteChanged != 0) {
  983. ProcessRouteTableChanges(FALSE);
  984. }
  985. RIP_UNLOCK_ADDRTABLE();
  986. }
  987. }
  988. dbgprintf("update thread stopping.");
  989. #ifndef CHICAGO
  990. FreeLibraryAndExitThread(g_hmodule, 0);
  991. #endif
  992. return(0);
  993. }
  994. //-----------------------------------------------------------------------------
  995. // Function: CleanupRouteTable
  996. //
  997. // Called at shutdown time - runs through all the routes in the route table
  998. // deleting from the system the routes that were learnt through RIP.
  999. //-----------------------------------------------------------------------------
  1000. VOID CleanupRouteTable() {
  1001. INT pos;
  1002. LPHASH_TABLE_ENTRY rt_entry, prev_rt_entry;
  1003. RIP_LOCK_ROUTETABLE();
  1004. // Walk the whole hash table - deleting all RIP added routes
  1005. // from each bucket
  1006. dbgprintf("deleting RIP routes from system table.");
  1007. for (pos = 0; pos < HASH_TABLE_SIZE; pos++) {
  1008. prev_rt_entry = rt_entry = g_ripcfg.lpRouteTable[pos];
  1009. while (rt_entry != NULL) {
  1010. prev_rt_entry = rt_entry;
  1011. rt_entry = rt_entry->next;
  1012. if (prev_rt_entry->dwProtocol == IRE_PROTO_RIP) {
  1013. // remove the route from IP's routing table
  1014. UpdateSystemRouteTable(prev_rt_entry, FALSE);
  1015. }
  1016. free(prev_rt_entry);
  1017. }
  1018. g_ripcfg.lpRouteTable[pos] = NULL;
  1019. }
  1020. RIP_UNLOCK_ROUTETABLE();
  1021. // if a route dump was made to shared memory, close the handle
  1022. RIP_LOCK_ADDRTABLE();
  1023. RIP_UNLOCK_ADDRTABLE();
  1024. }