Source code of Windows XP (NT5)
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.

2833 lines
56 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. hostent.c
  5. Abstract:
  6. Domain Name System (DNS) Library
  7. Hostent routines.
  8. Author:
  9. Jim Gilroy (jamesg) December 4, 2000
  10. Revision History:
  11. --*/
  12. #include "local.h"
  13. #include "ws2atm.h" // ATM address
  14. //
  15. // Max number of aliases
  16. //
  17. #define DNS_MAX_ALIAS_COUNT (8)
  18. //
  19. // Min size of hostent address buffer
  20. // - enough for one address of largest type
  21. //
  22. #define MIN_ADDR_BUF_SIZE (sizeof(ATM_ADDRESS))
  23. //
  24. // String alignment in buffer
  25. //
  26. // DCR: string buffer alignment exposed globally
  27. //
  28. // Since address and string DATA (not ptrs) can be intermixed
  29. // as we build, we MUST size strings for DWORD (at minimum) so
  30. // to that addresses may be DWORD aligned.
  31. // However, when we build we can pack as tightly as desired
  32. // though obviously unicode strings must WCHAR align.
  33. //
  34. #define HOSTENT_STRING_ALIGN_DWORD(size) DWORD_ALIGN_DWORD(size)
  35. #define HOSTENT_STRING_ALIGN_PTR(ptr) DWORD_ALIGN(ptr)
  36. #define REQUIRED_HOSTENT_STRING_ALIGN_DWORD(size) WORD_ALIGN_DWORD(size)
  37. #define REQUIRED_HOSTENT_STRING_ALIGN_PTR(ptr) WORD_ALIGN(ptr)
  38. //
  39. // Hostent utilities
  40. //
  41. BOOL
  42. Hostent_IsSupportedAddrType(
  43. IN WORD wType
  44. )
  45. /*++
  46. Routine Description:
  47. Is this a supported address type for hostent.
  48. Arguments:
  49. wType -- type in question
  50. Return Value:
  51. TRUE if type supported
  52. FALSE otherwise
  53. --*/
  54. {
  55. return ( wType == DNS_TYPE_A ||
  56. wType == DNS_TYPE_AAAA ||
  57. wType == DNS_TYPE_ATMA );
  58. }
  59. DWORD
  60. Hostent_Size(
  61. IN PHOSTENT pHostent,
  62. IN DNS_CHARSET CharSetExisting,
  63. IN DNS_CHARSET CharSetTarget,
  64. IN PDWORD pAliasCount,
  65. IN PDWORD pAddrCount
  66. )
  67. /*++
  68. Routine Description:
  69. Find size of hostent.
  70. Arguments:
  71. pHostent -- hostent
  72. CharSetExisting -- char set of pHostent
  73. CharSetTarget -- char set to size to
  74. pAliasCount -- count of aliases
  75. pAddrCount -- count of addrs
  76. Return Value:
  77. Size in bytes of hostent.
  78. --*/
  79. {
  80. DWORD sizeName = 0;
  81. DWORD sizeAliasNames = 0;
  82. DWORD sizeAliasPtr;
  83. DWORD sizeAddrPtr;
  84. DWORD sizeAddrs;
  85. DWORD sizeTotal;
  86. PCHAR palias;
  87. DWORD addrCount = 0;
  88. DWORD aliasCount = 0;
  89. DNSDBG( HOSTENT, (
  90. "Hostent_Size( %p, %d, %d )\n",
  91. pHostent,
  92. CharSetExisting,
  93. CharSetTarget ));
  94. //
  95. // name
  96. //
  97. if ( pHostent->h_name )
  98. {
  99. sizeName = Dns_GetBufferLengthForStringCopy(
  100. pHostent->h_name,
  101. 0,
  102. CharSetExisting,
  103. CharSetTarget );
  104. sizeName = HOSTENT_STRING_ALIGN_DWORD( sizeName );
  105. }
  106. //
  107. // aliases
  108. //
  109. if ( pHostent->h_aliases )
  110. {
  111. while ( palias = pHostent->h_aliases[aliasCount] )
  112. {
  113. sizeAliasNames += Dns_GetBufferLengthForStringCopy(
  114. palias,
  115. 0,
  116. CharSetExisting,
  117. CharSetTarget );
  118. sizeAliasNames = HOSTENT_STRING_ALIGN_DWORD( sizeAliasNames );
  119. aliasCount++;
  120. }
  121. }
  122. sizeAliasPtr = (aliasCount+1) * sizeof(PCHAR);
  123. //
  124. // addresses
  125. //
  126. if ( pHostent->h_addr_list )
  127. {
  128. while ( pHostent->h_addr_list[addrCount] )
  129. {
  130. addrCount++;
  131. }
  132. }
  133. sizeAddrPtr = (addrCount+1) * sizeof(PCHAR);
  134. sizeAddrs = addrCount * pHostent->h_length;
  135. //
  136. // calc total size
  137. //
  138. // note: be careful of alignment issues
  139. // our layout is
  140. // - hostent struct
  141. // - ptr arrays
  142. // - address + string data
  143. //
  144. // since address and string DATA (not ptrs) can be intermixed
  145. // as we build, we MUST size strings for DWORD (at minimum) so
  146. // to that addresses may be DWORD aligned
  147. //
  148. // in copying we can copy all addresses first and avoid intermix
  149. // but DWORD string alignment is still safe
  150. //
  151. sizeTotal = POINTER_ALIGN_DWORD( sizeof(HOSTENT) ) +
  152. sizeAliasPtr +
  153. sizeAddrPtr +
  154. sizeAddrs +
  155. sizeName +
  156. sizeAliasNames;
  157. if ( pAddrCount )
  158. {
  159. *pAddrCount = addrCount;
  160. }
  161. if ( pAliasCount )
  162. {
  163. *pAliasCount = aliasCount;
  164. }
  165. DNSDBG( HOSTENT, (
  166. "Hostent sized:\n"
  167. "\tname = %d\n"
  168. "\talias ptrs = %d\n"
  169. "\talias names = %d\n"
  170. "\taddr ptrs = %d\n"
  171. "\taddrs = %d\n"
  172. "\ttotal = %d\n",
  173. sizeName,
  174. sizeAliasPtr,
  175. sizeAliasNames,
  176. sizeAddrPtr,
  177. sizeAddrs,
  178. sizeTotal ));
  179. return sizeTotal;
  180. }
  181. PHOSTENT
  182. Hostent_Init(
  183. IN OUT PBYTE * ppBuffer,
  184. //IN OUT PINT pBufSize,
  185. IN INT Family,
  186. IN INT AddrLength,
  187. IN DWORD AddrCount,
  188. IN DWORD AliasCount
  189. )
  190. /*++
  191. Routine Description:
  192. Init hostent struct.
  193. Assumes length is adequate.
  194. Arguments:
  195. ppBuffer -- addr to ptr to buffer to write hostent;
  196. on return contains next location in buffer
  197. Family -- address family
  198. AddrLength -- address length
  199. AddrCount -- address count
  200. AliasCount -- alias count
  201. Return Value:
  202. Ptr to hostent.
  203. --*/
  204. {
  205. PBYTE pbuf = *ppBuffer;
  206. PHOSTENT phost;
  207. DWORD size;
  208. //
  209. // hostent
  210. // - must be pointer aligned
  211. //
  212. phost = (PHOSTENT) POINTER_ALIGN( pbuf );
  213. phost->h_name = NULL;
  214. phost->h_length = (SHORT) AddrLength;
  215. phost->h_addrtype = (SHORT) Family;
  216. pbuf = (PBYTE) (phost + 1);
  217. //
  218. // init alias array
  219. // - set hostent ptr
  220. // - clear entire alias array;
  221. // since this count is often defaulted nice to clear it just
  222. // to avoid junk
  223. //
  224. pbuf = (PBYTE) POINTER_ALIGN( pbuf );
  225. phost->h_aliases = (PCHAR *) pbuf;
  226. size = (AliasCount+1) * sizeof(PCHAR);
  227. RtlZeroMemory(
  228. pbuf,
  229. size );
  230. pbuf += size;
  231. //
  232. // init addr array
  233. // - set hostent ptr
  234. // - clear first address entry
  235. // callers responsibility to NULL last addr pointer when done
  236. //
  237. *(PCHAR *)pbuf = NULL;
  238. phost->h_addr_list = (PCHAR *) pbuf;
  239. pbuf += (AddrCount+1) * sizeof(PCHAR);
  240. //
  241. // return next position in buffer
  242. //
  243. *ppBuffer = pbuf;
  244. return phost;
  245. }
  246. VOID
  247. Dns_PtrArrayToOffsetArray(
  248. IN OUT PCHAR * PtrArray,
  249. IN PCHAR pBase
  250. )
  251. /*++
  252. Routine Description:
  253. Change an array of pointers into array of offsets.
  254. This is used to convert aliases lists to offsets.
  255. Arguments:
  256. pPtrArray -- addr of ptr to array of pointers to convert to offsets
  257. the array must be terminated by NULL ptr
  258. pBase -- base address to offset from
  259. Return Value:
  260. None
  261. --*/
  262. {
  263. PCHAR * pptr = PtrArray;
  264. PCHAR pdata;
  265. DNSDBG( TRACE, ( "Dns_PtrArrayToOffsetArray()\n" ));
  266. //
  267. // turn each pointer into offset
  268. //
  269. while( pdata = *pptr )
  270. {
  271. *pptr++ = (PCHAR)( (PCHAR)pdata - (PCHAR)pBase );
  272. }
  273. }
  274. VOID
  275. Hostent_ConvertToOffsets(
  276. IN OUT PHOSTENT pHostent
  277. )
  278. /*++
  279. Routine Description:
  280. Convert hostent to offsets.
  281. Arguments:
  282. pHostent -- hostent to convert to offsets
  283. Return Value:
  284. None
  285. --*/
  286. {
  287. PBYTE ptr;
  288. DNSDBG( TRACE, ( "Hostent_ConvertToOffsets()\n" ));
  289. //
  290. // convert
  291. // - name
  292. // - alias array pointer
  293. // - address array pointer
  294. //
  295. if ( ptr = pHostent->h_name )
  296. {
  297. pHostent->h_name = (PCHAR) (ptr - (PBYTE)pHostent);
  298. }
  299. // alias array
  300. // - convert array pointer
  301. // - convert pointers in array
  302. if ( ptr = (PBYTE)pHostent->h_aliases )
  303. {
  304. pHostent->h_aliases = (PCHAR *) (ptr - (PBYTE)pHostent);
  305. Dns_PtrArrayToOffsetArray(
  306. (PCHAR *) ptr,
  307. (PCHAR) pHostent );
  308. }
  309. // address array
  310. // - convert array pointer
  311. // - convert pointers in array
  312. if ( ptr = (PBYTE)pHostent->h_addr_list )
  313. {
  314. pHostent->h_addr_list = (PCHAR *) (ptr - (PBYTE)pHostent);
  315. Dns_PtrArrayToOffsetArray(
  316. (PCHAR *) ptr,
  317. (PCHAR) pHostent );
  318. }
  319. DNSDBG( TRACE, ( "Leave Hostent_ConvertToOffsets()\n" ));
  320. }
  321. PHOSTENT
  322. Hostent_Copy(
  323. IN OUT PBYTE * ppBuffer,
  324. IN OUT PINT pBufferSize,
  325. OUT PINT pHostentSize,
  326. IN PHOSTENT pHostent,
  327. IN DNS_CHARSET CharSetIn,
  328. IN DNS_CHARSET CharSetTarget,
  329. IN BOOL fOffsets,
  330. IN BOOL fAlloc
  331. )
  332. /*++
  333. Routine Description:
  334. Copy a hostent.
  335. Arguments:
  336. ppBuffer -- addr with ptr to buffer to write to;
  337. if no buffer then hostent is allocated
  338. updated with ptr to position in buffer after hostent
  339. pBufferSize -- addr containing size of buffer;
  340. updated with bytes left after hostent written
  341. (even if out of space, it contains missing number of
  342. bytes as negative number)
  343. pHostentSize -- addr to recv total size of hostent written
  344. pHostent -- existing hostent to copy
  345. CharSetIn -- charset of existing hostent
  346. CharSetTarget -- charset of target hostent
  347. fOffsets -- write hostent with offsets
  348. fAlloc -- allocate copy
  349. Return Value:
  350. Ptr to new hostent.
  351. NULL on error. See GetLastError().
  352. --*/
  353. {
  354. PBYTE pch;
  355. PHOSTENT phost = NULL;
  356. DWORD size;
  357. DWORD sizeTotal;
  358. DWORD bytesLeft;
  359. DWORD aliasCount;
  360. DWORD addrCount;
  361. DWORD addrLength;
  362. PCHAR * pptrArrayIn;
  363. PCHAR * pptrArrayOut;
  364. PCHAR pdataIn;
  365. DNSDBG( HOSTENT, (
  366. "Hostent_Copy()\n" ));
  367. //
  368. // determine required hostent size
  369. // - allow sizing skip for already allocated buffers only
  370. //
  371. sizeTotal = Hostent_Size(
  372. pHostent,
  373. CharSetIn,
  374. CharSetTarget,
  375. & aliasCount,
  376. & addrCount );
  377. //
  378. // alloc or reserve size in buffer
  379. //
  380. if ( fAlloc )
  381. {
  382. pch = ALLOCATE_HEAP( sizeTotal );
  383. if ( !pch )
  384. {
  385. goto Failed;
  386. }
  387. }
  388. else
  389. {
  390. pch = FlatBuf_Arg_ReserveAlignPointer(
  391. ppBuffer,
  392. pBufferSize,
  393. sizeTotal
  394. );
  395. if ( !pch )
  396. {
  397. goto Failed;
  398. }
  399. }
  400. //
  401. // note: assuming from here on down that we have adequate space
  402. //
  403. // reason we aren't building with FlatBuf routines is that
  404. // a) i wrote this first
  405. // b) we believe we have adequate space
  406. // c) i haven't built FlatBuf string conversion routines
  407. // which we need below (for RnR unicode to ANSI)
  408. //
  409. // we could reset buf pointers here and build directly with FlatBuf
  410. // routines; this isn't directly necessary
  411. //
  412. //
  413. // init hostent struct
  414. //
  415. addrLength = pHostent->h_length;
  416. phost = Hostent_Init(
  417. & pch,
  418. pHostent->h_addrtype,
  419. addrLength,
  420. addrCount,
  421. aliasCount );
  422. DNS_ASSERT( pch > (PBYTE)phost );
  423. //
  424. // copy addresses
  425. // - no need to align as previous is address
  426. //
  427. pptrArrayIn = pHostent->h_addr_list;
  428. pptrArrayOut = phost->h_addr_list;
  429. if ( pptrArrayIn )
  430. {
  431. while( pdataIn = *pptrArrayIn++ )
  432. {
  433. *pptrArrayOut++ = pch;
  434. RtlCopyMemory(
  435. pch,
  436. pdataIn,
  437. addrLength );
  438. pch += addrLength;
  439. }
  440. }
  441. *pptrArrayOut = NULL;
  442. //
  443. // copy the aliases
  444. //
  445. pptrArrayIn = pHostent->h_aliases;
  446. pptrArrayOut = phost->h_aliases;
  447. if ( pptrArrayIn )
  448. {
  449. while( pdataIn = *pptrArrayIn++ )
  450. {
  451. pch = REQUIRED_HOSTENT_STRING_ALIGN_PTR( pch );
  452. *pptrArrayOut++ = pch;
  453. size = Dns_StringCopy(
  454. pch,
  455. NULL, // infinite size
  456. pdataIn,
  457. 0, // unknown length
  458. CharSetIn,
  459. CharSetTarget
  460. );
  461. pch += size;
  462. }
  463. }
  464. *pptrArrayOut = NULL;
  465. //
  466. // copy the name
  467. //
  468. if ( pHostent->h_name )
  469. {
  470. pch = REQUIRED_HOSTENT_STRING_ALIGN_PTR( pch );
  471. phost->h_name = pch;
  472. size = Dns_StringCopy(
  473. pch,
  474. NULL, // infinite size
  475. pHostent->h_name,
  476. 0, // unknown length
  477. CharSetIn,
  478. CharSetTarget
  479. );
  480. pch += size;
  481. }
  482. //
  483. // copy is complete
  484. // - verify our write functions work
  485. //
  486. ASSERT( (DWORD)(pch-(PBYTE)phost) <= sizeTotal );
  487. if ( pHostentSize )
  488. {
  489. *pHostentSize = (INT)( pch - (PBYTE)phost );
  490. }
  491. if ( !fAlloc )
  492. {
  493. PBYTE pnext = *ppBuffer;
  494. // if we sized too small --
  495. // fix up the buf pointer and bytes left
  496. if ( pnext < pch )
  497. {
  498. ASSERT( FALSE );
  499. *ppBuffer = pch;
  500. *pBufferSize -= (INT)(pch - pnext);
  501. }
  502. }
  503. IF_DNSDBG( HOSTENT )
  504. {
  505. DnsDbg_Hostent(
  506. "Hostent copy:",
  507. phost,
  508. (CharSetTarget == DnsCharSetUnicode) );
  509. }
  510. //
  511. // convert to offsets?
  512. //
  513. if ( fOffsets )
  514. {
  515. Hostent_ConvertToOffsets( phost );
  516. }
  517. Failed:
  518. DNSDBG( TRACE, (
  519. "Leave Hostent_Copy() => %p\n",
  520. phost ));
  521. return phost;
  522. }
  523. DWORD
  524. Hostent_WriteIp4Addrs(
  525. IN OUT PHOSTENT pHostent,
  526. OUT PCHAR pAddrBuf,
  527. IN DWORD MaxBufCount,
  528. IN PIP4_ADDRESS Ip4Array,
  529. IN DWORD ArrayCount,
  530. IN BOOL fScreenZero
  531. )
  532. /*++
  533. Routine Description:
  534. Write IP4 addresses to hostent.
  535. Arguments:
  536. pHostent -- hostent
  537. pAddrBuf -- buffer to hold addresses
  538. MaxBufCount -- max IPs buffer can hold
  539. Ip4Array -- array of IP4 addresses
  540. ArrayCount -- array count
  541. fScreenZero -- screen out zero addresses?
  542. Return Value:
  543. Count of addresses written
  544. --*/
  545. {
  546. DWORD i = 0;
  547. DWORD stopCount = MaxBufCount;
  548. PIP4_ADDRESS pip = (PIP_ADDRESS) pAddrBuf;
  549. PIP4_ADDRESS * pipPtr = (PIP4_ADDRESS *) pHostent->h_addr_list;
  550. //
  551. // write IP addresses OR loopback if no IPs
  552. //
  553. if ( Ip4Array )
  554. {
  555. if ( ArrayCount < stopCount )
  556. {
  557. stopCount = ArrayCount;
  558. }
  559. for ( i=0; i < stopCount; ++i )
  560. {
  561. IP4_ADDRESS ip = Ip4Array[i];
  562. if ( ip != 0 || !fScreenZero )
  563. {
  564. *pip = ip;
  565. *pipPtr++ = pip++;
  566. }
  567. }
  568. }
  569. *pipPtr = NULL;
  570. // count of addresses written
  571. return( i );
  572. }
  573. DWORD
  574. Hostent_WriteLocalIp4Array(
  575. IN OUT PHOSTENT pHostent,
  576. OUT PCHAR pAddrBuf,
  577. IN DWORD MaxBufCount,
  578. IN PIP_ARRAY pIpArray
  579. )
  580. /*++
  581. Routine Description:
  582. Write local IP list into hostent.
  583. Arguments:
  584. pHostent -- hostent
  585. pAddrBuf -- buffer to hold addresses
  586. MaxBufCount -- max IPs buffer can hold
  587. pIpArray -- IP4 array of local addresses
  588. Return Value:
  589. Count of addresses written
  590. --*/
  591. {
  592. DWORD count = 0;
  593. //
  594. // write array
  595. //
  596. if ( pIpArray )
  597. {
  598. count = Hostent_WriteIp4Addrs(
  599. pHostent,
  600. pAddrBuf,
  601. MaxBufCount,
  602. pIpArray->AddrArray,
  603. pIpArray->AddrCount,
  604. TRUE // screen out zeros
  605. );
  606. }
  607. //
  608. // if no addresses written, write loopback
  609. //
  610. if ( count==0 )
  611. {
  612. pHostent->h_addr_list[0] = pAddrBuf;
  613. pHostent->h_addr_list[1] = NULL;
  614. *((IP4_ADDRESS*)pAddrBuf) = DNS_NET_ORDER_LOOPBACK;
  615. count = 1;
  616. }
  617. // count of addresses written
  618. return( count );
  619. }
  620. BOOL
  621. Hostent_SetToSingleAddress(
  622. IN OUT PHOSTENT pHostent,
  623. IN PCHAR pAddr,
  624. IN DWORD AddrLength
  625. )
  626. /*++
  627. Routine Description:
  628. Set address in hostent.
  629. Arguments:
  630. pHostent -- hostent to check
  631. pAddr -- ptr to address to check
  632. AddrLength -- address length
  633. Return Value:
  634. TRUE if address successfully copied into hostent.
  635. FALSE otherwise (no hostent, wrong length, hostent empty)
  636. --*/
  637. {
  638. PCHAR paddrHostent;
  639. //
  640. // validate
  641. // - must have hostent
  642. // - length must match
  643. //
  644. if ( !pHostent ||
  645. AddrLength != (DWORD)pHostent->h_length )
  646. {
  647. return FALSE;
  648. }
  649. //
  650. // slam address in on top of existing
  651. // - NULL 2nd addr pointer to terminate list
  652. //
  653. paddrHostent = pHostent->h_addr_list[0];
  654. if ( !paddrHostent )
  655. {
  656. return FALSE;
  657. }
  658. RtlCopyMemory(
  659. paddrHostent,
  660. pAddr,
  661. AddrLength );
  662. pHostent->h_addr_list[1] = NULL;
  663. return TRUE;
  664. }
  665. BOOL
  666. Hostent_IsAddressInHostent(
  667. IN OUT PHOSTENT pHostent,
  668. IN PCHAR pAddr,
  669. IN DWORD AddrLength,
  670. IN INT Family OPTIONAL
  671. )
  672. /*++
  673. Routine Description:
  674. Does hostent contain this address.
  675. Arguments:
  676. pHostent -- hostent to check
  677. pAddr -- ptr to address to check
  678. AddrLength -- address length
  679. Family -- address family
  680. Return Value:
  681. TRUE if address is in hostent.
  682. FALSE otherwise.
  683. --*/
  684. {
  685. BOOL freturn = FALSE;
  686. DWORD i;
  687. PCHAR paddrHostent;
  688. //
  689. // validate
  690. // - must have hostent
  691. // - must have address
  692. // - if family given, must match
  693. // - length must match
  694. //
  695. if ( !pHostent ||
  696. !pAddr ||
  697. AddrLength != (DWORD)pHostent->h_length ||
  698. ( Family && Family != pHostent->h_addrtype ) )
  699. {
  700. return freturn;
  701. }
  702. //
  703. // search for address -- if found return TRUE
  704. //
  705. i = 0;
  706. while ( paddrHostent = pHostent->h_addr_list[i++] )
  707. {
  708. freturn = RtlEqualMemory(
  709. paddrHostent,
  710. pAddr,
  711. AddrLength );
  712. if ( freturn )
  713. {
  714. break;
  715. }
  716. }
  717. return freturn;
  718. }
  719. BOOL
  720. Hostent_IsIp4AddressInHostent(
  721. IN OUT PHOSTENT pHostent,
  722. IN IP4_ADDRESS Ip4Addr
  723. )
  724. /*++
  725. Routine Description:
  726. Does hostent contain this address.
  727. Arguments:
  728. pHostent -- hostent to check
  729. pAddr -- ptr to address to check
  730. AddrLength -- address length
  731. Family -- address family
  732. Return Value:
  733. TRUE if address is in hostent.
  734. FALSE otherwise.
  735. --*/
  736. {
  737. DWORD i;
  738. PCHAR paddrHostent;
  739. //
  740. // validate
  741. // - must have hostent
  742. // - length must match
  743. //
  744. if ( !pHostent ||
  745. sizeof(IP4_ADDRESS) != (DWORD)pHostent->h_length )
  746. {
  747. return FALSE;
  748. }
  749. //
  750. // search for address -- if found return TRUE
  751. //
  752. i = 0;
  753. while ( paddrHostent = pHostent->h_addr_list[i++] )
  754. {
  755. if ( Ip4Addr == *(PIP4_ADDRESS)paddrHostent )
  756. {
  757. return TRUE;
  758. }
  759. }
  760. return FALSE;
  761. }
  762. //
  763. // Hostent building utilities
  764. //
  765. DNS_STATUS
  766. HostentBlob_Create(
  767. IN OUT PHOSTENT_BLOB * ppBlob,
  768. IN PHOSTENT_INIT pReq
  769. )
  770. /*++
  771. Routine Description:
  772. Initialize hostent (extending buffers as necessary)
  773. May allocate hostent buffer if existing too small.
  774. Returns required size.
  775. Arguments:
  776. ppBlob -- addr containing or to recv hostent object
  777. pReq -- hostent init request
  778. Return Value:
  779. --*/
  780. {
  781. PHOSTENT_BLOB pblob = *ppBlob;
  782. PHOSTENT phost;
  783. PCHAR pbuf;
  784. BOOL funicode = FALSE;
  785. DWORD bytesLeft;
  786. DWORD addrSize;
  787. DWORD addrType;
  788. DWORD countAlias;
  789. DWORD countAddr;
  790. DWORD sizeChar;
  791. DWORD sizeHostent = 0;
  792. DWORD sizeAliasPtr;
  793. DWORD sizeAddrPtr;
  794. DWORD sizeAddrs;
  795. DWORD sizeName;
  796. DWORD sizeAliasNames;
  797. DWORD sizeTotal;
  798. DNSDBG( HOSTENT, ( "HostentBlob_Create()\n" ));
  799. //
  800. // calculate required size
  801. //
  802. // size for all char allocs
  803. //
  804. // note, we save CharSet info, if known, but the real
  805. // action in sizing or building or printing strings is simply
  806. // unicode\not-unicode
  807. sizeChar = sizeof(CHAR);
  808. if ( pReq->fUnicode || pReq->CharSet == DnsCharSetUnicode )
  809. {
  810. sizeChar = sizeof(WCHAR);
  811. funicode = TRUE;
  812. }
  813. // limit alias count
  814. countAlias = pReq->AliasCount;
  815. if ( countAlias > DNS_MAX_ALIAS_COUNT )
  816. {
  817. countAlias = DNS_MAX_ALIAS_COUNT;
  818. }
  819. sizeAliasPtr = (countAlias+1) * sizeof(PCHAR);
  820. // size address pointer array
  821. // - always size for at least one address
  822. // - write PTR address after record write
  823. // - write loopback or other local address
  824. // into local hostent
  825. countAddr = pReq->AddrCount;
  826. if ( countAddr == 0 )
  827. {
  828. countAddr = 1;
  829. }
  830. sizeAddrPtr = (countAddr+1) * sizeof(PCHAR);
  831. //
  832. // determine address size and type
  833. // - may be specified directly
  834. // - or picked up from DNS type
  835. //
  836. // DCR: functionalize type-to\from-family and addr size
  837. //
  838. addrType = pReq->AddrFamily;
  839. if ( !addrType )
  840. {
  841. WORD wtype = pReq->wType;
  842. if ( wtype == DNS_TYPE_A )
  843. {
  844. addrType = AF_INET;
  845. }
  846. else if ( wtype == DNS_TYPE_AAAA ||
  847. wtype == DNS_TYPE_A6 )
  848. {
  849. addrType = AF_INET6;
  850. }
  851. else if ( wtype == DNS_TYPE_ATMA )
  852. {
  853. addrType = AF_ATM;
  854. }
  855. }
  856. if ( addrType == AF_INET )
  857. {
  858. addrSize = sizeof(IP4_ADDRESS);
  859. }
  860. else if ( addrType == AF_INET6 )
  861. {
  862. addrSize = sizeof(IP6_ADDRESS );
  863. }
  864. else if ( addrType == AF_ATM )
  865. {
  866. addrSize = sizeof(ATM_ADDRESS);
  867. }
  868. else
  869. {
  870. // should have type and count or neither
  871. DNS_ASSERT( pReq->AddrCount == 0 );
  872. addrSize = 0;
  873. }
  874. sizeAddrs = countAddr * addrSize;
  875. // always have buffer large enough for one
  876. // address of largest type
  877. if ( sizeAddrs < MIN_ADDR_BUF_SIZE )
  878. {
  879. sizeAddrs = MIN_ADDR_BUF_SIZE;
  880. }
  881. //
  882. // namelength
  883. // - if actual name use it
  884. // (charset must match type we're building)
  885. // - if size, use it
  886. // - if absent use MAX
  887. // - round to DWORD
  888. if ( pReq->pName )
  889. {
  890. if ( funicode )
  891. {
  892. sizeName = wcslen( (PWSTR)pReq->pName );
  893. }
  894. else
  895. {
  896. sizeName = strlen( pReq->pName );
  897. }
  898. }
  899. else
  900. {
  901. sizeName = pReq->NameLength;
  902. }
  903. if ( sizeName )
  904. {
  905. sizeName++;
  906. }
  907. else
  908. {
  909. sizeName = DNS_MAX_NAME_BUFFER_LENGTH;
  910. }
  911. sizeName = HOSTENT_STRING_ALIGN_DWORD( sizeChar*sizeName );
  912. //
  913. // alias name lengths
  914. // - if absent use MAX for each string
  915. // - round to DWORD
  916. //
  917. sizeAliasNames = pReq->AliasNameLength;
  918. if ( sizeAliasNames )
  919. {
  920. sizeAliasNames += pReq->AliasCount;
  921. }
  922. else
  923. {
  924. sizeAliasNames = DNS_MAX_NAME_BUFFER_LENGTH;
  925. }
  926. sizeAliasNames = HOSTENT_STRING_ALIGN_DWORD( sizeChar*sizeAliasNames );
  927. //
  928. // calc total size
  929. //
  930. // note: be careful of alignment issues
  931. // our layout is
  932. // - hostent struct
  933. // - ptr arrays
  934. // - address + string data
  935. //
  936. // since address and string DATA (not ptrs) can be intermixed
  937. // as we build, we MUST size strings for DWORD (at minimum) so
  938. // to that addresses may be DWORD aligned
  939. //
  940. sizeTotal = POINTER_ALIGN_DWORD( sizeof(HOSTENT) ) +
  941. sizeAliasPtr +
  942. sizeAddrPtr +
  943. sizeAddrs +
  944. sizeName +
  945. sizeAliasNames;
  946. //
  947. // if no blob, allocate one along with buffer
  948. //
  949. if ( !pblob )
  950. {
  951. pblob = (PHOSTENT_BLOB) ALLOCATE_HEAP( sizeTotal + sizeof(HOSTENT_BLOB) );
  952. if ( !pblob )
  953. {
  954. goto Failed;
  955. }
  956. RtlZeroMemory( pblob, sizeof(*pblob) );
  957. pbuf = (PCHAR) (pblob + 1);
  958. pblob->pBuffer = pbuf;
  959. pblob->BufferLength = sizeTotal;
  960. pblob->fAllocatedBlob = TRUE;
  961. pblob->fAllocatedBuf = FALSE;
  962. }
  963. //
  964. // check existing buffer for size
  965. // - allocate new buffer if necessary
  966. //
  967. else
  968. {
  969. pbuf = pblob->pBuffer;
  970. if ( !pbuf || pblob->BufferLength < sizeTotal )
  971. {
  972. if ( pbuf && pblob->fAllocatedBuf )
  973. {
  974. FREE_HEAP( pbuf );
  975. }
  976. pbuf = ALLOCATE_HEAP( sizeTotal );
  977. pblob->pBuffer = pbuf;
  978. if ( pbuf )
  979. {
  980. pblob->BufferLength = sizeTotal;
  981. pblob->fAllocatedBuf = TRUE;
  982. }
  983. //
  984. // DCR: alloc failure handling
  985. // - possibly keep previous buffers limitations
  986. //
  987. else // alloc failed
  988. {
  989. pblob->fAllocatedBuf = FALSE;
  990. return( DNS_ERROR_NO_MEMORY );
  991. }
  992. }
  993. }
  994. //
  995. // init hostent and buffer subfields
  996. //
  997. bytesLeft = pblob->BufferLength;
  998. //
  999. // hostent
  1000. //
  1001. phost = (PHOSTENT) pbuf;
  1002. pbuf += sizeof(HOSTENT);
  1003. bytesLeft -= sizeof(HOSTENT);
  1004. pblob->pHostent = phost;
  1005. phost->h_name = NULL;
  1006. phost->h_addr_list = NULL;
  1007. phost->h_aliases = NULL;
  1008. phost->h_length = (SHORT) addrSize;
  1009. phost->h_addrtype = (SHORT) addrType;
  1010. pblob->fWroteName = FALSE;
  1011. pblob->AliasCount = 0;
  1012. pblob->AddrCount = 0;
  1013. pblob->CharSet = pReq->CharSet;
  1014. pblob->fUnicode = funicode;
  1015. if ( funicode )
  1016. {
  1017. pblob->CharSet = DnsCharSetUnicode;
  1018. }
  1019. //
  1020. // init alias array
  1021. // - set hostent ptr
  1022. // - clear entire alias array;
  1023. // since this count is often defaulted nice to clear it just
  1024. // to avoid junk
  1025. //
  1026. //
  1027. #if 0
  1028. pwrite = FlatBuf_ReserveAlignPointer(
  1029. & pbuf,
  1030. & bytesLeft,
  1031. sizeAliasPtr );
  1032. #endif
  1033. if ( bytesLeft < sizeAliasPtr )
  1034. {
  1035. DNS_ASSERT( FALSE );
  1036. goto Failed;
  1037. }
  1038. RtlZeroMemory(
  1039. pbuf,
  1040. sizeAliasPtr );
  1041. phost->h_aliases = (PCHAR *) pbuf;
  1042. pbuf += sizeAliasPtr;
  1043. bytesLeft -= sizeAliasPtr;
  1044. pblob->MaxAliasCount = countAlias;
  1045. //
  1046. // init addr array
  1047. // - set hostent ptr
  1048. // - clear first address entry
  1049. // callers responsibility to NULL last addr pointer when done
  1050. //
  1051. if ( bytesLeft < sizeAddrPtr )
  1052. {
  1053. DNS_ASSERT( FALSE );
  1054. goto Failed;
  1055. }
  1056. * (PCHAR *)pbuf = NULL;
  1057. phost->h_addr_list = (PCHAR *) pbuf;
  1058. pbuf += sizeAddrPtr;
  1059. bytesLeft -= sizeAddrPtr;
  1060. pblob->MaxAddrCount = countAddr;
  1061. //
  1062. // set remaining buffer info
  1063. // - save current buffer space
  1064. // - save data on part of buffer available
  1065. // for use by data
  1066. //
  1067. pblob->pAvailBuffer = pbuf;
  1068. pblob->AvailLength = bytesLeft;
  1069. pblob->pCurrent = pbuf;
  1070. pblob->BytesLeft = bytesLeft;
  1071. *ppBlob = pblob;
  1072. IF_DNSDBG( HOSTENT )
  1073. {
  1074. DnsDbg_HostentBlob(
  1075. "HostentBlob After Create:",
  1076. pblob );
  1077. }
  1078. return( ERROR_SUCCESS );
  1079. Failed:
  1080. *ppBlob = pblob;
  1081. if ( pblob && pblob->pBuffer && pblob->fAllocatedBuf )
  1082. {
  1083. FREE_HEAP( pblob->pBuffer );
  1084. pblob->pBuffer = NULL;
  1085. pblob->fAllocatedBuf = FALSE;
  1086. }
  1087. DNSDBG( HOSTENT, ( "Hostent Blob create failed!\n" ));
  1088. return( DNS_ERROR_NO_MEMORY );
  1089. }
  1090. PHOSTENT_BLOB
  1091. HostentBlob_CreateAttachExisting(
  1092. IN PHOSTENT pHostent,
  1093. IN BOOL fUnicode
  1094. )
  1095. /*++
  1096. Routine Description:
  1097. Create hostent blob for existing hostent.
  1098. This is a hack to allow existing RnR TLS hostents to
  1099. be attached to hostent-blobs to smooth code transition.
  1100. A full version would obviously require init structure and
  1101. separate the sizing\init function from the creation
  1102. function.
  1103. Arguments:
  1104. pHostent -- existing hostent
  1105. fUnicode -- is unicode
  1106. Return Value:
  1107. Ptr to new hostent blob.
  1108. NULL on alloc failure. GetLastError() has error.
  1109. --*/
  1110. {
  1111. PHOSTENT_BLOB pblob;
  1112. DNSDBG( HOSTENT, ( "HostentBlob_CreateAttachExisting()\n" ));
  1113. //
  1114. // alloc
  1115. //
  1116. pblob = (PHOSTENT_BLOB) ALLOCATE_HEAP_ZERO( sizeof(HOSTENT_BLOB) );
  1117. if ( !pblob )
  1118. {
  1119. SetLastError( DNS_ERROR_NO_MEMORY );
  1120. return NULL;
  1121. }
  1122. //
  1123. // attach existing hostent
  1124. //
  1125. pblob->pHostent = pHostent;
  1126. pblob->fUnicode = fUnicode;
  1127. IF_DNSDBG( HOSTENT )
  1128. {
  1129. DnsDbg_HostentBlob(
  1130. "Leaving AttachExisting:",
  1131. pblob );
  1132. }
  1133. return pblob;
  1134. }
  1135. VOID
  1136. HostentBlob_Free(
  1137. IN OUT PHOSTENT_BLOB pBlob
  1138. )
  1139. /*++
  1140. Routine Description:
  1141. Free hostent blob.
  1142. Arguments:
  1143. pBlob -- blob to free
  1144. Return Value:
  1145. None
  1146. --*/
  1147. {
  1148. //
  1149. // free buffer?
  1150. //
  1151. if ( !pBlob )
  1152. {
  1153. return;
  1154. }
  1155. if ( pBlob->fAllocatedBuf )
  1156. {
  1157. FREE_HEAP( pBlob->pBuffer );
  1158. pBlob->pBuffer = NULL;
  1159. pBlob->fAllocatedBuf = FALSE;
  1160. }
  1161. //
  1162. // free blob itself?
  1163. //
  1164. if ( pBlob->fAllocatedBlob )
  1165. {
  1166. FREE_HEAP( pBlob );
  1167. }
  1168. }
  1169. DNS_STATUS
  1170. HostentBlob_WriteAddress(
  1171. IN OUT PHOSTENT_BLOB pBlob,
  1172. IN PVOID pAddress,
  1173. IN DWORD AddrSize,
  1174. IN DWORD AddrType
  1175. )
  1176. /*++
  1177. Routine Description:
  1178. Write IP4 address to hostent blob.
  1179. Arguments:
  1180. pBlob -- hostent build blob
  1181. pAddress - address to write
  1182. AddrSize - address size
  1183. AddrType - address type (hostent type, e.g. AF_INET)
  1184. Return Value:
  1185. ERROR_SUCCESS if successful.
  1186. ERROR_MORE_DATA if out of buffer space
  1187. ERROR_INVALID_DATA if address doesn't match hostent
  1188. --*/
  1189. {
  1190. DWORD count = pBlob->AddrCount;
  1191. PHOSTENT phost = pBlob->pHostent;
  1192. PCHAR pcurrent;
  1193. DWORD bytesLeft;
  1194. // verify type
  1195. // - set if empty or no addresses written
  1196. if ( phost->h_addrtype != (SHORT)AddrType )
  1197. {
  1198. if ( phost->h_addrtype != 0 )
  1199. {
  1200. return( ERROR_INVALID_DATA );
  1201. }
  1202. phost->h_addrtype = (SHORT) AddrType;
  1203. phost->h_length = (SHORT) AddrSize;
  1204. }
  1205. // verify space
  1206. if ( count >= pBlob->MaxAddrCount )
  1207. {
  1208. return( ERROR_MORE_DATA );
  1209. }
  1210. // align - to DWORD
  1211. pcurrent = DWORD_ALIGN( pBlob->pCurrent );
  1212. bytesLeft = pBlob->BytesLeft;
  1213. bytesLeft -= (DWORD)(pcurrent - pBlob->pCurrent);
  1214. if ( bytesLeft < AddrSize )
  1215. {
  1216. return( ERROR_MORE_DATA );
  1217. }
  1218. // copy
  1219. // - copy address to buffer
  1220. // - set pointer in addr list
  1221. // NULL following pointer
  1222. RtlCopyMemory(
  1223. pcurrent,
  1224. pAddress,
  1225. AddrSize );
  1226. phost->h_addr_list[count++] = pcurrent;
  1227. phost->h_addr_list[count] = NULL;
  1228. pBlob->AddrCount = count;
  1229. pBlob->pCurrent = pcurrent + AddrSize;
  1230. pBlob->BytesLeft = bytesLeft - AddrSize;
  1231. return( NO_ERROR );
  1232. }
  1233. DNS_STATUS
  1234. HostentBlob_WriteAddressArray(
  1235. IN OUT PHOSTENT_BLOB pBlob,
  1236. IN PVOID pAddrArray,
  1237. IN DWORD AddrCount,
  1238. IN DWORD AddrSize,
  1239. IN DWORD AddrType
  1240. )
  1241. /*++
  1242. Routine Description:
  1243. Write address array to hostent blob.
  1244. Arguments:
  1245. pBlob -- hostent build blob
  1246. pAddrArray - address array to write
  1247. AddrCount - address count
  1248. AddrSize - address size
  1249. AddrType - address type (hostent type, e.g. AF_INET)
  1250. Return Value:
  1251. ERROR_SUCCESS if successful.
  1252. ERROR_MORE_DATA if out of buffer space
  1253. ERROR_INVALID_DATA if address doesn't match hostent
  1254. --*/
  1255. {
  1256. DWORD count = AddrCount;
  1257. PHOSTENT phost = pBlob->pHostent;
  1258. PCHAR pcurrent;
  1259. DWORD totalSize;
  1260. DWORD i;
  1261. DWORD bytesLeft;
  1262. // verify type
  1263. // - set if empty or no addresses written
  1264. if ( phost->h_addrtype != (SHORT)AddrType )
  1265. {
  1266. if ( phost->h_addrtype != 0 )
  1267. {
  1268. return( ERROR_INVALID_DATA );
  1269. }
  1270. phost->h_addrtype = (SHORT) AddrType;
  1271. phost->h_length = (SHORT) AddrSize;
  1272. }
  1273. // verify space
  1274. if ( count > pBlob->MaxAddrCount )
  1275. {
  1276. return( ERROR_MORE_DATA );
  1277. }
  1278. // align - to DWORD
  1279. //
  1280. // note: we are assuming that pAddrArray is internally
  1281. // aligned adequately, otherwise we wouldn't be
  1282. // getting an intact array and would have to add serially
  1283. pcurrent = DWORD_ALIGN( pBlob->pCurrent );
  1284. bytesLeft = pBlob->BytesLeft;
  1285. bytesLeft -= (DWORD)(pcurrent - pBlob->pCurrent);
  1286. totalSize = count * AddrSize;
  1287. if ( bytesLeft < totalSize )
  1288. {
  1289. return( ERROR_MORE_DATA );
  1290. }
  1291. // copy
  1292. // - copy address array to buffer
  1293. // - set pointer to each address in array
  1294. // - NULL following pointer
  1295. RtlCopyMemory(
  1296. pcurrent,
  1297. pAddrArray,
  1298. totalSize );
  1299. for ( i=0; i<count; i++ )
  1300. {
  1301. phost->h_addr_list[i] = pcurrent;
  1302. pcurrent += AddrSize;
  1303. }
  1304. phost->h_addr_list[count] = NULL;
  1305. pBlob->AddrCount = count;
  1306. pBlob->pCurrent = pcurrent;
  1307. pBlob->BytesLeft = bytesLeft - totalSize;
  1308. return( NO_ERROR );
  1309. }
  1310. DNS_STATUS
  1311. HostentBlob_WriteNameOrAlias(
  1312. IN OUT PHOSTENT_BLOB pBlob,
  1313. IN PSTR pszName,
  1314. IN BOOL fAlias,
  1315. IN BOOL fUnicode
  1316. )
  1317. /*++
  1318. Routine Description:
  1319. Write name or alias to hostent
  1320. Arguments:
  1321. pBlob -- hostent build blob
  1322. pszName -- name to write
  1323. fAlias -- TRUE for alias; FALSE for name
  1324. fUnicode -- name is unicode
  1325. Return Value:
  1326. ERROR_SUCCESS if successful.
  1327. ERROR_MORE_DATA if out of buffer space
  1328. ERROR_INVALID_DATA if address doesn't match hostent
  1329. --*/
  1330. {
  1331. DWORD count = pBlob->AliasCount;
  1332. PHOSTENT phost = pBlob->pHostent;
  1333. DWORD length;
  1334. PCHAR pcurrent;
  1335. DWORD bytesLeft;
  1336. //
  1337. // check length
  1338. //
  1339. if ( fUnicode )
  1340. {
  1341. length = (wcslen( (PCWSTR)pszName ) + 1) * sizeof(WCHAR);
  1342. }
  1343. else
  1344. {
  1345. length = strlen( pszName ) + 1;
  1346. }
  1347. //
  1348. // verify space
  1349. // included ptr space
  1350. // - skip if already written name
  1351. // or exhausted alias array
  1352. //
  1353. if ( fAlias )
  1354. {
  1355. if ( count >= pBlob->MaxAliasCount )
  1356. {
  1357. return( ERROR_MORE_DATA );
  1358. }
  1359. }
  1360. else if ( pBlob->fWroteName )
  1361. {
  1362. return( ERROR_MORE_DATA );
  1363. }
  1364. // align
  1365. pcurrent = REQUIRED_HOSTENT_STRING_ALIGN_PTR( pBlob->pCurrent );
  1366. bytesLeft = pBlob->BytesLeft;
  1367. bytesLeft -= (DWORD)(pcurrent - pBlob->pCurrent);
  1368. if ( bytesLeft < length )
  1369. {
  1370. return( ERROR_MORE_DATA );
  1371. }
  1372. // copy
  1373. // - copy address to buffer
  1374. // - set pointer in addr list
  1375. // NULL following pointer
  1376. RtlCopyMemory(
  1377. pcurrent,
  1378. pszName,
  1379. length );
  1380. if ( fAlias )
  1381. {
  1382. phost->h_aliases[count++] = pcurrent;
  1383. phost->h_aliases[count] = NULL;
  1384. pBlob->AliasCount = count;
  1385. }
  1386. else
  1387. {
  1388. phost->h_name = pcurrent;
  1389. pBlob->fWroteName = TRUE;
  1390. }
  1391. length = REQUIRED_HOSTENT_STRING_ALIGN_DWORD( length );
  1392. pBlob->pCurrent = pcurrent + length;
  1393. pBlob->BytesLeft = bytesLeft - length;
  1394. return( NO_ERROR );
  1395. }
  1396. DNS_STATUS
  1397. HostentBlob_WriteRecords(
  1398. IN OUT PHOSTENT_BLOB pBlob,
  1399. IN PDNS_RECORD pRecords,
  1400. IN BOOL fWriteName
  1401. )
  1402. /*++
  1403. Routine Description:
  1404. Write name or alias to hostent
  1405. Arguments:
  1406. pBlob -- hostent build blob
  1407. pRecords -- records to convert to hostent
  1408. fWriteName -- write name
  1409. Return Value:
  1410. ERROR_SUCCESS if successful.
  1411. ERROR_MORE_DATA if out of buffer space
  1412. ERROR_INVALID_DATA if address doesn't match hostent
  1413. --*/
  1414. {
  1415. DNS_STATUS status = NO_ERROR;
  1416. PDNS_RECORD prr = pRecords;
  1417. DNSDBG( HOSTENT, (
  1418. "HostentBlob_WriteRecords( %p, %p, %d )\n",
  1419. pBlob,
  1420. pRecords,
  1421. fWriteName ));
  1422. //
  1423. // write each record in turn to hostent
  1424. //
  1425. while ( prr )
  1426. {
  1427. WORD wtype;
  1428. if ( prr->Flags.S.Section != DNSREC_ANSWER &&
  1429. prr->Flags.S.Section != 0 )
  1430. {
  1431. prr = prr->pNext;
  1432. continue;
  1433. }
  1434. wtype = prr->wType;
  1435. switch( wtype )
  1436. {
  1437. case DNS_TYPE_A:
  1438. status = HostentBlob_WriteAddress(
  1439. pBlob,
  1440. &prr->Data.A.IpAddress,
  1441. sizeof(IP4_ADDRESS),
  1442. AF_INET );
  1443. break;
  1444. case DNS_TYPE_AAAA:
  1445. status = HostentBlob_WriteAddress(
  1446. pBlob,
  1447. &prr->Data.AAAA.Ip6Address,
  1448. sizeof(IP6_ADDRESS ),
  1449. AF_INET6 );
  1450. break;
  1451. case DNS_TYPE_ATMA:
  1452. {
  1453. ATM_ADDRESS atmAddr;
  1454. // DCR: functionalize ATMA to ATM conversion
  1455. // not sure this num of digits is correct
  1456. // may have to actually parse address
  1457. atmAddr.AddressType = prr->Data.ATMA.AddressType;
  1458. atmAddr.NumofDigits = ATM_ADDR_SIZE;
  1459. RtlCopyMemory(
  1460. & atmAddr.Addr,
  1461. prr->Data.ATMA.Address,
  1462. ATM_ADDR_SIZE );
  1463. status = HostentBlob_WriteAddress(
  1464. pBlob,
  1465. & atmAddr,
  1466. sizeof(ATM_ADDRESS),
  1467. AF_ATM );
  1468. break;
  1469. }
  1470. case DNS_TYPE_CNAME:
  1471. // record name is an alias
  1472. status = HostentBlob_WriteNameOrAlias(
  1473. pBlob,
  1474. prr->pName,
  1475. TRUE, // alias
  1476. (prr->Flags.S.CharSet == DnsCharSetUnicode)
  1477. );
  1478. break;
  1479. case DNS_TYPE_PTR:
  1480. // target name is the hostent name
  1481. // but if already wrote name, PTR target becomes alias
  1482. status = HostentBlob_WriteNameOrAlias(
  1483. pBlob,
  1484. prr->Data.PTR.pNameHost,
  1485. pBlob->fWroteName
  1486. ? TRUE // alias
  1487. : FALSE, // name
  1488. (prr->Flags.S.CharSet == DnsCharSetUnicode)
  1489. );
  1490. break;
  1491. default:
  1492. DNSDBG( ANY, (
  1493. "Error record of type = %d while building hostent!\n",
  1494. wtype ));
  1495. status = ERROR_INVALID_DATA;
  1496. }
  1497. if ( status != ERROR_SUCCESS )
  1498. {
  1499. DNSDBG( ANY, (
  1500. "ERROR: failed writing record to hostent!\n"
  1501. "\tprr = %p\n"
  1502. "\ttype = %d\n"
  1503. "\tstatus = %d\n",
  1504. prr,
  1505. wtype,
  1506. status ));
  1507. }
  1508. prr = prr->pNext;
  1509. }
  1510. IF_DNSDBG( HOSTENT )
  1511. {
  1512. DnsDbg_HostentBlob(
  1513. "HostentBlob after WriteRecords():",
  1514. pBlob );
  1515. }
  1516. return( status );
  1517. }
  1518. DNS_STATUS
  1519. HostentBlob_CreateFromRecords(
  1520. IN OUT PHOSTENT_BLOB * ppBlob,
  1521. IN PDNS_RECORD pRecords,
  1522. IN BOOL fWriteName,
  1523. IN INT AddrFamily, OPTIONAL
  1524. IN WORD wType OPTIONAL
  1525. )
  1526. /*++
  1527. Routine Description:
  1528. Create hostent from records
  1529. Arguments:
  1530. ppBlob -- ptr with or to recv hostent blob
  1531. pRecords -- records to convert to hostent
  1532. fWriteName -- write name to hostent
  1533. AddrFamily -- addr family use if PTR records and no addr
  1534. wType -- query type, if known
  1535. Return Value:
  1536. Ptr to blob if successful.
  1537. NULL on error; GetLastError() has error.
  1538. --*/
  1539. {
  1540. DNS_STATUS status = NO_ERROR;
  1541. PDNS_RECORD prrFirstAddr = NULL;
  1542. PDNS_RECORD prr;
  1543. DWORD addrCount = 0;
  1544. WORD addrType = 0;
  1545. HOSTENT_INIT request;
  1546. PHOSTENT_BLOB pblob = *ppBlob;
  1547. DNSDBG( HOSTENT, (
  1548. "HostentBlob_CreateFromRecords()\n"
  1549. "\tpblob = %p\n"
  1550. "\tprr = %p\n",
  1551. pblob,
  1552. pRecords ));
  1553. //
  1554. // count addresses
  1555. //
  1556. // DCR: fix up section hack when hosts file records get ANSWER section
  1557. //
  1558. prr = pRecords;
  1559. while ( prr )
  1560. {
  1561. if ( ( prr->Flags.S.Section == 0 ||
  1562. prr->Flags.S.Section == DNSREC_ANSWER )
  1563. &&
  1564. Hostent_IsSupportedAddrType( prr->wType ) )
  1565. {
  1566. addrCount++;
  1567. if ( !prrFirstAddr )
  1568. {
  1569. prrFirstAddr = prr;
  1570. addrType = prr->wType;
  1571. }
  1572. }
  1573. prr = prr->pNext;
  1574. }
  1575. //
  1576. // create or reinit hostent blob
  1577. //
  1578. RtlZeroMemory( &request, sizeof(request) );
  1579. request.AliasCount = DNS_MAX_ALIAS_COUNT;
  1580. request.AddrCount = addrCount;
  1581. request.wType = addrType;
  1582. if ( !addrType )
  1583. {
  1584. request.AddrFamily = AddrFamily;
  1585. }
  1586. request.CharSet = (pRecords)
  1587. ? pRecords->Flags.S.CharSet
  1588. : DnsCharSetUnicode;
  1589. status = HostentBlob_Create(
  1590. & pblob,
  1591. & request );
  1592. if ( status != NO_ERROR )
  1593. {
  1594. goto Done;
  1595. }
  1596. //
  1597. // build hostent from answer records
  1598. //
  1599. // note: if manage to extract any useful data => continue
  1600. // this protects against new unwriteable records breaking us
  1601. //
  1602. status = HostentBlob_WriteRecords(
  1603. pblob,
  1604. pRecords,
  1605. TRUE // write name
  1606. );
  1607. if ( status != NO_ERROR )
  1608. {
  1609. if ( pblob->AddrCount ||
  1610. pblob->AliasCount ||
  1611. pblob->fWroteName )
  1612. {
  1613. status = NO_ERROR;
  1614. }
  1615. else
  1616. {
  1617. goto Done;
  1618. }
  1619. }
  1620. //
  1621. // write address from PTR record
  1622. // - first record PTR
  1623. // OR
  1624. // - queried for PTR and got CNAME answer, which can happen
  1625. // in classless reverse lookup case
  1626. //
  1627. // DCR: add PTR address lookup to HostentBlob_WriteRecords()
  1628. // - natural place
  1629. // - but would have to figure out handling of multiple PTRs
  1630. //
  1631. if ( pRecords &&
  1632. ( pRecords->wType == DNS_TYPE_PTR ||
  1633. ( wType == DNS_TYPE_PTR &&
  1634. pRecords->wType == DNS_TYPE_CNAME &&
  1635. pRecords->Flags.S.Section == DNSREC_ANSWER ) ) )
  1636. {
  1637. IP6_ADDRESS ip6;
  1638. DWORD addrLength = sizeof(IP6_ADDRESS);
  1639. INT family = 0;
  1640. DNSDBG( HOSTENT, (
  1641. "Writing address for PTR record %S\n",
  1642. pRecords->pName ));
  1643. // convert reverse name to IP
  1644. if ( Dns_StringToAddressEx(
  1645. (PCHAR) & ip6,
  1646. & addrLength,
  1647. (PCSTR) pRecords->pName,
  1648. & family,
  1649. IS_UNICODE_RECORD(pRecords),
  1650. TRUE // reverse lookup name
  1651. ) )
  1652. {
  1653. status = HostentBlob_WriteAddress(
  1654. pblob,
  1655. (PCHAR) &ip6,
  1656. addrLength,
  1657. family );
  1658. ASSERT( status == NO_ERROR );
  1659. status = ERROR_SUCCESS;
  1660. }
  1661. }
  1662. //
  1663. // write name?
  1664. //
  1665. if ( !pblob->fWroteName &&
  1666. fWriteName &&
  1667. prrFirstAddr )
  1668. {
  1669. status = HostentBlob_WriteNameOrAlias(
  1670. pblob,
  1671. prrFirstAddr->pName,
  1672. FALSE, // name
  1673. (prrFirstAddr->Flags.S.CharSet == DnsCharSetUnicode)
  1674. );
  1675. }
  1676. IF_DNSDBG( HOSTENT )
  1677. {
  1678. DnsDbg_HostentBlob(
  1679. "HostentBlob after CreateFromRecords():",
  1680. pblob );
  1681. }
  1682. Done:
  1683. if ( status != NO_ERROR && pblob )
  1684. {
  1685. HostentBlob_Free( pblob );
  1686. pblob = NULL;
  1687. }
  1688. *ppBlob = pblob;
  1689. DNSDBG( HOSTENT, (
  1690. "Leave HostentBlob_CreateFromRecords() => status = %d\n",
  1691. status ));
  1692. return( status );
  1693. }
  1694. //
  1695. // Hostent Query
  1696. //
  1697. PHOSTENT_BLOB
  1698. HostentBlob_Query(
  1699. IN PWSTR pwsName,
  1700. IN WORD wType,
  1701. IN DWORD Flags,
  1702. IN OUT PVOID * ppMsg, OPTIONAL
  1703. IN INT AddrFamily OPTIONAL
  1704. )
  1705. /*++
  1706. Routine Description:
  1707. Query DNS to create hostent.
  1708. Arguments:
  1709. pwsName -- name to query
  1710. wType -- query type
  1711. Flags -- query flags
  1712. ppMsg -- addr to recv ptr to message
  1713. AddrType -- address type (family) to reserve space for if querying
  1714. for PTR records
  1715. Return Value:
  1716. Ptr to blob if successful.
  1717. NULL on error; GetLastError() has error.
  1718. --*/
  1719. {
  1720. DNS_STATUS status = NO_ERROR;
  1721. PDNS_RECORD prrQuery = NULL;
  1722. PHOSTENT_BLOB pblob = NULL;
  1723. DNSDBG( HOSTENT, (
  1724. "HostentBlob_Query()\n"
  1725. "\tname = %S\n"
  1726. "\ttype = %d\n"
  1727. "\tflags = %08x\n"
  1728. "\tmsg out = %p\n",
  1729. pwsName,
  1730. wType,
  1731. Flags,
  1732. ppMsg ));
  1733. //
  1734. // query
  1735. // - if fails, dump any message before return
  1736. //
  1737. status = DnsQuery_W(
  1738. pwsName,
  1739. wType,
  1740. Flags,
  1741. NULL,
  1742. &prrQuery,
  1743. ppMsg );
  1744. // if failed, dump any message
  1745. if ( status != NO_ERROR )
  1746. {
  1747. if ( ppMsg && *ppMsg )
  1748. {
  1749. DnsApiFree( *ppMsg );
  1750. *ppMsg = NULL;
  1751. }
  1752. if ( status == RPC_S_SERVER_UNAVAILABLE )
  1753. {
  1754. status = WSATRY_AGAIN;
  1755. }
  1756. goto Done;
  1757. }
  1758. if ( !prrQuery )
  1759. {
  1760. ASSERT( FALSE );
  1761. status = DNS_ERROR_RCODE_NAME_ERROR;
  1762. goto Done;
  1763. }
  1764. //
  1765. // build hostent
  1766. //
  1767. status = HostentBlob_CreateFromRecords(
  1768. & pblob,
  1769. prrQuery,
  1770. TRUE, // write name from first answer
  1771. AddrFamily,
  1772. wType
  1773. );
  1774. if ( status != NO_ERROR )
  1775. {
  1776. goto Done;
  1777. }
  1778. //
  1779. // for address query must get answer
  1780. //
  1781. // DCR: DnsQuery() should convert to no-records on empty CNAME chain?
  1782. // DCR: should we go ahead and build hostent?
  1783. //
  1784. if ( pblob->AddrCount == 0 && Hostent_IsSupportedAddrType(wType) )
  1785. {
  1786. status = DNS_INFO_NO_RECORDS;
  1787. }
  1788. Done:
  1789. if ( prrQuery )
  1790. {
  1791. DnsRecordListFree(
  1792. prrQuery,
  1793. DnsFreeRecordListDeep );
  1794. }
  1795. if ( status != NO_ERROR && pblob )
  1796. {
  1797. HostentBlob_Free( pblob );
  1798. pblob = NULL;
  1799. }
  1800. DNSDBG( HOSTENT, (
  1801. "Leave HostentBlob_Query()\n"
  1802. "\tpblob = %p\n"
  1803. "\tstatus = %d\n",
  1804. pblob,
  1805. status ));
  1806. SetLastError( status );
  1807. return( pblob );
  1808. }
  1809. //
  1810. // Special hostents
  1811. //
  1812. PHOSTENT_BLOB
  1813. HostentBlob_Localhost(
  1814. IN INT Family
  1815. )
  1816. /*++
  1817. Routine Description:
  1818. Create hostent from records
  1819. Arguments:
  1820. AddrFamily -- address family
  1821. Return Value:
  1822. Ptr to blob if successful.
  1823. NULL on error; GetLastError() has error.
  1824. --*/
  1825. {
  1826. DNS_STATUS status = NO_ERROR;
  1827. PDNS_RECORD prrFirstAddr = NULL;
  1828. PDNS_RECORD prr;
  1829. DWORD addrCount = 0;
  1830. DWORD addrSize;
  1831. CHAR addrBuf[ sizeof(IP6_ADDRESS ) ];
  1832. HOSTENT_INIT request;
  1833. PHOSTENT_BLOB pblob = NULL;
  1834. DNSDBG( HOSTENT, ( "HostentBlob_Localhost()\n" ));
  1835. //
  1836. // create hostent blob
  1837. //
  1838. RtlZeroMemory( &request, sizeof(request) );
  1839. request.AliasCount = 1;
  1840. request.AddrCount = 1;
  1841. request.AddrFamily = Family;
  1842. request.fUnicode = TRUE;
  1843. status = HostentBlob_Create(
  1844. & pblob,
  1845. & request );
  1846. if ( status != NO_ERROR )
  1847. {
  1848. goto Done;
  1849. }
  1850. //
  1851. // write in loopback address
  1852. //
  1853. if ( Family == AF_INET )
  1854. {
  1855. * (PIP4_ADDRESS) addrBuf = DNS_NET_ORDER_LOOPBACK;
  1856. addrSize = sizeof(IP4_ADDRESS);
  1857. }
  1858. else if ( Family == AF_INET6 )
  1859. {
  1860. IP6_SET_ADDR_LOOPBACK( (PIP6_ADDRESS)addrBuf );
  1861. addrSize = sizeof(IN6_ADDR);
  1862. }
  1863. else
  1864. {
  1865. status = DNS_ERROR_INVALID_DATA;
  1866. goto Done;
  1867. }
  1868. status = HostentBlob_WriteAddress(
  1869. pblob,
  1870. addrBuf,
  1871. addrSize,
  1872. Family );
  1873. if ( status != NO_ERROR )
  1874. {
  1875. goto Done;
  1876. }
  1877. //
  1878. // write localhost
  1879. //
  1880. status = HostentBlob_WriteNameOrAlias(
  1881. pblob,
  1882. (PSTR) L"localhost",
  1883. FALSE, // name
  1884. TRUE // unicode
  1885. );
  1886. IF_DNSDBG( HOSTENT )
  1887. {
  1888. DnsDbg_HostentBlob(
  1889. "HostentBlob after CreateFromRecords():",
  1890. pblob );
  1891. }
  1892. Done:
  1893. if ( status != NO_ERROR && pblob )
  1894. {
  1895. HostentBlob_Free( pblob );
  1896. pblob = NULL;
  1897. }
  1898. SetLastError( status );
  1899. DNSDBG( HOSTENT, (
  1900. "Leave Hostent_Localhost() => status = %d\n",
  1901. status ));
  1902. return( pblob );
  1903. }
  1904. DNS_STATUS
  1905. HostentBlob_CreateFromIpArray(
  1906. IN OUT PHOSTENT_BLOB * ppBlob,
  1907. IN INT AddrFamily,
  1908. IN INT AddrSize,
  1909. IN INT AddrCount,
  1910. IN PCHAR pArray,
  1911. IN PSTR pName,
  1912. IN BOOL fUnicode
  1913. )
  1914. /*++
  1915. Routine Description:
  1916. Create hostent from records
  1917. Arguments:
  1918. ppBlob -- ptr with or to recv hostent blob
  1919. AddrFamily -- addr family use if PTR records and no addr
  1920. pArray -- array of addresses
  1921. pName -- name for hostent
  1922. fUnicode --
  1923. TRUE if name is and hostent will be in unicode
  1924. FALSE for narrow name and hostent
  1925. Return Value:
  1926. Ptr to blob if successful.
  1927. NULL on error; GetLastError() has error.
  1928. --*/
  1929. {
  1930. DNS_STATUS status = NO_ERROR;
  1931. HOSTENT_INIT request;
  1932. PHOSTENT_BLOB pblob = *ppBlob;
  1933. DNSDBG( HOSTENT, (
  1934. "HostentBlob_CreateFromIpArray()\n"
  1935. "\tppBlob = %p\n"
  1936. "\tfamily = %d\n"
  1937. "\tsize = %d\n"
  1938. "\tcount = %d\n"
  1939. "\tpArray = %p\n",
  1940. ppBlob,
  1941. AddrFamily,
  1942. AddrSize,
  1943. AddrCount,
  1944. pArray ));
  1945. //
  1946. // create or reinit hostent blob
  1947. //
  1948. RtlZeroMemory( &request, sizeof(request) );
  1949. request.AliasCount = DNS_MAX_ALIAS_COUNT;
  1950. request.AddrCount = AddrCount;
  1951. request.AddrFamily = AddrFamily;
  1952. request.fUnicode = fUnicode;
  1953. request.pName = pName;
  1954. status = HostentBlob_Create(
  1955. & pblob,
  1956. & request );
  1957. if ( status != NO_ERROR )
  1958. {
  1959. goto Done;
  1960. }
  1961. //
  1962. // write in array
  1963. //
  1964. if ( AddrCount )
  1965. {
  1966. status = HostentBlob_WriteAddressArray(
  1967. pblob,
  1968. pArray,
  1969. AddrCount,
  1970. AddrSize,
  1971. AddrFamily
  1972. );
  1973. if ( status != NO_ERROR )
  1974. {
  1975. goto Done;
  1976. }
  1977. }
  1978. //
  1979. // write name?
  1980. //
  1981. if ( pName )
  1982. {
  1983. status = HostentBlob_WriteNameOrAlias(
  1984. pblob,
  1985. pName,
  1986. FALSE, // name not alias
  1987. fUnicode
  1988. );
  1989. }
  1990. IF_DNSDBG( HOSTENT )
  1991. {
  1992. DnsDbg_HostentBlob(
  1993. "Leaving HostentBlob_CreateFromIpArray():",
  1994. pblob );
  1995. }
  1996. Done:
  1997. if ( status != NO_ERROR && pblob )
  1998. {
  1999. HostentBlob_Free( pblob );
  2000. pblob = NULL;
  2001. }
  2002. *ppBlob = pblob;
  2003. DNSDBG( HOSTENT, (
  2004. "Leave HostentBlob_CreateFromIpArray() => status = %d\n",
  2005. status ));
  2006. return( status );
  2007. }
  2008. DNS_STATUS
  2009. HostentBlob_CreateLocal(
  2010. IN OUT PHOSTENT_BLOB * ppBlob,
  2011. IN INT AddrFamily,
  2012. IN BOOL fLoopback,
  2013. IN BOOL fZero,
  2014. IN BOOL fHostnameOnly
  2015. )
  2016. /*++
  2017. Routine Description:
  2018. Create hostent from records
  2019. Arguments:
  2020. ppBlob -- ptr with or to recv hostent blob
  2021. AddrFamily -- addr family use if PTR records and no addr
  2022. Return Value:
  2023. Ptr to blob if successful.
  2024. NULL on error; GetLastError() has error.
  2025. --*/
  2026. {
  2027. DNS_STATUS status = NO_ERROR;
  2028. PHOSTENT_BLOB pblob = NULL;
  2029. WORD wtype;
  2030. INT size;
  2031. IP6_ADDRESS ip;
  2032. DNSDBG( HOSTENT, (
  2033. "HostentBlob_CreateLocal()\n"
  2034. "\tppBlob = %p\n"
  2035. "\tfamily = %d\n"
  2036. "\tfLoopback = %d\n"
  2037. "\tfZero = %d\n"
  2038. "\tfHostname = %d\n",
  2039. ppBlob,
  2040. AddrFamily,
  2041. fLoopback,
  2042. fZero,
  2043. fHostnameOnly
  2044. ));
  2045. //
  2046. // get family info
  2047. // - start with override IP = 0
  2048. // - if loopback switch to appropriate loopback
  2049. //
  2050. RtlZeroMemory(
  2051. &ip,
  2052. sizeof(ip) );
  2053. if ( AddrFamily == AF_INET )
  2054. {
  2055. wtype = DNS_TYPE_A;
  2056. size = sizeof(IP4_ADDRESS);
  2057. if ( fLoopback )
  2058. {
  2059. * (PIP4_ADDRESS) &ip = DNS_NET_ORDER_LOOPBACK;
  2060. }
  2061. }
  2062. else if ( AddrFamily == AF_INET6 )
  2063. {
  2064. wtype = DNS_TYPE_AAAA;
  2065. size = sizeof(IP6_ADDRESS);
  2066. if ( fLoopback )
  2067. {
  2068. IP6_SET_ADDR_LOOPBACK( &ip );
  2069. }
  2070. }
  2071. else
  2072. {
  2073. status = ERROR_INVALID_PARAMETER;
  2074. goto Done;
  2075. }
  2076. //
  2077. // query for local host info
  2078. //
  2079. pblob = HostentBlob_Query(
  2080. NULL, // NULL name gets local host data
  2081. wtype,
  2082. 0, // standard query
  2083. NULL, // no message
  2084. AddrFamily );
  2085. if ( !pblob )
  2086. {
  2087. DNS_ASSERT( FALSE );
  2088. status = GetLastError();
  2089. goto Done;
  2090. }
  2091. //
  2092. // overwrite with specific address
  2093. //
  2094. if ( fLoopback || fZero )
  2095. {
  2096. if ( ! Hostent_SetToSingleAddress(
  2097. pblob->pHostent,
  2098. (PCHAR) &ip,
  2099. size ) )
  2100. {
  2101. DNS_ASSERT( pblob->AddrCount == 0 );
  2102. pblob->AddrCount = 0;
  2103. status = HostentBlob_WriteAddress(
  2104. pblob,
  2105. & ip,
  2106. size,
  2107. AddrFamily );
  2108. if ( status != NO_ERROR )
  2109. {
  2110. DNS_ASSERT( status!=NO_ERROR );
  2111. goto Done;
  2112. }
  2113. }
  2114. }
  2115. //
  2116. // for gethostname()
  2117. // - chop name down to just hostname
  2118. // - kill off aliases
  2119. //
  2120. if ( fHostnameOnly )
  2121. {
  2122. PWSTR pname = (PWSTR) pblob->pHostent->h_name;
  2123. PWSTR pdomain;
  2124. DNS_ASSERT( pname );
  2125. if ( pname )
  2126. {
  2127. pdomain = Dns_GetDomainName_W( pname );
  2128. if ( pdomain )
  2129. {
  2130. DNS_ASSERT( pdomain > pname+1 );
  2131. DNS_ASSERT( *(pdomain-1) == L'.' );
  2132. *(pdomain-1) = 0;
  2133. }
  2134. }
  2135. pblob->pHostent->h_aliases = NULL;
  2136. }
  2137. IF_DNSDBG( HOSTENT )
  2138. {
  2139. DnsDbg_HostentBlob(
  2140. "Leaving HostentBlob_CreateLocal():",
  2141. pblob );
  2142. }
  2143. Done:
  2144. if ( status != NO_ERROR && pblob )
  2145. {
  2146. HostentBlob_Free( pblob );
  2147. pblob = NULL;
  2148. }
  2149. *ppBlob = pblob;
  2150. DNSDBG( HOSTENT, (
  2151. "Leave HostentBlob_CreateLocal() => status = %d\n",
  2152. status ));
  2153. return( status );
  2154. }
  2155. //
  2156. // End hostent.c
  2157. //