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