1 /* Copyright (C) 2014-2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 2 * SPDX-License-Identifier: GPL-3.0-or-later 3 */ 4 5 #pragma once 6 7 /** 8 * @file selection.h 9 * Provides server selection API (see `kr_server_selection`) 10 * and functions common to both implementations. 11 */ 12 13 #include "lib/cache/api.h" 14 15 /* After KR_NS_TIMEOUT_ROW_DEAD consecutive timeouts, we consider the upstream IP dead for KR_NS_TIMEOUT_RETRY_INTERVAL ms */ 16 #define KR_NS_TIMEOUT_ROW_DEAD 4 17 #define KR_NS_TIMEOUT_RETRY_INTERVAL 1000 18 19 /** 20 * These errors are to be reported as feedback to server selection. 21 * See `kr_server_selection::error` for more details. 22 */ 23 enum kr_selection_error { 24 KR_SELECTION_OK = 0, 25 26 // Network errors 27 KR_SELECTION_QUERY_TIMEOUT, 28 KR_SELECTION_TLS_HANDSHAKE_FAILED, 29 KR_SELECTION_TCP_CONNECT_FAILED, 30 KR_SELECTION_TCP_CONNECT_TIMEOUT, 31 32 // RCODEs 33 KR_SELECTION_REFUSED, 34 KR_SELECTION_SERVFAIL, 35 KR_SELECTION_FORMERR, /// inside an answer without an OPT record 36 KR_SELECTION_FORMERR_EDNS, /// with an OPT record 37 KR_SELECTION_NOTIMPL, 38 KR_SELECTION_OTHER_RCODE, 39 40 // DNS errors 41 KR_SELECTION_MALFORMED, 42 /** Name or type mismatch. */ 43 KR_SELECTION_MISMATCHED, 44 KR_SELECTION_TRUNCATED, 45 KR_SELECTION_DNSSEC_ERROR, 46 KR_SELECTION_LAME_DELEGATION, 47 /** Too long chain, or a cycle. */ 48 KR_SELECTION_BAD_CNAME, 49 50 /** Leave this last, as it is used as array size. */ 51 KR_SELECTION_NUMBER_OF_ERRORS 52 }; 53 54 enum kr_transport_protocol { 55 /** Selected name with no IPv4 address, it has to be resolved first. */ 56 KR_TRANSPORT_RESOLVE_A, 57 /** Selected name with no IPv6 address, it has to be resolved first. */ 58 KR_TRANSPORT_RESOLVE_AAAA, 59 KR_TRANSPORT_UDP, 60 KR_TRANSPORT_TCP, 61 KR_TRANSPORT_TLS, 62 }; 63 64 /** 65 * Output of the selection algorithm. 66 */ 67 struct kr_transport { 68 knot_dname_t *ns_name; /**< Set to "." for forwarding targets.*/ 69 union inaddr address; 70 size_t address_len; 71 enum kr_transport_protocol protocol; 72 unsigned timeout; /**< Timeout in ms to be set for UDP transmission. */ 73 /** Timeout was capped to a maximum value based on the other candidates 74 * when choosing this transport. The timeout therefore can be much lower 75 * than what we expect it to be. We basically probe the server for a sudden 76 * network change but we expect it to timeout in most cases. We have to keep 77 * this in mind when noting the timeout in cache. */ 78 bool timeout_capped; 79 /** True iff transport was set in worker.c:subreq_finalize, 80 * that means it may be different from the one originally chosen one.*/ 81 bool deduplicated; 82 }; 83 84 struct local_state { 85 int timeouts; /**< Number of timeouts that occurred resolving this query.*/ 86 bool truncated; /**< Query was truncated, switch to TCP. */ 87 /** Force resolution of a new NS name (if possible) 88 * Done by selection.c:error in some cases. */ 89 bool force_resolve; 90 /** Used to work around auths with broken TCP. */ 91 bool force_udp; 92 void *private; /**< Inner state of the implementation.*/ 93 }; 94 95 /** 96 * Specifies a API for selecting transports and giving feedback on the choices. 97 * 98 * The function pointers are to be used throughout resolver when some information about 99 * the transport is obtained. E.g. RTT in `worker.c` or RCODE in `iterate.c`,… 100 */ 101 struct kr_server_selection { 102 bool initialized; 103 /** 104 * Puts a pointer to next transport of @p qry to @p transport . 105 * 106 * Allocates new kr_transport in request's mempool, chooses transport to be used for this query. 107 * Selection may fail, so @p transport can be set to NULL. 108 * 109 * @param transport to be filled with pointer to the chosen transport or NULL on failure 110 */ 111 void (*choose_transport)(struct kr_query *qry, 112 struct kr_transport **transport); 113 /** Report back the RTT of network operation for transport in ms. */ 114 void (*update_rtt)(struct kr_query *qry, 115 const struct kr_transport *transport, unsigned rtt); 116 /** Report back error encountered with the chosen transport. See `enum kr_selection` */ 117 void (*error)(struct kr_query *qry, 118 const struct kr_transport *transport, 119 enum kr_selection_error error); 120 121 struct local_state *local_state; 122 }; 123 124 /** 125 * @brief Initialize the server selection API for @p qry. 126 * 127 * The implementation is to be chosen based on qry->flags. 128 */ 129 KR_EXPORT 130 void kr_server_selection_init(struct kr_query *qry); 131 132 /** 133 * @brief Add forwarding target to request. 134 * 135 * This is exposed to Lua in order to add forwarding targets to request. 136 * These are then shared by all the queries in said request. 137 */ 138 KR_EXPORT 139 int kr_forward_add_target(struct kr_request *req, const struct sockaddr *sock); 140 141 142 143 144 145 /* Below are internal parts shared by ./selection_{forward,iter}.c */ 146 147 /** 148 * To be held per IP address in the global LMDB cache 149 */ 150 struct rtt_state { 151 int32_t srtt; /**< Smoothed RTT, i.e. an estimate of round-trip time. */ 152 int32_t variance; /**< An estimate of RTT's standard derivation (not variance). */ 153 /** Note: some TCP and TLS failures are also considered as timeouts. */ 154 int32_t consecutive_timeouts; 155 /** Timestamp of pronouncing this IP bad based on KR_NS_TIMEOUT_ROW_DEAD */ 156 uint64_t dead_since; 157 }; 158 159 /** 160 * @brief To be held per IP address and locally "inside" query. 161 */ 162 struct address_state { 163 /** Used to distinguish old and valid records in local_state; -1 means unusable IP. */ 164 unsigned int generation; 165 struct rtt_state rtt_state; 166 knot_dname_t *ns_name; 167 bool tls_capable : 1; 168 /* TODO: uncomment these once we actually use this information in selection 169 bool tcp_waiting : 1; 170 bool tcp_connected : 1; 171 */ 172 int choice_array_index; 173 int error_count; 174 bool broken; 175 int errors[KR_SELECTION_NUMBER_OF_ERRORS]; 176 }; 177 178 /** 179 * @brief Array of these is one of inputs for the actual selection algorithm (`select_transport`) 180 */ 181 struct choice { 182 union inaddr address; 183 size_t address_len; 184 struct address_state *address_state; 185 /** used to overwrite the port number; 186 * if zero, `select_transport` determines it. */ 187 uint16_t port; 188 }; 189 190 /** 191 * @brief Array of these is description of names to be resolved (i.e. name without some address) 192 */ 193 struct to_resolve { 194 knot_dname_t *name; 195 /** Either KR_TRANSPORT_RESOLVE_A or KR_TRANSPORT_RESOLVE_AAAA is valid here. */ 196 enum kr_transport_protocol type; 197 }; 198 199 /** 200 * @brief Based on passed choices, choose the next transport. 201 * 202 * Common function to both implementations (iteration and forwarding). 203 * The `*_choose_transport` functions from `selection_*.h` preprocess the input for this one. 204 * 205 * @param choices Options to choose from, see struct above 206 * @param unresolved Array of names that can be resolved (i.e. no A/AAAA record) 207 * @param timeouts Number of timeouts that occurred in this query (used for exponential backoff) 208 * @param mempool Memory context of current request 209 * @param tcp Force TCP as transport protocol 210 * @param[out] choice_index Optionally index of the chosen transport in the @p choices array. 211 * @return Chosen transport (on mempool) or NULL when no choice is viable 212 */ 213 struct kr_transport *select_transport(struct choice choices[], int choices_len, 214 struct to_resolve unresolved[], 215 int unresolved_len, int timeouts, 216 struct knot_mm *mempool, bool tcp, 217 size_t *choice_index); 218 219 /** 220 * Common part of RTT feedback mechanism. Notes RTT to global cache. 221 */ 222 void update_rtt(struct kr_query *qry, struct address_state *addr_state, 223 const struct kr_transport *transport, unsigned rtt); 224 225 /** 226 * Common part of error feedback mechanism. 227 */ 228 void error(struct kr_query *qry, struct address_state *addr_state, 229 const struct kr_transport *transport, 230 enum kr_selection_error sel_error); 231 232 /** 233 * Get RTT state from cache. Returns `default_rtt_state` on unknown addresses. 234 * 235 * Note that this opens a cache transaction which is usually closed by calling 236 * `put_rtt_state`, i.e. callee is responsible for its closing 237 * (e.g. calling kr_cache_commit). 238 */ 239 struct rtt_state get_rtt_state(const uint8_t *ip, size_t len, 240 struct kr_cache *cache); 241 242 int put_rtt_state(const uint8_t *ip, size_t len, struct rtt_state state, 243 struct kr_cache *cache); 244 245 /** 246 * @internal Helper function for conversion between different IP representations. 247 */ 248 void bytes_to_ip(uint8_t *bytes, size_t len, uint16_t port, union inaddr *dst); 249 250 /** 251 * @internal Helper function for conversion between different IP representations. 252 */ 253 uint8_t *ip_to_bytes(const union inaddr *src, size_t len); 254 255 /** 256 * @internal Fetch per-address information from various sources. 257 * 258 * Note that this opens a RO cache transaction; the callee is responsible 259 * for its closing not too long afterwards (e.g. calling kr_cache_commit). 260 */ 261 void update_address_state(struct address_state *state, union inaddr *address, 262 size_t address_len, struct kr_query *qry); 263