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.

896 lines
18 KiB

  1. /*++
  2. Copyright (c) 2001-2001 Microsoft Corporation
  3. Module Name:
  4. iphelp.c
  5. Abstract:
  6. IP help API routines.
  7. Author:
  8. Jim Gilroy (jamesg) January 2001
  9. Revision History:
  10. --*/
  11. #include "local.h"
  12. BOOL
  13. IpHelp_Initialize(
  14. VOID
  15. )
  16. /*++
  17. Routine Description:
  18. Startup IP Help API
  19. Arguments:
  20. None
  21. Return Value:
  22. TRUE if started successfully.
  23. FALSE on error.
  24. --*/
  25. {
  26. return TRUE;
  27. }
  28. VOID
  29. IpHelp_Cleanup(
  30. VOID
  31. )
  32. /*++
  33. Routine Description:
  34. Cleanup IP Help API
  35. Arguments:
  36. None
  37. Return Value:
  38. None
  39. --*/
  40. {
  41. }
  42. DNS_STATUS
  43. IpHelp_GetAdaptersInfo(
  44. OUT PIP_ADAPTER_INFO * ppAdapterInfo
  45. )
  46. /*++
  47. Routine Description:
  48. Call IP Help GetAdaptersInfo()
  49. Arguments:
  50. ppAdapterInfo -- addr to receive pointer to adapter info retrieved
  51. Return Value:
  52. None
  53. --*/
  54. {
  55. DNS_STATUS status = NO_ERROR;
  56. DWORD bufferSize;
  57. INT fretry;
  58. PIP_ADAPTER_INFO pbuf;
  59. DNSDBG( TRACE, (
  60. "GetAdaptersInfo( %p )\n",
  61. ppAdapterInfo ));
  62. //
  63. // init IP Help (no-op) if already done
  64. //
  65. *ppAdapterInfo = NULL;
  66. //
  67. // call down to get buffer size
  68. //
  69. // start with reasonable alloc, then bump up if too small
  70. //
  71. fretry = 0;
  72. bufferSize = 1000;
  73. while ( fretry < 2 )
  74. {
  75. pbuf = (PIP_ADAPTER_INFO) ALLOCATE_HEAP( bufferSize );
  76. if ( !pbuf )
  77. {
  78. status = DNS_ERROR_NO_MEMORY;
  79. goto Unlock;
  80. }
  81. status = (DNS_STATUS) GetAdaptersInfo(
  82. pbuf,
  83. &bufferSize );
  84. if ( status == NO_ERROR )
  85. {
  86. break;
  87. }
  88. FREE_HEAP( pbuf );
  89. pbuf = NULL;
  90. // if buf too small on first try,
  91. // continue to retry with suggested buffer size
  92. if ( status == ERROR_BUFFER_OVERFLOW ||
  93. status == ERROR_INSUFFICIENT_BUFFER )
  94. {
  95. fretry++;
  96. continue;
  97. }
  98. // any other error is terminal
  99. DNSDBG( ANY, (
  100. "ERROR: GetAdapterInfo() failed with error %d\n",
  101. status ));
  102. status = DNS_ERROR_NO_DNS_SERVERS;
  103. break;
  104. }
  105. DNS_ASSERT( !pbuf || status==NO_ERROR );
  106. if ( status == NO_ERROR )
  107. {
  108. *ppAdapterInfo = pbuf;
  109. }
  110. Unlock:
  111. DNSDBG( TRACE, (
  112. "Leave GetAdaptersInfo() => %d\n",
  113. status ));
  114. return status;
  115. }
  116. DNS_STATUS
  117. IpHelp_GetPerAdapterInfo(
  118. IN DWORD AdapterIndex,
  119. OUT PIP_PER_ADAPTER_INFO * ppPerAdapterInfo
  120. )
  121. /*++
  122. Routine Description:
  123. Call IP Help GetPerAdapterInfo()
  124. Arguments:
  125. AdapterIndex -- index of adapter to get info for
  126. ppPerAdapterInfo -- addr to receive pointer to per adapter info
  127. Return Value:
  128. None
  129. --*/
  130. {
  131. DNS_STATUS status = NO_ERROR;
  132. DWORD bufferSize;
  133. INT fretry;
  134. PIP_PER_ADAPTER_INFO pbuf;
  135. DNSDBG( TRACE, (
  136. "GetPerAdapterInfo( %d, %p )\n",
  137. AdapterIndex,
  138. ppPerAdapterInfo ));
  139. //
  140. // init IP Help (no-op) if already done
  141. //
  142. *ppPerAdapterInfo = NULL;
  143. //
  144. // call down to get buffer size
  145. //
  146. // start with reasonable alloc, then bump up if too small
  147. //
  148. fretry = 0;
  149. bufferSize = 1000;
  150. while ( fretry < 2 )
  151. {
  152. pbuf = (PIP_PER_ADAPTER_INFO) ALLOCATE_HEAP( bufferSize );
  153. if ( !pbuf )
  154. {
  155. status = DNS_ERROR_NO_MEMORY;
  156. goto Unlock;
  157. }
  158. status = (DNS_STATUS) GetPerAdapterInfo(
  159. AdapterIndex,
  160. pbuf,
  161. &bufferSize );
  162. if ( status == NO_ERROR )
  163. {
  164. break;
  165. }
  166. FREE_HEAP( pbuf );
  167. pbuf = NULL;
  168. // if buf too small on first try,
  169. // continue to retry with suggested buffer size
  170. if ( status == ERROR_BUFFER_OVERFLOW ||
  171. status == ERROR_INSUFFICIENT_BUFFER )
  172. {
  173. fretry++;
  174. continue;
  175. }
  176. // any other error is terminal
  177. DNSDBG( ANY, (
  178. "ERROR: GetAdapterInfo() failed with error %d\n",
  179. status ));
  180. status = DNS_ERROR_NO_DNS_SERVERS;
  181. break;
  182. }
  183. DNS_ASSERT( !pbuf || status==NO_ERROR );
  184. if ( status == NO_ERROR )
  185. {
  186. *ppPerAdapterInfo = pbuf;
  187. }
  188. Unlock:
  189. DNSDBG( TRACE, (
  190. "Leave GetPerAdapterInfo() => %d\n",
  191. status ));
  192. return status;
  193. }
  194. DNS_STATUS
  195. IpHelp_GetBestInterface(
  196. IN IP4_ADDRESS Ip4Addr,
  197. OUT PDWORD pdwInterfaceIndex
  198. )
  199. /*++
  200. Routine Description:
  201. Call IP Help GetBestInterface()
  202. Arguments:
  203. Ip4Addr -- IP address to check
  204. pdwInterfaceIndex -- addr to recv interface index
  205. Return Value:
  206. ERROR_SUCCESS if successful.
  207. ErrorCode on failure.
  208. --*/
  209. {
  210. DNS_STATUS status;
  211. DNSDBG( TRACE, (
  212. "GetBestInterface( %08x, %p )\n",
  213. Ip4Addr,
  214. pdwInterfaceIndex ));
  215. //
  216. // init IP Help (no-op) if already done
  217. //
  218. status = (DNS_STATUS) GetBestInterface(
  219. Ip4Addr,
  220. pdwInterfaceIndex );
  221. DNSDBG( TRACE, (
  222. "Leave GetBestInterface() => %d\n"
  223. "\tip = %s\n"
  224. "\tinterface = %d\n",
  225. status,
  226. IP4_STRING( Ip4Addr ),
  227. *pdwInterfaceIndex ));
  228. return status;
  229. }
  230. DNS_STATUS
  231. IpHelp_ParseIpAddressString(
  232. IN OUT PIP4_ARRAY pIpArray,
  233. IN PIP_ADDR_STRING pIpAddrString,
  234. IN BOOL fGetSubnetMask,
  235. IN BOOL fReverse
  236. )
  237. /*++
  238. Routine Description:
  239. Build IP array from IP help IP_ADDR_STRING structure.
  240. Arguments:
  241. pIpArray -- IP array of DNS servers
  242. pIpAddrString -- pointer to address info with address data
  243. fGetSubnetMask -- get subnet masks
  244. fReverse -- reverse the IP array
  245. Return Value:
  246. ERROR_SUCCESS if successful.
  247. DNS_ERROR_NO_DNS_SERVERS if nothing parsed.
  248. --*/
  249. {
  250. PIP_ADDR_STRING pipBlob = pIpAddrString;
  251. IP4_ADDRESS ip;
  252. DWORD countServers = pIpArray->AddrCount;
  253. DNSDBG( TRACE, (
  254. "IpHelp_ParseIpAddressString()\n"
  255. "\tout IP array = %p\n"
  256. "\tIP string = %p\n"
  257. "\tsubnet? = %d\n"
  258. "\treverse? = %d\n",
  259. pIpArray,
  260. pIpAddrString,
  261. fGetSubnetMask,
  262. fReverse ));
  263. //
  264. // loop reading IP or subnet
  265. //
  266. // DCR_FIX0: address and subnet will be misaligned if read separately
  267. //
  268. // DCR: move to count\allocate model and if getting subnets get together
  269. //
  270. while ( pipBlob &&
  271. countServers < DNS_MAX_IP_INTERFACE_COUNT )
  272. {
  273. if ( fGetSubnetMask )
  274. {
  275. ip = inet_addr( pipBlob->IpMask.String );
  276. if ( ip != INADDR_ANY )
  277. {
  278. pIpArray->AddrArray[ countServers ] = ip;
  279. countServers++;
  280. }
  281. }
  282. else
  283. {
  284. ip = inet_addr( pipBlob->IpAddress.String );
  285. if ( ip != INADDR_ANY && ip != INADDR_NONE )
  286. {
  287. pIpArray->AddrArray[ countServers ] = ip;
  288. countServers++;
  289. }
  290. }
  291. pipBlob = pipBlob->Next;
  292. }
  293. // reset IP count
  294. pIpArray->AddrCount = countServers;
  295. // reverse array if desired
  296. if ( fReverse )
  297. {
  298. Dns_ReverseOrderOfIpArray( pIpArray );
  299. }
  300. DNSDBG( NETINFO, (
  301. "Leave IpHelp_ParseIpAddressString()\n"
  302. "\tcount = %d\n"
  303. "\tfirst IP = %s\n",
  304. countServers,
  305. countServers
  306. ? IP_STRING( pIpArray->AddrArray[0] )
  307. : "" ));
  308. return ( pIpArray->AddrCount ) ? ERROR_SUCCESS : DNS_ERROR_NO_DNS_SERVERS;
  309. }
  310. PIP_ADAPTER_ADDRESSES
  311. IpHelp_GetAdaptersAddresses(
  312. IN ULONG Family,
  313. IN DWORD Flags
  314. )
  315. /*++
  316. Routine Description:
  317. Call IP Help GetAdaptersAddresses
  318. Arguments:
  319. Family -- address family
  320. Flags -- flags
  321. Return Value:
  322. None
  323. --*/
  324. {
  325. DNS_STATUS status = NO_ERROR;
  326. INT retry;
  327. PIP_ADAPTER_ADDRESSES pbuf = NULL;
  328. DWORD bufSize = 0x1000; // start with 4K
  329. HMODULE hlib = NULL;
  330. FARPROC proc;
  331. DNSDBG( TRACE, (
  332. "GetAdaptersAddresses()\n"
  333. "\tFamily = %d\n"
  334. "\tFlags = %08x\n",
  335. Family,
  336. Flags ));
  337. //
  338. // init IP Help (no-op) if already done
  339. //
  340. hlib = LoadLibrary( L"iphlpapi.dll" );
  341. if ( !hlib )
  342. {
  343. goto Failed;
  344. }
  345. proc = GetProcAddress( hlib, "GetAdaptersAddresses" );
  346. if ( !proc )
  347. {
  348. goto Failed;
  349. }
  350. //
  351. // call down in loop to allow one buffer resizing
  352. //
  353. retry = 0;
  354. while ( 1 )
  355. {
  356. // allocate a buffer to hold results
  357. if ( pbuf )
  358. {
  359. FREE_HEAP( pbuf );
  360. }
  361. pbuf = ALLOCATE_HEAP( bufSize );
  362. if ( !pbuf )
  363. {
  364. goto Failed;
  365. }
  366. // call down
  367. status = (DNS_STATUS) (*proc)(
  368. Family,
  369. Flags,
  370. NULL, // no reserved,
  371. pbuf,
  372. & bufSize );
  373. if ( status == NO_ERROR )
  374. {
  375. break;
  376. }
  377. else if ( status != ERROR_BUFFER_OVERFLOW )
  378. {
  379. goto Failed;
  380. }
  381. DNSDBG( NETINFO, (
  382. "Retrying GetAdaptersAddresses() with buffer length %d\n",
  383. bufSize ));
  384. if ( retry != 0 )
  385. {
  386. DNS_ASSERT( FALSE );
  387. goto Failed;
  388. }
  389. continue;
  390. }
  391. // success
  392. DNSDBG( TRACE, (
  393. "Leave GetAdaptersAddresses() = %p\n",
  394. pbuf ));
  395. IF_DNSDBG( NETINFO )
  396. {
  397. DnsDbg_IpAdapterList(
  398. "IP Help Adapter List",
  399. pbuf,
  400. TRUE, // print addrs
  401. TRUE // print list
  402. );
  403. }
  404. return pbuf;
  405. Failed:
  406. FREE_HEAP( pbuf );
  407. if ( status == NO_ERROR )
  408. {
  409. status = GetLastError();
  410. }
  411. DNSDBG( ANY, (
  412. "Failed GetAdaptersAddresses() => %d\n",
  413. status ));
  414. SetLastError( status );
  415. return( NULL );
  416. }
  417. DNS_STATUS
  418. IpHelp_ReadAddrsFromList(
  419. IN PVOID pAddrList,
  420. IN BOOL fUnicast,
  421. IN DWORD ScreenMask, OPTIONAL
  422. IN DWORD ScreenFlags, OPTIONAL
  423. OUT PDNS_ADDR_ARRAY * ppComboArray, OPTIONAL
  424. OUT PDNS_ADDR_ARRAY * pp6OnlyArray, OPTIONAL
  425. OUT PDNS_ADDR_ARRAY * pp4OnlyArray, OPTIONAL
  426. OUT PDWORD pCount6, OPTIONAL
  427. OUT PDWORD pCount4 OPTIONAL
  428. )
  429. /*++
  430. Routine Description:
  431. Read IP addres from IP help IP_ADAPTER_XXX_ADDRESS list.
  432. Arguments:
  433. pAddrList -- any IP address list
  434. PIP_ADAPTER_UNICAST_ADDRESS
  435. PIP_ADAPTER_ANYCAST_ADDRESS
  436. PIP_ADAPTER_MULTICAST_ADDRESS
  437. PIP_ADAPTER_DNS_SERVER_ADDRESS
  438. fUnicast -- this is unicast address list
  439. ScreenMask -- mask of address flags we care about
  440. example:
  441. IP_ADAPTER_ADDRESS_DNS_ELIGIBLE | IP_ADAPTER_ADDRESS_TRANSIENT
  442. ScreenFlags -- required state of flags within mask
  443. example:
  444. IP_ADAPTER_ADDRESS_DNS_ELIGIBLE
  445. this (with above mask) would screen for eligible non-cluster addresses
  446. Return Value:
  447. NO_ERROR if successful.
  448. ErrorCode on failure.
  449. --*/
  450. {
  451. PIP_ADAPTER_UNICAST_ADDRESS pnextAddr;
  452. PIP_ADAPTER_UNICAST_ADDRESS paddr;
  453. DNS_STATUS status = NO_ERROR;
  454. DWORD count4 = 0;
  455. DWORD count6 = 0;
  456. DWORD countAll = 0;
  457. PADDR_ARRAY parrayCombo = NULL;
  458. PADDR_ARRAY parray6 = NULL;
  459. PADDR_ARRAY parray4 = NULL;
  460. DNS_ADDR dnsAddr;
  461. DNSDBG( TRACE, (
  462. "IpHelp_ReadAddrsFromList( %p )\n",
  463. pAddrList ));
  464. //
  465. // count
  466. //
  467. pnextAddr = (PIP_ADAPTER_UNICAST_ADDRESS) pAddrList;
  468. while ( paddr = pnextAddr )
  469. {
  470. PSOCKADDR psa;
  471. pnextAddr = paddr->Next;
  472. if ( ScreenMask &&
  473. (ScreenMask & paddr->Flags) != ScreenFlags )
  474. {
  475. continue;
  476. }
  477. // screen off expired, invalid, bogus
  478. if ( fUnicast && paddr->DadState != IpDadStatePreferred )
  479. {
  480. continue;
  481. }
  482. psa = paddr->Address.lpSockaddr;
  483. if ( !psa )
  484. {
  485. DNS_ASSERT( FALSE );
  486. continue;
  487. }
  488. #if 0
  489. // DCR: temphack -- screen link-local
  490. if ( SOCKADDR_IS_IP6(psa) )
  491. {
  492. if ( IP6_IS_ADDR_LINKLOCAL( (PIP6_ADDRESS)&((PSOCKADDR_IN6)psa)->sin6_addr ) )
  493. {
  494. continue;
  495. }
  496. }
  497. #endif
  498. if ( fUnicast && SOCKADDR_IS_LOOPBACK(psa) )
  499. {
  500. continue;
  501. }
  502. else if ( SOCKADDR_IS_IP6(psa) )
  503. {
  504. count6++;
  505. countAll++;
  506. }
  507. else if ( SOCKADDR_IS_IP4(psa) )
  508. {
  509. count4++;
  510. countAll++;
  511. }
  512. ELSE_ASSERT_FALSE;
  513. }
  514. //
  515. // alloc arrays
  516. //
  517. status = DNS_ERROR_NO_MEMORY;
  518. if ( ppComboArray )
  519. {
  520. if ( countAll )
  521. {
  522. parrayCombo = DnsAddrArray_Create( countAll );
  523. }
  524. *ppComboArray = parrayCombo;
  525. if ( !parrayCombo && (countAll) )
  526. {
  527. goto Failed;
  528. }
  529. }
  530. if ( pp6OnlyArray )
  531. {
  532. if ( count6 )
  533. {
  534. parray6 = DnsAddrArray_Create( count6 );
  535. }
  536. *pp6OnlyArray = parray6;
  537. if ( !parray6 && count6 )
  538. {
  539. goto Failed;
  540. }
  541. }
  542. if ( pp4OnlyArray )
  543. {
  544. if ( count4 )
  545. {
  546. parray4 = DnsAddrArray_Create( count4 );
  547. }
  548. *pp4OnlyArray = parray4;
  549. if ( !parray4 && count4 )
  550. {
  551. goto Failed;
  552. }
  553. }
  554. //
  555. // read addrs into array
  556. //
  557. pnextAddr = (PIP_ADAPTER_UNICAST_ADDRESS) pAddrList;
  558. while ( paddr = pnextAddr )
  559. {
  560. PSOCKADDR psa;
  561. DWORD flags = 0;
  562. DWORD subnetLen = 0;
  563. pnextAddr = paddr->Next;
  564. if ( ScreenMask &&
  565. (ScreenMask & paddr->Flags) != ScreenFlags )
  566. {
  567. continue;
  568. }
  569. // screen off expired, invalid, bogus
  570. if ( fUnicast && paddr->DadState != IpDadStatePreferred )
  571. {
  572. continue;
  573. }
  574. psa = paddr->Address.lpSockaddr;
  575. if ( !psa )
  576. {
  577. DNS_ASSERT( FALSE );
  578. continue;
  579. }
  580. #if 0
  581. // DCR: temphack -- screen link local
  582. if ( SOCKADDR_IS_IP6(psa) &&
  583. IP6_IS_ADDR_LINKLOCAL( (PIP6_ADDRESS)&((PSOCKADDR_IN6)psa)->sin6_addr ) )
  584. {
  585. continue;
  586. }
  587. #endif
  588. // screen off loopback
  589. if ( fUnicast && SOCKADDR_IS_LOOPBACK(psa) )
  590. {
  591. continue;
  592. }
  593. //
  594. // build DNS_ADDR
  595. //
  596. // DCR: FIX6: fix subnet length once DaveThaler is in
  597. //
  598. if ( fUnicast )
  599. {
  600. flags = paddr->Flags;
  601. subnetLen = 0;
  602. #if 0
  603. // TEST HACK: make transients
  604. if ( g_DnsTestMode )
  605. {
  606. flags |= IP_ADAPTER_ADDRESS_TRANSIENT;
  607. }
  608. #endif
  609. }
  610. if ( !DnsAddr_Build(
  611. & dnsAddr,
  612. psa,
  613. 0, // any family
  614. subnetLen,
  615. flags ) )
  616. {
  617. DNS_ASSERT( FALSE );
  618. continue;
  619. }
  620. //
  621. // AddrArray_AddSockaddrEx() with flag to choose types to add
  622. //
  623. // DCR: not sure we want local IP6 array as DNS_ADDR --
  624. // maybe just plain IP6
  625. //
  626. if ( parrayCombo )
  627. {
  628. DnsAddrArray_AddAddr(
  629. parrayCombo,
  630. & dnsAddr,
  631. 0, // any family
  632. 0 // no dup screen
  633. );
  634. }
  635. if ( parray6 )
  636. {
  637. DnsAddrArray_AddAddr(
  638. parray6,
  639. & dnsAddr,
  640. AF_INET6, // any family
  641. 0 // no dup screen
  642. );
  643. }
  644. if ( parray4 )
  645. {
  646. DnsAddrArray_AddAddr(
  647. parray4,
  648. & dnsAddr,
  649. AF_INET, // any family
  650. 0 // no dup screen
  651. );
  652. }
  653. }
  654. //
  655. // set counts
  656. //
  657. if ( pCount6 )
  658. {
  659. *pCount6 = count6;
  660. }
  661. if ( pCount4 )
  662. {
  663. *pCount4 = count4;
  664. }
  665. return NO_ERROR;
  666. Failed:
  667. //
  668. // cleanup any partial allocs
  669. //
  670. DnsAddrArray_Free( parrayCombo );
  671. DnsAddrArray_Free( parray6 );
  672. Dns_Free( parray4 );
  673. DNS_ASSERT( status != NO_ERROR );
  674. return status;
  675. }
  676. //
  677. // End iphelp.c
  678. //