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.

662 lines
13 KiB

  1. /*++
  2. Copyright (c) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. rrlist.c
  5. Abstract:
  6. Domain Name System (DNS) Library
  7. Record list manipulation.
  8. Author:
  9. Jim Gilroy (jamesg) January, 1997
  10. Environment:
  11. User Mode - Win32
  12. Revision History:
  13. --*/
  14. #include "local.h"
  15. PDNS_RECORD
  16. Dns_RecordSetDetach(
  17. IN OUT PDNS_RECORD pRR
  18. )
  19. /*++
  20. Routine Description:
  21. Detach first RR set from the rest of the list.
  22. Arguments:
  23. pRR - incoming record set
  24. Return Value:
  25. Ptr to first record of next RR set.
  26. NULL if at end of list.
  27. --*/
  28. {
  29. PDNS_RECORD prr = pRR;
  30. PDNS_RECORD pback; // previous RR in set
  31. WORD type; // first RR set type
  32. DWORD section; // section of first RR set
  33. if ( !prr )
  34. {
  35. return( NULL );
  36. }
  37. //
  38. // loop until find start of new RR set
  39. // - new type or
  40. // - new section or
  41. // - new name
  42. // note that NULL name is automatically considered
  43. // previous name
  44. //
  45. type = prr->wType;
  46. section = prr->Flags.S.Section;
  47. pback = prr;
  48. while ( prr = pback->pNext )
  49. {
  50. if ( prr->wType == type &&
  51. prr->Flags.S.Section == section &&
  52. ( prr->pName == NULL ||
  53. Dns_NameComparePrivate(
  54. prr->pName,
  55. pback->pName,
  56. pback->Flags.S.CharSet ) ) )
  57. {
  58. pback = prr;
  59. continue;
  60. }
  61. // should not be detaching nameless record
  62. // - fixup for robustness
  63. if ( !prr->pName )
  64. {
  65. ASSERT( prr->pName );
  66. prr->pName = Dns_NameCopyAllocate(
  67. pRR->pName,
  68. 0, // length unknown
  69. pRR->Flags.S.CharSet,
  70. prr->Flags.S.CharSet );
  71. SET_FREE_OWNER( prr );
  72. }
  73. break;
  74. }
  75. // have following RR set, NULL terminate first set
  76. if ( prr )
  77. {
  78. pback->pNext = NULL;
  79. }
  80. return( prr );
  81. }
  82. PDNS_RECORD
  83. WINAPI
  84. Dns_RecordListAppend(
  85. IN OUT PDNS_RECORD pHeadList,
  86. IN PDNS_RECORD pTailList
  87. )
  88. /*++
  89. Routine Description:
  90. Append record list onto another.
  91. Arguments:
  92. pHeadList -- record list to be head
  93. pTailList -- record list to append to pHeadList
  94. Return Value:
  95. Ptr to first record of combined RR set.
  96. - pHeadList UNLESS pHeadList is NULL,
  97. then it is pTailList.
  98. --*/
  99. {
  100. PDNS_RECORD prr = pHeadList;
  101. if ( !pTailList )
  102. {
  103. return prr;
  104. }
  105. if ( !prr )
  106. {
  107. return pTailList;
  108. }
  109. // find end of first list and append second list
  110. while ( prr->pNext )
  111. {
  112. prr = prr->pNext;
  113. }
  114. // should be appending new set (with new name)
  115. // or matching previous set
  116. DNS_ASSERT( !pTailList || pTailList->pName ||
  117. (pTailList->wType == prr->wType &&
  118. pTailList->Flags.S.Section == prr->Flags.S.Section) );
  119. prr->pNext = pTailList;
  120. return pHeadList;
  121. }
  122. DWORD
  123. Dns_RecordListCount(
  124. IN PDNS_RECORD pRRList,
  125. IN WORD wType
  126. )
  127. /*++
  128. Routine Description:
  129. Count records in list.
  130. Arguments:
  131. pRRList - incoming record set
  132. Return Value:
  133. Count of records of given type in list.
  134. --*/
  135. {
  136. DWORD count = 0;
  137. //
  138. // loop counting all records that match
  139. // - either direct match
  140. // - or if matching type is ALL
  141. //
  142. while ( pRRList )
  143. {
  144. if ( pRRList->wType == wType ||
  145. wType == DNS_TYPE_ALL )
  146. {
  147. count++;
  148. }
  149. pRRList = pRRList->pNext;
  150. }
  151. return( count );
  152. }
  153. DWORD
  154. Dns_RecordListGetMinimumTtl(
  155. IN PDNS_RECORD pRRList
  156. )
  157. /*++
  158. Routine Description:
  159. Get minimum TTL of record list
  160. Arguments:
  161. pRRList - incoming record set
  162. Return Value:
  163. Minimum TTL of records in list.
  164. --*/
  165. {
  166. PDNS_RECORD prr = pRRList;
  167. DWORD minTtl = MAXDWORD;
  168. DNSDBG( TRACE, (
  169. "Dns_RecordListGetMinimumTtl( %p )\n",
  170. pRRList ));
  171. //
  172. // loop through list build minimum TTL
  173. //
  174. while ( prr )
  175. {
  176. if ( prr->dwTtl < minTtl )
  177. {
  178. minTtl = prr->dwTtl;
  179. }
  180. prr = prr->pNext;
  181. }
  182. return minTtl;
  183. }
  184. //
  185. // Record screening
  186. //
  187. BOOL
  188. Dns_ScreenRecord(
  189. IN PDNS_RECORD pRR,
  190. IN DWORD ScreenFlag
  191. )
  192. /*++
  193. Routine Description:
  194. Screen a record.
  195. Arguments:
  196. pRR - incoming record
  197. ScreenFlag - screeing flag
  198. Return Value:
  199. TRUE if passes screening.
  200. FALSE if record fails screen.
  201. --*/
  202. {
  203. BOOL fsave = TRUE;
  204. DNSDBG( TRACE, (
  205. "Dns_ScreenRecord( %p, %08x )\n",
  206. pRR,
  207. ScreenFlag ));
  208. // section screening
  209. if ( ScreenFlag & SCREEN_OUT_SECTION )
  210. {
  211. if ( IS_ANSWER_RR(pRR) )
  212. {
  213. fsave = !(ScreenFlag & SCREEN_OUT_ANSWER);
  214. }
  215. else if ( IS_AUTHORITY_RR(pRR) )
  216. {
  217. fsave = !(ScreenFlag & SCREEN_OUT_AUTHORITY);
  218. }
  219. else if ( IS_ADDITIONAL_RR(pRR) )
  220. {
  221. fsave = !(ScreenFlag & SCREEN_OUT_ADDITIONAL);
  222. }
  223. if ( !fsave )
  224. {
  225. return FALSE;
  226. }
  227. }
  228. // type screening
  229. if ( ScreenFlag & SCREEN_OUT_NON_RPC )
  230. {
  231. fsave = Dns_IsRpcRecordType( pRR->wType );
  232. }
  233. return fsave;
  234. }
  235. PDNS_RECORD
  236. Dns_RecordListScreen(
  237. IN PDNS_RECORD pRR,
  238. IN DWORD ScreenFlag
  239. )
  240. /*++
  241. Routine Description:
  242. Screen records from record set.
  243. Arguments:
  244. pRR - incoming record set
  245. ScreenFlag - flag with record screening parameters
  246. Return Value:
  247. Ptr to new record set, if successful.
  248. NULL on error.
  249. --*/
  250. {
  251. PDNS_RECORD prr;
  252. PDNS_RECORD pnext;
  253. DNS_RRSET rrset;
  254. DNSDBG( TRACE, (
  255. "Dns_RecordListScreen( %p, %08x )\n",
  256. pRR,
  257. ScreenFlag ));
  258. // init copy rrset
  259. DNS_RRSET_INIT( rrset );
  260. //
  261. // loop through RR list
  262. //
  263. pnext = pRR;
  264. while ( pnext )
  265. {
  266. prr = pnext;
  267. pnext = prr->pNext;
  268. //
  269. // screen
  270. // - reappend record passing screen
  271. // - delete record failing screen
  272. //
  273. if ( Dns_ScreenRecord( prr, ScreenFlag ) )
  274. {
  275. prr->pNext = NULL;
  276. DNS_RRSET_ADD( rrset, prr );
  277. continue;
  278. }
  279. else
  280. {
  281. Dns_RecordFree( prr );
  282. }
  283. }
  284. return( rrset.pFirstRR );
  285. }
  286. //
  287. // List sorting
  288. //
  289. PDNS_RECORD
  290. Dns_PrioritizeSingleRecordSet(
  291. IN OUT PDNS_RECORD pRecordSet,
  292. IN PDNS_ADDR_ARRAY pArray
  293. )
  294. /*++
  295. Routine Description:
  296. Prioritize records in record set.
  297. Note: REQUIRES single record set.
  298. Caller should use Dns_PrioritizeRecordList() for multiple lists.
  299. Arguments:
  300. pRecordSet -- record set to prioritize
  301. pArray -- address array to sort against
  302. Return Value:
  303. Ptr to prioritized set.
  304. Set is NOT new, but is same set as pRecordSet, with records shuffled.
  305. --*/
  306. {
  307. PDNS_RECORD prr;
  308. PDNS_RECORD pprevRR;
  309. PDNS_RECORD prrUnmatched;
  310. DWORD iter;
  311. DNS_LIST listSubnetMatch;
  312. DNS_LIST listClassMatch;
  313. DNS_LIST listUnmatched;
  314. //
  315. // DCR_FIX: this whole routine is bogus
  316. // - it lets you do no intermediate ranking
  317. // it's binary and in order of IPs in list
  318. //
  319. // need
  320. // - knowledge of fast\slow interfaces (WAN for example)
  321. // then
  322. // - do best match on each RR in turn (rank it)
  323. // - then arrange in rank order
  324. //
  325. //
  326. // verify multirecord set
  327. // -- currently only handle type A
  328. //
  329. // DCR_ENHANCE: prioritize AAAA records?
  330. // may need scope info to do properly
  331. //
  332. prr = pRecordSet;
  333. if ( !prr ||
  334. prr->pNext == NULL ||
  335. prr->wType != DNS_TYPE_A )
  336. {
  337. return( pRecordSet );
  338. }
  339. // init prioritized list
  340. DNS_LIST_STRUCT_INIT( listSubnetMatch );
  341. DNS_LIST_STRUCT_INIT( listClassMatch );
  342. DNS_LIST_STRUCT_INIT( listUnmatched );
  343. //
  344. // loop through all RRs in set
  345. //
  346. while ( prr )
  347. {
  348. PDNS_RECORD pnext;
  349. DWORD matchLevel;
  350. ASSERT( prr->wType == DNS_TYPE_A );
  351. pnext = prr->pNext;
  352. prr->pNext = NULL;
  353. // check for subnet match
  354. matchLevel = DnsAddrArray_NetworkMatchIp4(
  355. pArray,
  356. prr->Data.A.IpAddress,
  357. NULL // don't need match addr
  358. );
  359. if ( matchLevel == 0 )
  360. {
  361. DNS_LIST_STRUCT_ADD( listUnmatched, prr );
  362. }
  363. else if ( matchLevel == DNSADDR_NETMATCH_SUBNET )
  364. {
  365. DNS_LIST_STRUCT_ADD( listSubnetMatch, prr );
  366. }
  367. else
  368. {
  369. DNS_LIST_STRUCT_ADD( listClassMatch, prr );
  370. }
  371. prr = pnext;
  372. }
  373. //
  374. // pull lists back together
  375. //
  376. if ( prr = listClassMatch.pFirst )
  377. {
  378. DNS_LIST_STRUCT_ADD( listSubnetMatch, prr );
  379. }
  380. if ( prr = listUnmatched.pFirst )
  381. {
  382. DNS_LIST_STRUCT_ADD( listSubnetMatch, prr );
  383. }
  384. prr = (PDNS_RECORD) listSubnetMatch.pFirst;
  385. DNS_ASSERT( prr );
  386. //
  387. // make sure first record has name
  388. // - use the name from the original first record
  389. // - or copy it
  390. //
  391. if ( !prr->pName || !FLAG_FreeOwner(prr) )
  392. {
  393. // steal name from first record
  394. if ( pRecordSet->pName && FLAG_FreeOwner(pRecordSet) )
  395. {
  396. prr->pName = pRecordSet->pName;
  397. FLAG_FreeOwner(prr) = TRUE;
  398. pRecordSet->pName = NULL;
  399. FLAG_FreeOwner(pRecordSet) = FALSE;
  400. }
  401. // if can't poach name, copy it
  402. // if copy fails, just point at it
  403. // note: if cared enough about mem failure could
  404. // just put original record back at the front
  405. else
  406. {
  407. PBYTE pnameCopy = NULL;
  408. pnameCopy = Dns_NameCopyAllocate(
  409. pRecordSet->pName,
  410. 0, // length unknown
  411. RECORD_CHARSET( prr ),
  412. RECORD_CHARSET( prr )
  413. );
  414. if ( pnameCopy )
  415. {
  416. prr->pName = pnameCopy;
  417. FLAG_FreeOwner( prr ) = TRUE;
  418. }
  419. else if ( !prr->pName )
  420. {
  421. prr->pName = pRecordSet->pName;
  422. FLAG_FreeOwner( prr ) = FALSE;
  423. }
  424. }
  425. }
  426. //
  427. // return prioritized list
  428. //
  429. return prr;
  430. }
  431. PDNS_RECORD
  432. Dns_PrioritizeRecordList(
  433. IN OUT PDNS_RECORD pRecordList,
  434. IN PDNS_ADDR_ARRAY pArray
  435. )
  436. /*++
  437. Routine Description:
  438. Prioritize records in record list.
  439. Record list may contain multiple record sets.
  440. Note, currently only prioritize A records, but may
  441. later do A6 also.
  442. Arguments:
  443. pRecordSet -- record set to prioritize
  444. pArray -- address array to sort against
  445. Return Value:
  446. Ptr to prioritized set.
  447. Set is NOT new, but is same set as pRecordSet, with records shuffled.
  448. --*/
  449. {
  450. PDNS_RECORD pnewList = NULL;
  451. PDNS_RECORD prr;
  452. PDNS_RECORD prrNextSet;
  453. if ( ! pRecordList ||
  454. ! pArray ||
  455. pArray->AddrCount == 0 )
  456. {
  457. return pRecordList;
  458. }
  459. //
  460. // loop through all record sets prioritizing
  461. // - whack off each RR set in turn
  462. // - prioritize it (if possible)
  463. // - pour it back into full list
  464. //
  465. //
  466. prr = pRecordList;
  467. while ( prr )
  468. {
  469. prrNextSet = Dns_RecordSetDetach( prr );
  470. prr = Dns_PrioritizeSingleRecordSet(
  471. prr,
  472. pArray );
  473. DNS_ASSERT( prr );
  474. pnewList = Dns_RecordListAppend(
  475. pnewList,
  476. prr );
  477. prr = prrNextSet;
  478. }
  479. return pnewList;
  480. }
  481. //
  482. // End rrlist.c
  483. //