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.

1920 lines
44 KiB

  1. //============================================================================
  2. // Copyright (c) 1995, Microsoft Corporation
  3. //
  4. // File: riptest.cxx
  5. //
  6. // History:
  7. // Abolade Gbadegesin Oct-16-1995 Created.
  8. //
  9. // Code for RIP test program
  10. //============================================================================
  11. extern "C" {
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <windows.h>
  16. #include <winsvc.h>
  17. #define FD_SETSIZE 256
  18. #include <winsock.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <malloc.h>
  23. #include <ipexport.h>
  24. #include <ipinfo.h>
  25. #include <llinfo.h>
  26. #include <rtm.h>
  27. #include <routprot.h>
  28. #include <mprerror.h>
  29. #include <rtutils.h>
  30. #include <ipriprm.h>
  31. #include <iprtrmib.h>
  32. #include <dim.h>
  33. #include <mprapi.h>
  34. #include <iphlpapi.h>
  35. #include "defs.h"
  36. #include "riptest.h"
  37. DWORD g_TraceID;
  38. RIPTEST_IF_CONFIG g_cfg;
  39. RIPTEST_IF_CONFIG g_def = {
  40. 50, // 50 routes
  41. 0x000000c0, // starting with 192.0.0.0
  42. 0x0000ffff, // using netmask 255.255.0.0
  43. 0x00000000, // and a next hop of 0
  44. 0x00000000, // and a route-tag of 0
  45. 0xffffffff, // sent to the broadcast address
  46. 0, // don't use a timeout to remove routes
  47. 2, // send version 2 packets
  48. 0, // random-sized packets
  49. 100, // use 100-millisecond packet gap
  50. "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", // all-zeroes authentication key
  51. IPRIP_AUTHTYPE_NONE, // no authentication
  52. 262144 // and set the send and recv buffers to this size
  53. };
  54. DWORD g_seed;
  55. RIPTEST_IF_BINDING g_bind;
  56. REG_OPTION g_options[] = {
  57. {
  58. STR_ROUTECOUNT,
  59. sizeof(DWORD),
  60. &g_cfg.RIC_RouteCount,
  61. &g_def.RIC_RouteCount,
  62. RegGetDWORD
  63. },
  64. {
  65. STR_ROUTESTART,
  66. sizeof(DWORD),
  67. &g_cfg.RIC_RouteStart,
  68. &g_def.RIC_RouteStart,
  69. RegGetAddress
  70. },
  71. {
  72. STR_ROUTEMASK,
  73. sizeof(DWORD),
  74. &g_cfg.RIC_RouteMask,
  75. &g_def.RIC_RouteMask,
  76. RegGetAddress
  77. },
  78. {
  79. STR_ROUTENEXTHOP,
  80. sizeof(DWORD),
  81. &g_cfg.RIC_RouteNexthop,
  82. &g_def.RIC_RouteNexthop,
  83. RegGetAddress
  84. },
  85. {
  86. STR_ROUTETAG,
  87. sizeof(DWORD),
  88. &g_cfg.RIC_RouteTag,
  89. &g_def.RIC_RouteTag,
  90. RegGetDWORD
  91. },
  92. {
  93. STR_ROUTETARGET,
  94. sizeof(DWORD),
  95. &g_cfg.RIC_RouteTarget,
  96. &g_def.RIC_RouteTarget,
  97. RegGetAddress
  98. },
  99. {
  100. STR_ROUTETIMEOUT,
  101. sizeof(DWORD),
  102. &g_cfg.RIC_RouteTimeout,
  103. &g_def.RIC_RouteTimeout,
  104. RegGetDWORD
  105. },
  106. {
  107. STR_PACKETVERSION,
  108. sizeof(DWORD),
  109. &g_cfg.RIC_PacketVersion,
  110. &g_def.RIC_PacketVersion,
  111. RegGetDWORD
  112. },
  113. {
  114. STR_PACKETENTRYCOUNT,
  115. sizeof(DWORD),
  116. &g_cfg.RIC_PacketEntryCount,
  117. &g_def.RIC_PacketEntryCount,
  118. RegGetDWORD
  119. },
  120. {
  121. STR_PACKETGAP,
  122. sizeof(DWORD),
  123. &g_cfg.RIC_PacketGap,
  124. &g_def.RIC_PacketGap,
  125. RegGetDWORD
  126. },
  127. {
  128. STR_AUTHKEY,
  129. IPRIP_MAX_AUTHKEY_SIZE,
  130. g_cfg.RIC_AuthKey,
  131. g_def.RIC_AuthKey,
  132. RegGetBinary
  133. },
  134. {
  135. STR_AUTHTYPE,
  136. sizeof(DWORD),
  137. &g_cfg.RIC_AuthType,
  138. &g_def.RIC_AuthType,
  139. RegGetDWORD
  140. },
  141. {
  142. STR_SOCKBUFSIZE,
  143. sizeof(DWORD),
  144. &g_cfg.RIC_SockBufSize,
  145. &g_def.RIC_SockBufSize,
  146. RegGetDWORD
  147. }
  148. };
  149. INT __cdecl
  150. main(
  151. INT iArgc,
  152. PSTR ppszArgv[]
  153. )
  154. {
  155. WSADATA wd;
  156. DWORD dwErr;
  157. //
  158. // must be at least one argument
  159. //
  160. if (iArgc != 2) {
  161. PrintUsage();
  162. return ERROR_INVALID_PARAMETER;
  163. }
  164. //
  165. // see if the user is just asking for instructions
  166. //
  167. if (strcmp(ppszArgv[1], "-?") == 0 || strcmp(ppszArgv[1], "/?") == 0) {
  168. PrintUsage();
  169. return 0;
  170. }
  171. //
  172. // first and only argument is name of interface
  173. //
  174. mbstowcs(g_bind.RIB_Netcard, ppszArgv[1], mbstowcs(NULL, ppszArgv[1], -1));
  175. //
  176. // register with the Tracing DLL
  177. //
  178. g_TraceID = PRINTREGISTER("RipTest");
  179. //
  180. // startup Winsock
  181. //
  182. dwErr = WSAStartup(MAKEWORD(1, 1), &wd);
  183. if (dwErr != NO_ERROR) {
  184. PRINTDEREGISTER(g_TraceID);
  185. return (INT)dwErr;
  186. }
  187. //
  188. // get the binding for the interface over which to send routes
  189. //
  190. dwErr = RegGetIfBinding();
  191. if (dwErr != NO_ERROR) {
  192. WSACleanup();
  193. PRINTDEREGISTER(g_TraceID);
  194. return (INT)dwErr;
  195. }
  196. //
  197. // seed the random number generator
  198. //
  199. g_seed = GetTickCount();
  200. srand(g_seed);
  201. while (TRUE) {
  202. PRINT0("\n\nbeginning test cycle...");
  203. //
  204. // get the parameters for the interface,
  205. // and quit if an error occurred or the defaults were written
  206. //
  207. dwErr = RegGetConfig();
  208. if (dwErr != NO_ERROR) { break; }
  209. //
  210. // run one test cycle
  211. //
  212. dwErr = RipTest();
  213. PRINT0("completed test cycle...");
  214. }
  215. WSACleanup();
  216. PRINTDEREGISTER(g_TraceID);
  217. return dwErr;
  218. }
  219. DWORD
  220. RegGetIfBinding(
  221. VOID
  222. )
  223. {
  224. #if 1
  225. PMIB_IPADDRTABLE AddrTable = NULL;
  226. DWORD dwErr;
  227. DWORD dwPrefixLength = lstrlen("\\DEVICE\\TCPIP_");
  228. DWORD dwSize;
  229. DWORD i;
  230. DWORD j;
  231. PIP_INTERFACE_INFO IfTable = NULL;
  232. //
  233. // Load the address table and interface table
  234. //
  235. do {
  236. dwSize = 0;
  237. dwErr = GetInterfaceInfo(IfTable, &dwSize);
  238. if (dwErr != ERROR_INSUFFICIENT_BUFFER) {
  239. PRINT1("error %d obtaining interface-table size", dwErr);
  240. break;
  241. }
  242. IfTable = (PIP_INTERFACE_INFO)HeapAlloc(GetProcessHeap(), 0, dwSize);
  243. if (!IfTable) {
  244. dwErr = GetLastError();
  245. PRINT2("error %d allocating %d-byte for interfaces", dwErr, dwSize);
  246. dwErr = ERROR_INSUFFICIENT_BUFFER; break;
  247. }
  248. dwErr = GetInterfaceInfo(IfTable, &dwSize);
  249. if (dwErr != NO_ERROR) {
  250. PRINT1("error %d getting interface table", dwErr);
  251. break;
  252. }
  253. dwSize = 0;
  254. dwErr = GetIpAddrTable(AddrTable, &dwSize, FALSE);
  255. if (dwErr != ERROR_INSUFFICIENT_BUFFER) {
  256. PRINT1("error %d obtaining address-table size", dwErr);
  257. break;
  258. }
  259. AddrTable = (PMIB_IPADDRTABLE)HeapAlloc(GetProcessHeap(), 0, dwSize);
  260. if (!AddrTable) {
  261. dwErr = GetLastError();
  262. PRINT2("error %d allocating %d-byte for addresses", dwErr, dwSize);
  263. dwErr = ERROR_INSUFFICIENT_BUFFER; break;
  264. }
  265. dwErr = GetIpAddrTable(AddrTable, &dwSize, FALSE);
  266. if (dwErr != NO_ERROR) {
  267. PRINT1("error %d getting address table", dwErr);
  268. break;
  269. }
  270. } while(FALSE);
  271. if (dwErr != NO_ERROR) {
  272. if (IfTable) { HeapFree(GetProcessHeap(), 0, IfTable); }
  273. if (AddrTable) { HeapFree(GetProcessHeap(), 0, AddrTable); }
  274. return dwErr;
  275. }
  276. //
  277. // Find the user's interface in the interface-table
  278. //
  279. dwErr = ERROR_INVALID_PARAMETER;
  280. for (i = 0; i < (DWORD)IfTable->NumAdapters; i++) {
  281. PRINT2("%d: %ls", IfTable->Adapter[i].Index, IfTable->Adapter[i].Name+dwPrefixLength);
  282. if (lstrcmpiW(
  283. IfTable->Adapter[i].Name+dwPrefixLength, g_bind.RIB_Netcard
  284. ) != 0) {
  285. continue;
  286. }
  287. //
  288. // We've found the interface.
  289. // Now look in the address-table for its address.
  290. //
  291. for (j = 0; j < AddrTable->dwNumEntries; j++) {
  292. PRINT2("%d: %s", AddrTable->table[j].dwIndex, INET_NTOA(AddrTable->table[j].dwAddr));
  293. if (AddrTable->table[j].dwIndex != IfTable->Adapter[i].Index) {
  294. continue;
  295. }
  296. //
  297. // We've found the address.
  298. //
  299. g_bind.RIB_Address = AddrTable->table[j].dwAddr;
  300. g_bind.RIB_Netmask = AddrTable->table[j].dwMask;
  301. dwErr = NO_ERROR;
  302. break;
  303. }
  304. if (j >= AddrTable->dwNumEntries) {
  305. PRINT0("the address for the interface could not be found");
  306. }
  307. break;
  308. }
  309. if (i >= (DWORD)IfTable->NumAdapters) {
  310. PRINT0("the interface specified could not be found");
  311. }
  312. HeapFree(GetProcessHeap(), 0, IfTable);
  313. HeapFree(GetProcessHeap(), 0, AddrTable);
  314. return dwErr;
  315. #else
  316. HKEY hkeyNetcard;
  317. PSTR pszAddress, pszNetmask;
  318. CHAR szNetcard[256], szValue[256];
  319. DWORD dwErr, dwType, dwSize, dwEnableDhcp;
  320. //
  321. // open the TCP/IP parameters key for the interface specified
  322. //
  323. strcpy(szNetcard, STR_SERVICES);
  324. strcat(szNetcard, g_bind.RIB_Netcard);
  325. strcat(szNetcard, STR_PARAMSTCP);
  326. dwErr = RegOpenKeyEx(
  327. HKEY_LOCAL_MACHINE, szNetcard, 0, KEY_ALL_ACCESS, &hkeyNetcard
  328. );
  329. if (dwErr != NO_ERROR) {
  330. PRINT2("error %d opening registry key %s", dwErr, szNetcard);
  331. return dwErr;
  332. }
  333. do {
  334. //
  335. // read the dhcp key to see whether DHCP is enabled
  336. //
  337. dwSize = sizeof(DWORD);
  338. dwErr = RegQueryValueEx(
  339. hkeyNetcard, STR_ENABLEDHCP, NULL,
  340. &dwType, (PBYTE)&dwEnableDhcp, &dwSize
  341. );
  342. if (dwErr != NO_ERROR) {
  343. PRINT3(
  344. "error %d reading value %s under key %s",
  345. dwErr, STR_ENABLEDHCP, szNetcard
  346. );
  347. break;
  348. }
  349. if (dwEnableDhcp) {
  350. pszAddress = STR_DHCPADDR;
  351. pszNetmask = STR_DHCPMASK;
  352. }
  353. else {
  354. pszAddress = STR_ADDRESS;
  355. pszNetmask = STR_NETMASK;
  356. }
  357. //
  358. // read the IP address and convert it
  359. //
  360. dwSize = sizeof(szValue);
  361. dwErr = RegQueryValueEx(
  362. hkeyNetcard, pszAddress, NULL,
  363. &dwType, (PBYTE)szValue, &dwSize
  364. );
  365. if (dwErr != NO_ERROR) {
  366. PRINT3(
  367. "error %d reading value %s under key %s",
  368. dwErr, pszAddress, szNetcard
  369. );
  370. break;
  371. }
  372. g_bind.RIB_Address = inet_addr(szValue);
  373. PRINT2("%s == %s", pszAddress, szValue);
  374. //
  375. // read the network mask and convert it
  376. //
  377. dwSize = sizeof(szValue);
  378. dwErr = RegQueryValueEx(
  379. hkeyNetcard, pszNetmask, NULL,
  380. &dwType, (PBYTE)szValue, &dwSize
  381. );
  382. if (dwErr != NO_ERROR) {
  383. PRINT3(
  384. "error %d reading value %s under key %s",
  385. dwErr, pszNetmask, szNetcard
  386. );
  387. break;
  388. }
  389. g_bind.RIB_Netmask = inet_addr(szValue);
  390. PRINT2("%s == %s", pszNetmask, szValue);
  391. } while(FALSE);
  392. RegCloseKey(hkeyNetcard);
  393. return dwErr;
  394. #endif
  395. }
  396. DWORD
  397. RegGetConfig(
  398. VOID
  399. )
  400. {
  401. CHAR szRipTest[256];
  402. DWORD dwErr, dwCreated;
  403. PREG_OPTION pro, proend;
  404. HKEY hkeyRipTest, hkeyIf;
  405. DWORD dwNetmask, dwPrefixLength;
  406. DWORD dwCount, dwLowestAddress, dwHighestAddress;
  407. //
  408. // create the RipTest key in case it doesn't exist
  409. //
  410. strcpy(szRipTest, STR_SERVICES);
  411. strcat(szRipTest, STR_RIPTEST);
  412. dwErr = RegCreateKeyEx(
  413. HKEY_LOCAL_MACHINE, szRipTest, 0, NULL, 0,
  414. KEY_ALL_ACCESS, NULL, &hkeyRipTest, &dwCreated
  415. );
  416. if (dwErr != NO_ERROR) {
  417. PRINT2("error %d creating registry key %s", dwErr, szRipTest);
  418. return dwErr;
  419. }
  420. //
  421. // create the key for the interface in case it doesn't exist
  422. //
  423. dwErr = RegCreateKeyExW(
  424. hkeyRipTest, g_bind.RIB_Netcard, 0, NULL, 0,
  425. KEY_ALL_ACCESS, NULL, &hkeyIf, &dwCreated
  426. );
  427. RegCloseKey(hkeyRipTest);
  428. if (dwErr != NO_ERROR) {
  429. PRINT3(
  430. "error %d creating subkey %S under registry key %s",
  431. dwErr, g_bind.RIB_Netcard, szRipTest
  432. );
  433. return dwErr;
  434. }
  435. PRINT0("loading options from registry: ");
  436. proend = g_options + (sizeof(g_options) / sizeof(REG_OPTION));
  437. for (pro = g_options; pro < proend; pro++) {
  438. //
  439. // read or initialize the option
  440. //
  441. pro->RO_GetOpt(hkeyIf, pro);
  442. }
  443. RegCloseKey(hkeyIf);
  444. //
  445. // if the defaults were used, give the user a chance to change them
  446. //
  447. if (dwCreated == REG_CREATED_NEW_KEY) {
  448. PRINT0("Default parameters have been written to the registry.");
  449. PRINT2("Please check the key %s\\%S,", szRipTest, g_bind.RIB_Netcard);
  450. PRINT0("modify the values if necessary, and run RIPTEST again.\n");
  451. return ERROR_CAN_NOT_COMPLETE;
  452. }
  453. //
  454. // check the route parameters for errors:
  455. //
  456. // make sure the class of the route is valid
  457. //
  458. dwLowestAddress = g_cfg.RIC_RouteStart;
  459. if (IS_LOOPBACK_ADDR(dwLowestAddress) ||
  460. CLASSD_ADDR(dwLowestAddress) || CLASSE_ADDR(dwLowestAddress)) {
  461. PRINT1(
  462. "ERROR: route %s is of an invalid network class",
  463. INET_NTOA(dwLowestAddress)
  464. );
  465. return ERROR_INVALID_PARAMETER;
  466. }
  467. //
  468. // make sure that from the specified starting address,
  469. // there are enough routes in the network class to generate
  470. // the configured number of routes
  471. //
  472. dwCount = g_cfg.RIC_RouteCount;
  473. dwNetmask = g_cfg.RIC_RouteMask;
  474. dwPrefixLength = PREFIX_LENGTH(dwNetmask);
  475. dwLowestAddress &= dwNetmask;
  476. dwHighestAddress = NTH_ADDRESS(dwLowestAddress, dwPrefixLength, dwCount);
  477. if (IS_LOOPBACK_ADDR(dwHighestAddress) ||
  478. NETCLASS_MASK(dwLowestAddress) != NETCLASS_MASK(dwHighestAddress)) {
  479. PRINT1(
  480. "ERROR: starting route %s is too near the end of its network class",
  481. INET_NTOA(dwLowestAddress)
  482. );
  483. return ERROR_INVALID_PARAMETER;
  484. }
  485. //
  486. // make sure that the authentication type is a supported value
  487. //
  488. if (g_cfg.RIC_AuthType != IPRIP_AUTHTYPE_NONE &&
  489. g_cfg.RIC_AuthType != IPRIP_AUTHTYPE_SIMPLE_PASSWORD) {
  490. PRINT1(
  491. "ERROR: authentication type %d is not supported",
  492. g_cfg.RIC_AuthType
  493. );
  494. return ERROR_INVALID_PARAMETER;
  495. }
  496. //
  497. // make sure the number of packet entries isn't out-of-range
  498. //
  499. if (g_cfg.RIC_PacketEntryCount > 25) {
  500. PRINT1(
  501. "ERROR: packet-enty count %d is too large",
  502. g_cfg.RIC_PacketEntryCount
  503. );
  504. return ERROR_INVALID_PARAMETER;
  505. }
  506. return NO_ERROR;
  507. }
  508. DWORD
  509. RegGetAddress(
  510. HKEY hKey,
  511. PREG_OPTION pOpt
  512. )
  513. {
  514. CHAR szValue[256];
  515. DWORD dwErr, dwType, dwSize;
  516. //
  517. // attempt to read the value
  518. //
  519. dwSize = sizeof(szValue);
  520. dwErr = RegQueryValueEx(
  521. hKey, pOpt->RO_Name, NULL, &dwType, (PBYTE)szValue, &dwSize
  522. );
  523. if (dwErr != NO_ERROR) {
  524. //
  525. // attempt to write the default value to the registry
  526. //
  527. strcpy(szValue, INET_NTOA(*(PDWORD)pOpt->RO_DefVal));
  528. dwSize = strlen(szValue) + 1;
  529. dwType = REG_SZ;
  530. dwErr = RegSetValueEx(
  531. hKey, pOpt->RO_Name, NULL, dwType, (PBYTE)szValue, dwSize
  532. );
  533. }
  534. //
  535. // by now the value in the registry should be in szValue
  536. //
  537. *(PDWORD)pOpt->RO_OptVal = inet_addr(szValue);
  538. PRINT2("%20s == %s", pOpt->RO_Name, szValue);
  539. return dwErr;
  540. }
  541. DWORD
  542. RegGetDWORD(
  543. HKEY hKey,
  544. PREG_OPTION pOpt
  545. )
  546. {
  547. DWORD dwErr, dwValue, dwType, dwSize;
  548. //
  549. // attempt to read the value
  550. //
  551. dwSize = sizeof(DWORD);
  552. dwErr = RegQueryValueEx(
  553. hKey, pOpt->RO_Name, NULL, &dwType, (PBYTE)&dwValue, &dwSize
  554. );
  555. if (dwErr != NO_ERROR) {
  556. //
  557. // attempt to write the default value to the registry
  558. //
  559. dwValue = *(PDWORD)pOpt->RO_DefVal;
  560. dwSize = sizeof(DWORD);
  561. dwType = REG_DWORD;
  562. dwErr = RegSetValueEx(
  563. hKey, pOpt->RO_Name, NULL, dwType, (PBYTE)&dwValue, dwSize
  564. );
  565. }
  566. //
  567. // by now the value in the registry should be in dwValue
  568. //
  569. *(PDWORD)pOpt->RO_OptVal = dwValue;
  570. PRINT2("%20s == %d", pOpt->RO_Name, dwValue);
  571. return dwErr;
  572. }
  573. DWORD
  574. RegGetBinary(
  575. HKEY hKey,
  576. PREG_OPTION pOpt
  577. )
  578. {
  579. PBYTE pValue;
  580. DWORD dwErr, dwType, dwSize;
  581. //
  582. // attempt to read the value
  583. //
  584. dwSize = pOpt->RO_Size;
  585. pValue = (PBYTE)pOpt->RO_OptVal;
  586. dwErr = RegQueryValueEx(
  587. hKey, pOpt->RO_Name, NULL, &dwType, pValue, &dwSize
  588. );
  589. if (dwErr != NO_ERROR) {
  590. //
  591. // attempt to write the default value to the registry
  592. //
  593. pValue = (PBYTE)pOpt->RO_DefVal;
  594. dwSize = pOpt->RO_Size;
  595. dwType = REG_BINARY;
  596. dwErr = RegSetValueEx(
  597. hKey, pOpt->RO_Name, NULL, dwType, pValue, dwSize
  598. );
  599. RtlCopyMemory(pOpt->RO_OptVal, pOpt->RO_DefVal, pOpt->RO_Size);
  600. }
  601. {
  602. PBYTE pb, pbend;
  603. CHAR *psz, szValue[256], szDigits[] = "0123456789ABCDEF";
  604. psz = szValue;
  605. pbend = (PBYTE)pOpt->RO_OptVal + pOpt->RO_Size;
  606. for (pb = (PBYTE)pOpt->RO_OptVal; pb < pbend; pb++) {
  607. *psz++ = szDigits[*pb / 16];
  608. *psz++ = szDigits[*pb % 16];
  609. *psz++ = ':';
  610. }
  611. if (psz != szValue) { --psz; }
  612. *psz = '\0';
  613. PRINT2("%20s == %s", pOpt->RO_Name, szValue);
  614. }
  615. return dwErr;
  616. }
  617. //
  618. // main stress function
  619. //
  620. DWORD
  621. RipTest(
  622. VOID
  623. )
  624. {
  625. SOCKET sock;
  626. SOCKADDR_IN sinaddr;
  627. DWORD dwErr, dwMetric;
  628. IPForwardEntry *ifelist = NULL;
  629. LIST_ENTRY rtrlist, *ple;
  630. PRIPTEST_ROUTER_INFO prrs;
  631. InitializeListHead(&rtrlist);
  632. do {
  633. //
  634. // create and set up socket to be used for route transmission
  635. //
  636. dwErr = InitializeSocket(&sock, RIPTEST_PORT);
  637. if (dwErr != NO_ERROR) {
  638. break;
  639. }
  640. //
  641. // transmit single route request on non-RIP port,
  642. // and build a list of responding routers
  643. //
  644. dwErr = DiscoverRouters(sock, &rtrlist);
  645. if (dwErr != NO_ERROR) { closesocket(sock); break; }
  646. //
  647. // generate the list of routes as configured
  648. //
  649. dwErr = GenerateRoutes(&ifelist);
  650. if (dwErr != NO_ERROR) { closesocket(sock); break; }
  651. //
  652. // re-initialize the socket, this time to the RIP port
  653. //
  654. closesocket(sock);
  655. dwErr = InitializeSocket(&sock, IPRIP_PORT);
  656. if (dwErr == SOCKET_ERROR) {
  657. break;
  658. }
  659. for (dwMetric = 8; (INT)dwMetric >= 2; dwMetric -= 3) {
  660. //
  661. // transmit the route table with the specified metric
  662. //
  663. dwErr = TransmitRoutes(sock, dwMetric, ifelist);
  664. //
  665. // give the router time to process the advertisements:
  666. // we allow 30 milliseconds per route, with a minimum of 15 seconds
  667. //
  668. Sleep(max(15000, 30 * g_cfg.RIC_RouteCount));
  669. //
  670. // make connections to Router on each of the responding machines,
  671. // and use MIB api functions to retrieve the route table.
  672. // Verify that the routes transmitted are present,
  673. // and add the servers to the displayed statistics
  674. //
  675. dwErr = VerifyRouteTables(dwMetric, &rtrlist, ifelist);
  676. }
  677. if (g_cfg.RIC_RouteTimeout != 0) {
  678. //
  679. // use timeout to clear routes
  680. //
  681. PRINT1(
  682. "waiting %d milliseconds for routes to timeout",
  683. max(15000, g_cfg.RIC_RouteTimeout * 1000)
  684. );
  685. Sleep(max(15000, g_cfg.RIC_RouteTimeout * 1000));
  686. }
  687. else {
  688. //
  689. // send updates to clean up the routes
  690. //
  691. PRINT0("sending announcements to purge routes advertised");
  692. dwErr = TransmitRoutes(sock, 16, ifelist);
  693. Sleep(max(15000, 30 * g_cfg.RIC_RouteCount));
  694. }
  695. closesocket(sock);
  696. } while(FALSE);
  697. //
  698. // cleanup the server list
  699. //
  700. while (!IsListEmpty(&rtrlist)) {
  701. ple = RemoveHeadList(&rtrlist);
  702. prrs = CONTAINING_RECORD(ple, RIPTEST_ROUTER_INFO, RRS_Link);
  703. HeapFree(GetProcessHeap(), 0, prrs);
  704. }
  705. if (ifelist != NULL) { HeapFree(GetProcessHeap(), 0, ifelist); }
  706. return dwErr;
  707. }
  708. DWORD
  709. InitializeSocket(
  710. SOCKET *psock,
  711. WORD wPort
  712. )
  713. {
  714. SOCKET sock;
  715. DWORD dwErr, dwOption;
  716. //
  717. // create the socket
  718. //
  719. sock = socket(AF_INET, SOCK_DGRAM, 0);
  720. if (sock == INVALID_SOCKET) {
  721. dwErr = WSAGetLastError();
  722. PRINT1("error %d creating socket", dwErr);
  723. return dwErr;
  724. }
  725. //
  726. // enable address sharing
  727. //
  728. dwOption = 1;
  729. dwErr = setsockopt(
  730. sock,
  731. SOL_SOCKET,
  732. SO_REUSEADDR,
  733. (PCCH)&dwOption,
  734. sizeof(DWORD)
  735. );
  736. if (dwErr == SOCKET_ERROR) {
  737. dwErr = WSAGetLastError();
  738. PRINT1("error %d enabling address re-use on socket", dwErr);
  739. }
  740. //
  741. // enlarge the receive buffer
  742. //
  743. dwOption = g_cfg.RIC_SockBufSize;
  744. dwErr = setsockopt(
  745. sock,
  746. SOL_SOCKET,
  747. SO_RCVBUF,
  748. (PCCH)&dwOption,
  749. sizeof(DWORD)
  750. );
  751. if (dwErr == SOCKET_ERROR) {
  752. dwErr = WSAGetLastError();
  753. PRINT2("error %d enlarging recv buffer to %d bytes", dwErr, dwOption);
  754. }
  755. //
  756. // enlarge the send buffer
  757. //
  758. dwOption = g_cfg.RIC_SockBufSize;
  759. dwErr = setsockopt(
  760. sock,
  761. SOL_SOCKET,
  762. SO_SNDBUF,
  763. (PCCH)&dwOption,
  764. sizeof(DWORD)
  765. );
  766. if (dwErr == SOCKET_ERROR) {
  767. dwErr = WSAGetLastError();
  768. PRINT2("error %d enlarging send buffer to %d bytes", dwErr, dwOption);
  769. }
  770. do {
  771. SOCKADDR_IN sinaddr;
  772. if (g_cfg.RIC_RouteTarget != IPRIP_MULTIADDR) {
  773. //
  774. // enable broadcasting
  775. //
  776. dwOption = 1;
  777. dwErr = setsockopt(
  778. sock,
  779. SOL_SOCKET,
  780. SO_BROADCAST,
  781. (PCCH)&dwOption,
  782. sizeof(DWORD)
  783. );
  784. if (dwErr == SOCKET_ERROR) {
  785. dwErr = WSAGetLastError();
  786. PRINT1("error %d enabling broadcast on socket", dwErr);
  787. break;
  788. }
  789. //
  790. // bind the socket to the RIPTEST port
  791. //
  792. sinaddr.sin_family = AF_INET;
  793. sinaddr.sin_port = htons(wPort);
  794. sinaddr.sin_addr.s_addr = g_bind.RIB_Address;
  795. dwErr = bind(sock, (PSOCKADDR)&sinaddr, sizeof(SOCKADDR_IN));
  796. if (dwErr == SOCKET_ERROR) {
  797. dwErr = WSAGetLastError();
  798. PRINT1("error %d binding socket", dwErr);
  799. break;
  800. }
  801. dwErr = NO_ERROR;
  802. }
  803. else {
  804. struct ip_mreq imOption;
  805. //
  806. // bind to the specified port
  807. //
  808. sinaddr.sin_family = AF_INET;
  809. sinaddr.sin_port = htons(wPort);
  810. sinaddr.sin_addr.s_addr = g_bind.RIB_Address;
  811. dwErr = bind(sock, (PSOCKADDR)&sinaddr, sizeof(SOCKADDR_IN));
  812. if (dwErr == SOCKET_ERROR) {
  813. dwErr = WSAGetLastError();
  814. PRINT1("error %d binding socket", dwErr);
  815. break;
  816. }
  817. //
  818. // set the outgoing interface for multicasts
  819. //
  820. sinaddr.sin_addr.s_addr = g_bind.RIB_Address;
  821. dwErr = setsockopt(
  822. sock,
  823. IPPROTO_IP,
  824. IP_MULTICAST_IF,
  825. (PCCH)&sinaddr.sin_addr,
  826. sizeof(IN_ADDR)
  827. );
  828. if (dwErr == SOCKET_ERROR) {
  829. dwErr = WSAGetLastError();
  830. PRINT1("error %d setting multicast interface", dwErr);
  831. break;
  832. }
  833. //
  834. // join the RIP multicast group
  835. //
  836. imOption.imr_multiaddr.s_addr = IPRIP_MULTIADDR;
  837. imOption.imr_interface.s_addr = g_bind.RIB_Address;
  838. dwErr = setsockopt(
  839. sock,
  840. IPPROTO_IP,
  841. IP_ADD_MEMBERSHIP,
  842. (PCCH)&imOption,
  843. sizeof(struct ip_mreq)
  844. );
  845. if (dwErr == SOCKET_ERROR) {
  846. dwErr = WSAGetLastError();
  847. PRINT1("error %d joining multicast group", dwErr);
  848. break;
  849. }
  850. dwErr = NO_ERROR;
  851. }
  852. } while(FALSE);
  853. if (dwErr != NO_ERROR) { closesocket(sock); }
  854. else { *psock = sock; }
  855. return dwErr;
  856. }
  857. DWORD
  858. DiscoverRouters(
  859. SOCKET sock,
  860. PLIST_ENTRY rtrlist
  861. )
  862. {
  863. INT iLength;
  864. PIPRIP_ENTRY pie;
  865. PIPRIP_HEADER phdr;
  866. SOCKADDR_IN sindest;
  867. DWORD dwErr, dwSize;
  868. PIPRIP_AUTHENT_ENTRY pae;
  869. BYTE pbuf[MAX_PACKET_SIZE];
  870. INT iErr;
  871. FD_SET fs;
  872. TIMEVAL tv;
  873. DWORD dwTicks, dwTicksBefore, dwTicksAfter;
  874. PRINT0("attempting to discover neighboring routers...");
  875. //
  876. // construct the RIP packet
  877. //
  878. phdr = (PIPRIP_HEADER)pbuf;
  879. pie = (PIPRIP_ENTRY)(phdr + 1);
  880. pae = (PIPRIP_AUTHENT_ENTRY)(phdr + 1);
  881. phdr->IH_Command = IPRIP_REQUEST;
  882. phdr->IH_Version = (CHAR)g_cfg.RIC_PacketVersion;
  883. phdr->IH_Reserved = 0;
  884. //
  885. // setup the authentication entry if necessary;
  886. // note that the code allows authentication in RIPv1 packets
  887. //
  888. if (g_cfg.RIC_AuthType == IPRIP_AUTHTYPE_SIMPLE_PASSWORD) {
  889. pae->IAE_AddrFamily = ADDRFAMILY_AUTHENT;
  890. pae->IAE_AuthType = (WORD)g_cfg.RIC_AuthType;
  891. RtlCopyMemory(
  892. pae->IAE_AuthKey,
  893. g_cfg.RIC_AuthKey,
  894. IPRIP_MAX_AUTHKEY_SIZE
  895. );
  896. ++pie;
  897. }
  898. //
  899. // setup the single packet entry; we request a meaningless address
  900. //
  901. pie->IE_AddrFamily = htons(AF_INET);
  902. pie->IE_RouteTag = 0;
  903. pie->IE_Destination = 0xccddeeff;
  904. pie->IE_SubnetMask = 0;
  905. pie->IE_Nexthop = 0;
  906. pie->IE_Metric = htonl(IPRIP_INFINITE);
  907. dwSize = (ULONG) ((PBYTE)(pie + 1) - pbuf);
  908. //
  909. // send the route request to the RIP port
  910. //
  911. PRINT1("\tsending REQUEST to %s", INET_NTOA(g_cfg.RIC_RouteTarget));
  912. sindest.sin_family = AF_INET;
  913. sindest.sin_port = htons(IPRIP_PORT);
  914. sindest.sin_addr.s_addr = g_cfg.RIC_RouteTarget;
  915. iLength = sendto(
  916. sock, (PCCH)pbuf, dwSize, 0,
  917. (PSOCKADDR)&sindest, sizeof(SOCKADDR_IN)
  918. );
  919. if (iLength == SOCKET_ERROR || (DWORD)iLength < dwSize) {
  920. dwErr = WSAGetLastError();
  921. PRINT1("error %d sending route request", dwErr);
  922. return dwErr;
  923. }
  924. //
  925. // wait a while before collecting responses
  926. //
  927. Sleep(10000);
  928. //
  929. // repeatedly receive for the next 10 seconds
  930. //
  931. tv.tv_sec = 10;
  932. tv.tv_usec = 0;
  933. //
  934. // this loop executes until 10 seconds have elapsed
  935. //
  936. while (tv.tv_sec > 0) {
  937. FD_ZERO(&fs);
  938. FD_SET(sock, &fs);
  939. //
  940. // get the tick count beofre starting select
  941. //
  942. dwTicksBefore = GetTickCount();
  943. //
  944. // enter the call to select
  945. //
  946. iErr = select(0, &fs, NULL, NULL, &tv);
  947. //
  948. // compute the elapsed time
  949. //
  950. dwTicksAfter = GetTickCount();
  951. if (dwTicksAfter < dwTicksBefore) {
  952. dwTicks = dwTicksAfter + ((DWORD)-1 - dwTicksBefore);
  953. }
  954. else {
  955. dwTicks = dwTicksAfter - dwTicksBefore;
  956. }
  957. //
  958. // update the timeout
  959. //
  960. if (tv.tv_usec < (INT)(dwTicks % 1000) * 1000) {
  961. //
  962. // borrow a second from the tv_sec field
  963. //
  964. --tv.tv_sec;
  965. tv.tv_usec += 1000000;
  966. }
  967. tv.tv_usec -= (dwTicks % 1000) * 1000;
  968. tv.tv_sec -= (dwTicks / 1000);
  969. //
  970. // process any incoming packets there might be
  971. //
  972. if (iErr != 0 && iErr != SOCKET_ERROR && FD_ISSET(sock, &fs)) {
  973. INT addrlen;
  974. SOCKADDR_IN sinsrc;
  975. PRIPTEST_ROUTER_INFO prs;
  976. //
  977. // receive the packet
  978. //
  979. addrlen = sizeof(sinsrc);
  980. iLength = recvfrom(
  981. sock, (PCHAR)pbuf, MAX_PACKET_SIZE, 0,
  982. (PSOCKADDR)&sinsrc, &addrlen
  983. );
  984. if (iLength == 0 || iLength == SOCKET_ERROR) {
  985. dwErr = WSAGetLastError();
  986. PRINT1("error %d receiving packet", dwErr);
  987. continue;
  988. }
  989. //
  990. // create a list entry for the responding router
  991. //
  992. dwErr = CreateRouterStatsEntry(
  993. rtrlist, sinsrc.sin_addr.s_addr, &prs
  994. );
  995. if (dwErr == NO_ERROR) {
  996. PRINT2(
  997. "\treceived RESPONSE from %s (%s)",
  998. INET_NTOA(sinsrc.sin_addr), prs->RRS_DnsName
  999. );
  1000. }
  1001. }
  1002. }
  1003. if (rtrlist->Flink == rtrlist) {
  1004. PRINT0("\tno neighboring routers discovered");
  1005. }
  1006. return NO_ERROR;
  1007. }
  1008. DWORD
  1009. GenerateRoutes(
  1010. IPForwardEntry **pifelist
  1011. )
  1012. {
  1013. CHAR szAddress[20];
  1014. IPForwardEntry *ifelist, *ife;
  1015. DWORD dwRouteCount, dwNetworkCount;
  1016. DWORD dwStartOffset, dwLowestAddress, dwHighestAddress;
  1017. DWORD dw, dwErr, dwAddress, dwNexthop, dwSubnetMask, dwPrefixLength;
  1018. dwNexthop = g_cfg.RIC_RouteNexthop;
  1019. dwSubnetMask = g_cfg.RIC_RouteMask;
  1020. dwPrefixLength = PREFIX_LENGTH(dwSubnetMask);
  1021. //
  1022. // find the last address in the start-address's network class
  1023. //
  1024. dwLowestAddress = g_cfg.RIC_RouteStart;
  1025. dwHighestAddress =
  1026. (CLASSA_ADDR(dwLowestAddress) ? inet_addr("126.255.255.255") :
  1027. (CLASSB_ADDR(dwLowestAddress) ? inet_addr("191.255.255.255") :
  1028. (CLASSC_ADDR(dwLowestAddress) ? inet_addr("223.255.255.255") : 0)));
  1029. //
  1030. // figure out how many networks the range can be split into
  1031. // using the specified network mask
  1032. //
  1033. dwLowestAddress &= dwSubnetMask;
  1034. dwNetworkCount = ((ntohl(dwHighestAddress) >> (32 - dwPrefixLength)) -
  1035. (ntohl(dwLowestAddress) >> (32 - dwPrefixLength)));
  1036. //
  1037. // choose a starting address for this iteration:
  1038. // we have at most K routes, and we are sending n routes,
  1039. // so the starting route must be at an offset of between 0 and (K - n)
  1040. //
  1041. dwRouteCount = g_cfg.RIC_RouteCount;
  1042. dwStartOffset = RANDOM(&g_seed, 0, (dwNetworkCount - dwRouteCount));
  1043. //
  1044. // allocate the array of routes
  1045. //
  1046. *pifelist =
  1047. ifelist = (IPForwardEntry *)HeapAlloc(
  1048. GetProcessHeap(), 0,
  1049. dwRouteCount * sizeof(IPForwardEntry)
  1050. );
  1051. if (ifelist == NULL) {
  1052. dwErr = GetLastError();
  1053. PRINT2(
  1054. "error %d allocating %d bytes for route list",
  1055. dwErr, dwRouteCount * sizeof(IPForwardEntry)
  1056. );
  1057. return dwErr;
  1058. }
  1059. RtlZeroMemory(ifelist, dwRouteCount * sizeof(IPForwardEntry));
  1060. //
  1061. // fill the table with routes
  1062. //
  1063. for (dw = dwStartOffset; dw < (dwStartOffset + dwRouteCount); dw++) {
  1064. dwAddress = NTH_ADDRESS(dwLowestAddress, dwPrefixLength, dw);
  1065. ife = ifelist + (dw - dwStartOffset);
  1066. ife->dwForwardDest = dwAddress;
  1067. ife->dwForwardMask = dwSubnetMask;
  1068. ife->dwForwardNextHop = dwNexthop;
  1069. }
  1070. return NO_ERROR;
  1071. }
  1072. DWORD
  1073. TransmitRoutes(
  1074. SOCKET sock,
  1075. DWORD dwMetric,
  1076. IPForwardEntry *ifelist
  1077. )
  1078. {
  1079. INT iLength;
  1080. WORD wRouteTag;
  1081. PIPRIP_HEADER pih;
  1082. SOCKADDR_IN sindest;
  1083. PIPRIP_ENTRY pie, pistart, piend;
  1084. PIPRIP_AUTHENT_ENTRY pae;
  1085. IPForwardEntry *ife, *ifend;
  1086. BYTE pbuf[2 * MAX_PACKET_SIZE];
  1087. DWORD dwErr, dwEntryCount;
  1088. //
  1089. // setup the message's header
  1090. //
  1091. pih = (PIPRIP_HEADER)pbuf;
  1092. pae = (PIPRIP_AUTHENT_ENTRY)(pih + 1);
  1093. pistart = (PIPRIP_ENTRY)(pih + 1);
  1094. pih->IH_Command = IPRIP_RESPONSE;
  1095. pih->IH_Version = (CHAR)g_cfg.RIC_PacketVersion;
  1096. pih->IH_Reserved = 0;
  1097. //
  1098. // setup the authentication entry if necessary;
  1099. // note that the code allows authentication in RIPv1 packets
  1100. //
  1101. if (g_cfg.RIC_AuthType == IPRIP_AUTHTYPE_SIMPLE_PASSWORD) {
  1102. pae->IAE_AddrFamily = ADDRFAMILY_AUTHENT;
  1103. pae->IAE_AuthType = (WORD)g_cfg.RIC_AuthType;
  1104. RtlCopyMemory(
  1105. pae->IAE_AuthKey,
  1106. g_cfg.RIC_AuthKey,
  1107. IPRIP_MAX_AUTHKEY_SIZE
  1108. );
  1109. ++pistart;
  1110. }
  1111. //
  1112. // pick off the configured number of routes to put in the packet
  1113. //
  1114. if (g_cfg.RIC_PacketEntryCount != 0) {
  1115. dwEntryCount = g_cfg.RIC_PacketEntryCount;
  1116. }
  1117. else {
  1118. //
  1119. // choose a random number of entries
  1120. //
  1121. if (g_cfg.RIC_AuthType == IPRIP_AUTHTYPE_NONE) {
  1122. dwEntryCount = RANDOM(&g_seed, 1, 25);
  1123. }
  1124. else {
  1125. dwEntryCount = RANDOM(&g_seed, 1, 24);
  1126. }
  1127. }
  1128. wRouteTag = LOWORD(g_cfg.RIC_RouteTag);
  1129. sindest.sin_family = AF_INET;
  1130. sindest.sin_port = htons(IPRIP_PORT);
  1131. sindest.sin_addr.s_addr = g_cfg.RIC_RouteTarget;
  1132. {
  1133. DWORD dwCount;
  1134. CHAR szDest[20], szFirst[20], szLast[20];
  1135. dwCount = g_cfg.RIC_RouteCount;
  1136. strcpy(szDest, INET_NTOA(sindest.sin_addr));
  1137. strcpy(szFirst, INET_NTOA(ifelist->dwForwardDest));
  1138. strcpy(szLast, INET_NTOA((ifelist + dwCount - 1)->dwForwardDest));
  1139. PRINT5(
  1140. "sending %d routes (%s - %s) to %s using metric %d",
  1141. dwCount, szFirst, szLast, szDest, dwMetric
  1142. );
  1143. }
  1144. //
  1145. // loop filling the buffer with packets and sending it when its full
  1146. //
  1147. piend = pistart + dwEntryCount;
  1148. ifend = ifelist + g_cfg.RIC_RouteCount;
  1149. for (ife = ifelist, pie = pistart; ife < ifend; ife++, pie++) {
  1150. //
  1151. // send the current buffer if it is full
  1152. //
  1153. if (pie >= piend) {
  1154. //
  1155. // sleep for the specified packet-gap
  1156. //
  1157. Sleep(g_cfg.RIC_PacketGap);
  1158. iLength = sendto(
  1159. sock, (PCCH)pbuf, (ULONG)((PBYTE)pie - pbuf), 0,
  1160. (PSOCKADDR)&sindest, sizeof(SOCKADDR_IN)
  1161. );
  1162. if (iLength == SOCKET_ERROR || iLength < ((PBYTE)piend - pbuf)) {
  1163. dwErr = WSAGetLastError();
  1164. PRINT2(
  1165. "error %d sending packet to %s",
  1166. dwErr, INET_NTOA(sindest.sin_addr)
  1167. );
  1168. }
  1169. if (g_cfg.RIC_PacketEntryCount != 0) {
  1170. dwEntryCount = g_cfg.RIC_PacketEntryCount;
  1171. }
  1172. else {
  1173. //
  1174. // choose a random number of entries
  1175. //
  1176. if (g_cfg.RIC_AuthType == IPRIP_AUTHTYPE_NONE) {
  1177. dwEntryCount = RANDOM(&g_seed, 1, 25);
  1178. }
  1179. else {
  1180. dwEntryCount = RANDOM(&g_seed, 1, 24);
  1181. }
  1182. }
  1183. piend = pistart + dwEntryCount;
  1184. pie = pistart;
  1185. }
  1186. //
  1187. // add another entry
  1188. //
  1189. pie->IE_AddrFamily = htons(AF_INET);
  1190. pie->IE_Destination = ife->dwForwardDest;
  1191. pie->IE_Metric = htonl(dwMetric);
  1192. pie->IE_RouteTag = htons(wRouteTag);
  1193. pie->IE_Nexthop = ife->dwForwardNextHop;
  1194. pie->IE_SubnetMask = ife->dwForwardMask;
  1195. }
  1196. //
  1197. // if there is anything left, send it
  1198. //
  1199. if (pie > pistart) {
  1200. iLength = sendto(
  1201. sock, (PCCH)pbuf, (ULONG)((PBYTE)pie - pbuf), 0,
  1202. (PSOCKADDR)&sindest, sizeof(SOCKADDR_IN)
  1203. );
  1204. }
  1205. return NO_ERROR;
  1206. }
  1207. DWORD
  1208. VerifyRouteTables(
  1209. DWORD dwMetric,
  1210. PLIST_ENTRY rtrlist,
  1211. IPForwardEntry *ifelist
  1212. )
  1213. {
  1214. PLIST_ENTRY ple;
  1215. MIB_OPAQUE_QUERY roq;
  1216. MIB_OPAQUE_INFO *proi;
  1217. WCHAR pwsRouter[256];
  1218. MIB_SERVER_HANDLE hRouter;
  1219. PRIPTEST_ROUTER_INFO prrs;
  1220. MIB_IPFORWARDTABLE *ifrlist;
  1221. IPForwardEntry *ife, *ifend;
  1222. MIB_IPFORWARDROW *ifr, *ifrend;
  1223. DWORD dwInvalidMetrics, dwRoutesMissing;
  1224. DWORD dwErr, dwNumEntries, dwInSize, dwOutSize;
  1225. //
  1226. // go through the list of routers, connecting to the Router
  1227. // on each machine and querying its routing table
  1228. //
  1229. for (ple = rtrlist->Flink; ple != rtrlist; ple = ple->Flink) {
  1230. prrs = CONTAINING_RECORD(ple, RIPTEST_ROUTER_INFO, RRS_Link);
  1231. PRINT1("-----STATS FOR %s-----", prrs->RRS_DnsName);
  1232. //
  1233. // initialize the query arguments
  1234. //
  1235. mbstowcs(pwsRouter, prrs->RRS_DnsName, strlen(prrs->RRS_DnsName) + 1);
  1236. roq.dwVarId = IP_FORWARDTABLE;
  1237. dwInSize = sizeof(MIB_OPAQUE_QUERY) - sizeof(DWORD);
  1238. proi = NULL;
  1239. dwOutSize = 0;
  1240. //
  1241. // perform the query
  1242. //
  1243. dwErr = MprAdminMIBServerConnect(pwsRouter, &hRouter);
  1244. if (dwErr != NO_ERROR) {
  1245. continue;
  1246. }
  1247. dwErr = MprAdminMIBEntryGet(
  1248. hRouter, PID_IP, IPRTRMGR_PID,
  1249. (PVOID)&roq, dwInSize, (PVOID *)&proi, &dwOutSize
  1250. );
  1251. if (dwErr != NO_ERROR) {
  1252. PRINT2(
  1253. "error %d querying route table on server %s",
  1254. dwErr, prrs->RRS_DnsName
  1255. );
  1256. MprAdminMIBServerDisconnect(hRouter);
  1257. continue;
  1258. }
  1259. else
  1260. if (proi == NULL) {
  1261. PRINT1(
  1262. "empty route table retrieved from server %s",
  1263. prrs->RRS_DnsName
  1264. );
  1265. MprAdminMIBServerDisconnect(hRouter);
  1266. continue;
  1267. }
  1268. //
  1269. // look through the table of routes retrieved,
  1270. // to verify thats the routes advertised are among them
  1271. //
  1272. dwRoutesMissing = 0;
  1273. dwInvalidMetrics = 0;
  1274. ifrlist = (PMIB_IPFORWARDTABLE)(proi->rgbyData);
  1275. dwNumEntries = ifrlist->dwNumEntries;
  1276. ifend = ifelist + g_cfg.RIC_RouteCount;
  1277. for (ife = ifelist; ife < ifend; ife++) {
  1278. //
  1279. // each time we find an advertised route,
  1280. // we swap it to the end of the table;
  1281. // thus, the size of the table that we need to search
  1282. // decreases with the number of routes we have found
  1283. //
  1284. ifrend = ifrlist->table + dwNumEntries;
  1285. for (ifr = ifrlist->table; ifr < ifrend; ifr++) {
  1286. if (ife->dwForwardDest == ifr->dwForwardDest) {
  1287. if (ifr->dwForwardMetric1 == (dwMetric + 1)) {
  1288. ife->dwForwardMetric5 = ROUTE_STATUS_OK;
  1289. }
  1290. else {
  1291. //
  1292. // set the status for this route
  1293. //
  1294. ++dwInvalidMetrics;
  1295. ife->dwForwardMetric5 = ROUTE_STATUS_METRIC;
  1296. PRINT3(
  1297. "\troute to %s has metric %d, expected %d",
  1298. INET_NTOA(ife->dwForwardDest),
  1299. ife->dwForwardMetric1, dwMetric + 1
  1300. );
  1301. }
  1302. //
  1303. // overwrite with the item at the end of the table;
  1304. // if we are at the end of the table, do nothing
  1305. //
  1306. if (ifr != (ifrend - 1)) { *ifr = *(ifrend - 1); }
  1307. --dwNumEntries;
  1308. break;
  1309. }
  1310. }
  1311. //
  1312. // if the item wasn't found, mark it as such
  1313. //
  1314. if (ifr >= ifrend) {
  1315. ++dwRoutesMissing;
  1316. ife->dwForwardMetric5 = ROUTE_STATUS_MISSING;
  1317. PRINT1("\troute to %s missing", INET_NTOA(ife->dwForwardDest));
  1318. }
  1319. }
  1320. MprAdminMIBBufferFree(proi);
  1321. MprAdminMIBServerDisconnect(hRouter);
  1322. PRINT2("%20s == %d", "routes missing", dwRoutesMissing);
  1323. PRINT2("%20s == %d", "invalid metrics", dwInvalidMetrics);
  1324. }
  1325. return NO_ERROR;
  1326. }
  1327. DWORD
  1328. CreateRouterStatsEntry(
  1329. PLIST_ENTRY rtrlist,
  1330. DWORD dwAddress,
  1331. PRIPTEST_ROUTER_INFO *pprrs
  1332. )
  1333. {
  1334. DWORD dwErr;
  1335. PHOSTENT phe;
  1336. PRIPTEST_ROUTER_INFO prrs;
  1337. phe = gethostbyaddr((const char *)&dwAddress, sizeof(DWORD), PF_INET);
  1338. if (phe == NULL) {
  1339. dwErr = WSAGetLastError();
  1340. PRINT2(
  1341. "error %d retrieving name for host %s", dwErr, INET_NTOA(dwAddress)
  1342. );
  1343. return dwErr;
  1344. }
  1345. prrs = (PRIPTEST_ROUTER_INFO)HeapAlloc(
  1346. GetProcessHeap(), 0,
  1347. sizeof(RIPTEST_ROUTER_INFO)
  1348. );
  1349. if (prrs == NULL) {
  1350. dwErr = GetLastError();
  1351. PRINT2(
  1352. "error %d allocating %d bytes for router stats",
  1353. dwErr, sizeof(RIPTEST_ROUTER_INFO)
  1354. );
  1355. return dwErr;
  1356. }
  1357. RtlZeroMemory(prrs, sizeof(RIPTEST_ROUTER_INFO));
  1358. prrs->RRS_Address = dwAddress;
  1359. strcpy(prrs->RRS_DnsName, phe->h_name);
  1360. InsertHeadList(rtrlist, &prrs->RRS_Link);
  1361. if (pprrs != NULL) { *pprrs = prrs; }
  1362. return NO_ERROR;
  1363. }
  1364. DWORD
  1365. PrintUsage(
  1366. VOID
  1367. )
  1368. {
  1369. printf("usage: riptest [adapter_guid]");
  1370. printf("\n\te.g. riptest {73C2D5F0-A352-11D1-9043-0060089FC48B}\n");
  1371. printf("\n\tThe first time RIPTEST is run, it sets up the registry");
  1372. printf("\n\twith defaults for the specified adapter.");
  1373. printf("\n");
  1374. return NO_ERROR;
  1375. }
  1376. } // end extern "C"