2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "dnscrypt.hh"
27 #include "dnsdist-protocols.hh"
30 #include "noinitvector.hh"
31 #include "uuid-utils.hh"
34 struct DOHUnitInterface;
37 class DNSDistPacketCache;
39 using QTag = std::unordered_map<string, string>;
40 using HeadersMap = std::unordered_map<std::string, std::string>;
44 StopWatch(bool realTime = false) :
45 d_needRealTime(realTime)
51 d_start = getCurrentTime();
54 void set(const struct timespec& from)
61 struct timespec now = getCurrentTime();
62 return 1000000.0 * (now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec) / 1000.0;
67 struct timespec now = getCurrentTime();
68 auto ret = 1000000.0 * (now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec) / 1000.0;
73 struct timespec getStartTime() const
78 struct timespec d_start
84 struct timespec getCurrentTime() const
87 if (gettime(&now, d_needRealTime) < 0) {
88 unixDie("Getting timestamp");
96 class CrossProtocolContext;
98 struct InternalQueryState
102 std::optional<boost::uuids::uuid> uniqueId{std::nullopt}; // 17
103 std::string d_deviceName;
104 std::string d_deviceID;
105 std::string d_requestorID;
110 origDest.sin4.sin_family = 0;
113 InternalQueryState(InternalQueryState&& rhs) = default;
114 InternalQueryState& operator=(InternalQueryState&& rhs) = default;
116 InternalQueryState(const InternalQueryState& orig) = delete;
117 InternalQueryState& operator=(const InternalQueryState& orig) = delete;
119 boost::optional<Netmask> subnet{boost::none}; // 40
120 ComboAddress origRemote; // 28
121 ComboAddress origDest; // 28
122 ComboAddress hopRemote;
123 ComboAddress hopLocal;
125 std::string poolName; // 24
126 StopWatch queryRealTime{true}; // 24
127 std::shared_ptr<DNSDistPacketCache> packetCache{nullptr}; // 16
128 std::unique_ptr<DNSCryptQuery> dnsCryptQuery{nullptr}; // 8
129 std::unique_ptr<QTag> qTag{nullptr}; // 8
130 std::unique_ptr<PacketBuffer> d_packet{nullptr}; // Initial packet, so we can restart the query from the response path if needed // 8
131 std::unique_ptr<ProtoBufData> d_protoBufData{nullptr};
132 boost::optional<uint32_t> tempFailureTTL{boost::none}; // 8
133 ClientState* cs{nullptr}; // 8
134 std::unique_ptr<DOHUnitInterface> du; // 8
135 size_t d_proxyProtocolPayloadSize{0}; // 8
136 int32_t d_streamID{-1}; // 4
137 std::unique_ptr<DOQUnit> doqu{nullptr}; // 8
138 uint32_t cacheKey{0}; // 4
139 uint32_t cacheKeyNoECS{0}; // 4
141 uint32_t cacheKeyUDP{0}; // 4
142 uint32_t ttlCap{0}; // cap the TTL _after_ inserting into the packet cache // 4
143 int backendFD{-1}; // 4
145 uint16_t qtype{0}; // 2
146 uint16_t qclass{0}; // 2
147 // origID is in network-byte order
148 uint16_t origID{0}; // 2
149 uint16_t origFlags{0}; // 2
150 uint16_t cacheFlags{0}; // DNS flags as sent to the backend // 2
151 uint16_t udpPayloadSize{0}; // Max UDP payload size from the query // 2
152 dnsdist::Protocol protocol; // 1
153 bool ednsAdded{false};
154 bool ecsAdded{false};
155 bool skipCache{false};
156 bool dnssecOK{false};
157 bool useZeroScope{false};
158 bool forwardedOverUDP{false};
159 bool selfGenerated{false};
168 IDState(const IDState& orig) = delete;
169 IDState(IDState&& rhs) noexcept :
170 internal(std::move(rhs.internal))
172 inUse.store(rhs.inUse.load());
173 age.store(rhs.age.load());
176 IDState& operator=(IDState&& rhs) noexcept
178 inUse.store(rhs.inUse.load());
179 age.store(rhs.age.load());
180 internal = std::move(rhs.internal);
189 /* For performance reasons we don't want to use a lock here, but that means
190 we need to be very careful when modifying this value. Modifications happen
192 - one of the UDP or DoH 'client' threads receiving a query, selecting a backend
193 then picking one of the states associated to this backend (via the idOffset).
194 Most of the time this state should not be in use and usageIndicator is -1, but we
195 might not yet have received a response for the query previously associated to this
196 state, meaning that we will 'reuse' this state and erase the existing state.
197 If we ever receive a response for this state, it will be discarded. This is
198 mostly fine for UDP except that we still need to be careful in order to miss
199 the 'outstanding' counters, which should only be increased when we are picking
200 an empty state, and not when reusing ;
201 For DoH, though, we have dynamically allocated a DOHUnit object that needs to
202 be freed, as well as internal objects internals to libh2o.
203 - one of the UDP receiver threads receiving a response from a backend, picking
204 the corresponding state and sending the response to the client ;
205 - the 'healthcheck' thread scanning the states to actively discover timeouts,
206 mostly to keep some counters like the 'outstanding' one sane.
209 - inUse tells us if there currently is a in-flight query whose state is stored
211 - locked tells us whether someone currently owns the state, so no-one else can touch
214 InternalQueryState internal;
215 std::atomic<uint16_t> age{0};
220 StateGuard(IDState& ids) :
228 StateGuard(const StateGuard&) = delete;
229 StateGuard(StateGuard&&) = delete;
230 StateGuard& operator=(const StateGuard&) = delete;
231 StateGuard& operator=(StateGuard&&) = delete;
237 [[nodiscard]] std::optional<StateGuard> acquire()
239 bool expected = false;
240 if (locked.compare_exchange_strong(expected, true)) {
241 return std::optional<StateGuard>(*this);
251 std::atomic<bool> inUse{false}; // 1
254 std::atomic<bool> locked{false}; // 1