blob: 95acdc5844772e2349fd9fa9e4d348195e705b5a [file] [log] [blame]
Ben Schwartze7601812017-04-28 16:38:29 -04001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "dns/DnsTlsTransport.h"
18
19#include <arpa/inet.h>
20#include <arpa/nameser.h>
21#include <errno.h>
22#include <openssl/err.h>
Ben Schwartze7601812017-04-28 16:38:29 -040023
24#define LOG_TAG "DnsTlsTransport"
25#define DBG 0
26
27#include "log/log.h"
28#include "Fwmark.h"
29#undef ADD // already defined in nameser.h
30#include "NetdConstants.h"
31#include "Permission.h"
32
33
34namespace android {
35namespace net {
36
37namespace {
38
39bool setNonBlocking(int fd, bool enabled) {
40 int flags = fcntl(fd, F_GETFL);
41 if (flags < 0) return false;
42
43 if (enabled) {
44 flags |= O_NONBLOCK;
45 } else {
46 flags &= ~O_NONBLOCK;
47 }
48 return (fcntl(fd, F_SETFL, flags) == 0);
49}
50
51int waitForReading(int fd) {
52 fd_set fds;
53 FD_ZERO(&fds);
54 FD_SET(fd, &fds);
55 const int ret = TEMP_FAILURE_RETRY(select(fd + 1, &fds, nullptr, nullptr, nullptr));
56 if (DBG && ret <= 0) {
57 ALOGD("select");
58 }
59 return ret;
60}
61
62int waitForWriting(int fd) {
63 fd_set fds;
64 FD_ZERO(&fds);
65 FD_SET(fd, &fds);
66 const int ret = TEMP_FAILURE_RETRY(select(fd + 1, nullptr, &fds, nullptr, nullptr));
67 if (DBG && ret <= 0) {
68 ALOGD("select");
69 }
70 return ret;
71}
72
73} // namespace
74
75android::base::unique_fd DnsTlsTransport::makeConnectedSocket() const {
Ben Schwartza13c23a2017-10-02 12:06:21 -040076 if (DBG) {
77 ALOGD("%u connecting TCP socket", mMark);
78 }
Ben Schwartze7601812017-04-28 16:38:29 -040079 android::base::unique_fd fd;
80 int type = SOCK_NONBLOCK | SOCK_CLOEXEC;
Ben Schwartz52504622017-07-11 12:21:13 -040081 switch (mServer.protocol) {
Ben Schwartze7601812017-04-28 16:38:29 -040082 case IPPROTO_TCP:
83 type |= SOCK_STREAM;
84 break;
85 default:
86 errno = EPROTONOSUPPORT;
87 return fd;
88 }
89
Ben Schwartz52504622017-07-11 12:21:13 -040090 fd.reset(socket(mServer.ss.ss_family, type, mServer.protocol));
Ben Schwartze7601812017-04-28 16:38:29 -040091 if (fd.get() == -1) {
92 return fd;
93 }
94
95 const socklen_t len = sizeof(mMark);
96 if (setsockopt(fd.get(), SOL_SOCKET, SO_MARK, &mMark, len) == -1) {
97 fd.reset();
98 } else if (connect(fd.get(),
Ben Schwartz52504622017-07-11 12:21:13 -040099 reinterpret_cast<const struct sockaddr *>(&mServer.ss), sizeof(mServer.ss)) != 0
Ben Schwartze7601812017-04-28 16:38:29 -0400100 && errno != EINPROGRESS) {
101 fd.reset();
102 }
103
Ben Schwartza13c23a2017-10-02 12:06:21 -0400104 if (!setNonBlocking(fd, false)) {
105 ALOGE("Failed to disable nonblocking status on DNS-over-TLS fd");
106 fd.reset();
107 }
108
Ben Schwartze7601812017-04-28 16:38:29 -0400109 return fd;
110}
111
112bool getSPKIDigest(const X509* cert, std::vector<uint8_t>* out) {
113 int spki_len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL);
114 unsigned char spki[spki_len];
115 unsigned char* temp = spki;
116 if (spki_len != i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp)) {
117 ALOGW("SPKI length mismatch");
118 return false;
119 }
120 out->resize(SHA256_SIZE);
121 unsigned int digest_len = 0;
122 int ret = EVP_Digest(spki, spki_len, out->data(), &digest_len, EVP_sha256(), NULL);
123 if (ret != 1) {
124 ALOGW("Server cert digest extraction failed");
125 return false;
126 }
127 if (digest_len != out->size()) {
128 ALOGW("Wrong digest length: %d", digest_len);
129 return false;
130 }
131 return true;
132}
133
Ben Schwartza13c23a2017-10-02 12:06:21 -0400134bool DnsTlsTransport::initialize() {
Ben Schwartz66810f62017-10-16 19:27:46 -0400135 // This method should only be called once, at the beginning, so locking should be
136 // unnecessary. This lock only serves to help catch bugs in code that calls this method.
137 std::lock_guard<std::mutex> guard(mLock);
138 if (mSslCtx) {
139 // This is a bug in the caller.
140 return false;
141 }
Ben Schwartza13c23a2017-10-02 12:06:21 -0400142 mSslCtx.reset(SSL_CTX_new(TLS_method()));
143 if (!mSslCtx) {
144 return false;
145 }
146 SSL_CTX_sess_set_new_cb(mSslCtx.get(), DnsTlsTransport::newSessionCallback);
147 SSL_CTX_sess_set_remove_cb(mSslCtx.get(), DnsTlsTransport::removeSessionCallback);
dalyk0ae643f2017-12-08 16:22:55 -0500148
149 // Enable TLS false start.
150 SSL_CTX_set_false_start_allowed_without_alpn(mSslCtx.get(), 1);
151 SSL_CTX_set_mode(mSslCtx.get(), SSL_MODE_ENABLE_FALSE_START);
Ben Schwartza13c23a2017-10-02 12:06:21 -0400152 return true;
153}
154
155bssl::UniquePtr<SSL> DnsTlsTransport::sslConnect(int fd) {
156 // Check TLS context.
157 if (!mSslCtx) {
158 ALOGE("Internal error: context is null in ssl connect");
159 return nullptr;
160 }
161 if (!SSL_CTX_set_max_proto_version(mSslCtx.get(), TLS1_3_VERSION) ||
162 !SSL_CTX_set_min_proto_version(mSslCtx.get(), TLS1_2_VERSION)) {
163 ALOGE("failed to min/max TLS versions");
Ben Schwartze7601812017-04-28 16:38:29 -0400164 return nullptr;
165 }
166
Ben Schwartza13c23a2017-10-02 12:06:21 -0400167 bssl::UniquePtr<SSL> ssl(SSL_new(mSslCtx.get()));
Ben Schwartz4204ecf2017-10-02 12:35:48 -0400168 // This file descriptor is owned by a unique_fd, so don't let libssl close it.
169 bssl::UniquePtr<BIO> bio(BIO_new_socket(fd, BIO_NOCLOSE));
Ben Schwartze7601812017-04-28 16:38:29 -0400170 SSL_set_bio(ssl.get(), bio.get(), bio.get());
171 bio.release();
172
Ben Schwartza13c23a2017-10-02 12:06:21 -0400173 // Add this transport as the 0-index extra data for the socket.
174 // This is used by newSessionCallback.
175 if (SSL_set_ex_data(ssl.get(), 0, this) != 1) {
176 ALOGE("failed to associate SSL socket to transport");
177 return nullptr;
178 }
179
180 // Add this transport as the 0-index extra data for the context.
181 // This is used by removeSessionCallback.
182 if (SSL_CTX_set_ex_data(mSslCtx.get(), 0, this) != 1) {
183 ALOGE("failed to associate SSL context to transport");
Ben Schwartze7601812017-04-28 16:38:29 -0400184 return nullptr;
185 }
186
Ben Schwartz1691bc42017-08-16 12:53:09 -0400187 if (!mServer.name.empty()) {
188 if (SSL_set_tlsext_host_name(ssl.get(), mServer.name.c_str()) != 1) {
189 ALOGE("Failed to set SNI to %s", mServer.name.c_str());
190 return nullptr;
191 }
192 X509_VERIFY_PARAM* param = SSL_get0_param(ssl.get());
193 X509_VERIFY_PARAM_set1_host(param, mServer.name.c_str(), 0);
194 // This will cause the handshake to fail if certificate verification fails.
195 SSL_set_verify(ssl.get(), SSL_VERIFY_PEER, nullptr);
196 }
197
Ben Schwartza13c23a2017-10-02 12:06:21 -0400198 bssl::UniquePtr<SSL_SESSION> session;
199 {
Ben Schwartz66810f62017-10-16 19:27:46 -0400200 std::lock_guard<std::mutex> guard(mLock);
Ben Schwartza13c23a2017-10-02 12:06:21 -0400201 if (!mSessions.empty()) {
202 session = std::move(mSessions.front());
203 mSessions.pop_front();
204 } else if (DBG) {
205 ALOGD("Starting without session ticket.");
206 }
207 }
208 if (session) {
209 SSL_set_session(ssl.get(), session.get());
210 }
211
Ben Schwartze7601812017-04-28 16:38:29 -0400212 for (;;) {
213 if (DBG) {
214 ALOGD("%u Calling SSL_connect", mMark);
215 }
216 int ret = SSL_connect(ssl.get());
217 if (DBG) {
218 ALOGD("%u SSL_connect returned %d", mMark, ret);
219 }
220 if (ret == 1) break; // SSL handshake complete;
221
222 const int ssl_err = SSL_get_error(ssl.get(), ret);
223 switch (ssl_err) {
224 case SSL_ERROR_WANT_READ:
225 if (waitForReading(fd) != 1) {
226 ALOGW("SSL_connect read error");
227 return nullptr;
228 }
229 break;
230 case SSL_ERROR_WANT_WRITE:
231 if (waitForWriting(fd) != 1) {
232 ALOGW("SSL_connect write error");
233 return nullptr;
234 }
235 break;
236 default:
237 ALOGW("SSL_connect error %d, errno=%d", ssl_err, errno);
238 return nullptr;
239 }
240 }
241
Ben Schwartz52504622017-07-11 12:21:13 -0400242 if (!mServer.fingerprints.empty()) {
Ben Schwartze7601812017-04-28 16:38:29 -0400243 if (DBG) {
244 ALOGD("Checking DNS over TLS fingerprint");
245 }
Ben Schwartzf028d392017-07-10 15:07:12 -0400246
247 // We only care that the chain is internally self-consistent, not that
248 // it chains to a trusted root, so we can ignore some kinds of errors.
249 // TODO: Add a CA root verification mode that respects these errors.
250 int verify_result = SSL_get_verify_result(ssl.get());
251 switch (verify_result) {
252 case X509_V_OK:
253 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
254 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
255 case X509_V_ERR_CERT_UNTRUSTED:
256 break;
257 default:
258 ALOGW("Invalid certificate chain, error %d", verify_result);
259 return nullptr;
260 }
261
262 STACK_OF(X509) *chain = SSL_get_peer_cert_chain(ssl.get());
263 if (!chain) {
Ben Schwartze7601812017-04-28 16:38:29 -0400264 ALOGW("Server has null certificate");
265 return nullptr;
266 }
Ben Schwartzf028d392017-07-10 15:07:12 -0400267 // Chain and its contents are owned by ssl, so we don't need to free explicitly.
268 bool matched = false;
269 for (size_t i = 0; i < sk_X509_num(chain); ++i) {
270 // This appears to be O(N^2), but there doesn't seem to be a straightforward
271 // way to walk a STACK_OF nondestructively in linear time.
272 X509* cert = sk_X509_value(chain, i);
273 std::vector<uint8_t> digest;
274 if (!getSPKIDigest(cert, &digest)) {
275 ALOGE("Digest computation failed");
276 return nullptr;
277 }
278
279 if (mServer.fingerprints.count(digest) > 0) {
280 matched = true;
281 break;
282 }
Ben Schwartze7601812017-04-28 16:38:29 -0400283 }
284
Ben Schwartzf028d392017-07-10 15:07:12 -0400285 if (!matched) {
Ben Schwartze7601812017-04-28 16:38:29 -0400286 ALOGW("No matching fingerprint");
287 return nullptr;
288 }
Ben Schwartzf028d392017-07-10 15:07:12 -0400289
Ben Schwartze7601812017-04-28 16:38:29 -0400290 if (DBG) {
291 ALOGD("DNS over TLS fingerprint is correct");
292 }
293 }
294
295 if (DBG) {
296 ALOGD("%u handshake complete", mMark);
297 }
Ben Schwartza13c23a2017-10-02 12:06:21 -0400298
299 return ssl;
300}
301
302// static
303int DnsTlsTransport::newSessionCallback(SSL* ssl, SSL_SESSION* session) {
304 if (!session) {
305 return 0;
306 }
307 if (DBG) {
308 ALOGD("Recording session ticket");
309 }
310 DnsTlsTransport* xport = reinterpret_cast<DnsTlsTransport*>(
311 SSL_get_ex_data(ssl, 0));
312 if (!xport) {
313 ALOGE("null transport in new session callback");
314 return 0;
315 }
316 xport->recordSession(session);
317 return 1;
318}
319
320void DnsTlsTransport::removeSessionCallback(SSL_CTX* ssl_ctx, SSL_SESSION* session) {
321 if (DBG) {
322 ALOGD("Removing session ticket");
323 }
324 DnsTlsTransport* xport = reinterpret_cast<DnsTlsTransport*>(
325 SSL_CTX_get_ex_data(ssl_ctx, 0));
326 if (!xport) {
327 ALOGE("null transport in remove session callback");
328 return;
329 }
330 xport->removeSession(session);
331}
332
333void DnsTlsTransport::recordSession(SSL_SESSION* session) {
Ben Schwartz66810f62017-10-16 19:27:46 -0400334 std::lock_guard<std::mutex> guard(mLock);
Ben Schwartza13c23a2017-10-02 12:06:21 -0400335 mSessions.emplace_front(session);
336 if (mSessions.size() > 5) {
337 if (DBG) {
338 ALOGD("Too many sessions; trimming");
339 }
340 mSessions.pop_back();
341 }
342}
343
344void DnsTlsTransport::removeSession(SSL_SESSION* session) {
Ben Schwartz66810f62017-10-16 19:27:46 -0400345 std::lock_guard<std::mutex> guard(mLock);
Ben Schwartza13c23a2017-10-02 12:06:21 -0400346 if (session) {
347 // TODO: Consider implementing targeted removal.
348 mSessions.clear();
349 }
350}
351
352void DnsTlsTransport::sslDisconnect(bssl::UniquePtr<SSL> ssl, base::unique_fd fd) {
353 if (ssl) {
354 SSL_shutdown(ssl.get());
355 ssl.reset();
356 }
357 fd.reset();
Ben Schwartze7601812017-04-28 16:38:29 -0400358}
359
360bool DnsTlsTransport::sslWrite(int fd, SSL *ssl, const uint8_t *buffer, int len) {
361 if (DBG) {
362 ALOGD("%u Writing %d bytes", mMark, len);
363 }
364 for (;;) {
365 int ret = SSL_write(ssl, buffer, len);
366 if (ret == len) break; // SSL write complete;
367
368 if (ret < 1) {
369 const int ssl_err = SSL_get_error(ssl, ret);
370 switch (ssl_err) {
371 case SSL_ERROR_WANT_WRITE:
372 if (waitForWriting(fd) != 1) {
373 if (DBG) {
374 ALOGW("SSL_write error");
375 }
376 return false;
377 }
378 continue;
379 case 0:
380 break; // SSL write complete;
381 default:
382 if (DBG) {
383 ALOGW("SSL_write error %d", ssl_err);
384 }
385 return false;
386 }
387 }
388 }
389 if (DBG) {
390 ALOGD("%u Wrote %d bytes", mMark, len);
391 }
392 return true;
393}
394
395// Read exactly len bytes into buffer or fail
396bool DnsTlsTransport::sslRead(int fd, SSL *ssl, uint8_t *buffer, int len) {
397 int remaining = len;
398 while (remaining > 0) {
399 int ret = SSL_read(ssl, buffer + (len - remaining), remaining);
400 if (ret == 0) {
401 ALOGE("SSL socket closed with %i of %i bytes remaining", remaining, len);
402 return false;
403 }
404
405 if (ret < 0) {
406 const int ssl_err = SSL_get_error(ssl, ret);
407 if (ssl_err == SSL_ERROR_WANT_READ) {
408 if (waitForReading(fd) != 1) {
409 if (DBG) {
410 ALOGW("SSL_read error");
411 }
412 return false;
413 }
414 continue;
415 } else {
416 if (DBG) {
417 ALOGW("SSL_read error %d", ssl_err);
418 }
419 return false;
420 }
421 }
422
423 remaining -= ret;
424 }
425 return true;
426}
427
Ben Schwartz66810f62017-10-16 19:27:46 -0400428DnsTlsTransport::Response DnsTlsTransport::query(const uint8_t *query, size_t qlen,
Ben Schwartze7601812017-04-28 16:38:29 -0400429 uint8_t *response, size_t limit, int *resplen) {
Ben Schwartza13c23a2017-10-02 12:06:21 -0400430 android::base::unique_fd fd = makeConnectedSocket();
431 if (fd.get() < 0) {
432 ALOGD("%u makeConnectedSocket() failed with: %s", mMark, strerror(errno));
433 return Response::network_error;
Ben Schwartze7601812017-04-28 16:38:29 -0400434 }
Ben Schwartza13c23a2017-10-02 12:06:21 -0400435 bssl::UniquePtr<SSL> ssl = sslConnect(fd.get());
436 if (!ssl) {
Ben Schwartze7601812017-04-28 16:38:29 -0400437 return Response::network_error;
438 }
439
Ben Schwartza13c23a2017-10-02 12:06:21 -0400440 Response res = sendQuery(fd.get(), ssl.get(), query, qlen);
441 if (res == Response::success) {
442 res = readResponse(fd.get(), ssl.get(), query, response, limit, resplen);
443 }
444
445 sslDisconnect(std::move(ssl), std::move(fd));
446 return res;
447}
448
Ben Schwartz66810f62017-10-16 19:27:46 -0400449DnsTlsTransport::Response DnsTlsTransport::sendQuery(int fd, SSL* ssl,
450 const uint8_t *query, size_t qlen) {
Ben Schwartza13c23a2017-10-02 12:06:21 -0400451 if (DBG) {
452 ALOGD("sending query");
453 }
Ben Schwartze7601812017-04-28 16:38:29 -0400454 uint8_t queryHeader[2];
455 queryHeader[0] = qlen >> 8;
456 queryHeader[1] = qlen;
Ben Schwartza13c23a2017-10-02 12:06:21 -0400457 if (!sslWrite(fd, ssl, queryHeader, 2)) {
Ben Schwartze7601812017-04-28 16:38:29 -0400458 return Response::network_error;
459 }
Ben Schwartza13c23a2017-10-02 12:06:21 -0400460 if (!sslWrite(fd, ssl, query, qlen)) {
Ben Schwartze7601812017-04-28 16:38:29 -0400461 return Response::network_error;
462 }
463 if (DBG) {
464 ALOGD("%u SSL_write complete", mMark);
465 }
Ben Schwartza13c23a2017-10-02 12:06:21 -0400466 return Response::success;
467}
Ben Schwartze7601812017-04-28 16:38:29 -0400468
Ben Schwartz66810f62017-10-16 19:27:46 -0400469DnsTlsTransport::Response DnsTlsTransport::readResponse(int fd, SSL* ssl,
470 const uint8_t *query, uint8_t *response, size_t limit, int *resplen) {
Ben Schwartza13c23a2017-10-02 12:06:21 -0400471 if (DBG) {
472 ALOGD("reading response");
473 }
Ben Schwartze7601812017-04-28 16:38:29 -0400474 uint8_t responseHeader[2];
Ben Schwartza13c23a2017-10-02 12:06:21 -0400475 if (!sslRead(fd, ssl, responseHeader, 2)) {
Ben Schwartze7601812017-04-28 16:38:29 -0400476 if (DBG) {
477 ALOGW("%u Failed to read 2-byte length header", mMark);
478 }
479 return Response::network_error;
480 }
481 const uint16_t responseSize = (responseHeader[0] << 8) | responseHeader[1];
482 if (DBG) {
483 ALOGD("%u Expecting response of size %i", mMark, responseSize);
484 }
485 if (responseSize > limit) {
486 ALOGE("%u Response doesn't fit in output buffer: %i", mMark, responseSize);
487 return Response::limit_error;
488 }
Ben Schwartza13c23a2017-10-02 12:06:21 -0400489 if (!sslRead(fd, ssl, response, responseSize)) {
Ben Schwartze7601812017-04-28 16:38:29 -0400490 if (DBG) {
491 ALOGW("%u Failed to read %i bytes", mMark, responseSize);
492 }
493 return Response::network_error;
494 }
495 if (DBG) {
496 ALOGD("%u SSL_read complete", mMark);
497 }
498
499 if (response[0] != query[0] || response[1] != query[1]) {
500 ALOGE("reply query ID != query ID");
501 return Response::internal_error;
502 }
503
Ben Schwartze7601812017-04-28 16:38:29 -0400504 *resplen = responseSize;
505 return Response::success;
506}
507
Ben Schwartz52504622017-07-11 12:21:13 -0400508// static
Ben Schwartz66810f62017-10-16 19:27:46 -0400509bool DnsTlsTransport::validate(const DnsTlsServer& server, unsigned netid) {
Ben Schwartze7601812017-04-28 16:38:29 -0400510 if (DBG) {
511 ALOGD("Beginning validation on %u", netid);
512 }
513 // Generate "<random>-dnsotls-ds.metric.gstatic.com", which we will lookup through |ss| in
514 // order to prove that it is actually a working DNS over TLS server.
515 static const char kDnsSafeChars[] =
516 "abcdefhijklmnopqrstuvwxyz"
517 "ABCDEFHIJKLMNOPQRSTUVWXYZ"
518 "0123456789";
519 const auto c = [](uint8_t rnd) -> uint8_t {
520 return kDnsSafeChars[(rnd % ARRAY_SIZE(kDnsSafeChars))];
521 };
522 uint8_t rnd[8];
523 arc4random_buf(rnd, ARRAY_SIZE(rnd));
524 // We could try to use res_mkquery() here, but it's basically the same.
525 uint8_t query[] = {
526 rnd[6], rnd[7], // [0-1] query ID
527 1, 0, // [2-3] flags; query[2] = 1 for recursion desired (RD).
528 0, 1, // [4-5] QDCOUNT (number of queries)
529 0, 0, // [6-7] ANCOUNT (number of answers)
530 0, 0, // [8-9] NSCOUNT (number of name server records)
531 0, 0, // [10-11] ARCOUNT (number of additional records)
532 17, c(rnd[0]), c(rnd[1]), c(rnd[2]), c(rnd[3]), c(rnd[4]), c(rnd[5]),
533 '-', 'd', 'n', 's', 'o', 't', 'l', 's', '-', 'd', 's',
534 6, 'm', 'e', 't', 'r', 'i', 'c',
535 7, 'g', 's', 't', 'a', 't', 'i', 'c',
536 3, 'c', 'o', 'm',
537 0, // null terminator of FQDN (root TLD)
538 0, ns_t_aaaa, // QTYPE
539 0, ns_c_in // QCLASS
540 };
541 const int qlen = ARRAY_SIZE(query);
542
543 const int kRecvBufSize = 4 * 1024;
544 uint8_t recvbuf[kRecvBufSize];
545
546 // At validation time, we only know the netId, so we have to guess/compute the
547 // corresponding socket mark.
548 Fwmark fwmark;
549 fwmark.permission = PERMISSION_SYSTEM;
550 fwmark.explicitlySelected = true;
551 fwmark.protectedFromVpn = true;
552 fwmark.netId = netid;
553 unsigned mark = fwmark.intValue;
Ben Schwartze7601812017-04-28 16:38:29 -0400554 int replylen = 0;
Ben Schwartz66810f62017-10-16 19:27:46 -0400555 DnsTlsTransport transport(server, mark);
556 if (!transport.initialize()) {
557 return false;
558 }
559 transport.query(query, qlen, recvbuf, kRecvBufSize, &replylen);
Ben Schwartze7601812017-04-28 16:38:29 -0400560 if (replylen == 0) {
561 if (DBG) {
Ben Schwartz52504622017-07-11 12:21:13 -0400562 ALOGD("query failed");
Ben Schwartze7601812017-04-28 16:38:29 -0400563 }
564 return false;
565 }
566
567 if (replylen < NS_HFIXEDSZ) {
568 if (DBG) {
569 ALOGW("short response: %d", replylen);
570 }
571 return false;
572 }
573
574 const int qdcount = (recvbuf[4] << 8) | recvbuf[5];
575 if (qdcount != 1) {
576 ALOGW("reply query count != 1: %d", qdcount);
577 return false;
578 }
579
580 const int ancount = (recvbuf[6] << 8) | recvbuf[7];
581 if (DBG) {
582 ALOGD("%u answer count: %d", netid, ancount);
583 }
584
585 // TODO: Further validate the response contents (check for valid AAAA record, ...).
586 // Note that currently, integration tests rely on this function accepting a
587 // response with zero records.
588#if 0
589 for (int i = 0; i < resplen; i++) {
590 ALOGD("recvbuf[%d] = %d %c", i, recvbuf[i], recvbuf[i]);
591 }
592#endif
593 return true;
594}
595
596} // namespace net
597} // namespace android