-
Notifications
You must be signed in to change notification settings - Fork 0
/
DnsTlsDispatcher.h
180 lines (143 loc) · 7.95 KB
/
DnsTlsDispatcher.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _DNS_DNSTLSDISPATCHER_H
#define _DNS_DNSTLSDISPATCHER_H
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <android-base/thread_annotations.h>
#include <netdutils/Slice.h>
#include "DnsTlsServer.h"
#include "DnsTlsTransport.h"
#include "IDnsTlsSocketFactory.h"
#include "PrivateDnsValidationObserver.h"
#include "resolv_private.h"
namespace android {
namespace net {
// This is a singleton class that manages the collection of active DnsTlsTransports.
// Queries made here are dispatched to an existing or newly constructed DnsTlsTransport.
// TODO: PrivateDnsValidationObserver is not implemented in this class. Remove it.
class DnsTlsDispatcher : public PrivateDnsValidationObserver {
public:
// Constructor with dependency injection for testing.
explicit DnsTlsDispatcher(std::unique_ptr<IDnsTlsSocketFactory> factory)
: mFactory(std::move(factory)) {}
static DnsTlsDispatcher& getInstance();
// Enqueues |query| for resolution via the given |tlsServers| on the
// network indicated by |mark|; writes the response into |ans|, and stores
// the count of bytes written in |resplen|. Returns a success or error code.
// The order in which servers from |tlsServers| are queried may not be the
// order passed in by the caller.
DnsTlsTransport::Response query(const std::list<DnsTlsServer>& tlsServers,
ResState* _Nonnull statp, const netdutils::Slice query,
const netdutils::Slice ans, int* _Nonnull resplen,
bool dotQuickFallback);
// Given a |query|, sends it to the server on the network indicated by |mark|,
// and writes the response into |ans|, and indicates the number of bytes written in |resplen|.
// If the whole procedure above triggers (or experiences) any new connection, |connectTriggered|
// is set. Returns a success or error code.
DnsTlsTransport::Response query(const DnsTlsServer& server, unsigned netId, unsigned mark,
const netdutils::Slice query, const netdutils::Slice ans,
int* _Nonnull resplen, bool* _Nonnull connectTriggered);
// Implement PrivateDnsValidationObserver.
void onValidationStateUpdate(const std::string&, Validation, uint32_t) override{};
void forceCleanup(unsigned netId) EXCLUDES(sLock);
private:
DnsTlsDispatcher();
// This lock is static so that it can be used to annotate the Transport struct.
// DnsTlsDispatcher is a singleton in practice, so making this static does not change
// the locking behavior.
static std::mutex sLock;
// Key = <mark, server>
typedef std::pair<unsigned, const DnsTlsServer> Key;
// Transport is a thin wrapper around DnsTlsTransport, adding reference counting and
// usage monitoring so we can expire idle sessions from the cache.
struct Transport {
Transport(const DnsTlsServer& server, unsigned mark, unsigned netId,
IDnsTlsSocketFactory* _Nonnull factory, bool revalidationEnabled, int triggerThr,
int unusableThr, int timeout)
: transport(server, mark, factory),
mNetId(netId),
revalidationEnabled(revalidationEnabled),
triggerThreshold(triggerThr),
unusableThreshold(unusableThr),
mTimeout(timeout) {}
// DnsTlsTransport is thread-safe, so it doesn't need to be guarded.
DnsTlsTransport transport;
// The expected network, assigned from dns_netid, to which Transport will send DNS packets.
const unsigned mNetId;
// This use counter and timestamp are used to ensure that only idle sessions are
// destroyed.
int useCount GUARDED_BY(sLock) = 0;
// lastUsed is only guaranteed to be meaningful after useCount is decremented to zero.
std::chrono::time_point<std::chrono::steady_clock> lastUsed GUARDED_BY(sLock);
// If DoT revalidation is disabled, it returns true; otherwise, it returns
// whether or not this Transport is usable.
bool usable() const REQUIRES(sLock);
bool checkRevalidationNecessary(DnsTlsTransport::Response code) REQUIRES(sLock);
std::chrono::milliseconds timeout() const { return mTimeout; }
static constexpr int kDotRevalidationThreshold = -1;
static constexpr int kDotXportUnusableThreshold = -1;
static constexpr int kDotQueryTimeoutMs = -1;
private:
// Used to track if this Transport is usable.
int continuousfailureCount GUARDED_BY(sLock) = 0;
// Used to indicate whether DoT revalidation is enabled for this Transport.
// The value is set to true only if:
// 1. both triggerThreshold and unusableThreshold are positive values.
// 2. private DNS mode is opportunistic.
const bool revalidationEnabled;
// The number of continuous failures to trigger a validation. It takes effect when DoT
// revalidation is on. If the value is not a positive value, DoT revalidation is disabled.
// Note that it must be at least 10, or it breaks ConnectTlsServerTimeout_ConcurrentQueries
// test.
const int triggerThreshold;
// The threshold to determine if this Transport is considered unusable.
// If continuousfailureCount reaches this value, this Transport is no longer used. It
// takes effect when DoT revalidation is on. If the value is not a positive value, DoT
// revalidation is disabled.
const int unusableThreshold;
// The time to await a future (the result of a DNS request) from the DnsTlsTransport
// of this Transport.
// To set an infinite timeout, assign the value to -1.
const std::chrono::milliseconds mTimeout;
};
Transport* _Nullable addTransport(const DnsTlsServer& server, unsigned mark, unsigned netId)
REQUIRES(sLock);
Transport* _Nullable getTransport(const Key& key) REQUIRES(sLock);
// Cache of reusable DnsTlsTransports. Transports stay in cache as long as
// they are in use and for a few minutes after.
std::map<Key, std::unique_ptr<Transport>> mStore GUARDED_BY(sLock);
// The last time we did a cleanup. For efficiency, we only perform a cleanup once every
// few minutes.
std::chrono::time_point<std::chrono::steady_clock> mLastCleanup GUARDED_BY(sLock);
DnsTlsTransport::Result queryInternal(Transport& transport, const netdutils::Slice query)
EXCLUDES(sLock);
// Drop any cache entries whose useCount is zero and which have not been used recently.
// This function performs a linear scan of mStore.
void cleanup(std::chrono::time_point<std::chrono::steady_clock> now) REQUIRES(sLock);
// Force dropping any Transports whose useCount is zero.
void forceCleanupLocked(unsigned netId) REQUIRES(sLock);
// Return a sorted list of usable DnsTlsServers in preference order.
std::list<DnsTlsServer> getOrderedAndUsableServerList(const std::list<DnsTlsServer>& tlsServers,
unsigned netId, unsigned mark);
// Trivial factory for DnsTlsSockets. Dependency injection is only used for testing.
std::unique_ptr<IDnsTlsSocketFactory> mFactory;
};
} // end of namespace net
} // end of namespace android
#endif // _DNS_DNSTLSDISPATCHER_H