blob: 624912d67cbcb92555dda58e33af0cd8a227a961 [file] [log] [blame]
[email protected]245b164e2013-06-13 22:31:421// Copyright 2013 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 "net/dns/mdns_client_impl.h"
6
kmarshall3e740be2015-03-02 21:30:447#include <algorithm>
Peter Boström8a7540692021-04-05 20:48:208#include <memory>
dchengc7eeda422015-12-26 03:56:489#include <utility>
vitalybuka20859742014-09-22 23:42:3010
[email protected]245b164e2013-06-13 22:31:4211#include "base/bind.h"
skyostil4891b25b2015-06-11 11:43:4512#include "base/location.h"
David Sandersde5fee542022-03-23 02:47:4413#include "base/observer_list.h"
Piotr Pawliczek3318cc92020-07-25 05:10:1314#include "base/strings/string_util.h"
Patrick Monette643cdf62021-10-15 19:13:4215#include "base/task/single_thread_task_runner.h"
gabf767595f2016-05-11 18:50:3516#include "base/threading/thread_task_runner_handle.h"
kmarshall3e740be2015-03-02 21:30:4417#include "base/time/clock.h"
[email protected]245b164e2013-06-13 22:31:4218#include "base/time/default_clock.h"
prashhird22b4a82014-09-17 17:27:2719#include "base/time/time.h"
kmarshall3e740be2015-03-02 21:30:4420#include "base/timer/timer.h"
[email protected]245b164e2013-06-13 22:31:4221#include "net/base/net_errors.h"
[email protected]245b164e2013-06-13 22:31:4222#include "net/base/rand_callback.h"
tfarina77021d62015-10-11 20:19:0323#include "net/dns/dns_util.h"
Eric Orth8afaf152018-11-07 21:01:2624#include "net/dns/public/dns_protocol.h"
Eric Orth1556c382018-11-08 06:05:0225#include "net/dns/public/util.h"
[email protected]21df16962013-07-01 17:39:5326#include "net/dns/record_rdata.h"
tfarina5dd13c22016-11-16 12:08:2627#include "net/socket/datagram_socket.h"
[email protected]245b164e2013-06-13 22:31:4228
[email protected]21df16962013-07-01 17:39:5329// TODO(gene): Remove this temporary method of disabling NSEC support once it
30// becomes clear whether this feature should be
31// supported. http://crbug.com/255232
32#define ENABLE_NSEC
33
[email protected]245b164e2013-06-13 22:31:4234namespace net {
35
36namespace {
[email protected]95b331b42013-12-02 06:26:3137
[email protected]bdd6c3d2014-01-30 08:07:4238// The fractions of the record's original TTL after which an active listener
39// (one that had |SetActiveRefresh(true)| called) will send a query to refresh
40// its cache. This happens both at 85% of the original TTL and again at 95% of
41// the original TTL.
42const double kListenerRefreshRatio1 = 0.85;
43const double kListenerRefreshRatio2 = 0.95;
[email protected]95b331b42013-12-02 06:26:3144
[email protected]95b331b42013-12-02 06:26:3145} // namespace
46
Qingsi Wang5410ef0b2019-03-05 20:26:4747void MDnsSocketFactoryImpl::CreateSockets(
48 std::vector<std::unique_ptr<DatagramServerSocket>>* sockets) {
[email protected]90d32142013-12-10 10:53:0649 InterfaceIndexFamilyList interfaces(GetMDnsInterfacesToBind());
50 for (size_t i = 0; i < interfaces.size(); ++i) {
ttuttle859dc7a2015-04-23 19:42:2951 DCHECK(interfaces[i].second == ADDRESS_FAMILY_IPV4 ||
52 interfaces[i].second == ADDRESS_FAMILY_IPV6);
Qingsi Wang5410ef0b2019-03-05 20:26:4753 std::unique_ptr<DatagramServerSocket> socket(CreateAndBindMDnsSocket(
Eric Orth9871aafa2018-10-02 19:59:1854 interfaces[i].second, interfaces[i].first, net_log_));
Qingsi Wang5410ef0b2019-03-05 20:26:4755 if (socket)
56 sockets->push_back(std::move(socket));
[email protected]90d32142013-12-10 10:53:0657 }
[email protected]95b331b42013-12-02 06:26:3158}
59
Qingsi Wang5410ef0b2019-03-05 20:26:4760MDnsConnection::SocketHandler::SocketHandler(
61 std::unique_ptr<DatagramServerSocket> socket,
62 MDnsConnection* connection)
63 : socket_(std::move(socket)),
[email protected]95b331b42013-12-02 06:26:3164 connection_(connection),
vitalybuka20859742014-09-22 23:42:3065 response_(dns_protocol::kMaxMulticastSize),
Qingsi Wang5410ef0b2019-03-05 20:26:4766 send_in_progress_(false) {}
[email protected]245b164e2013-06-13 22:31:4267
Chris Watkins68b15032017-12-01 03:07:1368MDnsConnection::SocketHandler::~SocketHandler() = default;
[email protected]245b164e2013-06-13 22:31:4269
70int MDnsConnection::SocketHandler::Start() {
[email protected]95b331b42013-12-02 06:26:3171 IPEndPoint end_point;
Qingsi Wang5410ef0b2019-03-05 20:26:4772 int rv = socket_->GetLocalAddress(&end_point);
[email protected]95b331b42013-12-02 06:26:3173 if (rv != OK)
74 return rv;
Qingsi Wang5410ef0b2019-03-05 20:26:4775 DCHECK(end_point.GetFamily() == ADDRESS_FAMILY_IPV4 ||
76 end_point.GetFamily() == ADDRESS_FAMILY_IPV6);
77 multicast_addr_ = dns_util::GetMdnsGroupEndPoint(end_point.GetFamily());
[email protected]245b164e2013-06-13 22:31:4278 return DoLoop(0);
79}
80
81int MDnsConnection::SocketHandler::DoLoop(int rv) {
82 do {
83 if (rv > 0)
[email protected]95b331b42013-12-02 06:26:3184 connection_->OnDatagramReceived(&response_, recv_addr_, rv);
[email protected]245b164e2013-06-13 22:31:4285
Qingsi Wang5410ef0b2019-03-05 20:26:4786 rv = socket_->RecvFrom(
Brad Lassey786929ad2018-02-21 20:54:2787 response_.io_buffer(), response_.io_buffer_size(), &recv_addr_,
Yannic Bonenberger922f6012019-09-07 16:20:1288 base::BindOnce(&MDnsConnection::SocketHandler::OnDatagramReceived,
89 base::Unretained(this)));
[email protected]245b164e2013-06-13 22:31:4290 } while (rv > 0);
91
92 if (rv != ERR_IO_PENDING)
93 return rv;
94
95 return OK;
96}
97
98void MDnsConnection::SocketHandler::OnDatagramReceived(int rv) {
99 if (rv >= OK)
100 rv = DoLoop(rv);
101
102 if (rv != OK)
vitalybuka20859742014-09-22 23:42:30103 connection_->PostOnError(this, rv);
[email protected]245b164e2013-06-13 22:31:42104}
105
vitalybuka20859742014-09-22 23:42:30106void MDnsConnection::SocketHandler::Send(const scoped_refptr<IOBuffer>& buffer,
107 unsigned size) {
108 if (send_in_progress_) {
109 send_queue_.push(std::make_pair(buffer, size));
110 return;
111 }
Yannic Bonenberger922f6012019-09-07 16:20:12112 int rv =
113 socket_->SendTo(buffer.get(), size, multicast_addr_,
114 base::BindOnce(&MDnsConnection::SocketHandler::SendDone,
115 base::Unretained(this)));
vitalybuka20859742014-09-22 23:42:30116 if (rv == ERR_IO_PENDING) {
117 send_in_progress_ = true;
118 } else if (rv < OK) {
119 connection_->PostOnError(this, rv);
120 }
[email protected]245b164e2013-06-13 22:31:42121}
122
123void MDnsConnection::SocketHandler::SendDone(int rv) {
vitalybuka20859742014-09-22 23:42:30124 DCHECK(send_in_progress_);
125 send_in_progress_ = false;
126 if (rv != OK)
127 connection_->PostOnError(this, rv);
128 while (!send_in_progress_ && !send_queue_.empty()) {
129 std::pair<scoped_refptr<IOBuffer>, unsigned> buffer = send_queue_.front();
130 send_queue_.pop();
131 Send(buffer.first, buffer.second);
132 }
[email protected]245b164e2013-06-13 22:31:42133}
134
vitalybuka20859742014-09-22 23:42:30135MDnsConnection::MDnsConnection(MDnsConnection::Delegate* delegate)
Jeremy Romand54000b22019-07-08 18:40:16136 : delegate_(delegate) {}
[email protected]245b164e2013-06-13 22:31:42137
Chris Watkins68b15032017-12-01 03:07:13138MDnsConnection::~MDnsConnection() = default;
[email protected]245b164e2013-06-13 22:31:42139
Eric Orthe857ebb2019-03-13 23:02:07140int MDnsConnection::Init(MDnsSocketFactory* socket_factory) {
Qingsi Wang5410ef0b2019-03-05 20:26:47141 std::vector<std::unique_ptr<DatagramServerSocket>> sockets;
142 socket_factory->CreateSockets(&sockets);
[email protected]e4411fbe2013-09-26 21:10:11143
Qingsi Wang5410ef0b2019-03-05 20:26:47144 for (std::unique_ptr<DatagramServerSocket>& socket : sockets) {
Bence Béky8f9d7d3952017-10-09 19:58:04145 socket_handlers_.push_back(std::make_unique<MDnsConnection::SocketHandler>(
Qingsi Wang5410ef0b2019-03-05 20:26:47146 std::move(socket), this));
[email protected]e4411fbe2013-09-26 21:10:11147 }
148
[email protected]03dd94252013-09-01 23:25:31149 // All unbound sockets need to be bound before processing untrusted input.
150 // This is done for security reasons, so that an attacker can't get an unbound
151 // socket.
Eric Orthe857ebb2019-03-13 23:02:07152 int last_failure = ERR_FAILED;
[email protected]e4411fbe2013-09-26 21:10:11153 for (size_t i = 0; i < socket_handlers_.size();) {
[email protected]9ac0c57a2013-10-02 23:00:54154 int rv = socket_handlers_[i]->Start();
155 if (rv != OK) {
Eric Orthe857ebb2019-03-13 23:02:07156 last_failure = rv;
[email protected]e4411fbe2013-09-26 21:10:11157 socket_handlers_.erase(socket_handlers_.begin() + i);
[email protected]9ac0c57a2013-10-02 23:00:54158 VLOG(1) << "Start failed, socket=" << i << ", error=" << rv;
[email protected]e4411fbe2013-09-26 21:10:11159 } else {
160 ++i;
161 }
162 }
[email protected]9ac0c57a2013-10-02 23:00:54163 VLOG(1) << "Sockets ready:" << socket_handlers_.size();
Eric Orthe857ebb2019-03-13 23:02:07164 DCHECK_NE(ERR_IO_PENDING, last_failure);
165 return socket_handlers_.empty() ? last_failure : OK;
[email protected]245b164e2013-06-13 22:31:42166}
167
vitalybuka20859742014-09-22 23:42:30168void MDnsConnection::Send(const scoped_refptr<IOBuffer>& buffer,
169 unsigned size) {
danakj22f90e72016-04-16 01:55:40170 for (std::unique_ptr<SocketHandler>& handler : socket_handlers_)
olli.raulad8734f2c72015-12-03 12:36:34171 handler->Send(buffer, size);
[email protected]245b164e2013-06-13 22:31:42172}
173
vitalybuka20859742014-09-22 23:42:30174void MDnsConnection::PostOnError(SocketHandler* loop, int rv) {
olli.raulad8734f2c72015-12-03 12:36:34175 int id = 0;
176 for (const auto& it : socket_handlers_) {
177 if (it.get() == loop)
178 break;
179 id++;
180 }
181 VLOG(1) << "Socket error. id=" << id << ", error=" << rv;
vitalybuka20859742014-09-22 23:42:30182 // Post to allow deletion of this object by delegate.
skyostil4891b25b2015-06-11 11:43:45183 base::ThreadTaskRunnerHandle::Get()->PostTask(
kylecharf4fe5172019-02-15 18:53:49184 FROM_HERE, base::BindOnce(&MDnsConnection::OnError,
185 weak_ptr_factory_.GetWeakPtr(), rv));
vitalybuka20859742014-09-22 23:42:30186}
187
188void MDnsConnection::OnError(int rv) {
[email protected]245b164e2013-06-13 22:31:42189 // TODO(noamsml): Specific handling of intermittent errors that can be handled
190 // in the connection.
vitalybuka20859742014-09-22 23:42:30191 delegate_->OnConnectionError(rv);
[email protected]245b164e2013-06-13 22:31:42192}
193
[email protected]245b164e2013-06-13 22:31:42194void MDnsConnection::OnDatagramReceived(
195 DnsResponse* response,
196 const IPEndPoint& recv_addr,
197 int bytes_read) {
198 // TODO(noamsml): More sophisticated error handling.
199 DCHECK_GT(bytes_read, 0);
200 delegate_->HandlePacket(response, bytes_read);
201}
202
tzik08d8d6e2018-07-09 04:11:47203MDnsClientImpl::Core::Core(base::Clock* clock, base::OneShotTimer* timer)
kmarshall3e740be2015-03-02 21:30:44204 : clock_(clock),
205 cleanup_timer_(timer),
Eric Orth6cb27ea2019-05-03 16:31:04206 connection_(new MDnsConnection(this)) {
207 DCHECK(cleanup_timer_);
208 DCHECK(!cleanup_timer_->IsRunning());
209}
[email protected]245b164e2013-06-13 22:31:42210
Eric Orth6cb27ea2019-05-03 16:31:04211MDnsClientImpl::Core::~Core() {
212 cleanup_timer_->Stop();
213}
[email protected]245b164e2013-06-13 22:31:42214
Eric Orthe857ebb2019-03-13 23:02:07215int MDnsClientImpl::Core::Init(MDnsSocketFactory* socket_factory) {
Eric Orth6cb27ea2019-05-03 16:31:04216 CHECK(!cleanup_timer_->IsRunning());
[email protected]e4411fbe2013-09-26 21:10:11217 return connection_->Init(socket_factory);
[email protected]245b164e2013-06-13 22:31:42218}
219
Avi Drissman13fc8932015-12-20 04:40:46220bool MDnsClientImpl::Core::SendQuery(uint16_t rrtype, const std::string& name) {
[email protected]245b164e2013-06-13 22:31:42221 std::string name_dns;
Bailey Berroe70f06c2019-03-11 22:22:46222 if (!DNSDomainFromUnrestrictedDot(name, &name_dns))
[email protected]245b164e2013-06-13 22:31:42223 return false;
224
225 DnsQuery query(0, name_dns, rrtype);
226 query.set_flags(0); // Remove the RD flag from the query. It is unneeded.
227
vitalybuka20859742014-09-22 23:42:30228 connection_->Send(query.io_buffer(), query.io_buffer()->size());
229 return true;
[email protected]245b164e2013-06-13 22:31:42230}
231
232void MDnsClientImpl::Core::HandlePacket(DnsResponse* response,
233 int bytes_read) {
234 unsigned offset;
[email protected]5e6f42732013-06-19 03:43:31235 // Note: We store cache keys rather than record pointers to avoid
236 // erroneous behavior in case a packet contains multiple exclusive
237 // records with the same type and name.
[email protected]bdd6c3d2014-01-30 08:07:42238 std::map<MDnsCache::Key, MDnsCache::UpdateType> update_keys;
Brad Lassey786929ad2018-02-21 20:54:27239 DCHECK_GT(bytes_read, 0);
[email protected]245b164e2013-06-13 22:31:42240 if (!response->InitParseWithoutQuery(bytes_read)) {
[email protected]423a4d42014-03-05 21:55:06241 DVLOG(1) << "Could not understand an mDNS packet.";
[email protected]245b164e2013-06-13 22:31:42242 return; // Message is unreadable.
243 }
244
245 // TODO(noamsml): duplicate query suppression.
246 if (!(response->flags() & dns_protocol::kFlagResponse))
247 return; // Message is a query. ignore it.
248
249 DnsRecordParser parser = response->Parser();
250 unsigned answer_count = response->answer_count() +
251 response->additional_answer_count();
252
253 for (unsigned i = 0; i < answer_count; i++) {
254 offset = parser.GetOffset();
danakj22f90e72016-04-16 01:55:40255 std::unique_ptr<const RecordParsed> record =
kmarshall3e740be2015-03-02 21:30:44256 RecordParsed::CreateFrom(&parser, clock_->Now());
[email protected]245b164e2013-06-13 22:31:42257
[email protected]5e6f42732013-06-19 03:43:31258 if (!record) {
[email protected]423a4d42014-03-05 21:55:06259 DVLOG(1) << "Could not understand an mDNS record.";
[email protected]245b164e2013-06-13 22:31:42260
261 if (offset == parser.GetOffset()) {
[email protected]423a4d42014-03-05 21:55:06262 DVLOG(1) << "Abandoned parsing the rest of the packet.";
[email protected]245b164e2013-06-13 22:31:42263 return; // The parser did not advance, abort reading the packet.
264 } else {
265 continue; // We may be able to extract other records from the packet.
266 }
267 }
268
[email protected]5e6f42732013-06-19 03:43:31269 if ((record->klass() & dns_protocol::kMDnsClassMask) !=
[email protected]245b164e2013-06-13 22:31:42270 dns_protocol::kClassIN) {
[email protected]423a4d42014-03-05 21:55:06271 DVLOG(1) << "Received an mDNS record with non-IN class. Ignoring.";
[email protected]245b164e2013-06-13 22:31:42272 continue; // Ignore all records not in the IN class.
273 }
274
[email protected]5e6f42732013-06-19 03:43:31275 MDnsCache::Key update_key = MDnsCache::Key::CreateFor(record.get());
dchengc7eeda422015-12-26 03:56:48276 MDnsCache::UpdateType update = cache_.UpdateDnsRecord(std::move(record));
[email protected]245b164e2013-06-13 22:31:42277
278 // Cleanup time may have changed.
279 ScheduleCleanup(cache_.next_expiration());
280
[email protected]bdd6c3d2014-01-30 08:07:42281 update_keys.insert(std::make_pair(update_key, update));
[email protected]5e6f42732013-06-19 03:43:31282 }
283
jdoerrie22a91d8b92018-10-05 08:43:26284 for (auto i = update_keys.begin(); i != update_keys.end(); i++) {
[email protected]5e6f42732013-06-19 03:43:31285 const RecordParsed* record = cache_.LookupKey(i->first);
[email protected]21df16962013-07-01 17:39:53286 if (!record)
287 continue;
288
289 if (record->type() == dns_protocol::kTypeNSEC) {
290#if defined(ENABLE_NSEC)
291 NotifyNsecRecord(record);
292#endif
293 } else {
294 AlertListeners(i->second, ListenerKey(record->name(), record->type()),
[email protected]5e6f42732013-06-19 03:43:31295 record);
[email protected]21df16962013-07-01 17:39:53296 }
297 }
298}
299
300void MDnsClientImpl::Core::NotifyNsecRecord(const RecordParsed* record) {
301 DCHECK_EQ(dns_protocol::kTypeNSEC, record->type());
302 const NsecRecordRdata* rdata = record->rdata<NsecRecordRdata>();
303 DCHECK(rdata);
304
305 // Remove all cached records matching the nonexistent RR types.
306 std::vector<const RecordParsed*> records_to_remove;
307
kmarshall3e740be2015-03-02 21:30:44308 cache_.FindDnsRecords(0, record->name(), &records_to_remove, clock_->Now());
[email protected]21df16962013-07-01 17:39:53309
jdoerrie22a91d8b92018-10-05 08:43:26310 for (auto i = records_to_remove.begin(); i != records_to_remove.end(); i++) {
[email protected]21df16962013-07-01 17:39:53311 if ((*i)->type() == dns_protocol::kTypeNSEC)
312 continue;
313 if (!rdata->GetBit((*i)->type())) {
danakj22f90e72016-04-16 01:55:40314 std::unique_ptr<const RecordParsed> record_removed =
315 cache_.RemoveRecord((*i));
[email protected]21df16962013-07-01 17:39:53316 DCHECK(record_removed);
317 OnRecordRemoved(record_removed.get());
318 }
319 }
320
321 // Alert all listeners waiting for the nonexistent RR types.
Piotr Pawliczek3318cc92020-07-25 05:10:13322 ListenerKey key(record->name(), 0);
323 auto i = listeners_.upper_bound(key);
324 for (; i != listeners_.end() &&
325 i->first.name_lowercase() == key.name_lowercase();
326 i++) {
327 if (!rdata->GetBit(i->first.type())) {
ericwilligers9d64a5f2016-10-18 00:28:49328 for (auto& observer : *i->second)
329 observer.AlertNsecRecord();
[email protected]245b164e2013-06-13 22:31:42330 }
331 }
332}
333
334void MDnsClientImpl::Core::OnConnectionError(int error) {
335 // TODO(noamsml): On connection error, recreate connection and flush cache.
kmarshall73a89b12015-09-01 22:18:13336 VLOG(1) << "MDNS OnConnectionError (code: " << error << ")";
[email protected]245b164e2013-06-13 22:31:42337}
338
Piotr Pawliczek3318cc92020-07-25 05:10:13339MDnsClientImpl::Core::ListenerKey::ListenerKey(const std::string& name,
340 uint16_t type)
341 : name_lowercase_(base::ToLowerASCII(name)), type_(type) {}
342
343bool MDnsClientImpl::Core::ListenerKey::operator<(
344 const MDnsClientImpl::Core::ListenerKey& key) const {
345 if (name_lowercase_ == key.name_lowercase_)
346 return type_ < key.type_;
347 return name_lowercase_ < key.name_lowercase_;
348}
349
[email protected]245b164e2013-06-13 22:31:42350void MDnsClientImpl::Core::AlertListeners(
[email protected]bdd6c3d2014-01-30 08:07:42351 MDnsCache::UpdateType update_type,
[email protected]245b164e2013-06-13 22:31:42352 const ListenerKey& key,
353 const RecordParsed* record) {
jdoerrie22a91d8b92018-10-05 08:43:26354 auto listener_map_iterator = listeners_.find(key);
[email protected]245b164e2013-06-13 22:31:42355 if (listener_map_iterator == listeners_.end()) return;
356
ericwilligers9d64a5f2016-10-18 00:28:49357 for (auto& observer : *listener_map_iterator->second)
358 observer.HandleRecordUpdate(update_type, record);
[email protected]245b164e2013-06-13 22:31:42359}
360
361void MDnsClientImpl::Core::AddListener(
362 MDnsListenerImpl* listener) {
[email protected]21df16962013-07-01 17:39:53363 ListenerKey key(listener->GetName(), listener->GetType());
[email protected]245b164e2013-06-13 22:31:42364
Trent Apteda250ec3ab2018-08-19 08:52:19365 auto& observer_list = listeners_[key];
avi9e72eb482016-12-09 21:10:54366 if (!observer_list)
Trent Apteda250ec3ab2018-08-19 08:52:19367 observer_list = std::make_unique<ObserverListType>();
[email protected]245b164e2013-06-13 22:31:42368
369 observer_list->AddObserver(listener);
370}
371
372void MDnsClientImpl::Core::RemoveListener(MDnsListenerImpl* listener) {
[email protected]21df16962013-07-01 17:39:53373 ListenerKey key(listener->GetName(), listener->GetType());
jdoerrie22a91d8b92018-10-05 08:43:26374 auto observer_list_iterator = listeners_.find(key);
[email protected]245b164e2013-06-13 22:31:42375
376 DCHECK(observer_list_iterator != listeners_.end());
377 DCHECK(observer_list_iterator->second->HasObserver(listener));
378
379 observer_list_iterator->second->RemoveObserver(listener);
380
381 // Remove the observer list from the map if it is empty
Mitsuru Oshima8bc2746e82021-01-15 07:01:13382 if (observer_list_iterator->second->empty()) {
[email protected]21df16962013-07-01 17:39:53383 // Schedule the actual removal for later in case the listener removal
384 // happens while iterating over the observer list.
skyostil4891b25b2015-06-11 11:43:45385 base::ThreadTaskRunnerHandle::Get()->PostTask(
kylecharf4fe5172019-02-15 18:53:49386 FROM_HERE, base::BindOnce(&MDnsClientImpl::Core::CleanupObserverList,
387 AsWeakPtr(), key));
[email protected]21df16962013-07-01 17:39:53388 }
389}
390
391void MDnsClientImpl::Core::CleanupObserverList(const ListenerKey& key) {
jdoerrie22a91d8b92018-10-05 08:43:26392 auto found = listeners_.find(key);
Mitsuru Oshima8bc2746e82021-01-15 07:01:13393 if (found != listeners_.end() && found->second->empty()) {
[email protected]21df16962013-07-01 17:39:53394 listeners_.erase(found);
[email protected]245b164e2013-06-13 22:31:42395 }
396}
397
398void MDnsClientImpl::Core::ScheduleCleanup(base::Time cleanup) {
Eric Orthacdd8ae2019-03-29 22:07:19399 // If cache is overfilled. Force an immediate cleanup.
400 if (cache_.IsCacheOverfilled())
401 cleanup = clock_->Now();
402
[email protected]245b164e2013-06-13 22:31:42403 // Cleanup is already scheduled, no need to do anything.
kmarshall3e740be2015-03-02 21:30:44404 if (cleanup == scheduled_cleanup_) {
405 return;
406 }
[email protected]245b164e2013-06-13 22:31:42407 scheduled_cleanup_ = cleanup;
408
409 // This cancels the previously scheduled cleanup.
kmarshall3e740be2015-03-02 21:30:44410 cleanup_timer_->Stop();
[email protected]245b164e2013-06-13 22:31:42411
412 // If |cleanup| is empty, then no cleanup necessary.
413 if (cleanup != base::Time()) {
Yannic Bonenberger922f6012019-09-07 16:20:12414 cleanup_timer_->Start(FROM_HERE,
415 std::max(base::TimeDelta(), cleanup - clock_->Now()),
416 base::BindOnce(&MDnsClientImpl::Core::DoCleanup,
417 base::Unretained(this)));
[email protected]245b164e2013-06-13 22:31:42418 }
419}
420
421void MDnsClientImpl::Core::DoCleanup() {
Anna Malova9b2095b2020-03-04 15:41:18422 cache_.CleanupRecords(
423 clock_->Now(), base::BindRepeating(&MDnsClientImpl::Core::OnRecordRemoved,
424 base::Unretained(this)));
[email protected]245b164e2013-06-13 22:31:42425
426 ScheduleCleanup(cache_.next_expiration());
427}
428
429void MDnsClientImpl::Core::OnRecordRemoved(
430 const RecordParsed* record) {
[email protected]bdd6c3d2014-01-30 08:07:42431 AlertListeners(MDnsCache::RecordRemoved,
[email protected]21df16962013-07-01 17:39:53432 ListenerKey(record->name(), record->type()), record);
[email protected]245b164e2013-06-13 22:31:42433}
434
435void MDnsClientImpl::Core::QueryCache(
Avi Drissman13fc8932015-12-20 04:40:46436 uint16_t rrtype,
437 const std::string& name,
[email protected]245b164e2013-06-13 22:31:42438 std::vector<const RecordParsed*>* records) const {
kmarshall3e740be2015-03-02 21:30:44439 cache_.FindDnsRecords(rrtype, name, records, clock_->Now());
[email protected]245b164e2013-06-13 22:31:42440}
441
kmarshall3e740be2015-03-02 21:30:44442MDnsClientImpl::MDnsClientImpl()
tzik26331742017-12-07 07:28:33443 : clock_(base::DefaultClock::GetInstance()),
tzik08d8d6e2018-07-09 04:11:47444 cleanup_timer_(new base::OneShotTimer()) {}
kmarshall3e740be2015-03-02 21:30:44445
tzik26331742017-12-07 07:28:33446MDnsClientImpl::MDnsClientImpl(base::Clock* clock,
tzik08d8d6e2018-07-09 04:11:47447 std::unique_ptr<base::OneShotTimer> timer)
tzik26331742017-12-07 07:28:33448 : clock_(clock), cleanup_timer_(std::move(timer)) {}
[email protected]245b164e2013-06-13 22:31:42449
Eric Orth6cb27ea2019-05-03 16:31:04450MDnsClientImpl::~MDnsClientImpl() {
451 StopListening();
452}
[email protected]245b164e2013-06-13 22:31:42453
Eric Orthe857ebb2019-03-13 23:02:07454int MDnsClientImpl::StartListening(MDnsSocketFactory* socket_factory) {
[email protected]9c61d252013-07-02 23:26:22455 DCHECK(!core_.get());
Peter Boström8a7540692021-04-05 20:48:20456 core_ = std::make_unique<Core>(clock_, cleanup_timer_.get());
Eric Orthe857ebb2019-03-13 23:02:07457 int rv = core_->Init(socket_factory);
458 if (rv != OK) {
459 DCHECK_NE(ERR_IO_PENDING, rv);
[email protected]9c61d252013-07-02 23:26:22460 core_.reset();
[email protected]245b164e2013-06-13 22:31:42461 }
Eric Orthe857ebb2019-03-13 23:02:07462 return rv;
[email protected]245b164e2013-06-13 22:31:42463}
464
[email protected]9c61d252013-07-02 23:26:22465void MDnsClientImpl::StopListening() {
466 core_.reset();
[email protected]245b164e2013-06-13 22:31:42467}
468
[email protected]9c61d252013-07-02 23:26:22469bool MDnsClientImpl::IsListening() const {
Raul Tambre94493c652019-03-11 17:18:35470 return core_.get() != nullptr;
[email protected]245b164e2013-06-13 22:31:42471}
472
danakj22f90e72016-04-16 01:55:40473std::unique_ptr<MDnsListener> MDnsClientImpl::CreateListener(
Avi Drissman13fc8932015-12-20 04:40:46474 uint16_t rrtype,
[email protected]245b164e2013-06-13 22:31:42475 const std::string& name,
476 MDnsListener::Delegate* delegate) {
danakj22f90e72016-04-16 01:55:40477 return std::unique_ptr<MDnsListener>(
tzik26331742017-12-07 07:28:33478 new MDnsListenerImpl(rrtype, name, clock_, delegate, this));
[email protected]245b164e2013-06-13 22:31:42479}
480
danakj22f90e72016-04-16 01:55:40481std::unique_ptr<MDnsTransaction> MDnsClientImpl::CreateTransaction(
Avi Drissman13fc8932015-12-20 04:40:46482 uint16_t rrtype,
[email protected]245b164e2013-06-13 22:31:42483 const std::string& name,
484 int flags,
485 const MDnsTransaction::ResultCallback& callback) {
danakj22f90e72016-04-16 01:55:40486 return std::unique_ptr<MDnsTransaction>(
[email protected]245b164e2013-06-13 22:31:42487 new MDnsTransactionImpl(rrtype, name, flags, callback, this));
488}
489
Avi Drissman13fc8932015-12-20 04:40:46490MDnsListenerImpl::MDnsListenerImpl(uint16_t rrtype,
kmarshall3e740be2015-03-02 21:30:44491 const std::string& name,
492 base::Clock* clock,
493 MDnsListener::Delegate* delegate,
494 MDnsClientImpl* client)
495 : rrtype_(rrtype),
496 name_(name),
497 clock_(clock),
498 client_(client),
499 delegate_(delegate),
500 started_(false),
Avi Drissman13fc8932015-12-20 04:40:46501 active_refresh_(false) {}
[email protected]bdd6c3d2014-01-30 08:07:42502
503MDnsListenerImpl::~MDnsListenerImpl() {
504 if (started_) {
505 DCHECK(client_->core());
506 client_->core()->RemoveListener(this);
507 }
[email protected]245b164e2013-06-13 22:31:42508}
509
510bool MDnsListenerImpl::Start() {
511 DCHECK(!started_);
512
[email protected]245b164e2013-06-13 22:31:42513 started_ = true;
514
515 DCHECK(client_->core());
516 client_->core()->AddListener(this);
517
518 return true;
519}
520
[email protected]bdd6c3d2014-01-30 08:07:42521void MDnsListenerImpl::SetActiveRefresh(bool active_refresh) {
522 active_refresh_ = active_refresh;
523
[email protected]245b164e2013-06-13 22:31:42524 if (started_) {
[email protected]bdd6c3d2014-01-30 08:07:42525 if (!active_refresh_) {
526 next_refresh_.Cancel();
527 } else if (last_update_ != base::Time()) {
528 ScheduleNextRefresh();
529 }
[email protected]245b164e2013-06-13 22:31:42530 }
531}
532
533const std::string& MDnsListenerImpl::GetName() const {
534 return name_;
535}
536
Avi Drissman13fc8932015-12-20 04:40:46537uint16_t MDnsListenerImpl::GetType() const {
[email protected]245b164e2013-06-13 22:31:42538 return rrtype_;
539}
540
[email protected]bdd6c3d2014-01-30 08:07:42541void MDnsListenerImpl::HandleRecordUpdate(MDnsCache::UpdateType update_type,
542 const RecordParsed* record) {
[email protected]245b164e2013-06-13 22:31:42543 DCHECK(started_);
[email protected]bdd6c3d2014-01-30 08:07:42544
545 if (update_type != MDnsCache::RecordRemoved) {
546 ttl_ = record->ttl();
547 last_update_ = record->time_created();
548
549 ScheduleNextRefresh();
550 }
551
552 if (update_type != MDnsCache::NoChange) {
553 MDnsListener::UpdateType update_external;
554
555 switch (update_type) {
556 case MDnsCache::RecordAdded:
557 update_external = MDnsListener::RECORD_ADDED;
558 break;
559 case MDnsCache::RecordChanged:
560 update_external = MDnsListener::RECORD_CHANGED;
561 break;
562 case MDnsCache::RecordRemoved:
563 update_external = MDnsListener::RECORD_REMOVED;
564 break;
565 case MDnsCache::NoChange:
566 default:
567 NOTREACHED();
568 // Dummy assignment to suppress compiler warning.
569 update_external = MDnsListener::RECORD_CHANGED;
570 break;
571 }
572
573 delegate_->OnRecordUpdate(update_external, record);
574 }
[email protected]245b164e2013-06-13 22:31:42575}
576
[email protected]21df16962013-07-01 17:39:53577void MDnsListenerImpl::AlertNsecRecord() {
578 DCHECK(started_);
579 delegate_->OnNsecRecord(name_, rrtype_);
580}
581
[email protected]bdd6c3d2014-01-30 08:07:42582void MDnsListenerImpl::ScheduleNextRefresh() {
583 DCHECK(last_update_ != base::Time());
584
585 if (!active_refresh_)
586 return;
587
588 // A zero TTL is a goodbye packet and should not be refreshed.
589 if (ttl_ == 0) {
590 next_refresh_.Cancel();
591 return;
592 }
593
Steve Kobesf5bea3e2020-07-08 20:15:43594 next_refresh_.Reset(
595 base::BindRepeating(&MDnsListenerImpl::DoRefresh, AsWeakPtr()));
[email protected]bdd6c3d2014-01-30 08:07:42596
597 // Schedule refreshes at both 85% and 95% of the original TTL. These will both
598 // be canceled and rescheduled if the record's TTL is updated due to a
599 // response being received.
Peter Kastinge5a38ed2021-10-02 03:06:35600 base::Time next_refresh1 =
601 last_update_ +
602 base::Milliseconds(static_cast<int>(base::Time::kMillisecondsPerSecond *
603 kListenerRefreshRatio1 * ttl_));
[email protected]bdd6c3d2014-01-30 08:07:42604
Peter Kastinge5a38ed2021-10-02 03:06:35605 base::Time next_refresh2 =
606 last_update_ +
607 base::Milliseconds(static_cast<int>(base::Time::kMillisecondsPerSecond *
608 kListenerRefreshRatio2 * ttl_));
[email protected]bdd6c3d2014-01-30 08:07:42609
skyostil4891b25b2015-06-11 11:43:45610 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
kmarshall3e740be2015-03-02 21:30:44611 FROM_HERE, next_refresh_.callback(), next_refresh1 - clock_->Now());
[email protected]bdd6c3d2014-01-30 08:07:42612
skyostil4891b25b2015-06-11 11:43:45613 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
kmarshall3e740be2015-03-02 21:30:44614 FROM_HERE, next_refresh_.callback(), next_refresh2 - clock_->Now());
[email protected]bdd6c3d2014-01-30 08:07:42615}
616
617void MDnsListenerImpl::DoRefresh() {
618 client_->core()->SendQuery(rrtype_, name_);
619}
620
[email protected]245b164e2013-06-13 22:31:42621MDnsTransactionImpl::MDnsTransactionImpl(
Avi Drissman13fc8932015-12-20 04:40:46622 uint16_t rrtype,
[email protected]245b164e2013-06-13 22:31:42623 const std::string& name,
624 int flags,
625 const MDnsTransaction::ResultCallback& callback,
626 MDnsClientImpl* client)
Avi Drissman13fc8932015-12-20 04:40:46627 : rrtype_(rrtype),
628 name_(name),
629 callback_(callback),
630 client_(client),
631 started_(false),
632 flags_(flags) {
[email protected]245b164e2013-06-13 22:31:42633 DCHECK((flags_ & MDnsTransaction::FLAG_MASK) == flags_);
634 DCHECK(flags_ & MDnsTransaction::QUERY_CACHE ||
635 flags_ & MDnsTransaction::QUERY_NETWORK);
636}
637
638MDnsTransactionImpl::~MDnsTransactionImpl() {
639 timeout_.Cancel();
640}
641
642bool MDnsTransactionImpl::Start() {
643 DCHECK(!started_);
644 started_ = true;
[email protected]f3c09992013-06-25 00:40:48645
[email protected]245b164e2013-06-13 22:31:42646 base::WeakPtr<MDnsTransactionImpl> weak_this = AsWeakPtr();
[email protected]245b164e2013-06-13 22:31:42647 if (flags_ & MDnsTransaction::QUERY_CACHE) {
[email protected]f3c09992013-06-25 00:40:48648 ServeRecordsFromCache();
649
650 if (!weak_this || !is_active()) return true;
[email protected]245b164e2013-06-13 22:31:42651 }
652
[email protected]f3c09992013-06-25 00:40:48653 if (flags_ & MDnsTransaction::QUERY_NETWORK) {
654 return QueryAndListen();
[email protected]245b164e2013-06-13 22:31:42655 }
656
[email protected]f3c09992013-06-25 00:40:48657 // If this is a cache only query, signal that the transaction is over
658 // immediately.
659 SignalTransactionOver();
[email protected]245b164e2013-06-13 22:31:42660 return true;
661}
662
663const std::string& MDnsTransactionImpl::GetName() const {
664 return name_;
665}
666
Avi Drissman13fc8932015-12-20 04:40:46667uint16_t MDnsTransactionImpl::GetType() const {
[email protected]245b164e2013-06-13 22:31:42668 return rrtype_;
669}
670
671void MDnsTransactionImpl::CacheRecordFound(const RecordParsed* record) {
672 DCHECK(started_);
673 OnRecordUpdate(MDnsListener::RECORD_ADDED, record);
674}
675
676void MDnsTransactionImpl::TriggerCallback(MDnsTransaction::Result result,
677 const RecordParsed* record) {
678 DCHECK(started_);
679 if (!is_active()) return;
680
681 // Ensure callback is run after touching all class state, so that
682 // the callback can delete the transaction.
683 MDnsTransaction::ResultCallback callback = callback_;
684
[email protected]21df16962013-07-01 17:39:53685 // Reset the transaction if it expects a single result, or if the result
686 // is a final one (everything except for a record).
687 if (flags_ & MDnsTransaction::SINGLE_RESULT ||
688 result != MDnsTransaction::RESULT_RECORD) {
[email protected]245b164e2013-06-13 22:31:42689 Reset();
[email protected]21df16962013-07-01 17:39:53690 }
[email protected]245b164e2013-06-13 22:31:42691
692 callback.Run(result, record);
693}
694
695void MDnsTransactionImpl::Reset() {
696 callback_.Reset();
697 listener_.reset();
698 timeout_.Cancel();
699}
700
701void MDnsTransactionImpl::OnRecordUpdate(MDnsListener::UpdateType update,
702 const RecordParsed* record) {
703 DCHECK(started_);
704 if (update == MDnsListener::RECORD_ADDED ||
705 update == MDnsListener::RECORD_CHANGED)
706 TriggerCallback(MDnsTransaction::RESULT_RECORD, record);
707}
708
709void MDnsTransactionImpl::SignalTransactionOver() {
710 DCHECK(started_);
[email protected]245b164e2013-06-13 22:31:42711 if (flags_ & MDnsTransaction::SINGLE_RESULT) {
Raul Tambre94493c652019-03-11 17:18:35712 TriggerCallback(MDnsTransaction::RESULT_NO_RESULTS, nullptr);
[email protected]245b164e2013-06-13 22:31:42713 } else {
Raul Tambre94493c652019-03-11 17:18:35714 TriggerCallback(MDnsTransaction::RESULT_DONE, nullptr);
[email protected]245b164e2013-06-13 22:31:42715 }
[email protected]245b164e2013-06-13 22:31:42716}
717
[email protected]f3c09992013-06-25 00:40:48718void MDnsTransactionImpl::ServeRecordsFromCache() {
719 std::vector<const RecordParsed*> records;
720 base::WeakPtr<MDnsTransactionImpl> weak_this = AsWeakPtr();
721
722 if (client_->core()) {
723 client_->core()->QueryCache(rrtype_, name_, &records);
jdoerrie22a91d8b92018-10-05 08:43:26724 for (auto i = records.begin(); i != records.end() && weak_this; ++i) {
[email protected]63b43f3e2013-08-07 19:21:12725 weak_this->TriggerCallback(MDnsTransaction::RESULT_RECORD, *i);
[email protected]f3c09992013-06-25 00:40:48726 }
[email protected]21df16962013-07-01 17:39:53727
728#if defined(ENABLE_NSEC)
729 if (records.empty()) {
730 DCHECK(weak_this);
731 client_->core()->QueryCache(dns_protocol::kTypeNSEC, name_, &records);
732 if (!records.empty()) {
733 const NsecRecordRdata* rdata =
734 records.front()->rdata<NsecRecordRdata>();
735 DCHECK(rdata);
736 if (!rdata->GetBit(rrtype_))
Raul Tambre94493c652019-03-11 17:18:35737 weak_this->TriggerCallback(MDnsTransaction::RESULT_NSEC, nullptr);
[email protected]21df16962013-07-01 17:39:53738 }
739 }
740#endif
[email protected]f3c09992013-06-25 00:40:48741 }
742}
743
744bool MDnsTransactionImpl::QueryAndListen() {
745 listener_ = client_->CreateListener(rrtype_, name_, this);
746 if (!listener_->Start())
747 return false;
748
749 DCHECK(client_->core());
750 if (!client_->core()->SendQuery(rrtype_, name_))
751 return false;
752
Steve Kobesf5bea3e2020-07-08 20:15:43753 timeout_.Reset(
754 base::BindOnce(&MDnsTransactionImpl::SignalTransactionOver, AsWeakPtr()));
skyostil4891b25b2015-06-11 11:43:45755 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
Eric Orth9871aafa2018-10-02 19:59:18756 FROM_HERE, timeout_.callback(), kTransactionTimeout);
[email protected]f3c09992013-06-25 00:40:48757
758 return true;
759}
760
[email protected]245b164e2013-06-13 22:31:42761void MDnsTransactionImpl::OnNsecRecord(const std::string& name, unsigned type) {
Raul Tambre94493c652019-03-11 17:18:35762 TriggerCallback(RESULT_NSEC, nullptr);
[email protected]245b164e2013-06-13 22:31:42763}
764
765void MDnsTransactionImpl::OnCachePurged() {
766 // TODO(noamsml): Cache purge situations not yet implemented
767}
768
769} // namespace net