OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "net/dns/mdns_client_impl.h" | 5 #include "net/dns/mdns_client_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/message_loop/message_loop_proxy.h" | 8 #include "base/message_loop/message_loop_proxy.h" |
9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "base/time/default_clock.h" | 10 #include "base/time/default_clock.h" |
11 #include "net/base/dns_util.h" | 11 #include "net/base/dns_util.h" |
12 #include "net/base/net_errors.h" | 12 #include "net/base/net_errors.h" |
13 #include "net/base/net_log.h" | 13 #include "net/base/net_log.h" |
14 #include "net/base/rand_callback.h" | 14 #include "net/base/rand_callback.h" |
15 #include "net/dns/dns_protocol.h" | 15 #include "net/dns/dns_protocol.h" |
16 #include "net/dns/record_rdata.h" | 16 #include "net/dns/record_rdata.h" |
17 #include "net/udp/datagram_socket.h" | 17 #include "net/udp/datagram_socket.h" |
18 | 18 |
19 // TODO(gene): Remove this temporary method of disabling NSEC support once it | 19 // TODO(gene): Remove this temporary method of disabling NSEC support once it |
20 // becomes clear whether this feature should be | 20 // becomes clear whether this feature should be |
21 // supported. http://crbug.com/255232 | 21 // supported. http://crbug.com/255232 |
22 #define ENABLE_NSEC | 22 #define ENABLE_NSEC |
23 | 23 |
24 namespace net { | 24 namespace net { |
25 | 25 |
26 namespace { | 26 namespace { |
| 27 |
27 const unsigned MDnsTransactionTimeoutSeconds = 3; | 28 const unsigned MDnsTransactionTimeoutSeconds = 3; |
| 29 |
| 30 int Bind(const IPEndPoint& multicast_addr, DatagramServerSocket* socket) { |
| 31 IPAddressNumber address_any(multicast_addr.address().size()); |
| 32 IPEndPoint bind_endpoint(address_any, multicast_addr.port()); |
| 33 |
| 34 socket->AllowAddressReuse(); |
| 35 int rv = socket->Listen(bind_endpoint); |
| 36 if (rv < OK) |
| 37 return rv; |
| 38 |
| 39 socket->SetMulticastLoopbackMode(false); |
| 40 return socket->JoinGroup(multicast_addr.address()); |
28 } | 41 } |
29 | 42 |
| 43 void CreateAndBindSocket(AddressFamily address_family, |
| 44 ScopedVector<DatagramServerSocket>* sockets) { |
| 45 scoped_ptr<DatagramServerSocket> socket( |
| 46 new UDPServerSocket(NULL, NetLog::Source())); |
| 47 |
| 48 IPEndPoint multicast_addr = GetMDnsIPEndPoint(address_family); |
| 49 int rv = Bind(multicast_addr, socket.get()); |
| 50 if (rv == OK) { |
| 51 sockets->push_back(socket.release()); |
| 52 } else { |
| 53 VLOG(1) << "Bind failed, endpoint=" << multicast_addr.ToStringWithoutPort() |
| 54 << ", error=" << rv; |
| 55 } |
| 56 } |
| 57 |
| 58 } // namespace |
| 59 |
| 60 void MDnsSocketFactoryImpl::CreateSockets( |
| 61 ScopedVector<DatagramServerSocket>* sockets) { |
| 62 CreateAndBindSocket(ADDRESS_FAMILY_IPV4, sockets); |
| 63 CreateAndBindSocket(ADDRESS_FAMILY_IPV6, sockets); |
| 64 } |
| 65 |
| 66 |
| 67 |
30 MDnsConnection::SocketHandler::SocketHandler( | 68 MDnsConnection::SocketHandler::SocketHandler( |
31 MDnsConnection* connection, const IPEndPoint& multicast_addr, | 69 scoped_ptr<DatagramServerSocket> socket, |
32 MDnsConnection::SocketFactory* socket_factory) | 70 MDnsConnection* connection) |
33 : socket_(socket_factory->CreateSocket()), connection_(connection), | 71 : socket_(socket.Pass()), |
34 response_(new DnsResponse(dns_protocol::kMaxMulticastSize)), | 72 connection_(connection), |
35 multicast_addr_(multicast_addr) { | 73 response_(dns_protocol::kMaxMulticastSize) { |
36 } | 74 } |
37 | 75 |
38 MDnsConnection::SocketHandler::~SocketHandler() { | 76 MDnsConnection::SocketHandler::~SocketHandler() { |
39 } | 77 } |
40 | 78 |
41 int MDnsConnection::SocketHandler::Start() { | 79 int MDnsConnection::SocketHandler::Start() { |
| 80 IPEndPoint end_point; |
| 81 int rv = socket_->GetLocalAddress(&end_point); |
| 82 if (rv != OK) |
| 83 return rv; |
| 84 DCHECK(end_point.GetFamily() == ADDRESS_FAMILY_IPV4 || |
| 85 end_point.GetFamily() == ADDRESS_FAMILY_IPV6); |
| 86 multicast_addr_ = GetMDnsIPEndPoint(end_point.GetFamily()); |
42 return DoLoop(0); | 87 return DoLoop(0); |
43 } | 88 } |
44 | 89 |
45 int MDnsConnection::SocketHandler::DoLoop(int rv) { | 90 int MDnsConnection::SocketHandler::DoLoop(int rv) { |
46 do { | 91 do { |
47 if (rv > 0) | 92 if (rv > 0) |
48 connection_->OnDatagramReceived(response_.get(), recv_addr_, rv); | 93 connection_->OnDatagramReceived(&response_, recv_addr_, rv); |
49 | 94 |
50 rv = socket_->RecvFrom( | 95 rv = socket_->RecvFrom( |
51 response_->io_buffer(), | 96 response_.io_buffer(), |
52 response_->io_buffer()->size(), | 97 response_.io_buffer()->size(), |
53 &recv_addr_, | 98 &recv_addr_, |
54 base::Bind(&MDnsConnection::SocketHandler::OnDatagramReceived, | 99 base::Bind(&MDnsConnection::SocketHandler::OnDatagramReceived, |
55 base::Unretained(this))); | 100 base::Unretained(this))); |
56 } while (rv > 0); | 101 } while (rv > 0); |
57 | 102 |
58 if (rv != ERR_IO_PENDING) | 103 if (rv != ERR_IO_PENDING) |
59 return rv; | 104 return rv; |
60 | 105 |
61 return OK; | 106 return OK; |
62 } | 107 } |
63 | 108 |
64 void MDnsConnection::SocketHandler::OnDatagramReceived(int rv) { | 109 void MDnsConnection::SocketHandler::OnDatagramReceived(int rv) { |
65 if (rv >= OK) | 110 if (rv >= OK) |
66 rv = DoLoop(rv); | 111 rv = DoLoop(rv); |
67 | 112 |
68 if (rv != OK) | 113 if (rv != OK) |
69 connection_->OnError(this, rv); | 114 connection_->OnError(this, rv); |
70 } | 115 } |
71 | 116 |
72 int MDnsConnection::SocketHandler::Send(IOBuffer* buffer, unsigned size) { | 117 int MDnsConnection::SocketHandler::Send(IOBuffer* buffer, unsigned size) { |
73 return socket_->SendTo( | 118 return socket_->SendTo(buffer, size, multicast_addr_, |
74 buffer, size, multicast_addr_, | 119 base::Bind(&MDnsConnection::SocketHandler::SendDone, |
75 base::Bind(&MDnsConnection::SocketHandler::SendDone, | 120 base::Unretained(this) )); |
76 base::Unretained(this) )); | |
77 } | 121 } |
78 | 122 |
79 void MDnsConnection::SocketHandler::SendDone(int rv) { | 123 void MDnsConnection::SocketHandler::SendDone(int rv) { |
80 // TODO(noamsml): Retry logic. | 124 // TODO(noamsml): Retry logic. |
81 } | 125 } |
82 | 126 |
83 int MDnsConnection::SocketHandler::Bind() { | |
84 IPAddressNumber address_any(multicast_addr_.address().size()); | |
85 | |
86 IPEndPoint bind_endpoint(address_any, multicast_addr_.port()); | |
87 | |
88 socket_->AllowAddressReuse(); | |
89 int rv = socket_->Listen(bind_endpoint); | |
90 | |
91 if (rv < OK) return rv; | |
92 | |
93 socket_->SetMulticastLoopbackMode(false); | |
94 | |
95 return socket_->JoinGroup(multicast_addr_.address()); | |
96 } | |
97 | |
98 MDnsConnection::MDnsConnection(MDnsConnection::Delegate* delegate) : | 127 MDnsConnection::MDnsConnection(MDnsConnection::Delegate* delegate) : |
99 delegate_(delegate) { | 128 delegate_(delegate) { |
100 } | 129 } |
101 | 130 |
102 MDnsConnection::~MDnsConnection() { | 131 MDnsConnection::~MDnsConnection() { |
103 } | 132 } |
104 | 133 |
105 bool MDnsConnection::Init(MDnsConnection::SocketFactory* socket_factory) { | 134 bool MDnsConnection::Init(MDnsSocketFactory* socket_factory) { |
106 // TODO(vitalybuka): crbug.com/297690 Make socket_factory return list | 135 ScopedVector<DatagramServerSocket> sockets; |
107 // of initialized sockets. | 136 socket_factory->CreateSockets(&sockets); |
108 socket_handlers_.push_back( | |
109 new SocketHandler(this, GetMDnsIPEndPoint(ADDRESS_FAMILY_IPV4), | |
110 socket_factory)); | |
111 socket_handlers_.push_back( | |
112 new SocketHandler(this, GetMDnsIPEndPoint(ADDRESS_FAMILY_IPV6), | |
113 socket_factory)); | |
114 | 137 |
115 for (size_t i = 0; i < socket_handlers_.size();) { | 138 for (size_t i = 0; i < sockets.size(); ++i) { |
116 int rv = socket_handlers_[i]->Bind(); | 139 socket_handlers_.push_back( |
117 if (rv != OK) { | 140 new MDnsConnection::SocketHandler(make_scoped_ptr(sockets[i]), this)); |
118 socket_handlers_.erase(socket_handlers_.begin() + i); | |
119 VLOG(1) << "Bind failed, socket=" << i << ", error=" << rv; | |
120 } else { | |
121 ++i; | |
122 } | |
123 } | 141 } |
| 142 sockets.weak_clear(); |
124 | 143 |
125 // All unbound sockets need to be bound before processing untrusted input. | 144 // All unbound sockets need to be bound before processing untrusted input. |
126 // This is done for security reasons, so that an attacker can't get an unbound | 145 // This is done for security reasons, so that an attacker can't get an unbound |
127 // socket. | 146 // socket. |
128 for (size_t i = 0; i < socket_handlers_.size();) { | 147 for (size_t i = 0; i < socket_handlers_.size();) { |
129 int rv = socket_handlers_[i]->Start(); | 148 int rv = socket_handlers_[i]->Start(); |
130 if (rv != OK) { | 149 if (rv != OK) { |
131 socket_handlers_.erase(socket_handlers_.begin() + i); | 150 socket_handlers_.erase(socket_handlers_.begin() + i); |
132 VLOG(1) << "Start failed, socket=" << i << ", error=" << rv; | 151 VLOG(1) << "Start failed, socket=" << i << ", error=" << rv; |
133 } else { | 152 } else { |
(...skipping 26 matching lines...) Expand all Loading... |
160 | 179 |
161 void MDnsConnection::OnDatagramReceived( | 180 void MDnsConnection::OnDatagramReceived( |
162 DnsResponse* response, | 181 DnsResponse* response, |
163 const IPEndPoint& recv_addr, | 182 const IPEndPoint& recv_addr, |
164 int bytes_read) { | 183 int bytes_read) { |
165 // TODO(noamsml): More sophisticated error handling. | 184 // TODO(noamsml): More sophisticated error handling. |
166 DCHECK_GT(bytes_read, 0); | 185 DCHECK_GT(bytes_read, 0); |
167 delegate_->HandlePacket(response, bytes_read); | 186 delegate_->HandlePacket(response, bytes_read); |
168 } | 187 } |
169 | 188 |
170 class MDnsConnectionSocketFactoryImpl | |
171 : public MDnsConnection::SocketFactory { | |
172 public: | |
173 MDnsConnectionSocketFactoryImpl(); | |
174 virtual ~MDnsConnectionSocketFactoryImpl(); | |
175 | |
176 virtual scoped_ptr<DatagramServerSocket> CreateSocket() OVERRIDE; | |
177 }; | |
178 | |
179 MDnsConnectionSocketFactoryImpl::MDnsConnectionSocketFactoryImpl() { | |
180 } | |
181 | |
182 MDnsConnectionSocketFactoryImpl::~MDnsConnectionSocketFactoryImpl() { | |
183 } | |
184 | |
185 scoped_ptr<DatagramServerSocket> | |
186 MDnsConnectionSocketFactoryImpl::CreateSocket() { | |
187 return scoped_ptr<DatagramServerSocket>(new UDPServerSocket( | |
188 NULL, NetLog::Source())); | |
189 } | |
190 | |
191 // static | |
192 scoped_ptr<MDnsConnection::SocketFactory> | |
193 MDnsConnection::SocketFactory::CreateDefault() { | |
194 return scoped_ptr<MDnsConnection::SocketFactory>( | |
195 new MDnsConnectionSocketFactoryImpl); | |
196 } | |
197 | |
198 MDnsClientImpl::Core::Core(MDnsClientImpl* client) | 189 MDnsClientImpl::Core::Core(MDnsClientImpl* client) |
199 : client_(client), connection_(new MDnsConnection(this)) { | 190 : client_(client), connection_(new MDnsConnection(this)) { |
200 } | 191 } |
201 | 192 |
202 MDnsClientImpl::Core::~Core() { | 193 MDnsClientImpl::Core::~Core() { |
203 STLDeleteValues(&listeners_); | 194 STLDeleteValues(&listeners_); |
204 } | 195 } |
205 | 196 |
206 bool MDnsClientImpl::Core::Init(MDnsConnection::SocketFactory* socket_factory) { | 197 bool MDnsClientImpl::Core::Init(MDnsSocketFactory* socket_factory) { |
207 return connection_->Init(socket_factory); | 198 return connection_->Init(socket_factory); |
208 } | 199 } |
209 | 200 |
210 bool MDnsClientImpl::Core::SendQuery(uint16 rrtype, std::string name) { | 201 bool MDnsClientImpl::Core::SendQuery(uint16 rrtype, std::string name) { |
211 std::string name_dns; | 202 std::string name_dns; |
212 if (!DNSDomainFromDot(name, &name_dns)) | 203 if (!DNSDomainFromDot(name, &name_dns)) |
213 return false; | 204 return false; |
214 | 205 |
215 DnsQuery query(0, name_dns, rrtype); | 206 DnsQuery query(0, name_dns, rrtype); |
216 query.set_flags(0); // Remove the RD flag from the query. It is unneeded. | 207 query.set_flags(0); // Remove the RD flag from the query. It is unneeded. |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
427 AlertListeners(MDnsListener::RECORD_REMOVED, | 418 AlertListeners(MDnsListener::RECORD_REMOVED, |
428 ListenerKey(record->name(), record->type()), record); | 419 ListenerKey(record->name(), record->type()), record); |
429 } | 420 } |
430 | 421 |
431 void MDnsClientImpl::Core::QueryCache( | 422 void MDnsClientImpl::Core::QueryCache( |
432 uint16 rrtype, const std::string& name, | 423 uint16 rrtype, const std::string& name, |
433 std::vector<const RecordParsed*>* records) const { | 424 std::vector<const RecordParsed*>* records) const { |
434 cache_.FindDnsRecords(rrtype, name, records, base::Time::Now()); | 425 cache_.FindDnsRecords(rrtype, name, records, base::Time::Now()); |
435 } | 426 } |
436 | 427 |
437 MDnsClientImpl::MDnsClientImpl( | 428 MDnsClientImpl::MDnsClientImpl() { |
438 scoped_ptr<MDnsConnection::SocketFactory> socket_factory) | |
439 : socket_factory_(socket_factory.Pass()) { | |
440 } | 429 } |
441 | 430 |
442 MDnsClientImpl::~MDnsClientImpl() { | 431 MDnsClientImpl::~MDnsClientImpl() { |
443 } | 432 } |
444 | 433 |
445 bool MDnsClientImpl::StartListening() { | 434 bool MDnsClientImpl::StartListening(MDnsSocketFactory* socket_factory) { |
446 DCHECK(!core_.get()); | 435 DCHECK(!core_.get()); |
447 core_.reset(new Core(this)); | 436 core_.reset(new Core(this)); |
448 if (!core_->Init(socket_factory_.get())) { | 437 if (!core_->Init(socket_factory)) { |
449 core_.reset(); | 438 core_.reset(); |
450 return false; | 439 return false; |
451 } | 440 } |
452 return true; | 441 return true; |
453 } | 442 } |
454 | 443 |
455 void MDnsClientImpl::StopListening() { | 444 void MDnsClientImpl::StopListening() { |
456 core_.reset(); | 445 core_.reset(); |
457 } | 446 } |
458 | 447 |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
664 | 653 |
665 void MDnsTransactionImpl::OnNsecRecord(const std::string& name, unsigned type) { | 654 void MDnsTransactionImpl::OnNsecRecord(const std::string& name, unsigned type) { |
666 TriggerCallback(RESULT_NSEC, NULL); | 655 TriggerCallback(RESULT_NSEC, NULL); |
667 } | 656 } |
668 | 657 |
669 void MDnsTransactionImpl::OnCachePurged() { | 658 void MDnsTransactionImpl::OnCachePurged() { |
670 // TODO(noamsml): Cache purge situations not yet implemented | 659 // TODO(noamsml): Cache purge situations not yet implemented |
671 } | 660 } |
672 | 661 |
673 } // namespace net | 662 } // namespace net |
OLD | NEW |