OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/certificate_transparency/mock_log_dns_traffic.h" | 5 #include "components/certificate_transparency/mock_log_dns_traffic.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <numeric> | 8 #include <numeric> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
(...skipping 27 matching lines...) Expand all Loading... |
38 net::NetworkChangeNotifier::SetDnsConfig(config); | 38 net::NetworkChangeNotifier::SetDnsConfig(config); |
39 } | 39 } |
40 }; | 40 }; |
41 | 41 |
42 // Always return min, to simplify testing. | 42 // Always return min, to simplify testing. |
43 // This should result in the DNS query ID always being 0. | 43 // This should result in the DNS query ID always being 0. |
44 int FakeRandInt(int min, int max) { | 44 int FakeRandInt(int min, int max) { |
45 return min; | 45 return min; |
46 } | 46 } |
47 | 47 |
48 std::vector<char> CreateDnsTxtRequest(base::StringPiece qname) { | 48 bool CreateDnsTxtRequest(base::StringPiece qname, std::vector<char>* request) { |
49 std::string encoded_qname; | 49 std::string encoded_qname; |
50 CHECK(net::DNSDomainFromDot(qname, &encoded_qname)); | 50 if (!net::DNSDomainFromDot(qname, &encoded_qname)) { |
| 51 // |qname| is an invalid domain name. |
| 52 return false; |
| 53 } |
51 | 54 |
52 // DNS query section: | 55 // DNS query section: |
53 // N bytes - qname | 56 // N bytes - qname |
54 // 2 bytes - record type | 57 // 2 bytes - record type |
55 // 2 bytes - record class | 58 // 2 bytes - record class |
56 // Total = N + 4 bytes | 59 // Total = N + 4 bytes |
57 const size_t query_section_size = encoded_qname.size() + 4; | 60 const size_t query_section_size = encoded_qname.size() + 4; |
58 | 61 |
59 std::vector<char> request(sizeof(net::dns_protocol::Header) + | 62 request->resize(sizeof(net::dns_protocol::Header) + query_section_size); |
60 query_section_size); | 63 base::BigEndianWriter writer(request->data(), request->size()); |
61 base::BigEndianWriter writer(request.data(), request.size()); | |
62 | 64 |
63 // Header | 65 // Header |
64 net::dns_protocol::Header header = {}; | 66 net::dns_protocol::Header header = {}; |
65 header.flags = base::HostToNet16(net::dns_protocol::kFlagRD); | 67 header.flags = base::HostToNet16(net::dns_protocol::kFlagRD); |
66 header.qdcount = base::HostToNet16(1); | 68 header.qdcount = base::HostToNet16(1); |
67 CHECK(writer.WriteBytes(&header, sizeof(header))); | |
68 // Query section | |
69 CHECK(writer.WriteBytes(encoded_qname.data(), encoded_qname.size())); | |
70 CHECK(writer.WriteU16(net::dns_protocol::kTypeTXT)); | |
71 CHECK(writer.WriteU16(net::dns_protocol::kClassIN)); | |
72 CHECK_EQ(0, writer.remaining()); | |
73 | 69 |
74 return request; | 70 if (!writer.WriteBytes(&header, sizeof(header)) || |
| 71 !writer.WriteBytes(encoded_qname.data(), encoded_qname.size()) || |
| 72 !writer.WriteU16(net::dns_protocol::kTypeTXT) || |
| 73 !writer.WriteU16(net::dns_protocol::kClassIN)) { |
| 74 return false; |
| 75 } |
| 76 |
| 77 if (writer.remaining() != 0) { |
| 78 // Less than the expected amount of data was written. |
| 79 return false; |
| 80 } |
| 81 |
| 82 return true; |
75 } | 83 } |
76 | 84 |
77 std::vector<char> CreateDnsTxtResponse(const std::vector<char>& request, | 85 bool CreateDnsTxtResponse(const std::vector<char>& request, |
78 base::StringPiece answer) { | 86 base::StringPiece answer, |
| 87 std::vector<char>* response) { |
79 // DNS answers section: | 88 // DNS answers section: |
80 // 2 bytes - qname pointer | 89 // 2 bytes - qname pointer |
81 // 2 bytes - record type | 90 // 2 bytes - record type |
82 // 2 bytes - record class | 91 // 2 bytes - record class |
83 // 4 bytes - time-to-live | 92 // 4 bytes - time-to-live |
84 // 2 bytes - size of answer (N) | 93 // 2 bytes - size of answer (N) |
85 // N bytes - answer | 94 // N bytes - answer |
86 // Total = 12 + N bytes | 95 // Total = 12 + N bytes |
87 const size_t answers_section_size = 12 + answer.size(); | 96 const size_t answers_section_size = 12 + answer.size(); |
88 constexpr uint32_t ttl = 86400; // seconds | 97 constexpr uint32_t ttl = 86400; // seconds |
89 | 98 |
90 std::vector<char> response(request.size() + answers_section_size); | 99 response->resize(request.size() + answers_section_size); |
91 std::copy(request.begin(), request.end(), response.begin()); | 100 std::copy(request.begin(), request.end(), response->begin()); |
| 101 |
92 // Modify the header | 102 // Modify the header |
93 net::dns_protocol::Header* header = | 103 net::dns_protocol::Header* header = |
94 reinterpret_cast<net::dns_protocol::Header*>(response.data()); | 104 reinterpret_cast<net::dns_protocol::Header*>(response->data()); |
95 header->ancount = base::HostToNet16(1); | 105 header->ancount = base::HostToNet16(1); |
96 header->flags |= base::HostToNet16(net::dns_protocol::kFlagResponse); | 106 header->flags |= base::HostToNet16(net::dns_protocol::kFlagResponse); |
97 | 107 |
| 108 // The qname is at the start of the query section (just after the header). |
| 109 const uint8_t qname_ptr = sizeof(*header); |
| 110 |
98 // Write the answer section | 111 // Write the answer section |
99 base::BigEndianWriter writer(response.data() + request.size(), | 112 base::BigEndianWriter writer(response->data() + request.size(), |
100 response.size() - request.size()); | 113 response->size() - request.size()); |
101 CHECK(writer.WriteU8(0xc0)); // qname is a pointer | 114 if (!writer.WriteU8(net::dns_protocol::kLabelPointer) || |
102 CHECK(writer.WriteU8( | 115 !writer.WriteU8(qname_ptr) || |
103 sizeof(*header))); // address of qname (start of query section) | 116 !writer.WriteU16(net::dns_protocol::kTypeTXT) || |
104 CHECK(writer.WriteU16(net::dns_protocol::kTypeTXT)); | 117 !writer.WriteU16(net::dns_protocol::kClassIN) || !writer.WriteU32(ttl) || |
105 CHECK(writer.WriteU16(net::dns_protocol::kClassIN)); | 118 !writer.WriteU16(answer.size()) || |
106 CHECK(writer.WriteU32(ttl)); | 119 !writer.WriteBytes(answer.data(), answer.size())) { |
107 CHECK(writer.WriteU16(answer.size())); | 120 return false; |
108 CHECK(writer.WriteBytes(answer.data(), answer.size())); | 121 } |
109 CHECK_EQ(0, writer.remaining()); | |
110 | 122 |
111 return response; | 123 if (writer.remaining() != 0) { |
| 124 // Less than the expected amount of data was written. |
| 125 return false; |
| 126 } |
| 127 |
| 128 return true; |
112 } | 129 } |
113 | 130 |
114 std::vector<char> CreateDnsErrorResponse(const std::vector<char>& request, | 131 bool CreateDnsErrorResponse(const std::vector<char>& request, |
115 uint8_t rcode) { | 132 uint8_t rcode, |
116 std::vector<char> response(request); | 133 std::vector<char>* response) { |
| 134 *response = request; |
117 // Modify the header | 135 // Modify the header |
118 net::dns_protocol::Header* header = | 136 net::dns_protocol::Header* header = |
119 reinterpret_cast<net::dns_protocol::Header*>(response.data()); | 137 reinterpret_cast<net::dns_protocol::Header*>(response->data()); |
120 header->ancount = base::HostToNet16(1); | 138 header->ancount = base::HostToNet16(1); |
121 header->flags |= base::HostToNet16(net::dns_protocol::kFlagResponse | rcode); | 139 header->flags |= base::HostToNet16(net::dns_protocol::kFlagResponse | rcode); |
122 | 140 return true; |
123 return response; | |
124 } | 141 } |
125 | 142 |
126 } // namespace | 143 } // namespace |
127 | 144 |
128 // A container for all of the data needed for simulating a socket. | 145 // A container for all of the data needed for simulating a socket. |
129 // This is useful because Mock{Read,Write}, SequencedSocketData and | 146 // This is useful because Mock{Read,Write}, SequencedSocketData and |
130 // MockClientSocketFactory all do not take ownership of or copy their arguments, | 147 // MockClientSocketFactory all do not take ownership of or copy their arguments, |
131 // so it is necessary to manage the lifetime of those arguments. Wrapping all | 148 // so it is necessary to manage the lifetime of those arguments. Wrapping all |
132 // of that up in a single class simplifies this. | 149 // of that up in a single class simplifies this. |
133 class MockLogDnsTraffic::MockSocketData { | 150 class MockLogDnsTraffic::MockSocketData { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 private: | 197 private: |
181 // This class only supports one write and one read, so just need to store one | 198 // This class only supports one write and one read, so just need to store one |
182 // payload each. | 199 // payload each. |
183 const std::vector<char> expected_write_payload_; | 200 const std::vector<char> expected_write_payload_; |
184 const std::vector<char> expected_read_payload_; | 201 const std::vector<char> expected_read_payload_; |
185 | 202 |
186 // Encapsulates the data that is expected to be written to a socket. | 203 // Encapsulates the data that is expected to be written to a socket. |
187 net::MockWrite expected_write_; | 204 net::MockWrite expected_write_; |
188 | 205 |
189 // Encapsulates the data/error that should be returned when reading from a | 206 // Encapsulates the data/error that should be returned when reading from a |
190 // socket. The second "expected" read is a sentinel that causes socket reads | 207 // socket. The second "expected" read is a sentinel (see |kNoMoreData|). |
191 // beyond the first to hang until they timeout. This results in better | |
192 // test failure messages (rather than a CHECK-fail due to a socket read | |
193 // overrunning the MockRead array) and behaviour more like a real socket when | |
194 // an unexpected second socket read occurs. | |
195 net::MockRead expected_reads_[2]; | 208 net::MockRead expected_reads_[2]; |
196 | 209 |
197 // Holds pointers to |expected_write_| and |expected_reads_|. This is what is | 210 // Holds pointers to |expected_write_| and |expected_reads_|. This is what is |
198 // added to net::MockClientSocketFactory to prepare a mock socket. | 211 // added to net::MockClientSocketFactory to prepare a mock socket. |
199 net::SequencedSocketData socket_data_; | 212 net::SequencedSocketData socket_data_; |
200 | 213 |
201 DISALLOW_COPY_AND_ASSIGN(MockSocketData); | 214 DISALLOW_COPY_AND_ASSIGN(MockSocketData); |
202 }; | 215 }; |
203 | 216 |
204 MockLogDnsTraffic::MockLogDnsTraffic() : socket_read_mode_(net::ASYNC) {} | 217 MockLogDnsTraffic::MockLogDnsTraffic() : socket_read_mode_(net::ASYNC) {} |
205 | 218 |
206 MockLogDnsTraffic::~MockLogDnsTraffic() {} | 219 MockLogDnsTraffic::~MockLogDnsTraffic() {} |
207 | 220 |
208 void MockLogDnsTraffic::ExpectRequestAndErrorResponse(base::StringPiece qname, | 221 bool MockLogDnsTraffic::ExpectRequestAndErrorResponse(base::StringPiece qname, |
209 uint8_t rcode) { | 222 uint8_t rcode) { |
210 std::vector<char> request = CreateDnsTxtRequest(qname); | 223 std::vector<char> request; |
211 EmplaceMockSocketData(CreateDnsTxtRequest(qname), | 224 if (!CreateDnsTxtRequest(qname, &request)) { |
212 CreateDnsErrorResponse(request, rcode)); | 225 return false; |
| 226 } |
| 227 |
| 228 std::vector<char> response; |
| 229 if (!CreateDnsErrorResponse(request, rcode, &response)) { |
| 230 return false; |
| 231 } |
| 232 |
| 233 EmplaceMockSocketData(request, response); |
| 234 return true; |
213 } | 235 } |
214 | 236 |
215 void MockLogDnsTraffic::ExpectRequestAndSocketError(base::StringPiece qname, | 237 bool MockLogDnsTraffic::ExpectRequestAndSocketError(base::StringPiece qname, |
216 net::Error error) { | 238 net::Error error) { |
217 EmplaceMockSocketData(CreateDnsTxtRequest(qname), error); | 239 std::vector<char> request; |
| 240 if (!CreateDnsTxtRequest(qname, &request)) { |
| 241 return false; |
| 242 } |
| 243 |
| 244 EmplaceMockSocketData(request, error); |
| 245 return true; |
218 } | 246 } |
219 | 247 |
220 void MockLogDnsTraffic::ExpectRequestAndTimeout(base::StringPiece qname) { | 248 bool MockLogDnsTraffic::ExpectRequestAndTimeout(base::StringPiece qname) { |
221 EmplaceMockSocketData(CreateDnsTxtRequest(qname)); | 249 std::vector<char> request; |
| 250 if (!CreateDnsTxtRequest(qname, &request)) { |
| 251 return false; |
| 252 } |
| 253 |
| 254 EmplaceMockSocketData(request); |
222 | 255 |
223 // Speed up timeout tests. | 256 // Speed up timeout tests. |
224 SetDnsTimeout(TestTimeouts::tiny_timeout()); | 257 SetDnsTimeout(TestTimeouts::tiny_timeout()); |
| 258 |
| 259 return true; |
225 } | 260 } |
226 | 261 |
227 void MockLogDnsTraffic::ExpectRequestAndResponse( | 262 bool MockLogDnsTraffic::ExpectRequestAndResponse( |
228 base::StringPiece qname, | 263 base::StringPiece qname, |
229 const std::vector<base::StringPiece>& txt_strings) { | 264 const std::vector<base::StringPiece>& txt_strings) { |
230 std::string answer; | 265 std::string answer; |
231 for (base::StringPiece str : txt_strings) { | 266 for (base::StringPiece str : txt_strings) { |
232 // The size of the string must precede it. The size must fit into 1 byte. | 267 // The size of the string must precede it. The size must fit into 1 byte. |
233 answer.insert(answer.end(), base::checked_cast<uint8_t>(str.size())); | 268 answer.insert(answer.end(), base::checked_cast<uint8_t>(str.size())); |
234 str.AppendToString(&answer); | 269 str.AppendToString(&answer); |
235 } | 270 } |
236 | 271 |
237 std::vector<char> request = CreateDnsTxtRequest(qname); | 272 std::vector<char> request; |
238 EmplaceMockSocketData(request, CreateDnsTxtResponse(request, answer)); | 273 if (!CreateDnsTxtRequest(qname, &request)) { |
| 274 return false; |
| 275 } |
| 276 |
| 277 std::vector<char> response; |
| 278 if (!CreateDnsTxtResponse(request, answer, &response)) { |
| 279 return false; |
| 280 } |
| 281 |
| 282 EmplaceMockSocketData(request, response); |
| 283 return true; |
239 } | 284 } |
240 | 285 |
241 void MockLogDnsTraffic::ExpectLeafIndexRequestAndResponse( | 286 bool MockLogDnsTraffic::ExpectLeafIndexRequestAndResponse( |
242 base::StringPiece qname, | 287 base::StringPiece qname, |
243 uint64_t leaf_index) { | 288 uint64_t leaf_index) { |
244 ExpectRequestAndResponse(qname, { base::Uint64ToString(leaf_index) }); | 289 return ExpectRequestAndResponse(qname, {base::Uint64ToString(leaf_index)}); |
245 } | 290 } |
246 | 291 |
247 void MockLogDnsTraffic::ExpectAuditProofRequestAndResponse( | 292 bool MockLogDnsTraffic::ExpectAuditProofRequestAndResponse( |
248 base::StringPiece qname, | 293 base::StringPiece qname, |
249 std::vector<std::string>::const_iterator audit_path_start, | 294 std::vector<std::string>::const_iterator audit_path_start, |
250 std::vector<std::string>::const_iterator audit_path_end) { | 295 std::vector<std::string>::const_iterator audit_path_end) { |
251 // Join nodes in the audit path into a single string. | 296 // Join nodes in the audit path into a single string. |
252 std::string proof = | 297 std::string proof = |
253 std::accumulate(audit_path_start, audit_path_end, std::string()); | 298 std::accumulate(audit_path_start, audit_path_end, std::string()); |
254 | 299 |
255 ExpectRequestAndResponse(qname, { proof }); | 300 return ExpectRequestAndResponse(qname, {proof}); |
256 } | 301 } |
257 | 302 |
258 void MockLogDnsTraffic::InitializeDnsConfig() { | 303 void MockLogDnsTraffic::InitializeDnsConfig() { |
259 net::DnsConfig dns_config; | 304 net::DnsConfig dns_config; |
260 // Use an invalid nameserver address. This prevents the tests accidentally | 305 // Use an invalid nameserver address. This prevents the tests accidentally |
261 // sending real DNS queries. The mock sockets don't care that the address | 306 // sending real DNS queries. The mock sockets don't care that the address |
262 // is invalid. | 307 // is invalid. |
263 dns_config.nameservers.push_back(net::IPEndPoint()); | 308 dns_config.nameservers.push_back(net::IPEndPoint()); |
264 // Don't attempt retransmissions - just fail. | 309 // Don't attempt retransmissions - just fail. |
265 dns_config.attempts = 1; | 310 dns_config.attempts = 1; |
(...skipping 25 matching lines...) Expand all Loading... |
291 } | 336 } |
292 | 337 |
293 void MockLogDnsTraffic::SetDnsTimeout(const base::TimeDelta& timeout) { | 338 void MockLogDnsTraffic::SetDnsTimeout(const base::TimeDelta& timeout) { |
294 net::DnsConfig dns_config; | 339 net::DnsConfig dns_config; |
295 DnsChangeNotifier::GetDnsConfig(&dns_config); | 340 DnsChangeNotifier::GetDnsConfig(&dns_config); |
296 dns_config.timeout = timeout; | 341 dns_config.timeout = timeout; |
297 DnsChangeNotifier::SetDnsConfig(dns_config); | 342 DnsChangeNotifier::SetDnsConfig(dns_config); |
298 } | 343 } |
299 | 344 |
300 } // namespace certificate_transparency | 345 } // namespace certificate_transparency |
OLD | NEW |