blob: bae6cb4911eccdc716910398e6901206d0dec658 [file] [log] [blame]
Dave Barach65457162017-10-10 17:53:14 -04001/*
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 <vnet/dns/dns.h>
17
18#include <vnet/vnet.h>
19#include <vnet/fib/fib.h>
20#include <vlibmemory/api.h>
21
22#include <vnet/udp/udp.h>
23
24#include <vnet/vnet_msg_enum.h>
25
26#define vl_typedefs /* define message structures */
27#include <vnet/vnet_all_api_h.h>
28#undef vl_typedefs
29
30#define vl_endianfun /* define message structures */
31#include <vnet/vnet_all_api_h.h>
32#undef vl_endianfun
33
34/* instantiate all the print functions we know about */
35#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
36#define vl_printfun
37#include <vnet/vnet_all_api_h.h>
38#undef vl_printfun
39
40#include <vlibapi/api_helper_macros.h>
41
42dns_main_t dns_main;
43
44static int
45dns_cache_clear (dns_main_t * dm)
46{
47 dns_cache_entry_t *ep;
48
49 if (dm->is_enabled == 0)
50 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
51
52 dns_cache_lock (dm);
53
54 /* *INDENT-OFF* */
55 pool_foreach (ep, dm->entries,
56 ({
57 vec_free (ep->name);
Dave Barach97494502017-11-04 09:44:38 -040058 vec_free (ep->pending_requests);
Dave Barach65457162017-10-10 17:53:14 -040059 }));
60 /* *INDENT-ON* */
61
62 pool_free (dm->entries);
63 hash_free (dm->cache_entry_by_name);
64 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
65 vec_free (dm->unresolved_entries);
66 dns_cache_unlock (dm);
67 return 0;
68}
69
70static int
71dns_enable_disable (dns_main_t * dm, int is_enable)
72{
73 vlib_thread_main_t *tm = &vlib_thread_main;
74 u32 n_vlib_mains = tm->n_vlib_mains;
Dave Barach8a9566e2018-10-23 10:47:36 -040075 vlib_main_t *vm = dm->vlib_main;
Dave Barach65457162017-10-10 17:53:14 -040076
Dave Barach2466f502019-05-29 13:46:35 -040077 /* Create the resolver process if not done already */
78 vnet_dns_create_resolver_process (dm);
79
Dave Barach65457162017-10-10 17:53:14 -040080 if (is_enable)
81 {
82 if (vec_len (dm->ip4_name_servers) == 0
83 && (vec_len (dm->ip6_name_servers) == 0))
84 return VNET_API_ERROR_NO_NAME_SERVERS;
85
Dave Barach8a9566e2018-10-23 10:47:36 -040086 if (dm->udp_ports_registered == 0)
87 {
88 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply,
89 dns46_reply_node.index, 1 /* is_ip4 */ );
90
91 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6,
92 dns46_reply_node.index, 0 /* is_ip4 */ );
93
94 udp_register_dst_port (vm, UDP_DST_PORT_dns,
95 dns4_request_node.index, 1 /* is_ip4 */ );
96
97 udp_register_dst_port (vm, UDP_DST_PORT_dns6,
98 dns6_request_node.index, 0 /* is_ip4 */ );
99
100 dm->udp_ports_registered = 1;
101 }
102
Dave Barach65457162017-10-10 17:53:14 -0400103 if (dm->cache_entry_by_name == 0)
104 {
105 if (n_vlib_mains > 1)
106 dm->cache_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
107 CLIB_CACHE_LINE_BYTES);
108
109 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
110 }
111
112 dm->is_enabled = 1;
113 }
114 else
115 {
116 dns_cache_clear (dm);
117 dm->is_enabled = 0;
118 }
119 return 0;
120}
121
122static void vl_api_dns_enable_disable_t_handler
123 (vl_api_dns_enable_disable_t * mp)
124{
125 vl_api_dns_enable_disable_reply_t *rmp;
126 dns_main_t *dm = &dns_main;
127 int rv;
128
129 rv = dns_enable_disable (dm, mp->enable);
130
131 REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
132}
133
134static int
135dns6_name_server_add_del (dns_main_t * dm,
136 u8 * server_address_as_u8, int is_add)
137{
138 int i;
139 ip6_address_t *ap;
140
141 if (is_add)
142 {
143 /* Already there? done... */
144 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
145 {
146 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
147 sizeof (ip6_address_t)))
148 return 0;
149 }
150
151 vec_add2 (dm->ip6_name_servers, ap, 1);
152 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
153 }
154 else
155 {
156 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
157 {
158 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
159 sizeof (ip6_address_t)))
160 {
161 vec_delete (dm->ip6_name_servers, 1, i);
162 return 0;
163 }
164 }
165 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
166 }
167 return 0;
168}
169
170static int
171dns4_name_server_add_del (dns_main_t * dm,
172 u8 * server_address_as_u8, int is_add)
173{
174 int i;
175 ip4_address_t *ap;
176
177 if (is_add)
178 {
179 /* Already there? done... */
180 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
181 {
182 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
183 sizeof (ip4_address_t)))
184 return 0;
185 }
186
187 vec_add2 (dm->ip4_name_servers, ap, 1);
188 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
189 }
190 else
191 {
192 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
193 {
194 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
195 sizeof (ip4_address_t)))
196 {
197 vec_delete (dm->ip4_name_servers, 1, i);
198 return 0;
199 }
200 }
201 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
202 }
203 return 0;
204}
205
206static void vl_api_dns_name_server_add_del_t_handler
207 (vl_api_dns_name_server_add_del_t * mp)
208{
209 dns_main_t *dm = &dns_main;
210 vl_api_dns_name_server_add_del_reply_t *rmp;
211 int rv;
212
213 if (mp->is_ip6)
214 rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
215 else
216 rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
217
218 REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
219}
220
Dave Barach580eda72018-01-09 17:00:00 -0500221void
222vnet_dns_send_dns4_request (dns_main_t * dm,
223 dns_cache_entry_t * ep, ip4_address_t * server)
Dave Barach65457162017-10-10 17:53:14 -0400224{
225 vlib_main_t *vm = dm->vlib_main;
226 f64 now = vlib_time_now (vm);
227 u32 bi;
228 vlib_buffer_t *b;
229 ip4_header_t *ip;
230 fib_prefix_t prefix;
231 fib_node_index_t fei;
232 u32 sw_if_index, fib_index;
233 udp_header_t *udp;
234 ip4_main_t *im4 = &ip4_main;
235 ip_lookup_main_t *lm4 = &im4->lookup_main;
236 ip_interface_address_t *ia = 0;
237 ip4_address_t *src_address;
238 u8 *dns_request;
239 vlib_frame_t *f;
240 u32 *to_next;
241
242 ASSERT (ep->dns_request);
243
244 /* Find a FIB path to the server */
245 clib_memcpy (&prefix.fp_addr.ip4, server, sizeof (*server));
246 prefix.fp_proto = FIB_PROTOCOL_IP4;
247 prefix.fp_len = 32;
248
249 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
250 if (fib_index == (u32) ~ 0)
251 {
252 clib_warning ("no fib table");
253 return;
254 }
255
256 fei = fib_table_lookup (fib_index, &prefix);
257
258 /* Couldn't find route to destination. Bail out. */
259 if (fei == FIB_NODE_INDEX_INVALID)
260 {
261 clib_warning ("no route to DNS server");
262 return;
263 }
264
265 sw_if_index = fib_entry_get_resolving_interface (fei);
266
267 if (sw_if_index == ~0)
268 {
269 clib_warning
270 ("route to %U exists, fei %d, get_resolving_interface returned"
Dave Barach580eda72018-01-09 17:00:00 -0500271 " ~0", format_ip4_address, &prefix.fp_addr, fei);
Dave Barach65457162017-10-10 17:53:14 -0400272 return;
273 }
274
275 /* *INDENT-OFF* */
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700276 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
Dave Barach65457162017-10-10 17:53:14 -0400277 ({
278 src_address = ip_interface_address_get_address (lm4, ia);
279 goto found_src_address;
280 }));
281 /* *INDENT-ON* */
282
283 clib_warning ("FIB BUG");
284 return;
285
286found_src_address:
287
288 /* Go get a buffer */
289 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
290 return;
291
292 b = vlib_get_buffer (vm, bi);
293 b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
294 vec_len (ep->dns_request);
295 b->total_length_not_including_first_buffer = 0;
296 b->flags =
297 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
298 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
299 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
300
301 ip = vlib_buffer_get_current (b);
Dave Barachb7b92992018-10-17 10:38:51 -0400302 clib_memset (ip, 0, sizeof (*ip));
Dave Barach65457162017-10-10 17:53:14 -0400303 udp = (udp_header_t *) (ip + 1);
Dave Barachb7b92992018-10-17 10:38:51 -0400304 clib_memset (udp, 0, sizeof (*udp));
Dave Barach65457162017-10-10 17:53:14 -0400305
306 dns_request = (u8 *) (udp + 1);
307
308 /* IP header */
309 ip->ip_version_and_header_length = 0x45;
310 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
311 ip->ttl = 255;
312 ip->protocol = IP_PROTOCOL_UDP;
313 ip->src_address.as_u32 = src_address->as_u32;
314 ip->dst_address.as_u32 = server->as_u32;
315 ip->checksum = ip4_header_checksum (ip);
316
317 /* UDP header */
318 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
319 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
320 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
321 vec_len (ep->dns_request));
322 udp->checksum = 0;
323
324 /* The actual DNS request */
325 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
326
327 /* Ship it to ip4_lookup */
328 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
329 to_next = vlib_frame_vector_args (f);
330 to_next[0] = bi;
331 f->n_vectors = 1;
332 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
333
334 ep->retry_timer = now + 2.0;
335}
336
Dave Barach580eda72018-01-09 17:00:00 -0500337void
338vnet_dns_send_dns6_request (dns_main_t * dm,
339 dns_cache_entry_t * ep, ip6_address_t * server)
Dave Barach65457162017-10-10 17:53:14 -0400340{
341 vlib_main_t *vm = dm->vlib_main;
342 f64 now = vlib_time_now (vm);
343 u32 bi;
344 vlib_buffer_t *b;
345 ip6_header_t *ip;
346 fib_prefix_t prefix;
347 fib_node_index_t fei;
348 u32 sw_if_index, fib_index;
349 udp_header_t *udp;
350 ip6_main_t *im6 = &ip6_main;
351 ip_lookup_main_t *lm6 = &im6->lookup_main;
352 ip_interface_address_t *ia = 0;
353 ip6_address_t *src_address;
354 u8 *dns_request;
355 vlib_frame_t *f;
356 u32 *to_next;
357 int junk __attribute__ ((unused));
358
359 ASSERT (ep->dns_request);
360
361 /* Find a FIB path to the server */
362 clib_memcpy (&prefix.fp_addr, server, sizeof (*server));
363 prefix.fp_proto = FIB_PROTOCOL_IP6;
364 prefix.fp_len = 32;
365
366 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
367 if (fib_index == (u32) ~ 0)
368 {
369 clib_warning ("no fib table");
370 return;
371 }
372
373 fei = fib_table_lookup (fib_index, &prefix);
374
375 /* Couldn't find route to destination. Bail out. */
376 if (fei == FIB_NODE_INDEX_INVALID)
377 {
378 clib_warning ("no route to DNS server");
379 }
380
381 sw_if_index = fib_entry_get_resolving_interface (fei);
382
383 /* *INDENT-OFF* */
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700384 foreach_ip_interface_address(lm6, ia, sw_if_index, 1 /* honor unnumbered */,
Dave Barach65457162017-10-10 17:53:14 -0400385 ({
386 src_address = ip_interface_address_get_address (lm6, ia);
387 goto found_src_address;
388 }));
389 /* *INDENT-ON* */
390
391 clib_warning ("FIB BUG");
392 return;
393
394found_src_address:
395
396 /* Go get a buffer */
397 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
398 return;
399
400 b = vlib_get_buffer (vm, bi);
401 b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
402 vec_len (ep->dns_request);
403 b->total_length_not_including_first_buffer = 0;
404 b->flags =
405 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
406
407 ip = vlib_buffer_get_current (b);
Dave Barachb7b92992018-10-17 10:38:51 -0400408 clib_memset (ip, 0, sizeof (*ip));
Dave Barach65457162017-10-10 17:53:14 -0400409 udp = (udp_header_t *) (ip + 1);
Dave Barachb7b92992018-10-17 10:38:51 -0400410 clib_memset (udp, 0, sizeof (*udp));
Dave Barach65457162017-10-10 17:53:14 -0400411
412 dns_request = (u8 *) (udp + 1);
413
414 /* IP header */
415 ip->ip_version_traffic_class_and_flow_label =
416 clib_host_to_net_u32 (0x6 << 28);
417
418 ip->payload_length =
419 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
420 - sizeof (ip6_header_t));
421 ip->hop_limit = 255;
422 ip->protocol = IP_PROTOCOL_UDP;
423 clib_memcpy (&ip->src_address, src_address, sizeof (ip6_address_t));
424 clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
425
426 /* UDP header */
427 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
428 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
429 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
430 vec_len (ep->dns_request));
431 udp->checksum = 0;
432 udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
433
434 /* The actual DNS request */
435 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
436
437 /* Ship it to ip6_lookup */
438 f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
439 to_next = vlib_frame_vector_args (f);
440 to_next[0] = bi;
441 f->n_vectors = 1;
442
443 ep->retry_timer = now + 2.0;
444}
445
446/**
447 * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
448 * A historical / hysterical micro-TLV scheme. DGMS.
449 */
450u8 *
451name_to_labels (u8 * name)
452{
453 int i;
454 int last_label_index;
455 u8 *rv;
456
457 rv = vec_dup (name);
458
459 /* punch in space for the first length */
460 vec_insert (rv, 1, 0);
461 last_label_index = 0;
462 i = 1;
463
464 while (i < vec_len (rv))
465 {
466 if (rv[i] == '.')
467 {
468 rv[last_label_index] = (i - last_label_index) - 1;
469 if ((i - last_label_index) > 63)
470 clib_warning ("stupid name, label length %d",
471 i - last_label_index);
472 last_label_index = i;
473 rv[i] = 0;
474 }
475 i++;
476 }
477 /* Set the last real label length */
478 rv[last_label_index] = (i - last_label_index) - 1;
479
480 /*
481 * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
482 * where to stop.
483 */
484 vec_add1 (rv, 0);
485 return rv;
486}
487
488/**
489 * arc-function for the above.
490 * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
491 * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
492 */
493u8 *
Dave Barach97494502017-11-04 09:44:38 -0400494vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
Dave Barach65457162017-10-10 17:53:14 -0400495{
496 u8 *reply = 0;
497 u16 offset;
498 u8 len;
499 int i;
500
501 *parse_from_here = 0;
502
503 /* chase initial pointer? */
504 if ((label[0] & 0xC0) == 0xC0)
505 {
506 *parse_from_here = label + 2;
507 offset = ((label[0] & 0x3f) << 8) + label[1];
508 label = full_text + offset;
509 }
510
511 len = *label++;
512
513 while (len)
514 {
515 for (i = 0; i < len; i++)
516 vec_add1 (reply, *label++);
517
518 /* chase pointer? */
519 if ((label[0] & 0xC0) == 0xC0)
520 {
521 *parse_from_here = label + 2;
522 offset = ((label[0] & 0x3f) << 8) + label[1];
523 label = full_text + offset;
524 }
525
526 len = *label++;
527 if (len)
528 vec_add1 (reply, '.');
529 }
530 if (*parse_from_here == 0)
531 *parse_from_here = label;
532 return reply;
533}
534
535void
536vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep)
537{
538 dns_header_t *h;
539 dns_query_t *qp;
540 u16 tmp;
Dave Barach580eda72018-01-09 17:00:00 -0500541 u8 *request, *name_copy;
Dave Barach65457162017-10-10 17:53:14 -0400542 u32 qp_offset;
543
Dave Barach0cb01bd2017-10-16 14:39:52 -0400544 /* This can easily happen if sitting in GDB, etc. */
Dave Barach580eda72018-01-09 17:00:00 -0500545 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID || ep->server_fails > 1)
Dave Barach0cb01bd2017-10-16 14:39:52 -0400546 return;
547
Dave Barach65457162017-10-10 17:53:14 -0400548 /* Construct the dns request, if we haven't been here already */
549 if (vec_len (ep->dns_request) == 0)
550 {
551 /*
552 * Start with the variadic portion of the exercise.
553 * Turn the name into a set of DNS "labels". Max length
554 * per label is 63, enforce that.
555 */
556 request = name_to_labels (ep->name);
Dave Barach580eda72018-01-09 17:00:00 -0500557 name_copy = vec_dup (request);
Dave Barach65457162017-10-10 17:53:14 -0400558 qp_offset = vec_len (request);
559
Dave Barach580eda72018-01-09 17:00:00 -0500560 /*
561 * At least when testing against "known good" DNS servers:
562 * it turns out that sending 2x requests - one for an A-record
563 * and another for a AAAA-record - seems to work better than
564 * sending a DNS_TYPE_ALL request.
565 */
566
Dave Barach65457162017-10-10 17:53:14 -0400567 /* Add space for the query header */
Dave Barach580eda72018-01-09 17:00:00 -0500568 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
Dave Barach65457162017-10-10 17:53:14 -0400569
570 qp = (dns_query_t *) (request + qp_offset);
571
Dave Barach580eda72018-01-09 17:00:00 -0500572 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
573 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
574 qp++;
575 clib_memcpy (qp, name_copy, vec_len (name_copy));
576 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
577 vec_free (name_copy);
578
579 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
Dave Barach65457162017-10-10 17:53:14 -0400580 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
581
582 /* Punch in space for the dns_header_t */
583 vec_insert (request, sizeof (dns_header_t), 0);
584
585 h = (dns_header_t *) request;
586
587 /* Transaction ID = pool index */
588 h->id = clib_host_to_net_u16 (ep - dm->entries);
589
590 /* Ask for a recursive lookup */
591 tmp = DNS_RD | DNS_OPCODE_QUERY;
592 h->flags = clib_host_to_net_u16 (tmp);
Dave Barach580eda72018-01-09 17:00:00 -0500593 h->qdcount = clib_host_to_net_u16 (2);
Dave Barach65457162017-10-10 17:53:14 -0400594 h->nscount = 0;
595 h->arcount = 0;
596
597 ep->dns_request = request;
598 }
599
600 /* Work out which server / address family we're going to use */
601
602 /* Retry using current server */
603 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
604 {
605 if (ep->server_af == 1 /* ip6 */ )
606 {
607 if (vec_len (dm->ip6_name_servers))
608 {
Dave Barach580eda72018-01-09 17:00:00 -0500609 vnet_dns_send_dns6_request
610 (dm, ep, dm->ip6_name_servers + ep->server_rotor);
Dave Barach65457162017-10-10 17:53:14 -0400611 goto out;
612 }
613 else
614 ep->server_af = 0;
615 }
616 if (vec_len (dm->ip4_name_servers))
617 {
Dave Barach580eda72018-01-09 17:00:00 -0500618 vnet_dns_send_dns4_request
619 (dm, ep, dm->ip4_name_servers + ep->server_rotor);
Dave Barach65457162017-10-10 17:53:14 -0400620 goto out;
621 }
622 }
623 else /* switch to a new server */
624 {
625 ep->retry_count = 1;
626 ep->server_rotor++;
627 if (ep->server_af == 1 /* ip6 */ )
628 {
629 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
630 {
631 ep->server_rotor = 0;
632 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
633 }
634 }
635 else
636 {
637 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
638 {
639 ep->server_rotor = 0;
640 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
641 }
642 }
643 }
644
645 if (ep->server_af == 1 /* ip6 */ )
Dave Barach580eda72018-01-09 17:00:00 -0500646 vnet_dns_send_dns6_request
647 (dm, ep, dm->ip6_name_servers + ep->server_rotor);
Dave Barach65457162017-10-10 17:53:14 -0400648 else
Dave Barach580eda72018-01-09 17:00:00 -0500649 vnet_dns_send_dns4_request
650 (dm, ep, dm->ip4_name_servers + ep->server_rotor);
Dave Barach65457162017-10-10 17:53:14 -0400651
652out:
653
654 vlib_process_signal_event_mt (dm->vlib_main, dns_resolver_node.index,
655 DNS_RESOLVER_EVENT_PENDING, 0);
656}
657
658int
659vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
660{
661 dns_cache_entry_t *ep;
662 int i;
663
664 if (dm->is_enabled == 0)
665 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
666
667 if (pool_is_free_index (dm->entries, index))
668 return VNET_API_ERROR_NO_SUCH_ENTRY;
669
670 ep = pool_elt_at_index (dm->entries, index);
Dave Barach65457162017-10-10 17:53:14 -0400671 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
672 {
673 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
674 if (index == dm->unresolved_entries[i])
675 {
676 vec_delete (dm->unresolved_entries, 1, i);
677 goto found;
678 }
679 clib_warning ("pool elt %d supposedly pending, but not found...",
680 index);
681 }
682
683found:
684 hash_unset_mem (dm->cache_entry_by_name, ep->name);
685 vec_free (ep->name);
Dave Barach97494502017-11-04 09:44:38 -0400686 vec_free (ep->pending_requests);
Dave Barach65457162017-10-10 17:53:14 -0400687 pool_put (dm->entries, ep);
688
689 return 0;
690}
691
692static int
693dns_delete_by_name (dns_main_t * dm, u8 * name)
694{
695 int rv;
696 uword *p;
697
698 if (dm->is_enabled == 0)
699 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
700
701 dns_cache_lock (dm);
702 p = hash_get_mem (dm->cache_entry_by_name, name);
703 if (!p)
704 {
705 dns_cache_unlock (dm);
706 return VNET_API_ERROR_NO_SUCH_ENTRY;
707 }
708 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
709
710 dns_cache_unlock (dm);
711
712 return rv;
713}
714
715static int
716delete_random_entry (dns_main_t * dm)
717{
718 int rv;
719 u32 victim_index, start_index, i;
720 u32 limit;
721 dns_cache_entry_t *ep;
722
723 if (dm->is_enabled == 0)
724 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
725
Dave Barachb9f2cf02017-10-17 13:13:42 -0400726 /*
727 * Silence spurious coverity warning. We know pool_elts >> 0, or
728 * we wouldn't be here...
729 */
730#ifdef __COVERITY__
731 if (pool_elts (dm->entries) == 0)
732 return VNET_API_ERROR_UNSPECIFIED;
733#endif
734
Dave Barach65457162017-10-10 17:53:14 -0400735 dns_cache_lock (dm);
736 limit = pool_elts (dm->entries);
737 start_index = random_u32 (&dm->random_seed) % limit;
738
739 for (i = 0; i < limit; i++)
740 {
741 victim_index = (start_index + i) % limit;
742
743 if (!pool_is_free_index (dm->entries, victim_index))
744 {
745 ep = pool_elt_at_index (dm->entries, victim_index);
746 /* Delete only valid, non-static entries */
747 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
748 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
749 {
750 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
751 dns_cache_unlock (dm);
752 return rv;
753 }
754 }
755 }
756 dns_cache_unlock (dm);
757
758 clib_warning ("Couldn't find an entry to delete?");
759 return VNET_API_ERROR_UNSPECIFIED;
760}
761
762static int
763dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
764{
765 dns_cache_entry_t *ep;
766 uword *p;
767 int rv;
768
769 if (dm->is_enabled == 0)
770 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
771
772 dns_cache_lock (dm);
773 p = hash_get_mem (dm->cache_entry_by_name, name);
774 if (p)
775 {
776 dns_cache_unlock (dm);
777 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
778 }
779
780 if (pool_elts (dm->entries) == dm->name_cache_size)
781 {
782 /* Will only fail if the cache is totally filled w/ static entries... */
783 rv = delete_random_entry (dm);
784 if (rv)
785 {
786 dns_cache_unlock (dm);
787 return rv;
788 }
789 }
790
791 pool_get (dm->entries, ep);
Dave Barachb7b92992018-10-17 10:38:51 -0400792 clib_memset (ep, 0, sizeof (*ep));
Dave Barach65457162017-10-10 17:53:14 -0400793
794 /* Note: consumes the name vector */
795 ep->name = name;
796 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
797 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
798 ep->dns_response = dns_reply_data;
799
800 dns_cache_unlock (dm);
801 return 0;
802}
803
Dave Barach97494502017-11-04 09:44:38 -0400804int
805vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t,
806 dns_cache_entry_t ** retp)
Dave Barach65457162017-10-10 17:53:14 -0400807{
808 dns_cache_entry_t *ep;
809 int rv;
810 f64 now;
811 uword *p;
Dave Barach97494502017-11-04 09:44:38 -0400812 dns_pending_request_t *pr;
813 int count;
Dave Barach65457162017-10-10 17:53:14 -0400814
815 now = vlib_time_now (dm->vlib_main);
816
817 /* In case we can't actually answer the question right now... */
818 *retp = 0;
819
820 dns_cache_lock (dm);
Dave Barach0cb01bd2017-10-16 14:39:52 -0400821search_again:
Dave Barach65457162017-10-10 17:53:14 -0400822 p = hash_get_mem (dm->cache_entry_by_name, name);
823 if (p)
824 {
825 ep = pool_elt_at_index (dm->entries, p[0]);
826 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
827 {
828 /* Has the entry expired? */
829 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
830 && (now > ep->expiration_time))
831 {
Dave Barach0cb01bd2017-10-16 14:39:52 -0400832 int i;
833 u32 *indices_to_delete = 0;
834
835 /*
836 * Take out the rest of the resolution chain
837 * This isn't optimal, but it won't happen very often.
838 */
839 while (ep)
840 {
841 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
842 {
843 vec_add1 (indices_to_delete, ep - dm->entries);
844
845 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
846 if (!p)
847 break;
848 ep = pool_elt_at_index (dm->entries, p[0]);
849 }
850 else
851 {
852 vec_add1 (indices_to_delete, ep - dm->entries);
853 break;
854 }
855 }
856 for (i = 0; i < vec_len (indices_to_delete); i++)
857 {
858 /* Reenable to watch re-resolutions */
859 if (0)
860 {
861 ep = pool_elt_at_index (dm->entries,
862 indices_to_delete[i]);
863 clib_warning ("Re-resolve %s", ep->name);
864 }
865
866 vnet_dns_delete_entry_by_index_nolock
867 (dm, indices_to_delete[i]);
868 }
869 vec_free (indices_to_delete);
Dave Barach65457162017-10-10 17:53:14 -0400870 /* Yes, kill it... */
Dave Barach65457162017-10-10 17:53:14 -0400871 goto re_resolve;
872 }
873
Dave Barach0cb01bd2017-10-16 14:39:52 -0400874 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
875 {
876 name = ep->cname;
877 goto search_again;
878 }
879
Dave Barach65457162017-10-10 17:53:14 -0400880 /* Note: caller must drop the lock! */
881 *retp = ep;
882 return (0);
883 }
Dave Barach0cb01bd2017-10-16 14:39:52 -0400884 else
885 {
886 /*
Dave Barachd2080152017-10-20 09:21:35 -0400887 * Resolution pending. Add request to the pending vector
Dave Barach97494502017-11-04 09:44:38 -0400888 * by copying the template request
Dave Barachd2080152017-10-20 09:21:35 -0400889 */
Dave Barach97494502017-11-04 09:44:38 -0400890 vec_add2 (ep->pending_requests, pr, 1);
891 memcpy (pr, t, sizeof (*pr));
Dave Barach0cb01bd2017-10-16 14:39:52 -0400892 dns_cache_unlock (dm);
893 return (0);
894 }
Dave Barach65457162017-10-10 17:53:14 -0400895 }
896
Dave Barach0cb01bd2017-10-16 14:39:52 -0400897re_resolve:
Dave Barach65457162017-10-10 17:53:14 -0400898 if (pool_elts (dm->entries) == dm->name_cache_size)
899 {
900 /* Will only fail if the cache is totally filled w/ static entries... */
901 rv = delete_random_entry (dm);
902 if (rv)
903 {
904 dns_cache_unlock (dm);
905 return rv;
906 }
907 }
908
Dave Barach65457162017-10-10 17:53:14 -0400909 /* add new hash table entry */
910 pool_get (dm->entries, ep);
Dave Barachb7b92992018-10-17 10:38:51 -0400911 clib_memset (ep, 0, sizeof (*ep));
Dave Barach65457162017-10-10 17:53:14 -0400912
913 ep->name = format (0, "%s%c", name, 0);
914 _vec_len (ep->name) = vec_len (ep->name) - 1;
915
916 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
917
918 vec_add1 (dm->unresolved_entries, ep - dm->entries);
Dave Barach97494502017-11-04 09:44:38 -0400919 vec_add2 (ep->pending_requests, pr, 1);
920
921 pr->request_type = t->request_type;
922
923 /* Remember details so we can reply later... */
924 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
925 t->request_type == DNS_API_PENDING_IP_TO_NAME)
926 {
927 pr->client_index = t->client_index;
928 pr->client_context = t->client_context;
929 }
930 else
931 {
932 pr->client_index = ~0;
933 pr->is_ip6 = t->is_ip6;
934 pr->dst_port = t->dst_port;
935 pr->id = t->id;
936 pr->name = t->name;
937 if (t->is_ip6)
938 count = 16;
939 else
940 count = 4;
941 clib_memcpy (pr->dst_address, t->dst_address, count);
942 }
943
Dave Barach65457162017-10-10 17:53:14 -0400944 vnet_send_dns_request (dm, ep);
945 dns_cache_unlock (dm);
Dave Barach65457162017-10-10 17:53:14 -0400946 return 0;
947}
948
Dave Barach0cb01bd2017-10-16 14:39:52 -0400949#define foreach_notification_to_move \
Dave Barach97494502017-11-04 09:44:38 -0400950_(pending_requests)
Dave Barach0cb01bd2017-10-16 14:39:52 -0400951
Dave Barach65457162017-10-10 17:53:14 -0400952/**
953 * Handle cname indirection. JFC. Called with the cache locked.
954 * returns 0 if the reply is not a CNAME.
955 */
956
957int
Dave Barach0cb01bd2017-10-16 14:39:52 -0400958vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
Dave Barach65457162017-10-10 17:53:14 -0400959{
960 dns_header_t *h;
961 dns_query_t *qp;
962 dns_rr_t *rr;
963 u8 *curpos;
964 u8 *pos, *pos2;
Dave Barachc6372eb2018-01-10 18:18:59 -0500965 u8 *cname_pos = 0;
Dave Barach65457162017-10-10 17:53:14 -0400966 int len, i;
967 u8 *cname = 0;
968 u8 *request = 0;
Dave Barachc6372eb2018-01-10 18:18:59 -0500969 u8 *name_copy;
Dave Barach65457162017-10-10 17:53:14 -0400970 u32 qp_offset;
971 u16 flags;
972 u16 rcode;
Dave Barach0cb01bd2017-10-16 14:39:52 -0400973 dns_cache_entry_t *ep, *next_ep;
974 f64 now;
Dave Barach65457162017-10-10 17:53:14 -0400975
976 h = (dns_header_t *) reply;
977 flags = clib_net_to_host_u16 (h->flags);
978 rcode = flags & DNS_RCODE_MASK;
979
980 /* See if the response is OK */
981 switch (rcode)
982 {
983 case DNS_RCODE_NO_ERROR:
984 break;
985
986 case DNS_RCODE_NAME_ERROR:
987 case DNS_RCODE_FORMAT_ERROR:
988 case DNS_RCODE_SERVER_FAILURE:
989 case DNS_RCODE_NOT_IMPLEMENTED:
990 case DNS_RCODE_REFUSED:
Dave Barach580eda72018-01-09 17:00:00 -0500991 return -1;
Dave Barach65457162017-10-10 17:53:14 -0400992 }
993
994 curpos = (u8 *) (h + 1);
995 pos = curpos;
996 len = *pos++;
997
998 /* Skip the questions */
999 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1000 {
1001 while (len)
1002 {
1003 pos += len;
1004 len = *pos++;
1005 }
Dave Barachb9f2cf02017-10-17 13:13:42 -04001006 pos += sizeof (dns_query_t);
Dave Barach65457162017-10-10 17:53:14 -04001007 }
1008 pos2 = pos;
1009 /* expect a pointer chase here for a CNAME record */
1010 if ((pos2[0] & 0xC0) == 0xC0)
1011 pos += 2;
1012 else
1013 return 0;
1014
Dave Barach580eda72018-01-09 17:00:00 -05001015 /* Walk the answer(s) to see what to do next */
1016 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1017 {
1018 rr = (dns_rr_t *) pos;
1019 switch (clib_net_to_host_u16 (rr->type))
1020 {
1021 /* Real address record? Done.. */
1022 case DNS_TYPE_A:
1023 case DNS_TYPE_AAAA:
1024 return 0;
Dave Barachc6372eb2018-01-10 18:18:59 -05001025 /*
1026 * Maybe chase a CNAME pointer?
1027 * It's not unheard-of for name-servers to return
1028 * both CNAME and A/AAAA records...
1029 */
Dave Barach580eda72018-01-09 17:00:00 -05001030 case DNS_TYPE_CNAME:
Dave Barachc6372eb2018-01-10 18:18:59 -05001031 cname_pos = pos;
1032 break;
Dave Barach65457162017-10-10 17:53:14 -04001033
Dave Barach580eda72018-01-09 17:00:00 -05001034 /* Some other junk, e.g. a nameserver... */
1035 default:
1036 break;
1037 }
1038 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
Dave Barachc6372eb2018-01-10 18:18:59 -05001039 /* Skip name... */
1040 if ((pos2[0] & 0xc0) == 0xc0)
1041 pos += 2;
Dave Barach580eda72018-01-09 17:00:00 -05001042 }
Dave Barach65457162017-10-10 17:53:14 -04001043
Dave Barach580eda72018-01-09 17:00:00 -05001044 /* Neither a CNAME nor a real address. Try another server */
Dave Barachc6372eb2018-01-10 18:18:59 -05001045 if (cname_pos == 0)
1046 {
1047 flags &= ~DNS_RCODE_MASK;
1048 flags |= DNS_RCODE_NAME_ERROR;
1049 h->flags = clib_host_to_net_u16 (flags);
1050 return -1;
1051 }
Dave Barach580eda72018-01-09 17:00:00 -05001052
Dave Barach0cb01bd2017-10-16 14:39:52 -04001053 /* This is a CNAME record, chase the name chain. */
Dave Barachc6372eb2018-01-10 18:18:59 -05001054 pos = cname_pos;
Dave Barach65457162017-10-10 17:53:14 -04001055
Dave Barach0cb01bd2017-10-16 14:39:52 -04001056 /* The last request is no longer pending.. */
1057 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
1058 if (ep_index == dm->unresolved_entries[i])
1059 {
1060 vec_delete (dm->unresolved_entries, 1, i);
1061 goto found_last_request;
1062 }
1063 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
1064
1065found_last_request:
1066
1067 now = vlib_time_now (dm->vlib_main);
Dave Barach97494502017-11-04 09:44:38 -04001068 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
Dave Barach0cb01bd2017-10-16 14:39:52 -04001069 /* Save the cname */
1070 vec_add1 (cname, 0);
1071 _vec_len (cname) -= 1;
1072 ep = pool_elt_at_index (dm->entries, ep_index);
1073 ep->cname = cname;
1074 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1075 /* Save the response */
Dave Barach580eda72018-01-09 17:00:00 -05001076 if (ep->dns_response)
1077 vec_free (ep->dns_response);
Dave Barach0cb01bd2017-10-16 14:39:52 -04001078 ep->dns_response = reply;
1079 /* Set up expiration time */
1080 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1081
1082 pool_get (dm->entries, next_ep);
1083
1084 /* Need to recompute ep post pool-get */
1085 ep = pool_elt_at_index (dm->entries, ep_index);
1086
Dave Barachb7b92992018-10-17 10:38:51 -04001087 clib_memset (next_ep, 0, sizeof (*next_ep));
Dave Barach0cb01bd2017-10-16 14:39:52 -04001088 next_ep->name = vec_dup (cname);
1089 vec_add1 (next_ep->name, 0);
1090 _vec_len (next_ep->name) -= 1;
1091
1092 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1093 next_ep - dm->entries);
1094
1095 /* Use the same server */
1096 next_ep->server_rotor = ep->server_rotor;
1097 next_ep->server_af = ep->server_af;
1098
1099 /* Move notification data to the next name in the chain */
1100#define _(a) next_ep->a = ep->a; ep->a = 0;
1101 foreach_notification_to_move;
1102#undef _
1103
Dave Barach65457162017-10-10 17:53:14 -04001104 request = name_to_labels (cname);
Dave Barachc6372eb2018-01-10 18:18:59 -05001105 name_copy = vec_dup (request);
Dave Barach65457162017-10-10 17:53:14 -04001106
1107 qp_offset = vec_len (request);
1108
1109 /* Add space for the query header */
Dave Barachc6372eb2018-01-10 18:18:59 -05001110 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
Dave Barach65457162017-10-10 17:53:14 -04001111
1112 qp = (dns_query_t *) (request + qp_offset);
1113
Dave Barachc6372eb2018-01-10 18:18:59 -05001114 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1115 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1116 clib_memcpy (qp, name_copy, vec_len (name_copy));
1117 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1118 vec_free (name_copy);
1119
1120 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
Dave Barach65457162017-10-10 17:53:14 -04001121 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1122
1123 /* Punch in space for the dns_header_t */
1124 vec_insert (request, sizeof (dns_header_t), 0);
1125
1126 h = (dns_header_t *) request;
1127
1128 /* Transaction ID = pool index */
Dave Barach0cb01bd2017-10-16 14:39:52 -04001129 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
Dave Barach65457162017-10-10 17:53:14 -04001130
1131 /* Ask for a recursive lookup */
1132 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
Dave Barachc6372eb2018-01-10 18:18:59 -05001133 h->qdcount = clib_host_to_net_u16 (2);
Dave Barach65457162017-10-10 17:53:14 -04001134 h->nscount = 0;
1135 h->arcount = 0;
1136
Dave Barach0cb01bd2017-10-16 14:39:52 -04001137 next_ep->dns_request = request;
1138 next_ep->retry_timer = now + 2.0;
1139 next_ep->retry_count = 0;
Dave Barach65457162017-10-10 17:53:14 -04001140
1141 /*
1142 * Enable this to watch recursive resolution happen...
1143 * fformat (stdout, "%U", format_dns_reply, request, 2);
1144 */
1145
Dave Barach0cb01bd2017-10-16 14:39:52 -04001146 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1147 vnet_send_dns_request (dm, next_ep);
Dave Barach65457162017-10-10 17:53:14 -04001148 return (1);
1149}
1150
1151int
1152vnet_dns_response_to_reply (u8 * response,
1153 vl_api_dns_resolve_name_reply_t * rmp,
1154 u32 * min_ttlp)
1155{
1156 dns_header_t *h;
1157 dns_query_t *qp;
1158 dns_rr_t *rr;
1159 int i, limit;
1160 u8 len;
Dave Barach52925382017-11-16 10:01:12 -05001161 u8 *curpos, *pos, *pos2;
Dave Barach65457162017-10-10 17:53:14 -04001162 u16 flags;
1163 u16 rcode;
1164 u32 ttl;
Dave Barach52925382017-11-16 10:01:12 -05001165 int pointer_chase;
Dave Barach65457162017-10-10 17:53:14 -04001166
1167 h = (dns_header_t *) response;
1168 flags = clib_net_to_host_u16 (h->flags);
1169 rcode = flags & DNS_RCODE_MASK;
1170
1171 /* See if the response is OK, etc. */
1172 switch (rcode)
1173 {
1174 default:
1175 case DNS_RCODE_NO_ERROR:
1176 break;
1177
1178 case DNS_RCODE_NAME_ERROR:
1179 case DNS_RCODE_FORMAT_ERROR:
1180 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1181
1182 case DNS_RCODE_SERVER_FAILURE:
1183 case DNS_RCODE_NOT_IMPLEMENTED:
1184 case DNS_RCODE_REFUSED:
1185 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1186 }
1187
1188 /* No answers? Loser... */
1189 if (clib_net_to_host_u16 (h->anscount) < 1)
1190 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1191
1192 curpos = (u8 *) (h + 1);
1193
1194 /* Skip the name we asked about */
1195 pos = curpos;
1196 len = *pos++;
1197 /* Should never happen, but stil... */
1198 if ((len & 0xC0) == 0xC0)
1199 curpos += 2;
1200 else
1201 {
1202 /* skip the name / label-set */
1203 while (len)
1204 {
1205 pos += len;
1206 len = *pos++;
1207 }
1208 curpos = pos;
1209 }
1210 /* Skip queries */
1211 limit = clib_net_to_host_u16 (h->qdcount);
1212 qp = (dns_query_t *) curpos;
1213 qp += limit;
1214 curpos = (u8 *) qp;
1215
1216 /* Parse answers */
1217 limit = clib_net_to_host_u16 (h->anscount);
1218
1219 for (i = 0; i < limit; i++)
1220 {
Dave Barach52925382017-11-16 10:01:12 -05001221 pos = pos2 = curpos;
1222 pointer_chase = 0;
Dave Barach65457162017-10-10 17:53:14 -04001223
1224 /* Expect pointer chases in the answer section... */
Dave Barach52925382017-11-16 10:01:12 -05001225 if ((pos2[0] & 0xC0) == 0xC0)
Dave Barach65457162017-10-10 17:53:14 -04001226 {
Dave Barach52925382017-11-16 10:01:12 -05001227 pos = pos2 + 2;
1228 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1229 pointer_chase = 1;
Dave Barach65457162017-10-10 17:53:14 -04001230 }
1231
Dave Barach52925382017-11-16 10:01:12 -05001232 len = *pos2++;
1233
1234 while (len)
1235 {
1236 pos2 += len;
1237 if ((pos2[0] & 0xc0) == 0xc0)
1238 {
1239 /*
1240 * If we've already done one pointer chase,
1241 * do not move the pos pointer.
1242 */
1243 if (pointer_chase == 0)
1244 pos = pos2 + 2;
1245 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1246 len = *pos2++;
1247 pointer_chase = 1;
1248 }
1249 else
1250 len = *pos2++;
1251 }
1252
1253 if (pointer_chase == 0)
1254 pos = pos2;
1255
1256 rr = (dns_rr_t *) pos;
Dave Barach65457162017-10-10 17:53:14 -04001257
1258 switch (clib_net_to_host_u16 (rr->type))
1259 {
1260 case DNS_TYPE_A:
1261 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1262 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1263 rmp->ip4_set = 1;
1264 ttl = clib_net_to_host_u32 (rr->ttl);
1265 if (min_ttlp && *min_ttlp > ttl)
1266 *min_ttlp = ttl;
1267 break;
1268 case DNS_TYPE_AAAA:
1269 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1270 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1271 ttl = clib_net_to_host_u32 (rr->ttl);
1272 if (min_ttlp && *min_ttlp > ttl)
1273 *min_ttlp = ttl;
1274 rmp->ip6_set = 1;
1275 break;
Dave Barach52925382017-11-16 10:01:12 -05001276
Dave Barach65457162017-10-10 17:53:14 -04001277 default:
1278 break;
1279 }
1280 /* Might as well stop ASAP */
1281 if (rmp->ip4_set && rmp->ip6_set)
1282 break;
Dave Barach52925382017-11-16 10:01:12 -05001283 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1284 curpos = pos;
Dave Barach65457162017-10-10 17:53:14 -04001285 }
1286
1287 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1288 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1289 return 0;
1290}
1291
Dave Barachd2080152017-10-20 09:21:35 -04001292int
1293vnet_dns_response_to_name (u8 * response,
1294 vl_api_dns_resolve_ip_reply_t * rmp,
1295 u32 * min_ttlp)
1296{
1297 dns_header_t *h;
1298 dns_query_t *qp;
1299 dns_rr_t *rr;
1300 int i, limit;
1301 u8 len;
Dave Barach52925382017-11-16 10:01:12 -05001302 u8 *curpos, *pos, *pos2;
Dave Barachd2080152017-10-20 09:21:35 -04001303 u16 flags;
1304 u16 rcode;
1305 u8 *name;
1306 u32 ttl;
1307 u8 *junk __attribute__ ((unused));
1308 int name_set = 0;
Dave Barach52925382017-11-16 10:01:12 -05001309 int pointer_chase;
Dave Barachd2080152017-10-20 09:21:35 -04001310
1311 h = (dns_header_t *) response;
1312 flags = clib_net_to_host_u16 (h->flags);
1313 rcode = flags & DNS_RCODE_MASK;
1314
1315 /* See if the response is OK, etc. */
1316 switch (rcode)
1317 {
1318 default:
1319 case DNS_RCODE_NO_ERROR:
1320 break;
1321
1322 case DNS_RCODE_NAME_ERROR:
1323 case DNS_RCODE_FORMAT_ERROR:
1324 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1325
1326 case DNS_RCODE_SERVER_FAILURE:
1327 case DNS_RCODE_NOT_IMPLEMENTED:
1328 case DNS_RCODE_REFUSED:
1329 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1330 }
1331
1332 /* No answers? Loser... */
1333 if (clib_net_to_host_u16 (h->anscount) < 1)
1334 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1335
1336 curpos = (u8 *) (h + 1);
1337
1338 /* Skip the name we asked about */
1339 pos = curpos;
1340 len = *pos++;
1341 /* Should never happen, but stil... */
1342 if ((len & 0xC0) == 0xC0)
1343 curpos += 2;
1344 else
1345 {
1346 /* skip the name / label-set */
1347 while (len)
1348 {
1349 pos += len;
1350 len = *pos++;
1351 }
1352 curpos = pos;
1353 }
1354 /* Skip queries */
1355 limit = clib_net_to_host_u16 (h->qdcount);
1356 qp = (dns_query_t *) curpos;
1357 qp += limit;
1358 curpos = (u8 *) qp;
1359
1360 /* Parse answers */
1361 limit = clib_net_to_host_u16 (h->anscount);
1362
1363 for (i = 0; i < limit; i++)
1364 {
Dave Barach52925382017-11-16 10:01:12 -05001365 pos = pos2 = curpos;
1366 pointer_chase = 0;
Dave Barachd2080152017-10-20 09:21:35 -04001367
1368 /* Expect pointer chases in the answer section... */
Dave Barach52925382017-11-16 10:01:12 -05001369 if ((pos2[0] & 0xC0) == 0xC0)
Dave Barachd2080152017-10-20 09:21:35 -04001370 {
Dave Barach52925382017-11-16 10:01:12 -05001371 pos = pos2 + 2;
1372 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1373 pointer_chase = 1;
Dave Barachd2080152017-10-20 09:21:35 -04001374 }
1375
Dave Barach52925382017-11-16 10:01:12 -05001376 len = *pos2++;
1377
1378 while (len)
1379 {
1380 pos2 += len;
1381 if ((pos2[0] & 0xc0) == 0xc0)
1382 {
1383 /*
1384 * If we've already done one pointer chase,
1385 * do not move the pos pointer.
1386 */
1387 if (pointer_chase == 0)
1388 pos = pos2 + 2;
1389 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1390 len = *pos2++;
1391 pointer_chase = 1;
1392 }
1393 else
1394 len = *pos2++;
1395 }
1396
1397 if (pointer_chase == 0)
1398 pos = pos2;
1399
1400 rr = (dns_rr_t *) pos;
Dave Barachd2080152017-10-20 09:21:35 -04001401
1402 switch (clib_net_to_host_u16 (rr->type))
1403 {
1404 case DNS_TYPE_PTR:
Dave Barach97494502017-11-04 09:44:38 -04001405 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
Dave Barachd2080152017-10-20 09:21:35 -04001406 memcpy (rmp->name, name, vec_len (name));
1407 ttl = clib_net_to_host_u32 (rr->ttl);
Dave Barach52925382017-11-16 10:01:12 -05001408 if (min_ttlp)
Dave Barachd2080152017-10-20 09:21:35 -04001409 *min_ttlp = ttl;
1410 rmp->name[vec_len (name)] = 0;
1411 name_set = 1;
1412 break;
1413 default:
1414 break;
1415 }
1416 /* Might as well stop ASAP */
1417 if (name_set == 1)
1418 break;
Dave Barach52925382017-11-16 10:01:12 -05001419 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1420 curpos = pos;
Dave Barachd2080152017-10-20 09:21:35 -04001421 }
1422
1423 if (name_set == 0)
1424 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1425 return 0;
1426}
1427
Dave Barach65457162017-10-10 17:53:14 -04001428static void
1429vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1430{
1431 dns_main_t *dm = &dns_main;
1432 vl_api_dns_resolve_name_reply_t *rmp;
1433 dns_cache_entry_t *ep;
Dave Barach97494502017-11-04 09:44:38 -04001434 dns_pending_request_t _t0, *t0 = &_t0;
Dave Barach65457162017-10-10 17:53:14 -04001435 int rv;
1436
1437 /* Sanitize the name slightly */
1438 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1439
Dave Barach97494502017-11-04 09:44:38 -04001440 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1441 t0->client_index = mp->client_index;
1442 t0->client_context = mp->context;
1443
1444 rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
Dave Barach65457162017-10-10 17:53:14 -04001445
1446 /* Error, e.g. not enabled? Tell the user */
1447 if (rv < 0)
1448 {
1449 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1450 return;
1451 }
1452
1453 /* Resolution pending? Don't reply... */
1454 if (ep == 0)
1455 return;
1456
1457 /* *INDENT-OFF* */
1458 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1459 ({
1460 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1461 rmp->retval = clib_host_to_net_u32 (rv);
1462 }));
1463 /* *INDENT-ON* */
1464
1465 /*
1466 * dns_resolve_name leaves the cache locked when it returns
1467 * a cached result, so unlock it here.
1468 */
1469 dns_cache_unlock (dm);
1470}
1471
Dave Barachd2080152017-10-20 09:21:35 -04001472static void
1473vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1474{
1475 dns_main_t *dm = &dns_main;
1476 vl_api_dns_resolve_ip_reply_t *rmp;
1477 dns_cache_entry_t *ep;
1478 int rv;
1479 int i, len;
1480 u8 *lookup_name = 0;
1481 u8 digit, nybble;
Dave Barach97494502017-11-04 09:44:38 -04001482 dns_pending_request_t _t0, *t0 = &_t0;
Dave Barachd2080152017-10-20 09:21:35 -04001483
1484 if (mp->is_ip6)
1485 {
1486 for (i = 15; i >= 0; i--)
1487 {
1488 digit = mp->address[i];
1489 nybble = (digit & 0x0F);
1490 if (nybble > 9)
1491 vec_add1 (lookup_name, (nybble - 10) + 'a');
1492 else
1493 vec_add1 (lookup_name, nybble + '0');
1494 vec_add1 (lookup_name, '.');
1495 nybble = (digit & 0xF0) >> 4;
1496 if (nybble > 9)
1497 vec_add1 (lookup_name, (nybble - 10) + 'a');
1498 else
1499 vec_add1 (lookup_name, nybble + '0');
1500 vec_add1 (lookup_name, '.');
1501 }
1502 len = vec_len (lookup_name);
1503 vec_validate (lookup_name, len + 8);
1504 memcpy (lookup_name + len, "ip6.arpa", 8);
1505 }
1506 else
1507 {
1508 for (i = 3; i >= 0; i--)
1509 {
1510 digit = mp->address[i];
1511 lookup_name = format (lookup_name, "%d.", digit);
1512 }
1513 lookup_name = format (lookup_name, "in-addr.arpa");
1514 }
1515
1516 vec_add1 (lookup_name, 0);
1517
Dave Barach97494502017-11-04 09:44:38 -04001518 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1519 t0->client_index = mp->client_index;
1520 t0->client_context = mp->context;
1521
1522 rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
Dave Barachd2080152017-10-20 09:21:35 -04001523
1524 vec_free (lookup_name);
1525
1526 /* Error, e.g. not enabled? Tell the user */
1527 if (rv < 0)
1528 {
1529 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1530 return;
1531 }
1532
1533 /* Resolution pending? Don't reply... */
1534 if (ep == 0)
1535 return;
1536
1537 /* *INDENT-OFF* */
1538 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1539 ({
1540 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1541 rmp->retval = clib_host_to_net_u32 (rv);
1542 }));
1543 /* *INDENT-ON* */
1544
1545 /*
Dave Barach97494502017-11-04 09:44:38 -04001546 * vnet_dns_resolve_name leaves the cache locked when it returns
Dave Barachd2080152017-10-20 09:21:35 -04001547 * a cached result, so unlock it here.
1548 */
1549 dns_cache_unlock (dm);
1550}
1551
Dave Barach65457162017-10-10 17:53:14 -04001552#define vl_msg_name_crc_list
1553#include <vpp/api/vpe_all_api_h.h>
1554#undef vl_msg_name_crc_list
1555
1556static void
1557setup_message_id_table (api_main_t * am)
1558{
1559#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1560 foreach_vl_msg_name_crc_dns;
1561#undef _
1562}
1563
1564#define foreach_dns_api_msg \
1565_(DNS_ENABLE_DISABLE, dns_enable_disable) \
1566_(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
Dave Barachd2080152017-10-20 09:21:35 -04001567_(DNS_RESOLVE_NAME, dns_resolve_name) \
1568_(DNS_RESOLVE_IP, dns_resolve_ip)
Dave Barach65457162017-10-10 17:53:14 -04001569
1570static clib_error_t *
1571dns_api_hookup (vlib_main_t * vm)
1572{
1573#define _(N,n) \
1574 vl_msg_api_set_handlers(VL_API_##N, #n, \
1575 vl_api_##n##_t_handler, \
1576 vl_noop_handler, \
1577 vl_api_##n##_t_endian, \
1578 vl_api_##n##_t_print, \
1579 sizeof(vl_api_##n##_t), 1);
1580 foreach_dns_api_msg;
1581#undef _
1582
1583 setup_message_id_table (&api_main);
1584 return 0;
1585}
1586
1587VLIB_API_INIT_FUNCTION (dns_api_hookup);
1588
1589
1590static clib_error_t *
1591dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1592{
1593 dns_main_t *dm = &dns_main;
1594
1595 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1596 {
1597 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1598 ;
1599 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1600 ;
1601 else
1602 return clib_error_return (0, "unknown input `%U'",
1603 format_unformat_error, input);
1604 }
1605 return 0;
1606}
1607
1608VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1609
1610static clib_error_t *
1611dns_init (vlib_main_t * vm)
1612{
1613 dns_main_t *dm = &dns_main;
1614
1615 dm->vlib_main = vm;
1616 dm->vnet_main = vnet_get_main ();
1617 dm->name_cache_size = 65535;
1618 dm->max_ttl_in_seconds = 86400;
1619 dm->random_seed = 0xDEADDABE;
1620
Dave Barach65457162017-10-10 17:53:14 -04001621 return 0;
1622}
1623
1624VLIB_INIT_FUNCTION (dns_init);
1625
1626uword
1627unformat_dns_reply (unformat_input_t * input, va_list * args)
1628{
1629 u8 **result = va_arg (*args, u8 **);
1630 u8 **namep = va_arg (*args, u8 **);
1631 ip4_address_t a4;
1632 ip6_address_t a6;
1633 int a4_set = 0;
1634 int a6_set = 0;
1635 u8 *name;
1636 int name_set = 0;
1637 u8 *ce;
1638 u32 qp_offset;
1639 dns_header_t *h;
1640 dns_query_t *qp;
1641 dns_rr_t *rr;
1642 u8 *rru8;
1643
1644 if (unformat (input, "%v", &name))
1645 name_set = 1;
1646
1647 if (unformat (input, "%U", unformat_ip4_address, &a4))
1648 {
1649 a4_set = 1;
1650 if (unformat (input, "%U", unformat_ip6_address, &a6))
1651 a6_set = 1;
1652 }
1653
1654 if (unformat (input, "%U", unformat_ip6_address, &a6))
1655 {
1656 a6_set = 1;
1657 if (unformat (input, "%U", unformat_ip4_address, &a6))
1658 a4_set = 1;
1659 }
1660
1661 /* Must have a name */
1662 if (!name_set)
1663 return 0;
1664
1665 /* Must have at least one address */
1666 if (!(a4_set + a6_set))
1667 return 0;
1668
1669 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1670 ce = name_to_labels (name);
1671 qp_offset = vec_len (ce);
1672
1673 /* Add space for the query header */
1674 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1675 qp = (dns_query_t *) (ce + qp_offset);
1676
1677 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1678 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1679
1680 /* Punch in space for the dns_header_t */
1681 vec_insert (ce, sizeof (dns_header_t), 0);
1682
1683 h = (dns_header_t *) ce;
1684
1685 /* Fake Transaction ID */
1686 h->id = 0xFFFF;
1687
1688 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1689 h->qdcount = clib_host_to_net_u16 (1);
1690 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1691 h->nscount = 0;
1692 h->arcount = 0;
1693
1694 /* Now append one or two A/AAAA RR's... */
1695 if (a4_set)
1696 {
1697 /* Pointer to the name (DGMS) */
1698 vec_add1 (ce, 0xC0);
1699 vec_add1 (ce, 0x0C);
1700 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1701 rr = (void *) rru8;
1702 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1703 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1704 rr->ttl = clib_host_to_net_u32 (86400);
1705 rr->rdlength = clib_host_to_net_u16 (4);
1706 memcpy (rr->rdata, &a4, sizeof (a4));
1707 }
1708 if (a6_set)
1709 {
1710 /* Pointer to the name (DGMS) */
1711 vec_add1 (ce, 0xC0);
1712 vec_add1 (ce, 0x0C);
1713 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1714 rr = (void *) rru8;
1715 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1716 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1717 rr->ttl = clib_host_to_net_u32 (86400);
1718 rr->rdlength = clib_host_to_net_u16 (16);
1719 memcpy (rr->rdata, &a6, sizeof (a6));
1720 }
1721 *result = ce;
1722 if (namep)
1723 *namep = name;
1724 else
1725 vec_free (name);
1726
1727 return 1;
1728}
1729
1730u8 *
1731format_dns_query (u8 * s, va_list * args)
1732{
1733 u8 **curpos = va_arg (*args, u8 **);
1734 int verbose = va_arg (*args, int);
1735 u8 *pos;
1736 dns_query_t *qp;
1737 int len, i;
1738 if (verbose > 1)
1739 s = format (s, " Name: ");
1740
1741 /* Unwind execrated counted-label sheit */
1742 pos = *curpos;
1743 len = *pos++;
1744
1745 while (len)
1746 {
1747 for (i = 0; i < len; i++)
1748 vec_add1 (s, *pos++);
1749
1750 len = *pos++;
1751 if (len)
1752 vec_add1 (s, '.');
1753 else
1754 {
1755 vec_add1 (s, ':');
1756 vec_add1 (s, ' ');
1757 }
1758 }
1759
1760 qp = (dns_query_t *) pos;
1761 if (verbose > 1)
1762 {
1763 switch (clib_net_to_host_u16 (qp->type))
1764 {
1765 case DNS_TYPE_A:
1766 s = format (s, "type A\n");
1767 break;
1768 case DNS_TYPE_AAAA:
1769 s = format (s, "type AAAA\n");
1770 break;
1771 case DNS_TYPE_ALL:
1772 s = format (s, "type ALL\n");
1773 break;
1774
1775 default:
1776 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1777 break;
1778 }
1779 }
1780
1781 pos += sizeof (*qp);
1782
1783 *curpos = pos;
1784 return s;
1785}
1786
1787/**
1788 * format dns reply data
1789 * verbose > 1, dump everything
1790 * verbose == 1, dump all A and AAAA records
1791 * verbose == 0, dump one A record, and one AAAA record
1792 */
1793
1794u8 *
1795format_dns_reply_data (u8 * s, va_list * args)
1796{
1797 u8 *reply = va_arg (*args, u8 *);
1798 u8 **curpos = va_arg (*args, u8 **);
1799 int verbose = va_arg (*args, int);
1800 int *print_ip4 = va_arg (*args, int *);
1801 int *print_ip6 = va_arg (*args, int *);
1802 int len;
1803 u8 *pos, *pos2;
1804 dns_rr_t *rr;
1805 int i;
Dave Barach52925382017-11-16 10:01:12 -05001806 int pointer_chase = 0;
Dave Barach65457162017-10-10 17:53:14 -04001807 u16 *tp;
Dave Barachd2080152017-10-20 09:21:35 -04001808 u16 rrtype_host_byte_order;
Dave Barach65457162017-10-10 17:53:14 -04001809
1810 pos = pos2 = *curpos;
1811
1812 if (verbose > 1)
1813 s = format (s, " ");
1814
1815 /* chase pointer? almost always yes here... */
Dave Barach52925382017-11-16 10:01:12 -05001816 if ((pos2[0] & 0xc0) == 0xc0)
Dave Barach65457162017-10-10 17:53:14 -04001817 {
Dave Barach52925382017-11-16 10:01:12 -05001818 pos = pos2 + 2;
1819 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1820 pointer_chase = 1;
Dave Barach65457162017-10-10 17:53:14 -04001821 }
1822
1823 len = *pos2++;
1824
1825 while (len)
1826 {
1827 for (i = 0; i < len; i++)
1828 {
1829 if (verbose > 1)
1830 vec_add1 (s, *pos2);
1831 pos2++;
1832 }
Dave Barach52925382017-11-16 10:01:12 -05001833 if ((pos2[0] & 0xc0) == 0xc0)
1834 {
1835 /*
1836 * If we've already done one pointer chase,
1837 * do not move the pos pointer.
1838 */
1839 if (pointer_chase == 0)
1840 pos = pos2 + 2;
1841 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1842 len = *pos2++;
1843 pointer_chase = 1;
1844 }
1845 else
1846 len = *pos2++;
Dave Barach65457162017-10-10 17:53:14 -04001847 if (len)
1848 {
1849 if (verbose > 1)
1850 vec_add1 (s, '.');
1851 }
1852 else
1853 {
1854 if (verbose > 1)
1855 vec_add1 (s, ' ');
1856 }
1857 }
1858
Dave Barach52925382017-11-16 10:01:12 -05001859 if (pointer_chase == 0)
Dave Barach65457162017-10-10 17:53:14 -04001860 pos = pos2;
1861
1862 rr = (dns_rr_t *) pos;
Dave Barachd2080152017-10-20 09:21:35 -04001863 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
Dave Barach65457162017-10-10 17:53:14 -04001864
Dave Barachd2080152017-10-20 09:21:35 -04001865 switch (rrtype_host_byte_order)
Dave Barach65457162017-10-10 17:53:14 -04001866 {
1867 case DNS_TYPE_A:
1868 if (verbose > 1)
1869 {
1870 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1871 format_ip4_address, rr->rdata);
1872 }
1873 else
1874 {
1875 if (*print_ip4)
1876 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1877 clib_net_to_host_u32 (rr->ttl));
1878 if (verbose == 0)
1879 *print_ip4 = 0;
1880
1881 }
1882 pos += sizeof (*rr) + 4;
1883 break;
1884
1885 case DNS_TYPE_AAAA:
1886 if (verbose > 1)
1887 {
1888 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1889 format_ip6_address, rr->rdata);
1890 }
1891 else
1892 {
1893 if (*print_ip6)
1894 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1895 clib_net_to_host_u32 (rr->ttl));
1896 if (verbose == 0)
1897 *print_ip6 = 0;
1898 }
1899 pos += sizeof (*rr) + 16;
1900 break;
1901
1902 case DNS_TYPE_TEXT:
1903 if (verbose > 1)
1904 {
1905 s = format (s, "TEXT: ");
1906 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1907 vec_add1 (s, rr->rdata[i]);
1908 vec_add1 (s, '\n');
1909 }
1910 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1911 break;
1912
Dave Barach0cb01bd2017-10-16 14:39:52 -04001913 case DNS_TYPE_HINFO:
1914 {
1915 /* Two counted strings. DGMS */
1916 u8 *len;
1917 u8 *curpos;
1918 int i;
1919 if (verbose > 1)
1920 {
1921 s = format (s, "HINFO: ");
1922 len = rr->rdata;
1923 curpos = len + 1;
1924 for (i = 0; i < *len; i++)
1925 vec_add1 (s, *curpos++);
1926
1927 vec_add1 (s, ' ');
1928 len = curpos++;
1929 for (i = 0; i < *len; i++)
1930 vec_add1 (s, *curpos++);
1931
1932 vec_add1 (s, '\n');
1933 }
1934 }
1935 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1936 break;
1937
Dave Barach65457162017-10-10 17:53:14 -04001938 case DNS_TYPE_NAMESERVER:
1939 if (verbose > 1)
1940 {
1941 s = format (s, "Nameserver: ");
1942 pos2 = rr->rdata;
1943
1944 /* chase pointer? */
Dave Barach52925382017-11-16 10:01:12 -05001945 if ((pos2[0] & 0xc0) == 0xc0)
1946 {
1947 pos = pos2 + 2;
1948 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1949 }
Dave Barach65457162017-10-10 17:53:14 -04001950
1951 len = *pos2++;
1952
1953 while (len)
1954 {
1955 for (i = 0; i < len; i++)
1956 vec_add1 (s, *pos2++);
1957
1958 /* chase pointer, typically to offset 12... */
1959 if (pos2[0] == 0xC0)
1960 pos2 = reply + pos2[1];
1961
1962 len = *pos2++;
1963 if (len)
1964 vec_add1 (s, '.');
1965 else
1966 vec_add1 (s, '\n');
1967 }
1968 }
1969 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1970 break;
1971
1972 case DNS_TYPE_MAIL_EXCHANGE:
1973 if (verbose > 1)
1974 {
1975 tp = (u16 *) rr->rdata;
1976
1977 s = format (s, "Mail Exchange: Preference %d ", (u32)
1978 clib_net_to_host_u16 (*tp));
1979
1980 pos2 = rr->rdata + 2;
1981
1982 /* chase pointer? */
1983 if (pos2[0] == 0xc0)
1984 pos2 = reply + pos2[1];
1985
1986 len = *pos2++;
1987
1988 while (len)
1989 {
1990 for (i = 0; i < len; i++)
1991 vec_add1 (s, *pos2++);
1992
1993 /* chase pointer */
1994 if (pos2[0] == 0xC0)
1995 pos2 = reply + pos2[1];
1996
1997 len = *pos2++;
1998 if (len)
1999 vec_add1 (s, '.');
2000 else
2001 vec_add1 (s, '\n');
2002 }
2003 }
2004
2005 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2006 break;
2007
Dave Barachd2080152017-10-20 09:21:35 -04002008 case DNS_TYPE_PTR:
Dave Barach65457162017-10-10 17:53:14 -04002009 case DNS_TYPE_CNAME:
2010 if (verbose > 1)
2011 {
2012 tp = (u16 *) rr->rdata;
2013
Dave Barachd2080152017-10-20 09:21:35 -04002014 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
2015 s = format (s, "CNAME: ");
2016 else
2017 s = format (s, "PTR: ");
Dave Barach65457162017-10-10 17:53:14 -04002018
2019 pos2 = rr->rdata;
2020
2021 /* chase pointer? */
2022 if (pos2[0] == 0xc0)
2023 pos2 = reply + pos2[1];
2024
2025 len = *pos2++;
2026
2027 while (len)
2028 {
2029 for (i = 0; i < len; i++)
2030 vec_add1 (s, *pos2++);
2031
2032 /* chase pointer */
2033 if (pos2[0] == 0xC0)
2034 pos2 = reply + pos2[1];
2035
2036 len = *pos2++;
2037 if (len)
2038 vec_add1 (s, '.');
2039 else
2040 vec_add1 (s, '\n');
2041 }
2042 }
2043 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2044 break;
2045
2046 default:
2047 if (verbose > 1)
2048 s = format (s, "type %d: len %d\n",
2049 (int) clib_net_to_host_u16 (rr->type),
2050 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
2051 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2052 break;
2053 }
2054
2055 *curpos = pos;
2056
2057 return s;
2058}
2059
2060u8 *
2061format_dns_reply (u8 * s, va_list * args)
2062{
2063 u8 *reply_as_u8 = va_arg (*args, u8 *);
2064 int verbose = va_arg (*args, int);
2065 dns_header_t *h;
2066 u16 id, flags;
2067 u8 *curpos;
2068 int i;
2069 int print_ip4 = 1;
2070 int print_ip6 = 1;
2071
2072 h = (dns_header_t *) reply_as_u8;
2073 id = clib_net_to_host_u16 (h->id);
2074 flags = clib_net_to_host_u16 (h->flags);
2075
2076 if (verbose > 1)
2077 {
2078 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2079 id);
2080 s = format (s, " %s %s %s %s\n",
2081 (flags & DNS_RA) ? "recur" : "no-recur",
2082 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2083 (flags & DNS_TC) ? "trunc" : "no-trunc",
2084 (flags & DNS_AA) ? "auth" : "non-auth");
2085 s = format (s, " %d queries, %d answers, %d name-servers,"
2086 " %d add'l recs\n",
2087 clib_net_to_host_u16 (h->qdcount),
2088 clib_net_to_host_u16 (h->anscount),
2089 clib_net_to_host_u16 (h->nscount),
2090 clib_net_to_host_u16 (h->arcount));
2091 }
2092
2093 curpos = (u8 *) (h + 1);
2094
2095 if (h->qdcount)
2096 {
2097 if (verbose > 1)
2098 s = format (s, " Queries:\n");
2099 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2100 {
2101 /* The query is variable-length, so curpos is a value-result parm */
2102 s = format (s, "%U", format_dns_query, &curpos, verbose);
2103 }
2104 }
2105 if (h->anscount)
2106 {
2107 if (verbose > 1)
2108 s = format (s, " Replies:\n");
2109
2110 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2111 {
2112 /* curpos is a value-result parm */
2113 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2114 verbose, &print_ip4, &print_ip6);
2115 }
2116 }
2117 return s;
2118}
2119
2120u8 *
2121format_dns_cache (u8 * s, va_list * args)
2122{
2123 dns_main_t *dm = va_arg (*args, dns_main_t *);
2124 f64 now = va_arg (*args, f64);
2125 int verbose = va_arg (*args, int);
2126 u8 *name = va_arg (*args, u8 *);
2127 dns_cache_entry_t *ep;
2128 char *ss;
2129 uword *p;
2130
2131 if (dm->is_enabled == 0)
2132 {
2133 s = format (s, "The DNS cache is disabled...");
2134 return s;
2135 }
2136
2137 if (pool_elts (dm->entries) == 0)
2138 {
2139 s = format (s, "The DNS cache is empty...");
2140 return s;
2141 }
2142
2143 dns_cache_lock (dm);
2144
2145 if (name)
2146 {
2147 p = hash_get_mem (dm->cache_entry_by_name, name);
2148 if (!p)
2149 {
2150 s = format (s, "%s is not in the cache...", name);
2151 dns_cache_unlock (dm);
2152 return (s);
2153 }
2154
2155 ep = pool_elt_at_index (dm->entries, p[0]);
2156 /* Magic to spit out a C-initializer to research hemorrhoids... */
2157 if (verbose == 3)
2158 {
2159 int i, j;
2160 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2161 s = format (s, "{\n");
2162 j = 0;
2163 for (i = 0; i < vec_len (ep->dns_response); i++)
2164 {
2165 if (j++ == 8)
2166 {
2167 j = 0;
2168 vec_add1 (s, '\n');
2169 }
2170 s = format (s, "0x%02x, ", ep->dns_response[i]);
2171 }
2172 s = format (s, "};\n");
2173 }
2174 else
2175 {
2176 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2177 {
2178 ASSERT (ep->dns_response);
2179 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2180 ss = "[S] ";
2181 else
2182 ss = " ";
2183
Dave Barach0cb01bd2017-10-16 14:39:52 -04002184 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2185 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2186 else
2187 s = format (s, "%s%s -> %U", ss, ep->name,
2188 format_dns_reply, ep->dns_response, verbose);
Dave Barach65457162017-10-10 17:53:14 -04002189 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2190 {
2191 f64 time_left = ep->expiration_time - now;
2192 if (time_left > 0.0)
2193 s = format (s, " TTL left %.1f", time_left);
2194 else
2195 s = format (s, " EXPIRED");
2196 }
2197 }
2198 else
2199 {
2200 ASSERT (ep->dns_request);
2201 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2202 verbose);
2203 }
2204 vec_add1 (s, '\n');
2205 }
2206 return s;
2207 }
2208
2209 /* *INDENT-OFF* */
2210 pool_foreach (ep, dm->entries,
2211 ({
2212 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2213 {
2214 ASSERT (ep->dns_response);
2215 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2216 ss = "[S] ";
2217 else
2218 ss = " ";
2219
Dave Barach0cb01bd2017-10-16 14:39:52 -04002220 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2221 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2222 else
2223 s = format (s, "%s%s -> %U", ss, ep->name,
2224 format_dns_reply,
2225 ep->dns_response,
2226 verbose);
Dave Barach65457162017-10-10 17:53:14 -04002227 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2228 {
2229 f64 time_left = ep->expiration_time - now;
2230 if (time_left > 0.0)
2231 s = format (s, " TTL left %.1f", time_left);
2232 else
2233 s = format (s, " EXPIRED");
Dave Barach0cb01bd2017-10-16 14:39:52 -04002234
2235 if (verbose > 2)
2236 s = format (s, " %d client notifications pending\n",
Dave Barach97494502017-11-04 09:44:38 -04002237 vec_len(ep->pending_requests));
Dave Barach65457162017-10-10 17:53:14 -04002238 }
2239 }
2240 else
2241 {
2242 ASSERT (ep->dns_request);
2243 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2244 verbose);
2245 }
2246 vec_add1 (s, '\n');
2247 }));
2248 /* *INDENT-ON* */
2249
2250 dns_cache_unlock (dm);
2251
2252 return s;
2253}
2254
2255static clib_error_t *
2256show_dns_cache_command_fn (vlib_main_t * vm,
2257 unformat_input_t * input, vlib_cli_command_t * cmd)
2258{
2259 dns_main_t *dm = &dns_main;
2260 int verbose = 0;
2261 u8 *name = 0;
2262 f64 now = vlib_time_now (vm);
2263
2264 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2265 {
2266 if (unformat (input, "verbose %d", &verbose))
2267 ;
2268 else if (unformat (input, "verbose"))
2269 verbose = 1;
2270 else if (unformat (input, "name %s", &name))
2271 ;
2272 else
2273 return clib_error_return (0, "unknown input `%U'",
2274 format_unformat_error, input);
2275 }
2276
2277 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2278
2279 return 0;
2280}
2281
2282/* *INDENT-OFF* */
2283VLIB_CLI_COMMAND (show_dns_cache_command) =
2284{
2285 .path = "show dns cache",
2286 .short_help = "show dns cache [verbose [nn]]",
2287 .function = show_dns_cache_command_fn,
2288};
2289/* *INDENT-ON* */
2290
2291static clib_error_t *
2292dns_cache_add_del_command_fn (vlib_main_t * vm,
2293 unformat_input_t * input,
2294 vlib_cli_command_t * cmd)
2295{
2296 dns_main_t *dm = &dns_main;
2297 u8 *dns_reply_data;
2298 u8 *name;
2299 int is_add = -1;
2300 int is_clear = -1;
2301 int rv;
2302 clib_error_t *error;
2303
2304 if (unformat (input, "add"))
2305 is_add = 1;
2306 if (unformat (input, "del"))
2307 is_add = 0;
2308 if (unformat (input, "clear"))
2309 is_clear = 1;
2310
2311 if (is_add == -1 && is_clear == -1)
2312 return clib_error_return (0, "add / del / clear required...");
2313
2314 if (is_clear == 1)
2315 {
2316 rv = dns_cache_clear (dm);
2317 switch (rv)
2318 {
2319 case 0:
2320 return 0;
2321
2322 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2323 error = clib_error_return (0, "Name resolution not enabled");
2324 return error;
2325 }
2326 }
2327
2328 /* Delete (by name)? */
2329 if (is_add == 0)
2330 {
2331 if (unformat (input, "%v", &name))
2332 {
2333 rv = dns_delete_by_name (dm, name);
2334 switch (rv)
2335 {
2336 case VNET_API_ERROR_NO_SUCH_ENTRY:
2337 error = clib_error_return (0, "%v not in the cache...", name);
2338 vec_free (name);
2339 return error;
2340
2341 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2342 error = clib_error_return (0, "Name resolution not enabled");
2343 vec_free (name);
2344 return error;
2345
2346 case 0:
2347 vec_free (name);
2348 return 0;
2349
2350 default:
2351 error = clib_error_return (0, "dns_delete_by_name returned %d",
2352 rv);
2353 vec_free (name);
2354 return error;
2355 }
2356 }
2357 return clib_error_return (0, "unknown input `%U'",
2358 format_unformat_error, input);
2359 }
2360
2361 /* Note: dns_add_static_entry consumes the name vector if OK... */
2362 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2363 {
2364 rv = dns_add_static_entry (dm, name, dns_reply_data);
2365 switch (rv)
2366 {
2367 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2368 vec_free (name);
2369 vec_free (dns_reply_data);
2370 return clib_error_return (0, "%v already in the cache...", name);
2371 case 0:
2372 return 0;
2373
2374 default:
2375 return clib_error_return (0, "dns_add_static_entry returned %d",
2376 rv);
2377 }
2378 }
2379
2380 return 0;
2381}
2382
2383/* *INDENT-OFF* */
2384VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2385{
2386 .path = "dns cache",
2387 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2388 .function = dns_cache_add_del_command_fn,
2389};
2390/* *INDENT-ON* */
2391
Dave Barach580eda72018-01-09 17:00:00 -05002392#define DNS_FORMAT_TEST 1
Dave Barach65457162017-10-10 17:53:14 -04002393
2394#if DNS_FORMAT_TEST > 0
2395#if 0
2396/* yahoo.com */
2397static u8 dns_reply_data_initializer[] =
2398 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2399 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2400 0x0, /* null lbl */
2401 0x0, 0xff, /* type ALL */
2402 0x0, 0x1, /* class IN */
2403 0xc0, 0xc, /* pointer to yahoo.com name */
2404 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2405 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2406 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2407 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2408 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2409 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2410 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2411 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2412 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2413 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2414 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2415 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2416 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2417 0x6e,
2418 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2419 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2420 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2421 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2422 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2423 0x0,
2424 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2425 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2426 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2427 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2428 0x0,
2429 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2430 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2431 0x0,
2432 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2433 0x0,
2434 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2435 0x0,
2436 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2437 0x6f,
2438 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2439 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2440 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2441 0x2, 0x58
2442};
2443
2444/* www.cisco.com, has no addresses in reply */
2445static u8 dns_reply_data_initializer[] = {
2446 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2447 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2448 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2449
2450 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2451 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2452 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2453 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2454 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2455};
Dave Barach52925382017-11-16 10:01:12 -05002456
2457/* bind8 (linux widget, w/ nasty double pointer chasees */
2458static u8 dns_reply_data_initializer[] = {
2459 /* 0 */
2460 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2461 /* 8 */
2462 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2463 /* 16 */
2464 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2465 /* 24 */
2466 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2467 /* 32 */
2468 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2469 /* 40 */
2470 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2471 /* 48 */
2472 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2473
2474 /* 56 */
2475 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2476
2477 /* 64 */
2478 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2479 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2480 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2481 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2482 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2483 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2484 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2485 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2486 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2487 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2488 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2489 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2490 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2491 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2492 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2493 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2494 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2495 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2496 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2497 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2498 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2499 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2500 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2501 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2502 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2503 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2504 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2505 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2506 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2507 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2508 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2509 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2510 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2511 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2512 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2513 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2514 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2515 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2516 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2517 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2518 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2519 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2520 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2521 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2522 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2523 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2524 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2525 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2526};
2527
Dave Barach65457162017-10-10 17:53:14 -04002528/* google.com */
2529static u8 dns_reply_data_initializer[] =
2530 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2531 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2532 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2533 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2534 0x2b,
2535 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2536 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2537 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2538 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2539 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2540 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2541 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2542 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2543 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2544 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2545 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2546 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2547 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2548 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2549 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2550 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2551 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2552 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2553 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2554 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2555 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2556 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2557 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2558 0x57,
2559 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2560};
Dave Barach580eda72018-01-09 17:00:00 -05002561
2562#else
2563/* www.weatherlink.com */
2564static u8 dns_reply_data_initializer[] = {
2565 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2566 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2567 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2568 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2569 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2570 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2571 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2572 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2573 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2574};
2575
Dave Barach65457162017-10-10 17:53:14 -04002576#endif
2577
2578static clib_error_t *
2579test_dns_fmt_command_fn (vlib_main_t * vm,
2580 unformat_input_t * input, vlib_cli_command_t * cmd)
2581{
2582 u8 *dns_reply_data = 0;
2583 int verbose = 0;
2584 int rv;
2585 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2586
2587 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2588 {
2589 if (unformat (input, "verbose %d", &verbose))
2590 ;
2591 else if (unformat (input, "verbose"))
2592 verbose = 1;
2593 else
2594 return clib_error_return (0, "unknown input `%U'",
2595 format_unformat_error, input);
2596 }
2597
2598 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2599
2600 memcpy (dns_reply_data, dns_reply_data_initializer,
2601 ARRAY_LEN (dns_reply_data_initializer));
2602
2603 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2604
Dave Barachb7b92992018-10-17 10:38:51 -04002605 clib_memset (rmp, 0, sizeof (*rmp));
Dave Barach65457162017-10-10 17:53:14 -04002606
2607 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2608
2609 switch (rv)
2610 {
2611 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2612 vlib_cli_output (vm, "no addresses found...");
2613 break;
2614
2615 default:
2616 vlib_cli_output (vm, "response to reply returned %d", rv);
2617 break;
2618
2619 case 0:
2620 if (rmp->ip4_set)
2621 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2622 (ip4_address_t *) rmp->ip4_address);
2623 if (rmp->ip6_set)
2624 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2625 (ip6_address_t *) rmp->ip6_address);
2626 break;
2627 }
2628
2629 vec_free (dns_reply_data);
2630
2631 return 0;
2632}
2633
2634
2635/* *INDENT-OFF* */
2636VLIB_CLI_COMMAND (test_dns_fmt_command) =
2637{
2638 .path = "test dns format",
2639 .short_help = "test dns format",
2640 .function = test_dns_fmt_command_fn,
2641};
2642/* *INDENT-ON* */
2643
2644static clib_error_t *
2645test_dns_unfmt_command_fn (vlib_main_t * vm,
2646 unformat_input_t * input, vlib_cli_command_t * cmd)
2647{
2648 u8 *dns_reply_data = 0;
2649 int verbose = 0;
2650 int reply_set = 0;
2651
2652 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2653 {
2654 if (unformat (input, "verbose %d", &verbose))
2655 ;
2656 else if (unformat (input, "verbose"))
2657 verbose = 1;
2658 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2659 reply_set = 1;
2660 else
2661 return clib_error_return (0, "unknown input `%U'",
2662 format_unformat_error, input);
2663 }
2664
2665 if (reply_set == 0)
2666 return clib_error_return (0, "dns data not set...");
2667
2668 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2669
2670 vec_free (dns_reply_data);
2671
2672 return 0;
2673}
2674
2675/* *INDENT-OFF* */
2676VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2677{
2678 .path = "test dns unformat",
2679 .short_help = "test dns unformat <name> [ip4][ip6]",
2680 .function = test_dns_unfmt_command_fn,
2681};
2682/* *INDENT-ON* */
Dave Barach0cb01bd2017-10-16 14:39:52 -04002683
2684static clib_error_t *
2685test_dns_expire_command_fn (vlib_main_t * vm,
2686 unformat_input_t * input,
2687 vlib_cli_command_t * cmd)
2688{
2689 dns_main_t *dm = &dns_main;
Filip Tehlar24b77d12019-03-12 06:17:59 -07002690 u8 *name = 0;
Dave Barach0cb01bd2017-10-16 14:39:52 -04002691 uword *p;
2692 clib_error_t *e;
2693 dns_cache_entry_t *ep;
2694
2695 if (unformat (input, "%v", &name))
2696 {
2697 vec_add1 (name, 0);
2698 _vec_len (name) -= 1;
2699 }
Filip Tehlar24b77d12019-03-12 06:17:59 -07002700 else
2701 return clib_error_return (0, "no name provided");
Dave Barach0cb01bd2017-10-16 14:39:52 -04002702
2703 dns_cache_lock (dm);
2704
2705 p = hash_get_mem (dm->cache_entry_by_name, name);
2706 if (!p)
2707 {
2708 dns_cache_unlock (dm);
2709 e = clib_error_return (0, "%s is not in the cache...", name);
2710 vec_free (name);
2711 return e;
2712 }
2713
2714 ep = pool_elt_at_index (dm->entries, p[0]);
2715
2716 ep->expiration_time = 0;
2717
2718 return 0;
2719}
2720
2721/* *INDENT-OFF* */
2722VLIB_CLI_COMMAND (test_dns_expire_command) =
2723{
2724 .path = "test dns expire",
2725 .short_help = "test dns expire <name>",
2726 .function = test_dns_expire_command_fn,
2727};
2728/* *INDENT-ON* */
Dave Barach65457162017-10-10 17:53:14 -04002729#endif
2730
Dave Barach97494502017-11-04 09:44:38 -04002731void
2732vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
2733 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2734{
2735 clib_warning ("Unimplemented...");
2736}
2737
2738
2739void
2740vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
2741 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2742{
2743 vlib_main_t *vm = dm->vlib_main;
Damjan Marionc8a26c62017-11-24 20:15:23 +01002744 u32 bi = 0;
Dave Barach97494502017-11-04 09:44:38 -04002745 fib_prefix_t prefix;
2746 fib_node_index_t fei;
2747 u32 sw_if_index, fib_index;
2748 ip4_main_t *im4 = &ip4_main;
2749 ip_lookup_main_t *lm4 = &im4->lookup_main;
2750 ip_interface_address_t *ia = 0;
2751 ip4_address_t *src_address;
2752 ip4_header_t *ip;
2753 udp_header_t *udp;
2754 dns_header_t *dh;
2755 vlib_frame_t *f;
2756 u32 *to_next;
2757 u8 *dns_response;
2758 u8 *reply;
2759 vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2760 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2761 u32 ttl, tmp;
2762 u32 qp_offset;
2763 dns_query_t *qp;
2764 dns_rr_t *rr;
2765 u8 *rrptr;
2766 int is_fail = 0;
2767
2768 ASSERT (ep && ep->dns_response);
2769
2770 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2771 {
2772 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
Dave Barachb7b92992018-10-17 10:38:51 -04002773 clib_memset (rnr, 0, sizeof (*rnr));
Dave Barach97494502017-11-04 09:44:38 -04002774 if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2775 {
2776 /* clib_warning ("response_to_reply failed..."); */
2777 is_fail = 1;
2778 }
2779 if (rnr->ip4_set == 0)
2780 {
2781 /* clib_warning ("No A-record..."); */
2782 is_fail = 1;
2783 }
2784 }
2785 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2786 {
Dave Barachb7b92992018-10-17 10:38:51 -04002787 clib_memset (rir, 0, sizeof (*rir));
Dave Barach97494502017-11-04 09:44:38 -04002788 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2789 {
2790 /* clib_warning ("response_to_name failed..."); */
2791 is_fail = 1;
2792 }
2793 }
2794 else
2795 {
2796 clib_warning ("Unknown request type %d", pr->request_type);
2797 return;
2798 }
2799
2800 /* Initialize a buffer */
2801 if (b0 == 0)
2802 {
2803 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2804 return;
2805 b0 = vlib_get_buffer (vm, bi);
2806 }
2807
2808 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2809 vlib_buffer_free_one (vm, b0->next_buffer);
2810
2811 /*
2812 * Reset the buffer. We recycle the DNS request packet in the cache
2813 * hit case, and reply immediately from the request node.
2814 *
2815 * In the resolution-required / deferred case, resetting a freshly-allocated
2816 * buffer won't hurt. We hope.
2817 */
Dave Barach97494502017-11-04 09:44:38 -04002818 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2819 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2820 b0->current_data = 0;
2821 b0->current_length = 0;
2822 b0->total_length_not_including_first_buffer = 0;
2823 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2824 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2825
2826 /* Find a FIB path to the peer we're trying to answer */
2827 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2828 prefix.fp_proto = FIB_PROTOCOL_IP4;
2829 prefix.fp_len = 32;
2830
2831 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2832 if (fib_index == (u32) ~ 0)
2833 {
2834 clib_warning ("no fib table");
2835 return;
2836 }
2837
2838 fei = fib_table_lookup (fib_index, &prefix);
2839
2840 /* Couldn't find route to destination. Bail out. */
2841 if (fei == FIB_NODE_INDEX_INVALID)
2842 {
2843 clib_warning ("no route to DNS server");
2844 return;
2845 }
2846
2847 sw_if_index = fib_entry_get_resolving_interface (fei);
2848
2849 if (sw_if_index == ~0)
2850 {
2851 clib_warning
2852 ("route to %U exists, fei %d, get_resolving_interface returned"
2853 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2854 return;
2855 }
2856
2857 /* *INDENT-OFF* */
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07002858 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
Dave Barach97494502017-11-04 09:44:38 -04002859 ({
2860 src_address = ip_interface_address_get_address (lm4, ia);
2861 goto found_src_address;
2862 }));
2863 /* *INDENT-ON* */
2864
2865 clib_warning ("FIB BUG");
2866 return;
2867
2868found_src_address:
2869
2870 ip = vlib_buffer_get_current (b0);
2871 udp = (udp_header_t *) (ip + 1);
2872 dns_response = (u8 *) (udp + 1);
Dave Barachb7b92992018-10-17 10:38:51 -04002873 clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
Dave Barach97494502017-11-04 09:44:38 -04002874
2875 /*
2876 * Start with the variadic portion of the exercise.
2877 * Turn the name into a set of DNS "labels". Max length
2878 * per label is 63, enforce that.
2879 */
2880 reply = name_to_labels (pr->name);
2881 vec_free (pr->name);
2882
2883 qp_offset = vec_len (reply);
2884
2885 /* Add space for the query header */
2886 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2887
2888 qp = (dns_query_t *) (reply + qp_offset);
2889
2890 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2891 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2892 else
2893 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2894
2895 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2896
2897 /* Punch in space for the dns_header_t */
2898 vec_insert (reply, sizeof (dns_header_t), 0);
2899
2900 dh = (dns_header_t *) reply;
2901
2902 /* Transaction ID = pool index */
2903 dh->id = pr->id;
2904
2905 /* Announce that we did a recursive lookup */
2906 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2907 if (is_fail)
2908 tmp |= DNS_RCODE_NAME_ERROR;
2909 dh->flags = clib_host_to_net_u16 (tmp);
2910 dh->qdcount = clib_host_to_net_u16 (1);
2911 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2912 dh->nscount = 0;
2913 dh->arcount = 0;
2914
2915 /* If the name resolution worked, cough up an appropriate RR */
2916 if (is_fail == 0)
2917 {
2918 /* Add the answer. First, a name pointer (0xC00C) */
2919 vec_add1 (reply, 0xC0);
2920 vec_add1 (reply, 0x0C);
2921
2922 /* Now, add single A-rec RR */
2923 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2924 {
2925 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2926 rr = (dns_rr_t *) rrptr;
2927
2928 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2929 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2930 rr->ttl = clib_host_to_net_u32 (ttl);
2931 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2932 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2933 }
2934 else
2935 {
2936 /* Or a single PTR RR */
2937 u8 *vecname = format (0, "%s", rir->name);
2938 u8 *label_vec = name_to_labels (vecname);
2939 vec_free (vecname);
2940
2941 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2942 rr = (dns_rr_t *) rrptr;
2943 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2944 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2945 rr->ttl = clib_host_to_net_u32 (ttl);
2946 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2947 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2948 vec_free (label_vec);
2949 }
2950 }
2951 clib_memcpy (dns_response, reply, vec_len (reply));
2952
2953 /* Set the packet length */
2954 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2955
2956 /* IP header */
2957 ip->ip_version_and_header_length = 0x45;
2958 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2959 ip->ttl = 255;
2960 ip->protocol = IP_PROTOCOL_UDP;
2961 ip->src_address.as_u32 = src_address->as_u32;
2962 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2963 sizeof (ip4_address_t));
2964 ip->checksum = ip4_header_checksum (ip);
2965
2966 /* UDP header */
2967 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2968 udp->dst_port = pr->dst_port;
2969 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2970 vec_len (reply));
2971 udp->checksum = 0;
2972 vec_free (reply);
2973
2974 /* Ship it to ip4_lookup */
2975 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2976 to_next = vlib_frame_vector_args (f);
2977 to_next[0] = bi;
2978 f->n_vectors = 1;
2979 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2980}
2981
Dave Barach65457162017-10-10 17:53:14 -04002982/*
2983 * fd.io coding-style-patch-verification: ON
2984 *
2985 * Local Variables:
2986 * eval: (c-set-style "gnu")
2987 * End:
2988 */