Branch data Line data Source code
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 : :
15 : : #include <iostream>
16 : : #include <vector>
17 : : #include <dns/message.h>
18 : : #include <dns/rrset.h>
19 : : #include <dns/name.h>
20 : : #include "response_scrubber.h"
21 : :
22 : : using namespace isc::dns;
23 : : using namespace std;
24 : :
25 : : // Compare addresses etc.
26 : :
27 : 19 : ResponseScrubber::Category ResponseScrubber::addressCheck(
28 : : const isc::asiolink::IOEndpoint& to, const isc::asiolink::IOEndpoint& from)
29 : : {
30 [ + + ]: 19 : if (from.getProtocol() == to.getProtocol()) {
31 [ + + ]: 36 : if (from.getAddress() == to.getAddress()) {
32 [ + + ]: 8 : if (from.getPort() == to.getPort()) {
33 : : return (ResponseScrubber::SUCCESS);
34 : : } else {
35 : 19 : return (ResponseScrubber::PORT);
36 : : }
37 : : } else {
38 : : return (ResponseScrubber::ADDRESS);
39 : : }
40 : : }
41 : : return (ResponseScrubber::PROTOCOL);
42 : : }
43 : :
44 : : // Do a general scrubbing. The QNAMES of RRsets in the specified section are
45 : : // compared against the list of name given and if they are not equal and not in
46 : : // the specified relationship (generally superdomain or subdomain) to at least
47 : : // of of the given names, they are removed.
48 : :
49 : : unsigned int
50 : 19 : ResponseScrubber::scrubSection(Message& message,
51 : : const vector<const Name*>& names,
52 : : const NameComparisonResult::NameRelation connection,
53 : : const Message::Section section)
54 : : {
55 : 19 : unsigned int count = 0; // Count of RRsets removed
56 : 19 : unsigned int kept = 0; // Count of RRsets kept
57 : 19 : bool removed = true; // Set true if RRset removed in a pass
58 : :
59 : : // Need to go through the section multiple times as when an RRset is
60 : : // removed, all iterators into the section are invalidated. This condition
61 : : // is flagged by "remove" being set true when an RRset is removed.
62 : :
63 [ + + ]: 53 : while (removed) {
64 : 34 : RRsetIterator i = message.beginSection(section);
65 : :
66 : : // Skips the ones that have been checked (and retained) in a previous
67 : : // pass through the "while" loop. (Although RRset removal invalidates
68 : : // iterators, it does not change the relative order of the retained
69 : : // RRsets in the section.)
70 [ + + ]: 47 : for (int j = 0; j < kept; ++j) {
71 [ + - ]: 13 : ++i;
72 : : }
73 : :
74 : : // Start looking at the remaining entries in the section.
75 : : removed = false;
76 [ + - ][ + - ]: 52 : for (; i != message.endSection(section); ++i) {
[ + - ][ + - ]
[ + + ]
77 : :
78 : : // Loop through the list of names given and see if any are in the
79 : : // given relationship with the QNAME of this RRset
80 : 33 : bool match = false;
81 [ + + ]: 48 : for (vector<const Name*>::const_iterator n = names.begin();
82 : 48 : n != names.end(); ++n) {
83 [ + - ][ + - ]: 33 : NameComparisonResult result = (*i)->getName().compare(**n);
[ + - ]
84 : : NameComparisonResult::NameRelation relationship =
85 : 33 : result.getRelation();
86 [ + + ]: 33 : if ((relationship == NameComparisonResult::EQUAL) ||
87 : : (relationship == connection)) {
88 : :
89 : : // RRset in the specified relationship, so a match has
90 : : // been found
91 : : match = true;
92 : : break;
93 : : }
94 : : }
95 : :
96 : : // Remove the RRset if there was no match to one of the given names.
97 [ + + ]: 33 : if (!match) {
98 [ + - ]: 15 : message.removeRRset(section, i);
99 : 15 : ++count; // One more RRset removed
100 : 15 : removed = true; // Something was removed
101 : 15 : break; // It invalidated the iterators, start again
102 : : } else {
103 : :
104 : : // There was a match so this is one more entry we can skip next
105 : : // time.
106 : 18 : ++kept;
107 : : }
108 : : }
109 : : }
110 : :
111 : 19 : return (count);
112 : : }
113 : :
114 : : // Perform the scrubbing of all sections of the message.
115 : :
116 : : unsigned int
117 : 5 : ResponseScrubber::scrubAllSections(Message& message, const Name& bailiwick) {
118 : :
119 : : // Leave the question section alone. Just go through the RRsets in the
120 : : // answer, authority and additional sections.
121 : 5 : unsigned int count = 0;
122 : 5 : const vector<const Name*> bailiwick_names(1, &bailiwick);
123 : : count += scrubSection(message, bailiwick_names,
124 [ + - ]: 5 : NameComparisonResult::SUBDOMAIN, Message::SECTION_ANSWER);
125 : : count += scrubSection(message, bailiwick_names,
126 [ + - ]: 5 : NameComparisonResult::SUBDOMAIN, Message::SECTION_AUTHORITY);
127 : : count += scrubSection(message, bailiwick_names,
128 [ + - ]: 5 : NameComparisonResult::SUBDOMAIN, Message::SECTION_ADDITIONAL);
129 : :
130 : 5 : return (count);
131 : : }
132 : :
133 : : // Scrub across sections.
134 : :
135 : : unsigned int
136 : 4 : ResponseScrubber::scrubCrossSections(isc::dns::Message& message) {
137 : :
138 : : // Get a list of the names in the answer section or, failing this, the
139 : : // question section. Note that pointers to the names within "message" are
140 : : // stored; this is OK as the relevant sections in "message" will not change
141 : : // during the lifetime of this method (it only affects the authority
142 : : // section).
143 : 4 : vector<const Name*> source;
144 [ + - ][ - + ]: 4 : if (message.getRRCount(Message::SECTION_ANSWER) != 0) {
145 [ # # ][ # # ]: 0 : for (RRsetIterator i = message.beginSection(Message::SECTION_ANSWER);
[ # # ][ # # ]
[ # # ]
146 [ # # ][ # # ]: 0 : i != message.endSection(Message::SECTION_ANSWER); ++i) {
147 [ # # ][ # # ]: 0 : const Name& qname = (*i)->getName();
148 [ # # ]: 0 : source.push_back(&qname);
149 : : }
150 : :
151 : : } else {
152 [ + - ][ + - ]: 24 : for (QuestionIterator i = message.beginQuestion();
[ + - ][ + + ]
[ + - ]
153 [ + - ][ + - ]: 16 : i != message.endQuestion(); ++i) {
154 [ + - ]: 4 : const Name& qname = (*i)->getName();
155 [ + - ]: 4 : source.push_back(&qname);
156 : : }
157 : : }
158 : :
159 [ + - ]: 4 : if (source.empty()) {
160 : : // TODO: Log the fact - should be at least a question present
161 : : return (0);
162 : : }
163 : :
164 : : // Could be duplicates, especially in the answer section, so sort the
165 : : // names and remove them.
166 [ + - ]: 4 : sort(source.begin(), source.end(), ResponseScrubber::compareNameLt);
167 : : vector<const Name*>::iterator endunique =
168 : : unique(source.begin(), source.end(), ResponseScrubber::compareNameEq);
169 : : source.erase(endunique, source.end());
170 : :
171 : : // Now purge the authority section of RRsets that are not equal to or a
172 : : // superdomain of the names in the question/answer section.
173 : : return (scrubSection(message, source,
174 [ + - ]: 4 : NameComparisonResult::SUPERDOMAIN, Message::SECTION_AUTHORITY));
175 : : }
176 : :
177 : : // Scrub a message
178 : :
179 : : unsigned int
180 : 1 : ResponseScrubber::scrub(const isc::dns::MessagePtr& message,
181 : : const isc::dns::Name& bailiwick)
182 : : {
183 : 1 : unsigned int sections_removed = scrubAllSections(*message, bailiwick);
184 : 1 : sections_removed += scrubCrossSections(*message);
185 : :
186 : 1 : return (sections_removed);
187 : 1 : }
188 : :
189 : :
|