blob: 4bf33eb871a446cd9711c50e173db39da78d1404 [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
Ben Schwartzded1b702017-10-25 14:41:02 -040017#define LOG_TAG "DnsTlsTransport"
18
Ben Schwartze7601812017-04-28 16:38:29 -040019#include "dns/DnsTlsTransport.h"
20
21#include <arpa/inet.h>
22#include <arpa/nameser.h>
Ben Schwartze7601812017-04-28 16:38:29 -040023
Ben Schwartzded1b702017-10-25 14:41:02 -040024#include "dns/DnsTlsServer.h"
25#include "dns/DnsTlsSocketFactory.h"
26#include "dns/IDnsTlsSocketFactory.h"
27
28//#define LOG_NDEBUG 0
Ben Schwartze7601812017-04-28 16:38:29 -040029
30#include "log/log.h"
31#include "Fwmark.h"
32#undef ADD // already defined in nameser.h
33#include "NetdConstants.h"
34#include "Permission.h"
35
Ben Schwartze7601812017-04-28 16:38:29 -040036namespace android {
37namespace net {
38
Ben Schwartzded1b702017-10-25 14:41:02 -040039DnsTlsTransport::Result DnsTlsTransport::query(const netdutils::Slice query) {
40 if (query.size() < 2) {
41 return (Result) { .code = Response::internal_error };
Ben Schwartze7601812017-04-28 16:38:29 -040042 }
Ben Schwartzded1b702017-10-25 14:41:02 -040043
44 const uint8_t* data = query.base();
45 uint16_t id = data[0] << 8 | data[1];
46
47 auto socket = mFactory->createDnsTlsSocket(mServer, mMark, &mCache);
48 if (!socket) {
49 return (Result) { .code = Response::network_error };
50 }
51
52 return socket->query(id, netdutils::drop(query, 2));
Ben Schwartze7601812017-04-28 16:38:29 -040053}
54
Ben Schwartzded1b702017-10-25 14:41:02 -040055DnsTlsTransport::~DnsTlsTransport() {
Ben Schwartza13c23a2017-10-02 12:06:21 -040056}
57
58// static
Ben Schwartzded1b702017-10-25 14:41:02 -040059// TODO: Use this function to preheat the session cache.
60// That may require moving it to DnsTlsDispatcher.
Ben Schwartz66810f62017-10-16 19:27:46 -040061bool DnsTlsTransport::validate(const DnsTlsServer& server, unsigned netid) {
Ben Schwartzded1b702017-10-25 14:41:02 -040062 ALOGV("Beginning validation on %u", netid);
Ben Schwartze7601812017-04-28 16:38:29 -040063 // Generate "<random>-dnsotls-ds.metric.gstatic.com", which we will lookup through |ss| in
64 // order to prove that it is actually a working DNS over TLS server.
65 static const char kDnsSafeChars[] =
66 "abcdefhijklmnopqrstuvwxyz"
67 "ABCDEFHIJKLMNOPQRSTUVWXYZ"
68 "0123456789";
69 const auto c = [](uint8_t rnd) -> uint8_t {
70 return kDnsSafeChars[(rnd % ARRAY_SIZE(kDnsSafeChars))];
71 };
72 uint8_t rnd[8];
73 arc4random_buf(rnd, ARRAY_SIZE(rnd));
74 // We could try to use res_mkquery() here, but it's basically the same.
75 uint8_t query[] = {
76 rnd[6], rnd[7], // [0-1] query ID
77 1, 0, // [2-3] flags; query[2] = 1 for recursion desired (RD).
78 0, 1, // [4-5] QDCOUNT (number of queries)
79 0, 0, // [6-7] ANCOUNT (number of answers)
80 0, 0, // [8-9] NSCOUNT (number of name server records)
81 0, 0, // [10-11] ARCOUNT (number of additional records)
82 17, c(rnd[0]), c(rnd[1]), c(rnd[2]), c(rnd[3]), c(rnd[4]), c(rnd[5]),
83 '-', 'd', 'n', 's', 'o', 't', 'l', 's', '-', 'd', 's',
84 6, 'm', 'e', 't', 'r', 'i', 'c',
85 7, 'g', 's', 't', 'a', 't', 'i', 'c',
86 3, 'c', 'o', 'm',
87 0, // null terminator of FQDN (root TLD)
88 0, ns_t_aaaa, // QTYPE
89 0, ns_c_in // QCLASS
90 };
91 const int qlen = ARRAY_SIZE(query);
92
Ben Schwartze7601812017-04-28 16:38:29 -040093 // At validation time, we only know the netId, so we have to guess/compute the
94 // corresponding socket mark.
95 Fwmark fwmark;
96 fwmark.permission = PERMISSION_SYSTEM;
97 fwmark.explicitlySelected = true;
98 fwmark.protectedFromVpn = true;
99 fwmark.netId = netid;
100 unsigned mark = fwmark.intValue;
Ben Schwartze7601812017-04-28 16:38:29 -0400101 int replylen = 0;
Ben Schwartzded1b702017-10-25 14:41:02 -0400102 DnsTlsSocketFactory factory;
103 DnsTlsTransport transport(server, mark, &factory);
104 auto r = transport.query(Slice(query, qlen));
105 if (r.code != Response::success) {
106 ALOGV("query failed");
Ben Schwartze7601812017-04-28 16:38:29 -0400107 return false;
108 }
109
Ben Schwartzded1b702017-10-25 14:41:02 -0400110 const std::vector<uint8_t>& recvbuf = r.response;
111 if (recvbuf.size() < NS_HFIXEDSZ) {
112 ALOGW("short response: %d", replylen);
Ben Schwartze7601812017-04-28 16:38:29 -0400113 return false;
114 }
115
116 const int qdcount = (recvbuf[4] << 8) | recvbuf[5];
117 if (qdcount != 1) {
118 ALOGW("reply query count != 1: %d", qdcount);
119 return false;
120 }
121
122 const int ancount = (recvbuf[6] << 8) | recvbuf[7];
Ben Schwartzded1b702017-10-25 14:41:02 -0400123 ALOGV("%u answer count: %d", netid, ancount);
Ben Schwartze7601812017-04-28 16:38:29 -0400124
125 // TODO: Further validate the response contents (check for valid AAAA record, ...).
126 // Note that currently, integration tests rely on this function accepting a
127 // response with zero records.
128#if 0
129 for (int i = 0; i < resplen; i++) {
130 ALOGD("recvbuf[%d] = %d %c", i, recvbuf[i], recvbuf[i]);
131 }
132#endif
133 return true;
134}
135
Ben Schwartzded1b702017-10-25 14:41:02 -0400136} // end of namespace net
137} // end of namespace android