| 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 |