1 /*------------------------------------------------------------------------------
2  *
3  * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4  * The YADIFA TM software product is provided under the BSD 3-clause license:
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *        * Redistributions in binary form must reproduce the above copyright
13  *          notice, this list of conditions and the following disclaimer in the
14  *          documentation and/or other materials provided with the distribution.
15  *        * Neither the name of EURid nor the names of its contributors may be
16  *          used to endorse or promote products derived from this software
17  *          without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  *------------------------------------------------------------------------------
32  *
33  */
34 
35 #ifndef DNS_UDP_H
36 #define DNS_UDP_H
37 
38 #include <dnscore/host_address.h>
39 #include <dnscore/message.h>
40 #include <dnscore/mutex.h>
41 #include <dnscore/async.h>
42 
43 // error codes
44 
45 #define DNS_UDP_TIMEOUT         ((s32)0x81000001)
46 #define DNS_UDP_INTERNAL        ((s32)0x81000002)
47 #define DNS_UDP_CANCEL          ((s32)0x81000003)
48 
49 //
50 
51 #define DNS_UDP_TIMEOUT_US     3000000   // 3s
52 
53 #define DNS_UDP_TIMEOUT_US_MIN 1000000   // 1s
54 #define DNS_UDP_TIMEOUT_US_MAX 3600000000// 1h
55 
56 #define DNS_UDP_SEND_RATE      1000      // 1000 queries/s
57 #define DNS_UDP_SEND_BANDWIDTH 1000000   // 1MB/s
58 #define DNS_UDP_RECV_BANDWIDTH 1000000   // 1MB/s
59 
60 #define DNS_UDP_SEND_RATE_MIN  1         // q/s
61 #define DNS_UDP_SEND_RATE_MAX  1000000   // q/s
62 
63 #define DNS_UDP_SEND_BANDWIDTH_MIN  512       // 512B/s
64 #define DNS_UDP_SEND_BANDWIDTH_MAX  100000000 // 100MB/s
65 
66 #define DNS_UDP_RECV_BANDWIDTH_MIN  512       // 512B/s
67 #define DNS_UDP_RECV_BANDWIDTH_MAX  100000000 // 100MB/s
68 
69 #define DNS_UDP_SEND_QUEUE     200000    // 200000 messages
70 
71 #define DNS_UDP_SEND_QUEUE_MIN 1
72 #define DNS_UDP_SEND_QUEUE_MAX 0x1000000 // 16.7M messages
73 
74 #define DNS_UDP_PORT_COUNT      256      // A.K.A workers
75 #define DNS_UDP_PORT_COUNT_MIN  1
76 #define DNS_UDP_PORT_COUNT_MAX  4000
77 
78 #define DNS_UDP_RETRY_COUNT      2       // tries after the first failure
79 #define DNS_UDP_RETRY_COUNT_MIN  0
80 #define DNS_UDP_RETRY_COUNT_MAX  16
81 
82 #define DNS_UDP_PER_DNS_RATE     5       // packets per second
83 #define DNS_UDP_PER_DNS_RATE_MIN 1
84 #define DNS_UDP_PER_DNS_RATE_MAX 65536
85 
86 #define DNS_UDP_PER_DNS_BANDWIDTH     4096  // bytes per second
87 #define DNS_UDP_PER_DNS_BANDWIDTH_MIN 512
88 #define DNS_UDP_PER_DNS_BANDWIDTH_MAX 65536
89 
90 #define DNS_UDP_PER_DNS_FREQ_MIN     10000  // us between two queries
91 #define DNS_UDP_PER_DNS_FREQ_MIN_MIN 0
92 #define DNS_UDP_PER_DNS_FREQ_MIN_MAX 1000000
93 
94 #define DNS_UDP_READ_BUFFER_COUNT       4096
95 #define DNS_UDP_READ_BUFFER_COUNT_MIN      1
96 #define DNS_UDP_READ_BUFFER_COUNT_MAX   8192
97 
98 #define DNS_UDP_TCP_THREAD_POOL_SIZE 1
99 #define DNS_UDP_TCP_THREAD_POOL_MIN 1
100 #define DNS_UDP_TCP_THREAD_POOL_MAX 64
101 
102 #define DNS_UDP_TCP_FALLBACK_ON_TIMEOUT 0
103 
104 #define DNS_UDP_CALLBACK_THREAD_COUNT 4
105 #define DNS_UDP_CALLBACK_THREAD_COUNT_MIN 1
106 #define DNS_UDP_CALLBACK_THREAD_COUNT_MAX 8
107 
108 #define DNS_UDP_CALLBACK_QUEUE_SIZE 0x100000
109 #define DNS_UDP_CALLBACK_QUEUE_SIZE_MIN 0x1000
110 #define DNS_UDP_CALLBACK_QUEUE_SIZE_MAX 0x1000000
111 
112 #define DNS_SIMPLE_MESSAGE_HAS_WAIT_COND 0
113 
114 #define DNS_SIMPLE_MESSAGE_FLAGS_DNSSEC MESSAGE_EDNS0_DNSSEC
115 
116 #define DNS_SIMPLE_MESSAGE_STATUS_QUEUED        0x01
117 #define DNS_SIMPLE_MESSAGE_STATUS_COLLECTED     0x02
118 #define DNS_SIMPLE_MESSAGE_STATUS_SENT          0x04
119 #define DNS_SIMPLE_MESSAGE_STATUS_AGGREGATED    0x08
120 #define DNS_SIMPLE_MESSAGE_STATUS_RECEIVED      0x10
121 #define DNS_SIMPLE_MESSAGE_STATUS_TIMEDOUT      0x20
122 #define DNS_SIMPLE_MESSAGE_STATUS_FAILURE       0x40
123 #define DNS_SIMPLE_MESSAGE_STATUS_INVALID       0x80
124 
125 struct dns_udp_settings_s
126 {
127     s64 timeout;
128     u32 send_rate;
129     u32 send_bandwidth;
130     u32 recv_bandwidth;
131     u32 queue_size;
132     u32 port_count;
133     u32 retry_count;
134 
135     u32 per_dns_rate;
136     u32 per_dns_bandwidth;
137     u32 per_dns_freq_min;
138 
139     u32 udp_read_buffer_count;
140 
141     u32 callback_queue_size;
142     u8 callback_thread_count;
143 
144     u8 tcp_thread_pool_size;
145     bool tcp_fallback_on_timeout;
146 
147 
148 
149 };
150 
151 typedef struct dns_udp_settings_s dns_udp_settings_s;
152 
153 // reference count common to all dns_simple_message (aggregation of answer for same query)
154 
155 struct dns_simple_message_async_node_s
156 {
157     struct dns_simple_message_async_node_s *next;
158     async_message_s *async;
159 };
160 
161 typedef struct dns_simple_message_async_node_s dns_simple_message_async_node_s;
162 
163 /*
164  * This is basically a DNS query descriptor (retries and all)
165  */
166 
167 struct dns_simple_message_s
168 {
169     host_address *name_server;
170 
171     message_data *answer;   // answer, can be shared
172 
173     dns_simple_message_async_node_s async_node;
174     volatile s64 queued_time_us;
175     volatile s64 sent_time_us;
176     volatile s64 received_time_us;
177 
178     smp_int rc; // number of references for this message
179     group_mutex_t mtx;
180     volatile thread_t owner;
181 
182     int sender_socket;              // used so a repeated message will be sent from the same address:port
183     u32 worker_index;               // seems to be only useful to get the priority queue index
184     u16 qtype;
185     u16 qclass;
186     u16 flags;
187     u16 source_port;                // seems useless
188     u16 dns_id;
189     s8  retries_left;
190     volatile u8  status;
191     u8 recurse:1,tcp:1,tcp_used:1,tcp_replied:1;
192     //bool recurse;
193     //bool tcp;                       // try TCP
194     u8 fqdn[MAX_DOMAIN_LENGTH];
195 };
196 
197 typedef struct dns_simple_message_s dns_simple_message_s;
198 
199 /**
200  * This needs to be called before dns_udp_handler_init() or some settings will not be taken
201  * into account
202  *
203  * @param settings that will be used by the dns_udp handler
204  */
205 
206 void dns_udp_handler_configure(const dns_udp_settings_s *settings);
207 void dns_udp_handler_host_limit_set(const host_address* name_server,
208         u32 rate,
209         u32 bandwidth,
210         u32 freq_min);
211 int dns_udp_handler_init();
212 int dns_udp_handler_start();
213 int dns_udp_handler_stop();
214 int dns_udp_handler_finalize();
215 
216 /**
217  * Cancels all pending queries.
218  * Their handlers will be called with the error message DNS_UDP_CANCEL
219  * The purpose is cleaning up before shutdown.
220  */
221 
222 void dns_udp_cancel_all_queries();
223 
224 void dns_udp_send_simple_message(const host_address* name_server, const u8 *fqdn, u16 qtype, u16 qclass, u16 flags, async_done_callback *cb, void* cbargs);
225 void dns_udp_send_recursive_message(const host_address* name_server, const u8 *fqdn, u16 qtype, u16 qclass, u16 flags, async_done_callback *cb, void* cbargs);
226 ya_result dns_udp_send_simple_message_sync(const host_address* name_server, const u8 *fqdn, u16 qtype, u16 qclass,u16 flags, dns_simple_message_s **to_release);
227 ya_result dns_udp_send_recursive_message_sync(const host_address* name_server, const u8 *fqdn, u16 qtype, u16 qclass,u16 flags, dns_simple_message_s **to_release);
228 
229 bool dns_udp_simple_message_trylock(dns_simple_message_s *simple_message);
230 void dns_udp_simple_message_lock(dns_simple_message_s *simple_message);
231 void dns_udp_simple_message_unlock(dns_simple_message_s *simple_message);
232 
233 void dns_udp_simple_message_retain(dns_simple_message_s *simple_message);
234 void dns_udp_simple_message_release(dns_simple_message_s *simple_message);
235 
dns_udp_simple_message_get_answer(const dns_simple_message_s * simple_message)236 static inline const message_data *dns_udp_simple_message_get_answer(const dns_simple_message_s *simple_message)
237 {
238     return simple_message->answer;
239 }
240 
241 u32 dns_udp_send_queue_size();
242 u32 dns_udp_pending_queries_count();
243 u32 dns_udp_pending_feedback_count();
244 
245 /**
246  */
247 
248 typedef bool dns_udp_query_hook(dns_simple_message_s *simple_message, message_data *mesg);
249 
250 /**
251  * Sets a hook for queries.
252  *
253  * The hook is called by the service on each messages and is expected to answer
254  * TRUE if it wrote an answer on it
255  * FALSE if it did not
256  *
257  * Every use of the dns_udp service is affected by this.
258  * Only one hook is possible at a given time.
259  *
260  * @param hook a function or NULL to reset to no HOOK.
261  */
262 
263 void dns_udp_set_query_hook(dns_udp_query_hook *hook);
264 
265 /**
266  *
267  * Mark a simple message as being timed-out
268  * Meant for use in hooks.
269  * Use with care.
270  *
271  * @param simple_message
272  */
273 
274 void dns_udp_mark_as_timedout(dns_simple_message_s *simple_message);
275 
276 #endif // DNS_UDP_H
277 
278