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