response_scrubber.cc 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <iostream>
  15. #include <vector>
  16. #include <dns/message.h>
  17. #include <dns/rrset.h>
  18. #include <dns/name.h>
  19. #include "response_scrubber.h"
  20. using namespace isc::dns;
  21. using namespace std;
  22. // Compare addresses etc.
  23. ResponseScrubber::Category ResponseScrubber::addressCheck(
  24. const isc::asiolink::IOEndpoint& to, const isc::asiolink::IOEndpoint& from)
  25. {
  26. if (from.getProtocol() == to.getProtocol()) {
  27. if (from.getAddress() == to.getAddress()) {
  28. if (from.getPort() == to.getPort()) {
  29. return (ResponseScrubber::SUCCESS);
  30. } else {
  31. return (ResponseScrubber::PORT);
  32. }
  33. } else {
  34. return (ResponseScrubber::ADDRESS);
  35. }
  36. }
  37. return (ResponseScrubber::PROTOCOL);
  38. }
  39. // Do a general scrubbing. The QNAMES of RRsets in the specified section are
  40. // compared against the list of name given and if they are not equal and not in
  41. // the specified relationship (generally superdomain or subdomain) to at least
  42. // of of the given names, they are removed.
  43. unsigned int
  44. ResponseScrubber::scrubSection(Message& message,
  45. const vector<const Name*>& names,
  46. const NameComparisonResult::NameRelation connection,
  47. const Message::Section section)
  48. {
  49. unsigned int count = 0; // Count of RRsets removed
  50. unsigned int kept = 0; // Count of RRsets kept
  51. bool removed = true; // Set true if RRset removed in a pass
  52. // Need to go through the section multiple times as when an RRset is
  53. // removed, all iterators into the section are invalidated. This condition
  54. // is flagged by "remove" being set true when an RRset is removed.
  55. while (removed) {
  56. RRsetIterator i = message.beginSection(section);
  57. // Skips the ones that have been checked (and retained) in a previous
  58. // pass through the "while" loop. (Although RRset removal invalidates
  59. // iterators, it does not change the relative order of the retained
  60. // RRsets in the section.)
  61. for (int j = 0; j < kept; ++j) {
  62. ++i;
  63. }
  64. // Start looking at the remaining entries in the section.
  65. removed = false;
  66. for (; i != message.endSection(section); ++i) {
  67. // Loop through the list of names given and see if any are in the
  68. // given relationship with the QNAME of this RRset
  69. bool match = false;
  70. for (vector<const Name*>::const_iterator n = names.begin();
  71. n != names.end(); ++n) {
  72. NameComparisonResult result = (*i)->getName().compare(**n);
  73. NameComparisonResult::NameRelation relationship =
  74. result.getRelation();
  75. if ((relationship == NameComparisonResult::EQUAL) ||
  76. (relationship == connection)) {
  77. // RRset in the specified relationship, so a match has
  78. // been found
  79. match = true;
  80. break;
  81. }
  82. }
  83. // Remove the RRset if there was no match to one of the given names.
  84. if (!match) {
  85. message.removeRRset(section, i);
  86. ++count; // One more RRset removed
  87. removed = true; // Something was removed
  88. break; // It invalidated the iterators, start again
  89. } else {
  90. // There was a match so this is one more entry we can skip next
  91. // time.
  92. ++kept;
  93. }
  94. }
  95. }
  96. return (count);
  97. }
  98. // Perform the scrubbing of all sections of the message.
  99. unsigned int
  100. ResponseScrubber::scrubAllSections(Message& message, const Name& bailiwick) {
  101. // Leave the question section alone. Just go through the RRsets in the
  102. // answer, authority and additional sections.
  103. unsigned int count = 0;
  104. const vector<const Name*> bailiwick_names(1, &bailiwick);
  105. count += scrubSection(message, bailiwick_names,
  106. NameComparisonResult::SUBDOMAIN, Message::SECTION_ANSWER);
  107. count += scrubSection(message, bailiwick_names,
  108. NameComparisonResult::SUBDOMAIN, Message::SECTION_AUTHORITY);
  109. count += scrubSection(message, bailiwick_names,
  110. NameComparisonResult::SUBDOMAIN, Message::SECTION_ADDITIONAL);
  111. return (count);
  112. }
  113. // Scrub across sections.
  114. unsigned int
  115. ResponseScrubber::scrubCrossSections(isc::dns::Message& message) {
  116. // Get a list of the names in the answer section or, failing this, the
  117. // question section. Note that pointers to the names within "message" are
  118. // stored; this is OK as the relevant sections in "message" will not change
  119. // during the lifetime of this method (it only affects the authority
  120. // section).
  121. vector<const Name*> source;
  122. if (message.getRRCount(Message::SECTION_ANSWER) != 0) {
  123. for (RRsetIterator i = message.beginSection(Message::SECTION_ANSWER);
  124. i != message.endSection(Message::SECTION_ANSWER); ++i) {
  125. const Name& qname = (*i)->getName();
  126. source.push_back(&qname);
  127. }
  128. } else {
  129. for (QuestionIterator i = message.beginQuestion();
  130. i != message.endQuestion(); ++i) {
  131. const Name& qname = (*i)->getName();
  132. source.push_back(&qname);
  133. }
  134. }
  135. if (source.empty()) {
  136. // TODO: Log the fact - should be at least a question present
  137. return (0);
  138. }
  139. // Could be duplicates, especially in the answer section, so sort the
  140. // names and remove them.
  141. sort(source.begin(), source.end(), ResponseScrubber::compareNameLt);
  142. vector<const Name*>::iterator endunique =
  143. unique(source.begin(), source.end(), ResponseScrubber::compareNameEq);
  144. source.erase(endunique, source.end());
  145. // Now purge the authority section of RRsets that are not equal to or a
  146. // superdomain of the names in the question/answer section.
  147. return (scrubSection(message, source,
  148. NameComparisonResult::SUPERDOMAIN, Message::SECTION_AUTHORITY));
  149. }
  150. // Scrub a message
  151. unsigned int
  152. ResponseScrubber::scrub(const isc::dns::MessagePtr& message,
  153. const isc::dns::Name& bailiwick)
  154. {
  155. unsigned int sections_removed = scrubAllSections(*message, bailiwick);
  156. sections_removed += scrubCrossSections(*message);
  157. return (sections_removed);
  158. }