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.

898 lines
19 KiB

  1. /*++
  2. Copyright (c) 1996-2000 Microsoft Corporation
  3. Module Name:
  4. update.c
  5. Abstract:
  6. Domain Name System (DNS) Library
  7. Update client routines.
  8. Author:
  9. Jim Gilroy (jamesg) October, 1996
  10. Environment:
  11. User Mode - Win32
  12. Revision History:
  13. --*/
  14. #include "local.h"
  15. //
  16. // Update Timeouts
  17. //
  18. // note, max is a little longer than might be expected as DNS server
  19. // may have to contact primary and wait for primary to do update (inc.
  20. // disk access) then response
  21. //
  22. #define INITIAL_UPDATE_TIMEOUT (4) // 4 seconds
  23. #define MAX_UPDATE_TIMEOUT (60) // 60 seconds
  24. PCHAR
  25. Dns_WriteNoDataUpdateRecordToMessage(
  26. IN PCHAR pch,
  27. IN PCHAR pchStop,
  28. IN WORD wClass,
  29. IN WORD wType
  30. )
  31. /*++
  32. Routine Description:
  33. No data RR cases:
  34. This includes prereqs and deletes except for specific record cases.
  35. Arguments:
  36. pch - ptr to next byte in packet buffer
  37. pchStop - end of packet buffer
  38. wClass - class
  39. wType - desired RR type
  40. Return Value:
  41. Ptr to next postion in buffer, if successful.
  42. NULL on error.
  43. --*/
  44. {
  45. PDNS_WIRE_RECORD pdnsRR;
  46. DNSDBG( WRITE, (
  47. "Writing update RR to packet buffer at %p.\n",
  48. pch ));
  49. //
  50. // out of space
  51. //
  52. pdnsRR = (PDNS_WIRE_RECORD) pch;
  53. pch += sizeof( DNS_WIRE_RECORD );
  54. if ( pch >= pchStop )
  55. {
  56. DNS_PRINT(( "ERROR out of space writing record to packet.\n" ));
  57. return( NULL );
  58. }
  59. //
  60. // set type and class
  61. //
  62. *(UNALIGNED WORD *) &pdnsRR->RecordType = htons( wType );
  63. *(UNALIGNED WORD *) &pdnsRR->RecordClass = htons( wClass );
  64. //
  65. // TTL and datalength zero for all no data cases
  66. // - prereqs except specific record delete
  67. // - deletes except specific record delete
  68. //
  69. *(UNALIGNED DWORD *) &pdnsRR->TimeToLive = 0;
  70. *(UNALIGNED WORD *) &pdnsRR->DataLength = 0;
  71. return( pch );
  72. }
  73. PCHAR
  74. Dns_WriteDataUpdateRecordToMessage(
  75. IN PCHAR pch,
  76. IN PCHAR pchStop,
  77. IN WORD wClass,
  78. IN WORD wType,
  79. IN DWORD dwTtl,
  80. IN WORD wDataLength
  81. )
  82. /*++
  83. Routine Description:
  84. No data RR cases:
  85. This includes prereqs and deletes except for specific record cases.
  86. Arguments:
  87. pch - ptr to next byte in packet buffer
  88. pchStop - end of packet buffer
  89. wClass - class
  90. wType - desired RR type
  91. dwTtl - time to live
  92. wDataLength - data length
  93. Return Value:
  94. Ptr to next postion in buffer, if successful.
  95. NULL on error.
  96. --*/
  97. {
  98. PDNS_WIRE_RECORD pdnsRR;
  99. DNSDBG( WRITE2, (
  100. "Writing RR to packet buffer at %p.\n",
  101. pch ));
  102. //
  103. // out of space
  104. //
  105. pdnsRR = (PDNS_WIRE_RECORD) pch;
  106. pch += sizeof( DNS_WIRE_RECORD );
  107. if ( pch + wDataLength >= pchStop )
  108. {
  109. DNS_PRINT(( "ERROR out of space writing record to packet.\n" ));
  110. return( NULL );
  111. }
  112. //
  113. // set type and class
  114. //
  115. *(UNALIGNED WORD *) &pdnsRR->RecordType = htons( wType );
  116. *(UNALIGNED WORD *) &pdnsRR->RecordClass = htons( wClass );
  117. //
  118. // TTL and datalength zero for all no data cases
  119. // - prereqs except specific record delete
  120. // - deletes except specific record delete
  121. //
  122. *(UNALIGNED DWORD *) &pdnsRR->TimeToLive = htonl( dwTtl );
  123. *(UNALIGNED WORD *) &pdnsRR->DataLength = htons( wDataLength );
  124. return( pch );
  125. }
  126. //
  127. // Host update routines
  128. //
  129. #if 0
  130. PDNS_MSG_BUF
  131. Dns_BuildHostUpdateMessage(
  132. IN OUT PDNS_MSG_BUF pMsg,
  133. IN LPSTR pszZone,
  134. IN LPSTR pszName,
  135. IN PIP_ARRAY aipAddresses,
  136. IN DWORD dwTtl
  137. )
  138. /*++
  139. Routine Description:
  140. Build server update message.
  141. Arguments:
  142. pMsg -- existing message buffer, to use; NULL to allocate new one
  143. pszZone -- zone name for update
  144. pszName -- full DNS hostname being updated
  145. aipAddresses -- IP addresses to be updated
  146. Return Value:
  147. ERROR_SUCCESS if successful.
  148. Error status on failure.
  149. --*/
  150. {
  151. PDNS_HEADER pdnsMsg;
  152. PCHAR pch;
  153. PCHAR pchstop;
  154. DWORD i;
  155. WORD nameOffset;
  156. IF_DNSDBG( UPDATE )
  157. {
  158. DNS_PRINT((
  159. "Enter Dns_BuildHostUpdateMessage()\n"
  160. "\tpMsg = %p\n"
  161. "\tpszZone = %s\n"
  162. "\tpszName = %s\n"
  163. "\tdwTtl = %d\n",
  164. pMsg,
  165. pszZone,
  166. pszName,
  167. dwTtl ));
  168. DnsDbg_IpArray(
  169. "\tHost IP array\n",
  170. "host",
  171. aipAddresses );
  172. }
  173. //
  174. // create message buffer
  175. //
  176. if ( !pMsg )
  177. {
  178. DNS_PRINT(( "Allocating new UPDATE message buffer.\n" ));
  179. pMsg = ALLOCATE_HEAP( DNS_UDP_ALLOC_LENGTH );
  180. if ( !pMsg )
  181. {
  182. return( NULL );
  183. }
  184. RtlZeroMemory(
  185. pMsg,
  186. DNS_UDP_ALLOC_LENGTH );
  187. pMsg->BufferLength = DNS_UDP_MAX_PACKET_LENGTH;
  188. pMsg->pBufferEnd = (PCHAR)&pMsg->MessageHead + pMsg->BufferLength;
  189. //
  190. // set default sockaddr info
  191. // - caller MUST choose remote IP address
  192. pMsg->RemoteAddress.sin_family = AF_INET;
  193. pMsg->RemoteAddress.sin_port = NET_ORDER_DNS_PORT;
  194. pMsg->RemoteAddressLength = sizeof( SOCKADDR_IN );
  195. // set header for update
  196. pMsg->MessageHead.Opcode = DNS_OPCODE_UPDATE;
  197. }
  198. //
  199. // existing message, just verify
  200. //
  201. ELSE_ASSERT( pMsg->MessageHead.Opcode == DNS_OPCODE_UPDATE );
  202. //
  203. // reset current pointer after header
  204. // - note: send length is set based on this ptr
  205. //
  206. pMsg->pCurrent = pMsg->MessageBody;
  207. //
  208. // build message
  209. //
  210. pch = pMsg->pCurrent;
  211. pchstop = pMsg->pBufferEnd;
  212. //
  213. // zone section
  214. //
  215. pMsg->MessageHead.QuestionCount = 1;
  216. pch = Dns_WriteDottedNameToPacket(
  217. pch,
  218. pchstop,
  219. pszZone,
  220. NULL,
  221. 0,
  222. FALSE );
  223. if ( !pch )
  224. {
  225. return( NULL );
  226. }
  227. *(UNALIGNED WORD *) pch = DNS_RTYPE_SOA;
  228. pch += sizeof(WORD);
  229. *(UNALIGNED WORD *) pch = DNS_RCLASS_INTERNET;
  230. pch += sizeof(WORD);
  231. //
  232. // prerequisites -- no records
  233. //
  234. pMsg->MessageHead.AnswerCount = 0;
  235. //
  236. // update
  237. // - delete A records at name
  238. // - add new A records
  239. //
  240. // save offset to host name for future writes
  241. nameOffset = (WORD)(pch - (PCHAR) &pMsg->MessageHead);
  242. pch = Dns_WriteDottedNameToPacket(
  243. pch,
  244. pchstop,
  245. pszName,
  246. pszZone,
  247. DNS_OFFSET_TO_QUESTION_NAME,
  248. FALSE );
  249. if ( !pch )
  250. {
  251. DNS_PRINT(( "ERROR writing dotted name to packet.\n" ));
  252. return( NULL );
  253. }
  254. pch = Dns_WriteNoDataUpdateRecordToMessage(
  255. pch,
  256. pchstop,
  257. DNS_CLASS_ALL, // delete all
  258. DNS_TYPE_A // A records
  259. );
  260. DNS_ASSERT( pch );
  261. //
  262. // add A record for each address in array
  263. // - use offset for name
  264. // - write IP
  265. for ( i=0; i<aipAddresses->AddrCount; i++ )
  266. {
  267. *(UNALIGNED WORD *) pch = htons( (WORD)(nameOffset|(WORD)0xC000) );
  268. pch += sizeof( WORD );
  269. pch = Dns_WriteDataUpdateRecordToMessage(
  270. pch,
  271. pchstop,
  272. DNS_CLASS_INTERNET,
  273. DNS_TYPE_A, // A records
  274. dwTtl,
  275. sizeof(IP_ADDRESS)
  276. );
  277. DNS_ASSERT( pch );
  278. *(UNALIGNED DWORD *) pch = aipAddresses->AddrArray[i];
  279. pch += sizeof(DWORD);
  280. }
  281. // total update sections RRs
  282. // one delete RR, plus one for each new IP
  283. pMsg->MessageHead.NameServerCount = (USHORT)(aipAddresses->AddrCount + 1);
  284. //
  285. // additional section - no records
  286. //
  287. pMsg->MessageHead.AdditionalCount = 0;
  288. //
  289. // reset current ptr -- need for send routine
  290. //
  291. pMsg->pCurrent = pch;
  292. IF_DNSDBG( SEND )
  293. {
  294. DnsDbg_Message(
  295. "UPDATE packet built",
  296. pMsg );
  297. }
  298. return( pMsg );
  299. }
  300. #endif
  301. PDNS_RECORD
  302. Dns_HostUpdateRRSet(
  303. IN LPSTR pszHostName,
  304. IN PIP_ARRAY AddrArray,
  305. IN DWORD dwTtl
  306. )
  307. /*++
  308. Routine Description:
  309. Create records for host update:
  310. -- whack of all A records
  311. -- add of all A records in new set
  312. Arguments:
  313. pszHostName -- host name, FULL FQDN
  314. AddrArray -- new IPs of host
  315. dwTtl -- TTL for records
  316. Return Value:
  317. Ptr to record list.
  318. NULL on error.
  319. --*/
  320. {
  321. DNS_RRSET rrset;
  322. PDNS_RECORD prr;
  323. DWORD i;
  324. //
  325. // create whack
  326. //
  327. prr = Dns_AllocateRecord( 0 );
  328. if ( ! prr )
  329. {
  330. return( NULL );
  331. }
  332. prr->pName = pszHostName;
  333. prr->wType = DNS_TYPE_A;
  334. prr->Flags.S.Section = DNSREC_UPDATE;
  335. prr->Flags.S.Delete = TRUE;
  336. //
  337. // create update record for each address
  338. //
  339. if ( !AddrArray )
  340. {
  341. return( prr );
  342. }
  343. DNS_RRSET_INIT( rrset );
  344. DNS_RRSET_ADD( rrset, prr );
  345. for ( i=0; i<AddrArray->AddrCount; i++ )
  346. {
  347. prr = Dns_AllocateRecord( sizeof(DNS_A_DATA) );
  348. if ( ! prr )
  349. {
  350. Dns_RecordListFree( rrset.pFirstRR, FALSE );
  351. return( NULL );
  352. }
  353. prr->pName = pszHostName;
  354. prr->wType = DNS_TYPE_A;
  355. prr->Flags.S.Section = DNSREC_UPDATE;
  356. prr->dwTtl = dwTtl;
  357. prr->Data.A.IpAddress = AddrArray->AddrArray[i];
  358. DNS_RRSET_ADD( rrset, prr );
  359. }
  360. // return ptr to first record in list
  361. return( rrset.pFirstRR );
  362. }
  363. //
  364. // DCR: dead code, remove
  365. //
  366. DNS_STATUS
  367. Dns_UpdateHostAddrs(
  368. IN LPSTR pszName,
  369. IN PIP_ARRAY aipAddresses,
  370. IN PIP_ARRAY aipServers,
  371. IN DWORD dwTtl
  372. )
  373. /*++
  374. Routine Description:
  375. Updates client's A records registered with DNS server.
  376. Arguments:
  377. pszName -- name (FQDN) of client to update
  378. aipAddresses -- counted array of new client IP addrs
  379. aipServers -- counted array of DNS server IP addrs
  380. dwTtl -- TTL for new A records
  381. Return Value:
  382. ERROR_SUCCESS if successful.
  383. Error status on failure.
  384. --*/
  385. {
  386. PDNS_RECORD prr;
  387. DNS_STATUS status;
  388. IF_DNSDBG( UPDATE )
  389. {
  390. DNS_PRINT((
  391. "Enter Dns_UpdateHostAddrs()\n"
  392. "\tpszName = %s\n"
  393. "\tdwTtl = %d\n",
  394. pszName,
  395. dwTtl ));
  396. DnsDbg_IpArray(
  397. "\tHost IP array\n",
  398. "\tHost",
  399. aipAddresses );
  400. DnsDbg_IpArray(
  401. "\tNS IP array\n",
  402. "\tNS",
  403. aipServers );
  404. }
  405. //
  406. // never let anyone set a TTL longer than 1 hour
  407. //
  408. // DCR: define policy on what our clients should use for TTL
  409. // one hour is not bad
  410. // could key off type of address
  411. // RAS -- 15 minutes (as may be back up again quickly)
  412. // DHCP -- one hour (may move)
  413. // static -- one day (machines may be reconfigured)
  414. //
  415. if ( dwTtl > 3600 )
  416. {
  417. dwTtl = 3600;
  418. }
  419. //
  420. // build update RR set
  421. //
  422. prr = Dns_HostUpdateRRSet(
  423. pszName,
  424. aipAddresses,
  425. dwTtl );
  426. if ( ! prr )
  427. {
  428. status = GetLastError();
  429. DNS_ASSERT( status == DNS_ERROR_NO_MEMORY );
  430. return status;
  431. }
  432. //
  433. // do the update
  434. //
  435. status = Dns_UpdateLib(
  436. prr,
  437. 0, // no flags
  438. NULL, // no adapter list
  439. NULL, // use default credentials
  440. NULL // response not desired
  441. );
  442. Dns_RecordListFree( prr, FALSE );
  443. DNSDBG( UPDATE, (
  444. "Leave Dns_UpdateHostAddrs() status=%p %s\n",
  445. status,
  446. Dns_StatusString(status) ));
  447. return( status );
  448. }
  449. DNS_STATUS
  450. Dns_UpdateLib(
  451. IN PDNS_RECORD pRecord,
  452. IN DWORD dwFlags,
  453. IN PDNS_NETINFO pNetworkInfo,
  454. IN HANDLE hCreds OPTIONAL,
  455. OUT PDNS_MSG_BUF * ppMsgRecv OPTIONAL
  456. )
  457. /*++
  458. Routine Description:
  459. Send DNS update.
  460. Arguments:
  461. pRecord -- list of records to send in update
  462. dwFlags -- update flags; primarily security
  463. pNetworkInfo -- adapter list with necessary info for update
  464. - zone name
  465. - primary name server name
  466. - primary name server IP
  467. ppMsgRecv -- OPTIONAL addr to recv ptr to response message
  468. Return Value:
  469. ERROR_SUCCESS if successful.
  470. Error status on failure.
  471. --*/
  472. {
  473. PDNS_MSG_BUF pmsgSend = NULL;
  474. PDNS_MSG_BUF pmsgRecv = NULL;
  475. DNS_STATUS status = NO_ERROR;
  476. WORD length;
  477. PIP_ARRAY parrayServers = NULL;
  478. LPSTR pszzone;
  479. LPSTR pszserverName;
  480. BOOL fsecure = FALSE;
  481. BOOL fswitchToTcp = FALSE;
  482. DNS_HEADER header;
  483. PCHAR pCreds=NULL;
  484. DNSDBG( UPDATE, (
  485. "Dns_UpdateLib()\n"
  486. "\tflags = %p\n"
  487. "\tpRecord = %p\n"
  488. "\t\towner = %s\n",
  489. dwFlags,
  490. pRecord,
  491. pRecord ? pRecord->pName : NULL ));
  492. //
  493. // if not a UPDATE compatibile adapter list -- no action
  494. //
  495. if ( !IS_UPDATE_NETWORK_INFO(pNetworkInfo) )
  496. {
  497. return( ERROR_INVALID_PARAMETER );
  498. }
  499. //
  500. // suck info from adapter list
  501. //
  502. pszzone = pNetworkInfo->pSearchList->pszDomainOrZoneName;
  503. parrayServers = Dns_ConvertNetworkInfoToIpArray( pNetworkInfo );
  504. pszserverName = pNetworkInfo->aAdapterInfoList[0]->pszAdapterDomain;
  505. DNS_ASSERT( pszzone && parrayServers );
  506. //
  507. // build recv message buffer
  508. // - must be big enough for TCP
  509. //
  510. pmsgRecv = Dns_AllocateMsgBuf( DNS_TCP_DEFAULT_PACKET_LENGTH );
  511. if ( !pmsgRecv )
  512. {
  513. status = DNS_ERROR_NO_MEMORY;
  514. goto Cleanup;
  515. }
  516. //
  517. // build update packet
  518. // note currently this function allocates TCP sized buffer if records
  519. // given; if this changes need to alloc TCP buffer here
  520. //
  521. CLEAR_DNS_HEADER_FLAGS_AND_XID( &header );
  522. header.Opcode = DNS_OPCODE_UPDATE;
  523. pmsgSend = Dns_BuildPacket(
  524. &header, // copy header
  525. TRUE, // ... but not header counts
  526. pszzone, // question zone\type SOA
  527. DNS_TYPE_SOA,
  528. pRecord,
  529. 0, // no other flags
  530. TRUE // building an update packet
  531. );
  532. if ( !pmsgSend)
  533. {
  534. DNS_PRINT(( "ERROR: failed send buffer allocation.\n" ));
  535. status = DNS_ERROR_NO_MEMORY;
  536. goto Cleanup;
  537. }
  538. //
  539. // try non-secure first unless explicitly secure only
  540. //
  541. fsecure = (dwFlags & DNS_UPDATE_SECURITY_ONLY);
  542. if ( !fsecure )
  543. {
  544. status = Dns_SendAndRecv(
  545. pmsgSend,
  546. & pmsgRecv,
  547. NULL, // no response records
  548. dwFlags,
  549. parrayServers,
  550. pNetworkInfo );
  551. if ( status == ERROR_SUCCESS )
  552. {
  553. status = Dns_MapRcodeToStatus( pmsgRecv->MessageHead.ResponseCode );
  554. }
  555. if ( status != DNS_ERROR_RCODE_REFUSED ||
  556. dwFlags & DNS_UPDATE_SECURITY_OFF )
  557. {
  558. goto Cleanup;
  559. }
  560. DNSDBG( UPDATE, (
  561. "Failed unsecure update, switching to secure!\n"
  562. "\tcurrent time (ms) = %d\n",
  563. GetCurrentTime() ));
  564. fsecure = TRUE;
  565. }
  566. //
  567. // security
  568. // - must have server name
  569. // - must start package
  570. //
  571. if ( fsecure )
  572. {
  573. if ( !pszserverName )
  574. {
  575. status = ERROR_INVALID_PARAMETER;
  576. goto Cleanup;
  577. }
  578. status = Dns_StartSecurity( FALSE );
  579. if ( status != ERROR_SUCCESS )
  580. {
  581. goto Cleanup;
  582. }
  583. pCreds = Dns_GetApiContextCredentials(hCreds);
  584. status = Dns_DoSecureUpdate(
  585. pmsgSend,
  586. pmsgRecv,
  587. NULL,
  588. dwFlags,
  589. pNetworkInfo,
  590. parrayServers,
  591. pszserverName,
  592. pCreds, // initialized in DnsAcquireContextHandle
  593. NULL // default context name
  594. );
  595. if ( status == ERROR_SUCCESS )
  596. {
  597. status = Dns_MapRcodeToStatus( pmsgRecv->MessageHead.ResponseCode );
  598. }
  599. }
  600. Cleanup:
  601. // free server array sucked from adapter list
  602. if ( parrayServers )
  603. {
  604. FREE_HEAP( parrayServers );
  605. }
  606. // return recv message buffer
  607. if ( ppMsgRecv )
  608. {
  609. *ppMsgRecv = pmsgRecv;
  610. }
  611. else
  612. {
  613. FREE_HEAP( pmsgRecv );
  614. }
  615. FREE_HEAP( pmsgSend);
  616. DNSDBG( UPDATE, (
  617. "Dns_UpdateLib() completed, status = %p %s.\n",
  618. status,
  619. Dns_StatusString(status) ));
  620. return( status );
  621. }
  622. DNS_STATUS
  623. Dns_UpdateLibEx(
  624. IN PDNS_RECORD pRecord,
  625. IN DWORD dwFlags,
  626. IN PDNS_NAME pszZone,
  627. IN PDNS_NAME pszServerName,
  628. IN PIP_ARRAY aipServers,
  629. IN HANDLE hCreds OPTIONAL,
  630. OUT PDNS_MSG_BUF * ppMsgRecv OPTIONAL
  631. )
  632. /*++
  633. Routine Description:
  634. Send DNS update.
  635. This routine builds an UPDATE compatible pNetworkInfo from the
  636. information given. Then calls Dns_Update().
  637. Arguments:
  638. pRecord -- list of records to send in update
  639. pszZone -- zone name for update
  640. pszServerName -- server name
  641. aipServers -- DNS servers to send update to
  642. hCreds -- Optional Credentials info
  643. ppMsgRecv -- addr for ptr to recv buffer, if desired
  644. Return Value:
  645. ERROR_SUCCESS if successful.
  646. Error status on failure.
  647. --*/
  648. {
  649. PDNS_NETINFO pNetworkInfo;
  650. DNS_STATUS status = NO_ERROR;
  651. //
  652. // convert params into UPDATE compatible adapter list
  653. //
  654. pNetworkInfo = Dns_CreateUpdateNetworkInfo(
  655. pszZone,
  656. pszServerName,
  657. aipServers,
  658. 0 );
  659. if ( !pNetworkInfo )
  660. {
  661. return( ERROR_INVALID_PARAMETER );
  662. }
  663. //
  664. // call real update function
  665. //
  666. status = Dns_UpdateLib(
  667. pRecord,
  668. dwFlags,
  669. pNetworkInfo,
  670. hCreds,
  671. ppMsgRecv );
  672. Dns_FreeNetworkInfo( pNetworkInfo );
  673. return status;
  674. }
  675. //
  676. // End update.c
  677. //