response_scrubber.cc 6.9 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 asiolink::IOEndpoint& to, const 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)) && (!removed); ++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 nomatch = true;
  70. for (vector<const Name*>::const_iterator n = names.begin();
  71. ((n != names.end()) && nomatch); ++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. nomatch = false;
  80. }
  81. }
  82. // Remove the RRset if there was no match to one of the given names.
  83. if (nomatch) {
  84. message.removeRRset(section, i);
  85. ++count; // One more RRset removed
  86. removed = true; // Something was removed
  87. } else {
  88. // There was a match so this is one more entry we can skip next
  89. // time.
  90. ++kept;
  91. }
  92. }
  93. }
  94. return count;
  95. }
  96. // Perform the scrubbing of all sections of the message.
  97. unsigned int
  98. ResponseScrubber::scrubAllSections(Message& message, const Name& bailiwick) {
  99. // Leave the question section alone. Just go through the RRsets in the
  100. // answer, authority and additional sections.
  101. unsigned int count = 0;
  102. const vector<const Name*> bailiwick_names(1, &bailiwick);
  103. count += scrubSection(message, bailiwick_names,
  104. NameComparisonResult::SUBDOMAIN, Message::SECTION_ANSWER);
  105. count += scrubSection(message, bailiwick_names,
  106. NameComparisonResult::SUBDOMAIN, Message::SECTION_AUTHORITY);
  107. count += scrubSection(message, bailiwick_names,
  108. NameComparisonResult::SUBDOMAIN, Message::SECTION_ADDITIONAL);
  109. return count;
  110. }
  111. // Scrub across sections.
  112. unsigned int
  113. ResponseScrubber::scrubCrossSections(isc::dns::Message& message) {
  114. // Get a list of the names in the answer section or, failing this, the
  115. // question section. Note that pointers to the names within "message" are
  116. // stored; this is OK as the relevant sections in "message" will not change
  117. // during the lifetime of this method (it only affects the authority
  118. // section).
  119. vector<const Name*> source;
  120. if (message.getRRCount(Message::SECTION_ANSWER) != 0) {
  121. for (RRsetIterator i = message.beginSection(Message::SECTION_ANSWER);
  122. i != message.endSection(Message::SECTION_ANSWER); ++i) {
  123. const Name& qname = (*i)->getName();
  124. source.push_back(&qname);
  125. }
  126. } else {
  127. for (QuestionIterator i = message.beginQuestion();
  128. i != message.endQuestion(); ++i) {
  129. const Name& qname = (*i)->getName();
  130. source.push_back(&qname);
  131. }
  132. }
  133. if (source.empty()) {
  134. // TODO: Log the fact - should be at least a question present
  135. return (0);
  136. }
  137. // Could be duplicates, especially in the answer section, so sort the
  138. // names and remove them.
  139. sort(source.begin(), source.end(), ResponseScrubber::compareNameLt);
  140. vector<const Name*>::iterator endunique =
  141. unique(source.begin(), source.end(), ResponseScrubber::compareNameEq);
  142. source.erase(endunique, source.end());
  143. // Now purge the authority section of RRsets that are not equal to or a
  144. // superdomain of the names in the question/answer section.
  145. return (scrubSection(message, source,
  146. NameComparisonResult::SUPERDOMAIN, Message::SECTION_AUTHORITY));
  147. }
  148. // Scrub a message
  149. unsigned int
  150. ResponseScrubber::scrub(const isc::dns::MessagePtr& message,
  151. const isc::dns::Name& bailiwick)
  152. {
  153. unsigned int sections_removed = scrubAllSections(*message, bailiwick);
  154. sections_removed += scrubCrossSections(*message);
  155. return sections_removed;
  156. }