Line data Source code
1 : /*
2 : * Copyright (c) 2017 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 :
16 : #include <dns/dns.h>
17 : #include <vlibapi/api.h>
18 : #include <vlibmemory/api.h>
19 :
20 : #include <vlib/vlib.h>
21 : #include <vnet/vnet.h>
22 :
23 : /* define message IDs */
24 : #include <dns/dns.api_enum.h>
25 : #include <dns/dns.api_types.h>
26 :
27 : #include <vlibapi/api_helper_macros.h>
28 :
29 : int
30 : vnet_dns_response_to_reply (u8 * response,
31 : vl_api_dns_resolve_name_reply_t * rmp,
32 : u32 * min_ttlp);
33 : int
34 : vnet_dns_response_to_name (u8 * response,
35 : vl_api_dns_resolve_ip_reply_t * rmp,
36 : u32 * min_ttlp);
37 :
38 : static void
39 0 : resolve_event (vlib_main_t * vm, dns_main_t * dm, f64 now, u8 * reply)
40 : {
41 : dns_pending_request_t *pr;
42 : dns_header_t *d;
43 : u32 pool_index;
44 : dns_cache_entry_t *ep;
45 : u32 min_ttl;
46 : u16 flags;
47 : u16 rcode;
48 : int i;
49 : int entry_was_valid;
50 : int remove_count;
51 0 : int rv = 0;
52 :
53 0 : d = (dns_header_t *) reply;
54 0 : flags = clib_net_to_host_u16 (d->flags);
55 0 : rcode = flags & DNS_RCODE_MASK;
56 :
57 : /* $$$ u16 limits cache to 65K entries, fix later multiple dst ports */
58 0 : pool_index = clib_net_to_host_u16 (d->id);
59 0 : dns_cache_lock (dm, 10);
60 :
61 0 : if (pool_is_free_index (dm->entries, pool_index))
62 : {
63 0 : vec_free (reply);
64 : if (0)
65 : clib_warning ("pool index %d is free", pool_index);
66 0 : vlib_node_increment_counter (vm, dns46_reply_node.index,
67 : DNS46_REPLY_ERROR_NO_ELT, 1);
68 0 : dns_cache_unlock (dm);
69 0 : return;
70 : }
71 :
72 0 : ep = pool_elt_at_index (dm->entries, pool_index);
73 :
74 0 : if (ep->dns_response)
75 0 : vec_free (ep->dns_response);
76 :
77 : /* Handle [sic] recursion AKA CNAME indirection */
78 0 : rv = vnet_dns_cname_indirection_nolock (vm, dm, pool_index, reply);
79 :
80 : /* CNAME found, further resolution pending, we're done here */
81 0 : if (rv > 0)
82 : {
83 0 : dns_cache_unlock (dm);
84 0 : return;
85 : }
86 : /* Server backfire: refused to answer, or sent zero replies */
87 0 : if (rv < 0)
88 : {
89 : /* Try a different server */
90 0 : if (ep->server_af /* ip6 */ )
91 : {
92 : if (0)
93 : clib_warning ("Server %U failed to resolve '%s'",
94 : format_ip6_address,
95 : dm->ip6_name_servers + ep->server_rotor, ep->name);
96 : /* Any more servers to try? */
97 0 : if (ep->server_fails > 1 || vec_len (dm->ip6_name_servers) <= 1)
98 : {
99 : /* No, tell the client to go away */
100 0 : goto reply;
101 : }
102 0 : ep->retry_count = 0;
103 0 : ep->server_rotor++;
104 0 : ep->server_fails++;
105 0 : if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
106 0 : ep->server_rotor = 0;
107 : if (0)
108 : clib_warning ("Try server %U", format_ip6_address,
109 : dm->ip6_name_servers + ep->server_rotor);
110 0 : vnet_dns_send_dns6_request
111 0 : (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor);
112 : }
113 : else
114 : {
115 : if (0)
116 : clib_warning ("Server %U failed to resolve '%s'",
117 : format_ip4_address,
118 : dm->ip4_name_servers + ep->server_rotor, ep->name);
119 :
120 0 : if (ep->server_fails > 1 || vec_len (dm->ip4_name_servers) <= 1)
121 : {
122 : /* No, tell the client to go away */
123 0 : goto reply;
124 : }
125 0 : ep->retry_count = 0;
126 0 : ep->server_rotor++;
127 0 : ep->server_fails++;
128 0 : if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
129 0 : ep->server_rotor = 0;
130 : if (0)
131 : clib_warning ("Try server %U", format_ip4_address,
132 : dm->ip4_name_servers + ep->server_rotor);
133 0 : vnet_dns_send_dns4_request
134 0 : (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor);
135 : }
136 0 : dns_cache_unlock (dm);
137 0 : return;
138 : }
139 :
140 0 : reply:
141 : /* Save the response */
142 0 : ep->dns_response = reply;
143 :
144 : /*
145 : * Pick a sensible default cache entry expiration time.
146 : * We don't play the 10-second timeout game.
147 : */
148 0 : ep->expiration_time = now + 600.0;
149 :
150 : if (0)
151 : clib_warning ("resolving '%s', was %s valid",
152 : ep->name, (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID) ?
153 : "already" : "not");
154 : /*
155 : * The world is a mess. A single DNS request sent to e.g. 8.8.8.8
156 : * may yield multiple, subtly different responses - all with the same
157 : * DNS protocol-level ID.
158 : *
159 : * Last response wins in terms of what ends up in the cache.
160 : * First response wins in terms of the response sent to the client.
161 : */
162 :
163 : /* Strong hint that we may not find a pending resolution entry */
164 0 : entry_was_valid = (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID) ? 1 : 0;
165 :
166 0 : if (vec_len (ep->dns_response))
167 0 : ep->flags |= DNS_CACHE_ENTRY_FLAG_VALID;
168 :
169 : /* Most likely, send 1 message */
170 0 : for (i = 0; i < vec_len (ep->pending_requests); i++)
171 : {
172 : vl_api_registration_t *regp;
173 :
174 0 : pr = vec_elt_at_index (ep->pending_requests, i);
175 :
176 0 : switch (pr->request_type)
177 : {
178 0 : case DNS_API_PENDING_NAME_TO_IP:
179 : {
180 : vl_api_dns_resolve_name_reply_t *rmp;
181 0 : regp = vl_api_client_index_to_registration (pr->client_index);
182 0 : if (regp == 0)
183 0 : continue;
184 :
185 0 : rmp = vl_msg_api_alloc (sizeof (*rmp));
186 0 : rmp->_vl_msg_id =
187 0 : clib_host_to_net_u16 (VL_API_DNS_RESOLVE_NAME_REPLY
188 0 : + dm->msg_id_base);
189 0 : rmp->context = pr->client_context;
190 0 : min_ttl = ~0;
191 0 : rv = vnet_dns_response_to_reply (ep->dns_response, rmp, &min_ttl);
192 0 : if (min_ttl != ~0)
193 0 : ep->expiration_time = now + min_ttl;
194 0 : rmp->retval = clib_host_to_net_u32 (rv);
195 0 : vl_api_send_msg (regp, (u8 *) rmp);
196 : }
197 0 : break;
198 :
199 0 : case DNS_API_PENDING_IP_TO_NAME:
200 : {
201 : vl_api_dns_resolve_ip_reply_t *rmp;
202 :
203 0 : regp = vl_api_client_index_to_registration (pr->client_index);
204 0 : if (regp == 0)
205 0 : continue;
206 :
207 0 : rmp = vl_msg_api_alloc (sizeof (*rmp));
208 0 : rmp->_vl_msg_id =
209 0 : clib_host_to_net_u16 (VL_API_DNS_RESOLVE_IP_REPLY
210 0 : + dm->msg_id_base);
211 0 : rmp->context = pr->client_context;
212 0 : min_ttl = ~0;
213 0 : rv = vnet_dns_response_to_name (ep->dns_response, rmp, &min_ttl);
214 0 : if (min_ttl != ~0)
215 0 : ep->expiration_time = now + min_ttl;
216 0 : rmp->retval = clib_host_to_net_u32 (rv);
217 0 : vl_api_send_msg (regp, (u8 *) rmp);
218 : }
219 0 : break;
220 :
221 0 : case DNS_PEER_PENDING_IP_TO_NAME:
222 : case DNS_PEER_PENDING_NAME_TO_IP:
223 0 : if (pr->is_ip6)
224 0 : vnet_send_dns6_reply (vm, dm, pr, ep, 0 /* allocate a buffer */ );
225 : else
226 0 : vnet_send_dns4_reply (vm, dm, pr, ep, 0 /* allocate a buffer */ );
227 0 : break;
228 0 : default:
229 0 : clib_warning ("request type %d unknown", pr->request_type);
230 0 : break;
231 : }
232 : }
233 0 : vec_free (ep->pending_requests);
234 :
235 0 : remove_count = 0;
236 0 : for (i = 0; i < vec_len (dm->unresolved_entries); i++)
237 : {
238 0 : if (dm->unresolved_entries[i] == pool_index)
239 : {
240 0 : vec_delete (dm->unresolved_entries, 1, i);
241 0 : remove_count++;
242 0 : i--;
243 : }
244 : }
245 : /* See multiple response comment above... */
246 0 : if (remove_count == 0)
247 : {
248 0 : u32 error_code = entry_was_valid ? DNS46_REPLY_ERROR_MULTIPLE_REPLY :
249 : DNS46_REPLY_ERROR_NO_UNRESOLVED_ENTRY;
250 :
251 0 : vlib_node_increment_counter (vm, dns46_reply_node.index, error_code, 1);
252 0 : dns_cache_unlock (dm);
253 0 : return;
254 : }
255 :
256 : /* Deal with bogus names, server issues, etc. */
257 0 : switch (rcode)
258 : {
259 0 : default:
260 : case DNS_RCODE_NO_ERROR:
261 0 : break;
262 :
263 0 : case DNS_RCODE_SERVER_FAILURE:
264 : case DNS_RCODE_NOT_IMPLEMENTED:
265 : case DNS_RCODE_REFUSED:
266 0 : if (ep->server_af == 0)
267 0 : clib_warning ("name server %U can't resolve '%s'",
268 : format_ip4_address,
269 : dm->ip4_name_servers + ep->server_rotor, ep->name);
270 : else
271 0 : clib_warning ("name server %U can't resolve '%s'",
272 : format_ip6_address,
273 : dm->ip6_name_servers + ep->server_rotor, ep->name);
274 : /* FALLTHROUGH */
275 : case DNS_RCODE_NAME_ERROR:
276 : case DNS_RCODE_FORMAT_ERROR:
277 : /* remove trash from the cache... */
278 0 : vnet_dns_delete_entry_by_index_nolock (dm, ep - dm->entries);
279 0 : break;
280 : }
281 :
282 :
283 0 : dns_cache_unlock (dm);
284 0 : return;
285 : }
286 :
287 : static void
288 0 : retry_scan (vlib_main_t * vm, dns_main_t * dm, f64 now)
289 : {
290 : int i;
291 : dns_cache_entry_t *ep;
292 :
293 0 : for (i = 0; i < vec_len (dm->unresolved_entries); i++)
294 : {
295 0 : dns_cache_lock (dm, 11);
296 0 : ep = pool_elt_at_index (dm->entries, dm->unresolved_entries[i]);
297 :
298 0 : ASSERT ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID) == 0);
299 0 : vnet_send_dns_request (vm, dm, ep);
300 0 : dns_cache_unlock (dm);
301 : }
302 0 : }
303 :
304 : static uword
305 5 : dns_resolver_process (vlib_main_t * vm,
306 : vlib_node_runtime_t * rt, vlib_frame_t * f)
307 : {
308 5 : dns_main_t *dm = &dns_main;
309 : f64 now;
310 5 : f64 timeout = 1000.0;
311 5 : uword *event_data = 0;
312 : uword event_type;
313 : int i;
314 :
315 : while (1)
316 : {
317 6 : vlib_process_wait_for_event_or_clock (vm, timeout);
318 :
319 1 : now = vlib_time_now (vm);
320 :
321 1 : event_type = vlib_process_get_events (vm, (uword **) & event_data);
322 :
323 1 : switch (event_type)
324 : {
325 : /* Send one of these when a resolution is pending */
326 1 : case DNS_RESOLVER_EVENT_PENDING:
327 1 : timeout = 2.0;
328 1 : break;
329 :
330 0 : case DNS_RESOLVER_EVENT_RESOLVED:
331 0 : for (i = 0; i < vec_len (event_data); i++)
332 0 : resolve_event (vm, dm, now, (u8 *) event_data[i]);
333 0 : break;
334 :
335 0 : case ~0: /* timeout */
336 0 : retry_scan (vm, dm, now);
337 0 : break;
338 : }
339 1 : vec_reset_length (event_data);
340 :
341 : /* No work? Back to slow timeout mode... */
342 1 : if (vec_len (dm->unresolved_entries) == 0)
343 0 : timeout = 1000.0;
344 : }
345 : return 0; /* or not */
346 : }
347 :
348 : void
349 5 : vnet_dns_create_resolver_process (vlib_main_t * vm, dns_main_t * dm)
350 : {
351 : /* Already created the resolver process? */
352 5 : if (dm->resolver_process_node_index > 0)
353 0 : return;
354 :
355 : /* No, create it now and make a note of the node index */
356 5 : dm->resolver_process_node_index = vlib_process_create
357 : (vm, "dns-resolver-process",
358 : dns_resolver_process, 16 /* log2_n_stack_bytes */ );
359 : }
360 :
361 : /*
362 : * fd.io coding-style-patch-verification: ON
363 : *
364 : * Local Variables:
365 : * eval: (c-set-style "gnu")
366 : * End:
367 : */
|