Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(55)

Side by Side Diff: components/certificate_transparency/mock_log_dns_traffic.cc

Issue 2149973003: Extracts CT DNS test utilities into a standalone class (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "components/certificate_transparency/mock_log_dns_traffic.h"
6
7 #include <algorithm>
8 #include <numeric>
9 #include <vector>
10
11 #include "base/big_endian.h"
12 #include "base/sys_byteorder.h"
13 #include "base/test/test_timeouts.h"
14 #include "net/dns/dns_client.h"
15 #include "net/dns/dns_protocol.h"
16 #include "net/dns/dns_util.h"
17 #include "net/socket/socket_test_util.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace certificate_transparency {
21
22 namespace {
23
24 // Always return min, to simplify testing.
25 // This should result in the DNS query ID always being 0.
26 int FakeRandInt(int min, int max) {
27 return min;
28 }
29
30 std::vector<char> CreateDnsTxtRequest(base::StringPiece qname) {
31 std::string encoded_qname;
32 EXPECT_TRUE(net::DNSDomainFromDot(qname, &encoded_qname));
33
34 const size_t query_section_size = encoded_qname.size() + 4;
Eran Messeri 2016/07/21 14:47:02 What does the '4' here stand for? Would it make se
Rob Percival 2016/07/21 17:32:21 It's the 4 bytes you see written below, just after
Eran Messeri 2016/07/22 15:55:48 Splitting sounds better.
35
36 std::vector<char> request(sizeof(net::dns_protocol::Header) +
37 query_section_size);
38 base::BigEndianWriter writer(request.data(), request.size());
39
40 // Header
41 net::dns_protocol::Header header = {};
42 header.flags = base::HostToNet16(net::dns_protocol::kFlagRD);
43 header.qdcount = base::HostToNet16(1);
44 EXPECT_TRUE(writer.WriteBytes(&header, sizeof(header)));
45 // Query section
46 EXPECT_TRUE(writer.WriteBytes(encoded_qname.data(), encoded_qname.size()));
47 EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kTypeTXT));
48 EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kClassIN));
49 EXPECT_EQ(0, writer.remaining());
50
51 return request;
52 }
53
54 std::vector<char> CreateDnsTxtResponse(const std::vector<char>& request,
55 base::StringPiece answer) {
56 const size_t answers_section_size = 12 + answer.size();
Eran Messeri 2016/07/21 14:47:02 Another magic number, please have a constant expla
Rob Percival 2016/07/21 17:32:21 Again, this is the 12 bytes you see written a litt
Eran Messeri 2016/07/22 15:55:48 Again, breaking down seems better as it's clear wh
57 constexpr uint32_t ttl = 86400; // seconds
58
59 std::vector<char> response(request.size() + answers_section_size);
60 std::copy(request.begin(), request.end(), response.begin());
61 // Modify the header
62 net::dns_protocol::Header* header =
63 reinterpret_cast<net::dns_protocol::Header*>(response.data());
64 header->ancount = base::HostToNet16(1);
65 header->flags |= base::HostToNet16(net::dns_protocol::kFlagResponse);
66
67 // Write the answer section
68 base::BigEndianWriter writer(response.data() + request.size(),
69 response.size() - request.size());
70 EXPECT_TRUE(writer.WriteU8(0xc0)); // qname is a pointer
71 EXPECT_TRUE(writer.WriteU8(
72 sizeof(*header))); // address of qname (start of query section)
73 EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kTypeTXT));
74 EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kClassIN));
75 EXPECT_TRUE(writer.WriteU32(ttl));
76 EXPECT_TRUE(writer.WriteU16(answer.size()));
77 EXPECT_TRUE(writer.WriteBytes(answer.data(), answer.size()));
78 EXPECT_EQ(0, writer.remaining());
79
80 return response;
81 }
82
83 std::vector<char> CreateDnsErrorResponse(const std::vector<char>& request,
84 uint8_t rcode) {
85 std::vector<char> response(request);
86 // Modify the header
87 net::dns_protocol::Header* header =
88 reinterpret_cast<net::dns_protocol::Header*>(response.data());
89 header->ancount = base::HostToNet16(1);
90 header->flags |= base::HostToNet16(net::dns_protocol::kFlagResponse | rcode);
91
92 return response;
93 }
94
95 } // namespace
96
97 namespace detail {
98
99 MockSocketData::MockSocketData(const std::vector<char>& write,
100 const std::vector<char>& read)
101 : expected_write_payload_(write),
102 expected_read_payload_(read),
103 expected_write_(net::SYNCHRONOUS,
104 expected_write_payload_.data(),
105 expected_write_payload_.size(),
106 0),
107 expected_reads_{net::MockRead(net::ASYNC,
108 expected_read_payload_.data(),
109 expected_read_payload_.size(),
110 1),
111 eof_},
112 socket_data_(expected_reads_, 2, &expected_write_, 1) {}
113
114 MockSocketData::MockSocketData(const std::vector<char>& write, int net_error)
115 : expected_write_payload_(write),
116 expected_write_(net::SYNCHRONOUS,
117 expected_write_payload_.data(),
118 expected_write_payload_.size(),
119 0),
120 expected_reads_{net::MockRead(net::ASYNC, net_error, 1), eof_},
121 socket_data_(expected_reads_, 2, &expected_write_, 1) {}
122
123 MockSocketData::MockSocketData(const std::vector<char>& write)
124 : expected_write_payload_(write),
125 expected_write_(net::SYNCHRONOUS,
126 expected_write_payload_.data(),
127 expected_write_payload_.size(),
128 0),
129 expected_reads_{net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING, 1),
130 eof_},
131 socket_data_(expected_reads_, 2, &expected_write_, 1) {}
132
133 MockSocketData::~MockSocketData() {}
134
135 void MockSocketData::AddToFactory(
136 net::MockClientSocketFactory* socket_factory) {
137 socket_factory->AddSocketDataProvider(&socket_data_);
138 }
139
140 const net::MockRead MockSocketData::eof_(net::SYNCHRONOUS,
141 net::ERR_IO_PENDING,
142 2);
143
144 } // namespace detail
145
146 using detail::MockSocketData;
147
148 MockLogDnsTraffic::MockLogDnsTraffic() : socket_read_mode_(net::ASYNC) {
149 // Use an invalid nameserver address. This prevents the tests accidentally
150 // sending real DNS queries. The mock sockets don't care that the address
151 // is invalid.
152 dns_config_.nameservers.push_back(net::IPEndPoint());
153 // Don't attempt retransmissions - just fail.
154 dns_config_.attempts = 1;
155 // This ensures timeouts are long enough for memory tests.
156 dns_config_.timeout = TestTimeouts::action_timeout();
157 // Simplify testing - don't require random numbers for the source port.
158 // This means our FakeRandInt function should only be called to get query
159 // IDs.
160 dns_config_.randomize_ports = false;
161 }
162
163 MockLogDnsTraffic::~MockLogDnsTraffic() {}
164
165 void MockLogDnsTraffic::ExpectRequestAndErrorResponse(base::StringPiece qname,
166 uint8_t rcode) {
167 std::vector<char> request = CreateDnsTxtRequest(qname);
168 std::vector<char> response = CreateDnsErrorResponse(request, rcode);
169
170 mock_socket_data_.emplace_back(new MockSocketData(request, response));
Eran Messeri 2016/07/21 14:47:02 inline request and response, since they're not use
Rob Percival 2016/07/21 17:32:21 Creating |response| requires |request|, so they ca
Eran Messeri 2016/07/22 15:55:48 So at the very least you could inline creating the
171 mock_socket_data_.back()->SetReadMode(socket_read_mode_);
172 mock_socket_data_.back()->AddToFactory(&socket_factory_);
173 }
174
175 void MockLogDnsTraffic::ExpectRequestAndSocketError(base::StringPiece qname,
176 int net_error) {
177 std::vector<char> request = CreateDnsTxtRequest(qname);
178
179 mock_socket_data_.emplace_back(new MockSocketData(request, net_error));
Eran Messeri 2016/07/21 14:47:02 Seems like you could have a helper method/function
Rob Percival 2016/07/21 17:32:21 Done.
180 mock_socket_data_.back()->SetReadMode(socket_read_mode_);
181 mock_socket_data_.back()->AddToFactory(&socket_factory_);
182 }
183
184 void MockLogDnsTraffic::ExpectRequestAndTimeout(base::StringPiece qname) {
185 std::vector<char> request = CreateDnsTxtRequest(qname);
186
187 mock_socket_data_.emplace_back(new MockSocketData(request));
188 mock_socket_data_.back()->SetReadMode(socket_read_mode_);
189 mock_socket_data_.back()->AddToFactory(&socket_factory_);
190
191 // Speed up timeout tests.
192 dns_config_.timeout = TestTimeouts::tiny_timeout();
193 }
194
195 void MockLogDnsTraffic::ExpectLeafIndexRequestAndResponse(
196 base::StringPiece qname,
197 base::StringPiece leaf_index) {
198 // Prepend size to leaf_index to create the query answer (rdata)
199 ASSERT_LE(leaf_index.size(), 0xFFul); // size must fit into a single byte
200 std::string answer = leaf_index.as_string();
201 answer.insert(answer.begin(), static_cast<char>(leaf_index.size()));
202
203 ExpectRequestAndResponse(qname, answer);
204 }
205
206 void MockLogDnsTraffic::ExpectAuditProofRequestAndResponse(
207 base::StringPiece qname,
208 std::vector<std::string>::const_iterator audit_path_start,
209 std::vector<std::string>::const_iterator audit_path_end) {
210 // Join nodes in the audit path into a single string.
211 std::string proof =
212 std::accumulate(audit_path_start, audit_path_end, std::string());
213
214 // Prepend size to proof to create the query answer (rdata)
215 ASSERT_LE(proof.size(), 0xFFul); // size must fit into a single byte
216 proof.insert(proof.begin(), static_cast<char>(proof.size()));
217
218 ExpectRequestAndResponse(qname, proof);
219 }
220
221 std::unique_ptr<net::DnsClient> MockLogDnsTraffic::CreateDnsClient() {
222 std::unique_ptr<net::DnsClient> client =
223 net::DnsClient::CreateClientForTesting(nullptr, &socket_factory_,
224 base::Bind(&FakeRandInt));
225 client->SetConfig(dns_config_);
226 return client;
227 }
228
229 void MockLogDnsTraffic::ExpectRequestAndResponse(base::StringPiece qname,
230 base::StringPiece answer) {
231 std::vector<char> request = CreateDnsTxtRequest(qname);
232 std::vector<char> response = CreateDnsTxtResponse(request, answer);
233
234 mock_socket_data_.emplace_back(new MockSocketData(request, response));
235 mock_socket_data_.back()->SetReadMode(socket_read_mode_);
236 mock_socket_data_.back()->AddToFactory(&socket_factory_);
237 }
238
239 } // namespace certificate_transparency
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698