blob: d361aa11b3b0ec8af001710d6b106d0e12dbac8c [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;
75
76 if (is_enable)
77 {
78 if (vec_len (dm->ip4_name_servers) == 0
79 && (vec_len (dm->ip6_name_servers) == 0))
80 return VNET_API_ERROR_NO_NAME_SERVERS;
81
82 if (dm->cache_entry_by_name == 0)
83 {
84 if (n_vlib_mains > 1)
85 dm->cache_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
86 CLIB_CACHE_LINE_BYTES);
87
88 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
89 }
90
91 dm->is_enabled = 1;
92 }
93 else
94 {
95 dns_cache_clear (dm);
96 dm->is_enabled = 0;
97 }
98 return 0;
99}
100
101static void vl_api_dns_enable_disable_t_handler
102 (vl_api_dns_enable_disable_t * mp)
103{
104 vl_api_dns_enable_disable_reply_t *rmp;
105 dns_main_t *dm = &dns_main;
106 int rv;
107
108 rv = dns_enable_disable (dm, mp->enable);
109
110 REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
111}
112
113static int
114dns6_name_server_add_del (dns_main_t * dm,
115 u8 * server_address_as_u8, int is_add)
116{
117 int i;
118 ip6_address_t *ap;
119
120 if (is_add)
121 {
122 /* Already there? done... */
123 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
124 {
125 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
126 sizeof (ip6_address_t)))
127 return 0;
128 }
129
130 vec_add2 (dm->ip6_name_servers, ap, 1);
131 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
132 }
133 else
134 {
135 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
136 {
137 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
138 sizeof (ip6_address_t)))
139 {
140 vec_delete (dm->ip6_name_servers, 1, i);
141 return 0;
142 }
143 }
144 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
145 }
146 return 0;
147}
148
149static int
150dns4_name_server_add_del (dns_main_t * dm,
151 u8 * server_address_as_u8, int is_add)
152{
153 int i;
154 ip4_address_t *ap;
155
156 if (is_add)
157 {
158 /* Already there? done... */
159 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
160 {
161 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
162 sizeof (ip4_address_t)))
163 return 0;
164 }
165
166 vec_add2 (dm->ip4_name_servers, ap, 1);
167 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
168 }
169 else
170 {
171 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
172 {
173 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
174 sizeof (ip4_address_t)))
175 {
176 vec_delete (dm->ip4_name_servers, 1, i);
177 return 0;
178 }
179 }
180 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
181 }
182 return 0;
183}
184
185static void vl_api_dns_name_server_add_del_t_handler
186 (vl_api_dns_name_server_add_del_t * mp)
187{
188 dns_main_t *dm = &dns_main;
189 vl_api_dns_name_server_add_del_reply_t *rmp;
190 int rv;
191
192 if (mp->is_ip6)
193 rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
194 else
195 rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
196
197 REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
198}
199
200static void
201send_dns4_request (dns_main_t * dm,
202 dns_cache_entry_t * ep, ip4_address_t * server)
203{
204 vlib_main_t *vm = dm->vlib_main;
205 f64 now = vlib_time_now (vm);
206 u32 bi;
207 vlib_buffer_t *b;
208 ip4_header_t *ip;
209 fib_prefix_t prefix;
210 fib_node_index_t fei;
211 u32 sw_if_index, fib_index;
212 udp_header_t *udp;
213 ip4_main_t *im4 = &ip4_main;
214 ip_lookup_main_t *lm4 = &im4->lookup_main;
215 ip_interface_address_t *ia = 0;
216 ip4_address_t *src_address;
217 u8 *dns_request;
218 vlib_frame_t *f;
219 u32 *to_next;
220
221 ASSERT (ep->dns_request);
222
223 /* Find a FIB path to the server */
224 clib_memcpy (&prefix.fp_addr.ip4, server, sizeof (*server));
225 prefix.fp_proto = FIB_PROTOCOL_IP4;
226 prefix.fp_len = 32;
227
228 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
229 if (fib_index == (u32) ~ 0)
230 {
231 clib_warning ("no fib table");
232 return;
233 }
234
235 fei = fib_table_lookup (fib_index, &prefix);
236
237 /* Couldn't find route to destination. Bail out. */
238 if (fei == FIB_NODE_INDEX_INVALID)
239 {
240 clib_warning ("no route to DNS server");
241 return;
242 }
243
244 sw_if_index = fib_entry_get_resolving_interface (fei);
245
246 if (sw_if_index == ~0)
247 {
248 clib_warning
249 ("route to %U exists, fei %d, get_resolving_interface returned"
250 " ~0", fei, format_ip4_address, &prefix.fp_addr);
251 return;
252 }
253
254 /* *INDENT-OFF* */
255 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnummbered */,
256 ({
257 src_address = ip_interface_address_get_address (lm4, ia);
258 goto found_src_address;
259 }));
260 /* *INDENT-ON* */
261
262 clib_warning ("FIB BUG");
263 return;
264
265found_src_address:
266
267 /* Go get a buffer */
268 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
269 return;
270
271 b = vlib_get_buffer (vm, bi);
272 b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
273 vec_len (ep->dns_request);
274 b->total_length_not_including_first_buffer = 0;
275 b->flags =
276 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
277 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
278 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
279
280 ip = vlib_buffer_get_current (b);
281 memset (ip, 0, sizeof (*ip));
282 udp = (udp_header_t *) (ip + 1);
283 memset (udp, 0, sizeof (*udp));
284
285 dns_request = (u8 *) (udp + 1);
286
287 /* IP header */
288 ip->ip_version_and_header_length = 0x45;
289 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
290 ip->ttl = 255;
291 ip->protocol = IP_PROTOCOL_UDP;
292 ip->src_address.as_u32 = src_address->as_u32;
293 ip->dst_address.as_u32 = server->as_u32;
294 ip->checksum = ip4_header_checksum (ip);
295
296 /* UDP header */
297 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
298 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
299 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
300 vec_len (ep->dns_request));
301 udp->checksum = 0;
302
303 /* The actual DNS request */
304 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
305
306 /* Ship it to ip4_lookup */
307 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
308 to_next = vlib_frame_vector_args (f);
309 to_next[0] = bi;
310 f->n_vectors = 1;
311 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
312
313 ep->retry_timer = now + 2.0;
314}
315
316static void
317send_dns6_request (dns_main_t * dm,
318 dns_cache_entry_t * ep, ip6_address_t * server)
319{
320 vlib_main_t *vm = dm->vlib_main;
321 f64 now = vlib_time_now (vm);
322 u32 bi;
323 vlib_buffer_t *b;
324 ip6_header_t *ip;
325 fib_prefix_t prefix;
326 fib_node_index_t fei;
327 u32 sw_if_index, fib_index;
328 udp_header_t *udp;
329 ip6_main_t *im6 = &ip6_main;
330 ip_lookup_main_t *lm6 = &im6->lookup_main;
331 ip_interface_address_t *ia = 0;
332 ip6_address_t *src_address;
333 u8 *dns_request;
334 vlib_frame_t *f;
335 u32 *to_next;
336 int junk __attribute__ ((unused));
337
338 ASSERT (ep->dns_request);
339
340 /* Find a FIB path to the server */
341 clib_memcpy (&prefix.fp_addr, server, sizeof (*server));
342 prefix.fp_proto = FIB_PROTOCOL_IP6;
343 prefix.fp_len = 32;
344
345 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
346 if (fib_index == (u32) ~ 0)
347 {
348 clib_warning ("no fib table");
349 return;
350 }
351
352 fei = fib_table_lookup (fib_index, &prefix);
353
354 /* Couldn't find route to destination. Bail out. */
355 if (fei == FIB_NODE_INDEX_INVALID)
356 {
357 clib_warning ("no route to DNS server");
358 }
359
360 sw_if_index = fib_entry_get_resolving_interface (fei);
361
362 /* *INDENT-OFF* */
363 foreach_ip_interface_address(lm6, ia, sw_if_index, 1 /* honor unnummbered */,
364 ({
365 src_address = ip_interface_address_get_address (lm6, ia);
366 goto found_src_address;
367 }));
368 /* *INDENT-ON* */
369
370 clib_warning ("FIB BUG");
371 return;
372
373found_src_address:
374
375 /* Go get a buffer */
376 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
377 return;
378
379 b = vlib_get_buffer (vm, bi);
380 b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
381 vec_len (ep->dns_request);
382 b->total_length_not_including_first_buffer = 0;
383 b->flags =
384 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
385
386 ip = vlib_buffer_get_current (b);
387 memset (ip, 0, sizeof (*ip));
388 udp = (udp_header_t *) (ip + 1);
389 memset (udp, 0, sizeof (*udp));
390
391 dns_request = (u8 *) (udp + 1);
392
393 /* IP header */
394 ip->ip_version_traffic_class_and_flow_label =
395 clib_host_to_net_u32 (0x6 << 28);
396
397 ip->payload_length =
398 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
399 - sizeof (ip6_header_t));
400 ip->hop_limit = 255;
401 ip->protocol = IP_PROTOCOL_UDP;
402 clib_memcpy (&ip->src_address, src_address, sizeof (ip6_address_t));
403 clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
404
405 /* UDP header */
406 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
407 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
408 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
409 vec_len (ep->dns_request));
410 udp->checksum = 0;
411 udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
412
413 /* The actual DNS request */
414 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
415
416 /* Ship it to ip6_lookup */
417 f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
418 to_next = vlib_frame_vector_args (f);
419 to_next[0] = bi;
420 f->n_vectors = 1;
421
422 ep->retry_timer = now + 2.0;
423}
424
425/**
426 * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
427 * A historical / hysterical micro-TLV scheme. DGMS.
428 */
429u8 *
430name_to_labels (u8 * name)
431{
432 int i;
433 int last_label_index;
434 u8 *rv;
435
436 rv = vec_dup (name);
437
438 /* punch in space for the first length */
439 vec_insert (rv, 1, 0);
440 last_label_index = 0;
441 i = 1;
442
443 while (i < vec_len (rv))
444 {
445 if (rv[i] == '.')
446 {
447 rv[last_label_index] = (i - last_label_index) - 1;
448 if ((i - last_label_index) > 63)
449 clib_warning ("stupid name, label length %d",
450 i - last_label_index);
451 last_label_index = i;
452 rv[i] = 0;
453 }
454 i++;
455 }
456 /* Set the last real label length */
457 rv[last_label_index] = (i - last_label_index) - 1;
458
459 /*
460 * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
461 * where to stop.
462 */
463 vec_add1 (rv, 0);
464 return rv;
465}
466
467/**
468 * arc-function for the above.
469 * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
470 * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
471 */
472u8 *
Dave Barach97494502017-11-04 09:44:38 -0400473vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
Dave Barach65457162017-10-10 17:53:14 -0400474{
475 u8 *reply = 0;
476 u16 offset;
477 u8 len;
478 int i;
479
480 *parse_from_here = 0;
481
482 /* chase initial pointer? */
483 if ((label[0] & 0xC0) == 0xC0)
484 {
485 *parse_from_here = label + 2;
486 offset = ((label[0] & 0x3f) << 8) + label[1];
487 label = full_text + offset;
488 }
489
490 len = *label++;
491
492 while (len)
493 {
494 for (i = 0; i < len; i++)
495 vec_add1 (reply, *label++);
496
497 /* chase pointer? */
498 if ((label[0] & 0xC0) == 0xC0)
499 {
500 *parse_from_here = label + 2;
501 offset = ((label[0] & 0x3f) << 8) + label[1];
502 label = full_text + offset;
503 }
504
505 len = *label++;
506 if (len)
507 vec_add1 (reply, '.');
508 }
509 if (*parse_from_here == 0)
510 *parse_from_here = label;
511 return reply;
512}
513
514void
515vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep)
516{
517 dns_header_t *h;
518 dns_query_t *qp;
519 u16 tmp;
520 u8 *request;
521 u32 qp_offset;
522
Dave Barach0cb01bd2017-10-16 14:39:52 -0400523 /* This can easily happen if sitting in GDB, etc. */
524 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
525 return;
526
Dave Barach65457162017-10-10 17:53:14 -0400527 /* Construct the dns request, if we haven't been here already */
528 if (vec_len (ep->dns_request) == 0)
529 {
530 /*
531 * Start with the variadic portion of the exercise.
532 * Turn the name into a set of DNS "labels". Max length
533 * per label is 63, enforce that.
534 */
535 request = name_to_labels (ep->name);
536 qp_offset = vec_len (request);
537
538 /* Add space for the query header */
539 vec_validate (request, qp_offset + sizeof (dns_query_t) - 1);
540
541 qp = (dns_query_t *) (request + qp_offset);
542
543 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
544 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
545
546 /* Punch in space for the dns_header_t */
547 vec_insert (request, sizeof (dns_header_t), 0);
548
549 h = (dns_header_t *) request;
550
551 /* Transaction ID = pool index */
552 h->id = clib_host_to_net_u16 (ep - dm->entries);
553
554 /* Ask for a recursive lookup */
555 tmp = DNS_RD | DNS_OPCODE_QUERY;
556 h->flags = clib_host_to_net_u16 (tmp);
557 h->qdcount = clib_host_to_net_u16 (1);
558 h->nscount = 0;
559 h->arcount = 0;
560
561 ep->dns_request = request;
562 }
563
564 /* Work out which server / address family we're going to use */
565
566 /* Retry using current server */
567 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
568 {
569 if (ep->server_af == 1 /* ip6 */ )
570 {
571 if (vec_len (dm->ip6_name_servers))
572 {
573 send_dns6_request (dm, ep,
574 dm->ip6_name_servers + ep->server_rotor);
575 goto out;
576 }
577 else
578 ep->server_af = 0;
579 }
580 if (vec_len (dm->ip4_name_servers))
581 {
582 send_dns4_request (dm, ep, dm->ip4_name_servers + ep->server_rotor);
583 goto out;
584 }
585 }
586 else /* switch to a new server */
587 {
588 ep->retry_count = 1;
589 ep->server_rotor++;
590 if (ep->server_af == 1 /* ip6 */ )
591 {
592 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
593 {
594 ep->server_rotor = 0;
595 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
596 }
597 }
598 else
599 {
600 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
601 {
602 ep->server_rotor = 0;
603 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
604 }
605 }
606 }
607
608 if (ep->server_af == 1 /* ip6 */ )
609 send_dns6_request (dm, ep, dm->ip6_name_servers + ep->server_rotor);
610 else
611 send_dns4_request (dm, ep, dm->ip4_name_servers + ep->server_rotor);
612
613out:
614
615 vlib_process_signal_event_mt (dm->vlib_main, dns_resolver_node.index,
616 DNS_RESOLVER_EVENT_PENDING, 0);
617}
618
619int
620vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
621{
622 dns_cache_entry_t *ep;
623 int i;
624
625 if (dm->is_enabled == 0)
626 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
627
628 if (pool_is_free_index (dm->entries, index))
629 return VNET_API_ERROR_NO_SUCH_ENTRY;
630
631 ep = pool_elt_at_index (dm->entries, index);
Dave Barach65457162017-10-10 17:53:14 -0400632 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
633 {
634 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
635 if (index == dm->unresolved_entries[i])
636 {
637 vec_delete (dm->unresolved_entries, 1, i);
638 goto found;
639 }
640 clib_warning ("pool elt %d supposedly pending, but not found...",
641 index);
642 }
643
644found:
645 hash_unset_mem (dm->cache_entry_by_name, ep->name);
646 vec_free (ep->name);
Dave Barach97494502017-11-04 09:44:38 -0400647 vec_free (ep->pending_requests);
Dave Barach65457162017-10-10 17:53:14 -0400648 pool_put (dm->entries, ep);
649
650 return 0;
651}
652
653static int
654dns_delete_by_name (dns_main_t * dm, u8 * name)
655{
656 int rv;
657 uword *p;
658
659 if (dm->is_enabled == 0)
660 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
661
662 dns_cache_lock (dm);
663 p = hash_get_mem (dm->cache_entry_by_name, name);
664 if (!p)
665 {
666 dns_cache_unlock (dm);
667 return VNET_API_ERROR_NO_SUCH_ENTRY;
668 }
669 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
670
671 dns_cache_unlock (dm);
672
673 return rv;
674}
675
676static int
677delete_random_entry (dns_main_t * dm)
678{
679 int rv;
680 u32 victim_index, start_index, i;
681 u32 limit;
682 dns_cache_entry_t *ep;
683
684 if (dm->is_enabled == 0)
685 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
686
Dave Barachb9f2cf02017-10-17 13:13:42 -0400687 /*
688 * Silence spurious coverity warning. We know pool_elts >> 0, or
689 * we wouldn't be here...
690 */
691#ifdef __COVERITY__
692 if (pool_elts (dm->entries) == 0)
693 return VNET_API_ERROR_UNSPECIFIED;
694#endif
695
Dave Barach65457162017-10-10 17:53:14 -0400696 dns_cache_lock (dm);
697 limit = pool_elts (dm->entries);
698 start_index = random_u32 (&dm->random_seed) % limit;
699
700 for (i = 0; i < limit; i++)
701 {
702 victim_index = (start_index + i) % limit;
703
704 if (!pool_is_free_index (dm->entries, victim_index))
705 {
706 ep = pool_elt_at_index (dm->entries, victim_index);
707 /* Delete only valid, non-static entries */
708 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
709 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
710 {
711 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
712 dns_cache_unlock (dm);
713 return rv;
714 }
715 }
716 }
717 dns_cache_unlock (dm);
718
719 clib_warning ("Couldn't find an entry to delete?");
720 return VNET_API_ERROR_UNSPECIFIED;
721}
722
723static int
724dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
725{
726 dns_cache_entry_t *ep;
727 uword *p;
728 int rv;
729
730 if (dm->is_enabled == 0)
731 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
732
733 dns_cache_lock (dm);
734 p = hash_get_mem (dm->cache_entry_by_name, name);
735 if (p)
736 {
737 dns_cache_unlock (dm);
738 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
739 }
740
741 if (pool_elts (dm->entries) == dm->name_cache_size)
742 {
743 /* Will only fail if the cache is totally filled w/ static entries... */
744 rv = delete_random_entry (dm);
745 if (rv)
746 {
747 dns_cache_unlock (dm);
748 return rv;
749 }
750 }
751
752 pool_get (dm->entries, ep);
753 memset (ep, 0, sizeof (*ep));
754
755 /* Note: consumes the name vector */
756 ep->name = name;
757 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
758 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
759 ep->dns_response = dns_reply_data;
760
761 dns_cache_unlock (dm);
762 return 0;
763}
764
Dave Barach97494502017-11-04 09:44:38 -0400765int
766vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t,
767 dns_cache_entry_t ** retp)
Dave Barach65457162017-10-10 17:53:14 -0400768{
769 dns_cache_entry_t *ep;
770 int rv;
771 f64 now;
772 uword *p;
Dave Barach97494502017-11-04 09:44:38 -0400773 dns_pending_request_t *pr;
774 int count;
Dave Barach65457162017-10-10 17:53:14 -0400775
776 now = vlib_time_now (dm->vlib_main);
777
778 /* In case we can't actually answer the question right now... */
779 *retp = 0;
780
781 dns_cache_lock (dm);
Dave Barach0cb01bd2017-10-16 14:39:52 -0400782search_again:
Dave Barach65457162017-10-10 17:53:14 -0400783 p = hash_get_mem (dm->cache_entry_by_name, name);
784 if (p)
785 {
786 ep = pool_elt_at_index (dm->entries, p[0]);
787 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
788 {
789 /* Has the entry expired? */
790 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
791 && (now > ep->expiration_time))
792 {
Dave Barach0cb01bd2017-10-16 14:39:52 -0400793 int i;
794 u32 *indices_to_delete = 0;
795
796 /*
797 * Take out the rest of the resolution chain
798 * This isn't optimal, but it won't happen very often.
799 */
800 while (ep)
801 {
802 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
803 {
804 vec_add1 (indices_to_delete, ep - dm->entries);
805
806 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
807 if (!p)
808 break;
809 ep = pool_elt_at_index (dm->entries, p[0]);
810 }
811 else
812 {
813 vec_add1 (indices_to_delete, ep - dm->entries);
814 break;
815 }
816 }
817 for (i = 0; i < vec_len (indices_to_delete); i++)
818 {
819 /* Reenable to watch re-resolutions */
820 if (0)
821 {
822 ep = pool_elt_at_index (dm->entries,
823 indices_to_delete[i]);
824 clib_warning ("Re-resolve %s", ep->name);
825 }
826
827 vnet_dns_delete_entry_by_index_nolock
828 (dm, indices_to_delete[i]);
829 }
830 vec_free (indices_to_delete);
Dave Barach65457162017-10-10 17:53:14 -0400831 /* Yes, kill it... */
Dave Barach65457162017-10-10 17:53:14 -0400832 goto re_resolve;
833 }
834
Dave Barach0cb01bd2017-10-16 14:39:52 -0400835 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
836 {
837 name = ep->cname;
838 goto search_again;
839 }
840
Dave Barach65457162017-10-10 17:53:14 -0400841 /* Note: caller must drop the lock! */
842 *retp = ep;
843 return (0);
844 }
Dave Barach0cb01bd2017-10-16 14:39:52 -0400845 else
846 {
847 /*
Dave Barachd2080152017-10-20 09:21:35 -0400848 * Resolution pending. Add request to the pending vector
Dave Barach97494502017-11-04 09:44:38 -0400849 * by copying the template request
Dave Barachd2080152017-10-20 09:21:35 -0400850 */
Dave Barach97494502017-11-04 09:44:38 -0400851 vec_add2 (ep->pending_requests, pr, 1);
852 memcpy (pr, t, sizeof (*pr));
Dave Barach0cb01bd2017-10-16 14:39:52 -0400853 dns_cache_unlock (dm);
854 return (0);
855 }
Dave Barach65457162017-10-10 17:53:14 -0400856 }
857
Dave Barach0cb01bd2017-10-16 14:39:52 -0400858re_resolve:
Dave Barach65457162017-10-10 17:53:14 -0400859 if (pool_elts (dm->entries) == dm->name_cache_size)
860 {
861 /* Will only fail if the cache is totally filled w/ static entries... */
862 rv = delete_random_entry (dm);
863 if (rv)
864 {
865 dns_cache_unlock (dm);
866 return rv;
867 }
868 }
869
Dave Barach65457162017-10-10 17:53:14 -0400870 /* add new hash table entry */
871 pool_get (dm->entries, ep);
872 memset (ep, 0, sizeof (*ep));
873
874 ep->name = format (0, "%s%c", name, 0);
875 _vec_len (ep->name) = vec_len (ep->name) - 1;
876
877 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
878
879 vec_add1 (dm->unresolved_entries, ep - dm->entries);
Dave Barach97494502017-11-04 09:44:38 -0400880 vec_add2 (ep->pending_requests, pr, 1);
881
882 pr->request_type = t->request_type;
883
884 /* Remember details so we can reply later... */
885 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
886 t->request_type == DNS_API_PENDING_IP_TO_NAME)
887 {
888 pr->client_index = t->client_index;
889 pr->client_context = t->client_context;
890 }
891 else
892 {
893 pr->client_index = ~0;
894 pr->is_ip6 = t->is_ip6;
895 pr->dst_port = t->dst_port;
896 pr->id = t->id;
897 pr->name = t->name;
898 if (t->is_ip6)
899 count = 16;
900 else
901 count = 4;
902 clib_memcpy (pr->dst_address, t->dst_address, count);
903 }
904
Dave Barach65457162017-10-10 17:53:14 -0400905 vnet_send_dns_request (dm, ep);
906 dns_cache_unlock (dm);
Dave Barach65457162017-10-10 17:53:14 -0400907 return 0;
908}
909
Dave Barach0cb01bd2017-10-16 14:39:52 -0400910#define foreach_notification_to_move \
Dave Barach97494502017-11-04 09:44:38 -0400911_(pending_requests)
Dave Barach0cb01bd2017-10-16 14:39:52 -0400912
Dave Barach65457162017-10-10 17:53:14 -0400913/**
914 * Handle cname indirection. JFC. Called with the cache locked.
915 * returns 0 if the reply is not a CNAME.
916 */
917
918int
Dave Barach0cb01bd2017-10-16 14:39:52 -0400919vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
Dave Barach65457162017-10-10 17:53:14 -0400920{
921 dns_header_t *h;
922 dns_query_t *qp;
923 dns_rr_t *rr;
924 u8 *curpos;
925 u8 *pos, *pos2;
926 int len, i;
927 u8 *cname = 0;
928 u8 *request = 0;
929 u32 qp_offset;
930 u16 flags;
931 u16 rcode;
Dave Barach0cb01bd2017-10-16 14:39:52 -0400932 dns_cache_entry_t *ep, *next_ep;
933 f64 now;
Dave Barach65457162017-10-10 17:53:14 -0400934
935 h = (dns_header_t *) reply;
936 flags = clib_net_to_host_u16 (h->flags);
937 rcode = flags & DNS_RCODE_MASK;
938
939 /* See if the response is OK */
940 switch (rcode)
941 {
942 case DNS_RCODE_NO_ERROR:
943 break;
944
945 case DNS_RCODE_NAME_ERROR:
946 case DNS_RCODE_FORMAT_ERROR:
947 case DNS_RCODE_SERVER_FAILURE:
948 case DNS_RCODE_NOT_IMPLEMENTED:
949 case DNS_RCODE_REFUSED:
950 return 0;
951 }
952
953 curpos = (u8 *) (h + 1);
954 pos = curpos;
955 len = *pos++;
956
957 /* Skip the questions */
958 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
959 {
960 while (len)
961 {
962 pos += len;
963 len = *pos++;
964 }
Dave Barachb9f2cf02017-10-17 13:13:42 -0400965 pos += sizeof (dns_query_t);
Dave Barach65457162017-10-10 17:53:14 -0400966 }
967 pos2 = pos;
968 /* expect a pointer chase here for a CNAME record */
969 if ((pos2[0] & 0xC0) == 0xC0)
970 pos += 2;
971 else
972 return 0;
973
974 rr = (dns_rr_t *) pos;
975
976 /* This is a real record, not a CNAME record */
977 if (clib_net_to_host_u16 (rr->type) != DNS_TYPE_CNAME)
978 return 0;
979
Dave Barach0cb01bd2017-10-16 14:39:52 -0400980 /* This is a CNAME record, chase the name chain. */
Dave Barach65457162017-10-10 17:53:14 -0400981
Dave Barach0cb01bd2017-10-16 14:39:52 -0400982 /* The last request is no longer pending.. */
983 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
984 if (ep_index == dm->unresolved_entries[i])
985 {
986 vec_delete (dm->unresolved_entries, 1, i);
987 goto found_last_request;
988 }
989 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
990
991found_last_request:
992
993 now = vlib_time_now (dm->vlib_main);
Dave Barach97494502017-11-04 09:44:38 -0400994 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
Dave Barach0cb01bd2017-10-16 14:39:52 -0400995 /* Save the cname */
996 vec_add1 (cname, 0);
997 _vec_len (cname) -= 1;
998 ep = pool_elt_at_index (dm->entries, ep_index);
999 ep->cname = cname;
1000 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1001 /* Save the response */
1002 ep->dns_response = reply;
1003 /* Set up expiration time */
1004 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1005
1006 pool_get (dm->entries, next_ep);
1007
1008 /* Need to recompute ep post pool-get */
1009 ep = pool_elt_at_index (dm->entries, ep_index);
1010
1011 memset (next_ep, 0, sizeof (*next_ep));
1012 next_ep->name = vec_dup (cname);
1013 vec_add1 (next_ep->name, 0);
1014 _vec_len (next_ep->name) -= 1;
1015
1016 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1017 next_ep - dm->entries);
1018
1019 /* Use the same server */
1020 next_ep->server_rotor = ep->server_rotor;
1021 next_ep->server_af = ep->server_af;
1022
1023 /* Move notification data to the next name in the chain */
1024#define _(a) next_ep->a = ep->a; ep->a = 0;
1025 foreach_notification_to_move;
1026#undef _
1027
Dave Barach65457162017-10-10 17:53:14 -04001028 request = name_to_labels (cname);
Dave Barach65457162017-10-10 17:53:14 -04001029
1030 qp_offset = vec_len (request);
1031
1032 /* Add space for the query header */
1033 vec_validate (request, qp_offset + sizeof (dns_query_t) - 1);
1034
1035 qp = (dns_query_t *) (request + qp_offset);
1036
1037 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1038 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1039
1040 /* Punch in space for the dns_header_t */
1041 vec_insert (request, sizeof (dns_header_t), 0);
1042
1043 h = (dns_header_t *) request;
1044
1045 /* Transaction ID = pool index */
Dave Barach0cb01bd2017-10-16 14:39:52 -04001046 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
Dave Barach65457162017-10-10 17:53:14 -04001047
1048 /* Ask for a recursive lookup */
1049 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1050 h->qdcount = clib_host_to_net_u16 (1);
1051 h->nscount = 0;
1052 h->arcount = 0;
1053
Dave Barach0cb01bd2017-10-16 14:39:52 -04001054 next_ep->dns_request = request;
1055 next_ep->retry_timer = now + 2.0;
1056 next_ep->retry_count = 0;
Dave Barach65457162017-10-10 17:53:14 -04001057
1058 /*
1059 * Enable this to watch recursive resolution happen...
1060 * fformat (stdout, "%U", format_dns_reply, request, 2);
1061 */
1062
Dave Barach0cb01bd2017-10-16 14:39:52 -04001063 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1064 vnet_send_dns_request (dm, next_ep);
Dave Barach65457162017-10-10 17:53:14 -04001065 return (1);
1066}
1067
1068int
1069vnet_dns_response_to_reply (u8 * response,
1070 vl_api_dns_resolve_name_reply_t * rmp,
1071 u32 * min_ttlp)
1072{
1073 dns_header_t *h;
1074 dns_query_t *qp;
1075 dns_rr_t *rr;
1076 int i, limit;
1077 u8 len;
1078 u8 *curpos, *pos;
1079 u16 flags;
1080 u16 rcode;
1081 u32 ttl;
1082
1083 h = (dns_header_t *) response;
1084 flags = clib_net_to_host_u16 (h->flags);
1085 rcode = flags & DNS_RCODE_MASK;
1086
1087 /* See if the response is OK, etc. */
1088 switch (rcode)
1089 {
1090 default:
1091 case DNS_RCODE_NO_ERROR:
1092 break;
1093
1094 case DNS_RCODE_NAME_ERROR:
1095 case DNS_RCODE_FORMAT_ERROR:
1096 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1097
1098 case DNS_RCODE_SERVER_FAILURE:
1099 case DNS_RCODE_NOT_IMPLEMENTED:
1100 case DNS_RCODE_REFUSED:
1101 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1102 }
1103
1104 /* No answers? Loser... */
1105 if (clib_net_to_host_u16 (h->anscount) < 1)
1106 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1107
1108 curpos = (u8 *) (h + 1);
1109
1110 /* Skip the name we asked about */
1111 pos = curpos;
1112 len = *pos++;
1113 /* Should never happen, but stil... */
1114 if ((len & 0xC0) == 0xC0)
1115 curpos += 2;
1116 else
1117 {
1118 /* skip the name / label-set */
1119 while (len)
1120 {
1121 pos += len;
1122 len = *pos++;
1123 }
1124 curpos = pos;
1125 }
1126 /* Skip queries */
1127 limit = clib_net_to_host_u16 (h->qdcount);
1128 qp = (dns_query_t *) curpos;
1129 qp += limit;
1130 curpos = (u8 *) qp;
1131
1132 /* Parse answers */
1133 limit = clib_net_to_host_u16 (h->anscount);
1134
1135 for (i = 0; i < limit; i++)
1136 {
1137 pos = curpos;
1138
1139 /* Expect pointer chases in the answer section... */
1140 if ((pos[0] & 0xC0) == 0xC0)
1141 curpos += 2;
1142 else
1143 {
1144 len = *pos++;
1145 while (len)
1146 {
1147 if ((pos[0] & 0xC0) == 0xC0)
1148 {
1149 curpos = pos + 2;
Dave Barachb9f2cf02017-10-17 13:13:42 -04001150 goto curpos_set;
Dave Barach65457162017-10-10 17:53:14 -04001151 }
1152 pos += len;
1153 len = *pos++;
1154 }
1155 curpos = pos;
1156 }
1157
Dave Barachb9f2cf02017-10-17 13:13:42 -04001158 curpos_set:
Dave Barach65457162017-10-10 17:53:14 -04001159 rr = (dns_rr_t *) curpos;
1160
1161 switch (clib_net_to_host_u16 (rr->type))
1162 {
1163 case DNS_TYPE_A:
1164 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1165 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1166 rmp->ip4_set = 1;
1167 ttl = clib_net_to_host_u32 (rr->ttl);
1168 if (min_ttlp && *min_ttlp > ttl)
1169 *min_ttlp = ttl;
1170 break;
1171 case DNS_TYPE_AAAA:
1172 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1173 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1174 ttl = clib_net_to_host_u32 (rr->ttl);
1175 if (min_ttlp && *min_ttlp > ttl)
1176 *min_ttlp = ttl;
1177 rmp->ip6_set = 1;
1178 break;
1179 default:
1180 break;
1181 }
1182 /* Might as well stop ASAP */
1183 if (rmp->ip4_set && rmp->ip6_set)
1184 break;
1185 curpos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1186 }
1187
1188 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1189 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1190 return 0;
1191}
1192
Dave Barachd2080152017-10-20 09:21:35 -04001193int
1194vnet_dns_response_to_name (u8 * response,
1195 vl_api_dns_resolve_ip_reply_t * rmp,
1196 u32 * min_ttlp)
1197{
1198 dns_header_t *h;
1199 dns_query_t *qp;
1200 dns_rr_t *rr;
1201 int i, limit;
1202 u8 len;
1203 u8 *curpos, *pos;
1204 u16 flags;
1205 u16 rcode;
1206 u8 *name;
1207 u32 ttl;
1208 u8 *junk __attribute__ ((unused));
1209 int name_set = 0;
1210
1211 h = (dns_header_t *) response;
1212 flags = clib_net_to_host_u16 (h->flags);
1213 rcode = flags & DNS_RCODE_MASK;
1214
1215 /* See if the response is OK, etc. */
1216 switch (rcode)
1217 {
1218 default:
1219 case DNS_RCODE_NO_ERROR:
1220 break;
1221
1222 case DNS_RCODE_NAME_ERROR:
1223 case DNS_RCODE_FORMAT_ERROR:
1224 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1225
1226 case DNS_RCODE_SERVER_FAILURE:
1227 case DNS_RCODE_NOT_IMPLEMENTED:
1228 case DNS_RCODE_REFUSED:
1229 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1230 }
1231
1232 /* No answers? Loser... */
1233 if (clib_net_to_host_u16 (h->anscount) < 1)
1234 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1235
1236 curpos = (u8 *) (h + 1);
1237
1238 /* Skip the name we asked about */
1239 pos = curpos;
1240 len = *pos++;
1241 /* Should never happen, but stil... */
1242 if ((len & 0xC0) == 0xC0)
1243 curpos += 2;
1244 else
1245 {
1246 /* skip the name / label-set */
1247 while (len)
1248 {
1249 pos += len;
1250 len = *pos++;
1251 }
1252 curpos = pos;
1253 }
1254 /* Skip queries */
1255 limit = clib_net_to_host_u16 (h->qdcount);
1256 qp = (dns_query_t *) curpos;
1257 qp += limit;
1258 curpos = (u8 *) qp;
1259
1260 /* Parse answers */
1261 limit = clib_net_to_host_u16 (h->anscount);
1262
1263 for (i = 0; i < limit; i++)
1264 {
1265 pos = curpos;
1266
1267 /* Expect pointer chases in the answer section... */
1268 if ((pos[0] & 0xC0) == 0xC0)
1269 curpos += 2;
1270 else
1271 {
1272 len = *pos++;
1273 while (len)
1274 {
1275 if ((pos[0] & 0xC0) == 0xC0)
1276 {
1277 curpos = pos + 2;
1278 goto curpos_set;
1279 }
1280 pos += len;
1281 len = *pos++;
1282 }
1283 curpos = pos;
1284 }
1285
1286 curpos_set:
1287 rr = (dns_rr_t *) curpos;
1288
1289 switch (clib_net_to_host_u16 (rr->type))
1290 {
1291 case DNS_TYPE_PTR:
Dave Barach97494502017-11-04 09:44:38 -04001292 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
Dave Barachd2080152017-10-20 09:21:35 -04001293 memcpy (rmp->name, name, vec_len (name));
1294 ttl = clib_net_to_host_u32 (rr->ttl);
1295 if (*min_ttlp)
1296 *min_ttlp = ttl;
1297 rmp->name[vec_len (name)] = 0;
1298 name_set = 1;
1299 break;
1300 default:
1301 break;
1302 }
1303 /* Might as well stop ASAP */
1304 if (name_set == 1)
1305 break;
1306 curpos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1307 }
1308
1309 if (name_set == 0)
1310 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1311 return 0;
1312}
1313
Dave Barach65457162017-10-10 17:53:14 -04001314static void
1315vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1316{
1317 dns_main_t *dm = &dns_main;
1318 vl_api_dns_resolve_name_reply_t *rmp;
1319 dns_cache_entry_t *ep;
Dave Barach97494502017-11-04 09:44:38 -04001320 dns_pending_request_t _t0, *t0 = &_t0;
Dave Barach65457162017-10-10 17:53:14 -04001321 int rv;
1322
1323 /* Sanitize the name slightly */
1324 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1325
Dave Barach97494502017-11-04 09:44:38 -04001326 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1327 t0->client_index = mp->client_index;
1328 t0->client_context = mp->context;
1329
1330 rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
Dave Barach65457162017-10-10 17:53:14 -04001331
1332 /* Error, e.g. not enabled? Tell the user */
1333 if (rv < 0)
1334 {
1335 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1336 return;
1337 }
1338
1339 /* Resolution pending? Don't reply... */
1340 if (ep == 0)
1341 return;
1342
1343 /* *INDENT-OFF* */
1344 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1345 ({
1346 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1347 rmp->retval = clib_host_to_net_u32 (rv);
1348 }));
1349 /* *INDENT-ON* */
1350
1351 /*
1352 * dns_resolve_name leaves the cache locked when it returns
1353 * a cached result, so unlock it here.
1354 */
1355 dns_cache_unlock (dm);
1356}
1357
Dave Barachd2080152017-10-20 09:21:35 -04001358static void
1359vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1360{
1361 dns_main_t *dm = &dns_main;
1362 vl_api_dns_resolve_ip_reply_t *rmp;
1363 dns_cache_entry_t *ep;
1364 int rv;
1365 int i, len;
1366 u8 *lookup_name = 0;
1367 u8 digit, nybble;
Dave Barach97494502017-11-04 09:44:38 -04001368 dns_pending_request_t _t0, *t0 = &_t0;
Dave Barachd2080152017-10-20 09:21:35 -04001369
1370 if (mp->is_ip6)
1371 {
1372 for (i = 15; i >= 0; i--)
1373 {
1374 digit = mp->address[i];
1375 nybble = (digit & 0x0F);
1376 if (nybble > 9)
1377 vec_add1 (lookup_name, (nybble - 10) + 'a');
1378 else
1379 vec_add1 (lookup_name, nybble + '0');
1380 vec_add1 (lookup_name, '.');
1381 nybble = (digit & 0xF0) >> 4;
1382 if (nybble > 9)
1383 vec_add1 (lookup_name, (nybble - 10) + 'a');
1384 else
1385 vec_add1 (lookup_name, nybble + '0');
1386 vec_add1 (lookup_name, '.');
1387 }
1388 len = vec_len (lookup_name);
1389 vec_validate (lookup_name, len + 8);
1390 memcpy (lookup_name + len, "ip6.arpa", 8);
1391 }
1392 else
1393 {
1394 for (i = 3; i >= 0; i--)
1395 {
1396 digit = mp->address[i];
1397 lookup_name = format (lookup_name, "%d.", digit);
1398 }
1399 lookup_name = format (lookup_name, "in-addr.arpa");
1400 }
1401
1402 vec_add1 (lookup_name, 0);
1403
Dave Barach97494502017-11-04 09:44:38 -04001404 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1405 t0->client_index = mp->client_index;
1406 t0->client_context = mp->context;
1407
1408 rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
Dave Barachd2080152017-10-20 09:21:35 -04001409
1410 vec_free (lookup_name);
1411
1412 /* Error, e.g. not enabled? Tell the user */
1413 if (rv < 0)
1414 {
1415 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1416 return;
1417 }
1418
1419 /* Resolution pending? Don't reply... */
1420 if (ep == 0)
1421 return;
1422
1423 /* *INDENT-OFF* */
1424 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1425 ({
1426 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1427 rmp->retval = clib_host_to_net_u32 (rv);
1428 }));
1429 /* *INDENT-ON* */
1430
1431 /*
Dave Barach97494502017-11-04 09:44:38 -04001432 * vnet_dns_resolve_name leaves the cache locked when it returns
Dave Barachd2080152017-10-20 09:21:35 -04001433 * a cached result, so unlock it here.
1434 */
1435 dns_cache_unlock (dm);
1436}
1437
Dave Barach65457162017-10-10 17:53:14 -04001438#define vl_msg_name_crc_list
1439#include <vpp/api/vpe_all_api_h.h>
1440#undef vl_msg_name_crc_list
1441
1442static void
1443setup_message_id_table (api_main_t * am)
1444{
1445#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1446 foreach_vl_msg_name_crc_dns;
1447#undef _
1448}
1449
1450#define foreach_dns_api_msg \
1451_(DNS_ENABLE_DISABLE, dns_enable_disable) \
1452_(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
Dave Barachd2080152017-10-20 09:21:35 -04001453_(DNS_RESOLVE_NAME, dns_resolve_name) \
1454_(DNS_RESOLVE_IP, dns_resolve_ip)
Dave Barach65457162017-10-10 17:53:14 -04001455
1456static clib_error_t *
1457dns_api_hookup (vlib_main_t * vm)
1458{
1459#define _(N,n) \
1460 vl_msg_api_set_handlers(VL_API_##N, #n, \
1461 vl_api_##n##_t_handler, \
1462 vl_noop_handler, \
1463 vl_api_##n##_t_endian, \
1464 vl_api_##n##_t_print, \
1465 sizeof(vl_api_##n##_t), 1);
1466 foreach_dns_api_msg;
1467#undef _
1468
1469 setup_message_id_table (&api_main);
1470 return 0;
1471}
1472
1473VLIB_API_INIT_FUNCTION (dns_api_hookup);
1474
1475
1476static clib_error_t *
1477dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1478{
1479 dns_main_t *dm = &dns_main;
1480
1481 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1482 {
1483 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1484 ;
1485 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1486 ;
1487 else
1488 return clib_error_return (0, "unknown input `%U'",
1489 format_unformat_error, input);
1490 }
1491 return 0;
1492}
1493
1494VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1495
1496static clib_error_t *
1497dns_init (vlib_main_t * vm)
1498{
1499 dns_main_t *dm = &dns_main;
1500
1501 dm->vlib_main = vm;
1502 dm->vnet_main = vnet_get_main ();
1503 dm->name_cache_size = 65535;
1504 dm->max_ttl_in_seconds = 86400;
1505 dm->random_seed = 0xDEADDABE;
1506
1507 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply, dns46_reply_node.index,
1508 1 /* is_ip4 */ );
1509
1510 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6, dns46_reply_node.index,
1511 0 /* is_ip4 */ );
1512
Dave Barach65457162017-10-10 17:53:14 -04001513 udp_register_dst_port (vm, UDP_DST_PORT_dns, dns4_request_node.index,
1514 1 /* is_ip4 */ );
Dave Barach97494502017-11-04 09:44:38 -04001515
Dave Barach65457162017-10-10 17:53:14 -04001516 udp_register_dst_port (vm, UDP_DST_PORT_dns6, dns6_request_node.index,
1517 0 /* is_ip4 */ );
Dave Barach65457162017-10-10 17:53:14 -04001518 return 0;
1519}
1520
1521VLIB_INIT_FUNCTION (dns_init);
1522
1523uword
1524unformat_dns_reply (unformat_input_t * input, va_list * args)
1525{
1526 u8 **result = va_arg (*args, u8 **);
1527 u8 **namep = va_arg (*args, u8 **);
1528 ip4_address_t a4;
1529 ip6_address_t a6;
1530 int a4_set = 0;
1531 int a6_set = 0;
1532 u8 *name;
1533 int name_set = 0;
1534 u8 *ce;
1535 u32 qp_offset;
1536 dns_header_t *h;
1537 dns_query_t *qp;
1538 dns_rr_t *rr;
1539 u8 *rru8;
1540
1541 if (unformat (input, "%v", &name))
1542 name_set = 1;
1543
1544 if (unformat (input, "%U", unformat_ip4_address, &a4))
1545 {
1546 a4_set = 1;
1547 if (unformat (input, "%U", unformat_ip6_address, &a6))
1548 a6_set = 1;
1549 }
1550
1551 if (unformat (input, "%U", unformat_ip6_address, &a6))
1552 {
1553 a6_set = 1;
1554 if (unformat (input, "%U", unformat_ip4_address, &a6))
1555 a4_set = 1;
1556 }
1557
1558 /* Must have a name */
1559 if (!name_set)
1560 return 0;
1561
1562 /* Must have at least one address */
1563 if (!(a4_set + a6_set))
1564 return 0;
1565
1566 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1567 ce = name_to_labels (name);
1568 qp_offset = vec_len (ce);
1569
1570 /* Add space for the query header */
1571 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1572 qp = (dns_query_t *) (ce + qp_offset);
1573
1574 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1575 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1576
1577 /* Punch in space for the dns_header_t */
1578 vec_insert (ce, sizeof (dns_header_t), 0);
1579
1580 h = (dns_header_t *) ce;
1581
1582 /* Fake Transaction ID */
1583 h->id = 0xFFFF;
1584
1585 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1586 h->qdcount = clib_host_to_net_u16 (1);
1587 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1588 h->nscount = 0;
1589 h->arcount = 0;
1590
1591 /* Now append one or two A/AAAA RR's... */
1592 if (a4_set)
1593 {
1594 /* Pointer to the name (DGMS) */
1595 vec_add1 (ce, 0xC0);
1596 vec_add1 (ce, 0x0C);
1597 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1598 rr = (void *) rru8;
1599 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1600 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1601 rr->ttl = clib_host_to_net_u32 (86400);
1602 rr->rdlength = clib_host_to_net_u16 (4);
1603 memcpy (rr->rdata, &a4, sizeof (a4));
1604 }
1605 if (a6_set)
1606 {
1607 /* Pointer to the name (DGMS) */
1608 vec_add1 (ce, 0xC0);
1609 vec_add1 (ce, 0x0C);
1610 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1611 rr = (void *) rru8;
1612 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1613 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1614 rr->ttl = clib_host_to_net_u32 (86400);
1615 rr->rdlength = clib_host_to_net_u16 (16);
1616 memcpy (rr->rdata, &a6, sizeof (a6));
1617 }
1618 *result = ce;
1619 if (namep)
1620 *namep = name;
1621 else
1622 vec_free (name);
1623
1624 return 1;
1625}
1626
1627u8 *
1628format_dns_query (u8 * s, va_list * args)
1629{
1630 u8 **curpos = va_arg (*args, u8 **);
1631 int verbose = va_arg (*args, int);
1632 u8 *pos;
1633 dns_query_t *qp;
1634 int len, i;
1635 if (verbose > 1)
1636 s = format (s, " Name: ");
1637
1638 /* Unwind execrated counted-label sheit */
1639 pos = *curpos;
1640 len = *pos++;
1641
1642 while (len)
1643 {
1644 for (i = 0; i < len; i++)
1645 vec_add1 (s, *pos++);
1646
1647 len = *pos++;
1648 if (len)
1649 vec_add1 (s, '.');
1650 else
1651 {
1652 vec_add1 (s, ':');
1653 vec_add1 (s, ' ');
1654 }
1655 }
1656
1657 qp = (dns_query_t *) pos;
1658 if (verbose > 1)
1659 {
1660 switch (clib_net_to_host_u16 (qp->type))
1661 {
1662 case DNS_TYPE_A:
1663 s = format (s, "type A\n");
1664 break;
1665 case DNS_TYPE_AAAA:
1666 s = format (s, "type AAAA\n");
1667 break;
1668 case DNS_TYPE_ALL:
1669 s = format (s, "type ALL\n");
1670 break;
1671
1672 default:
1673 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1674 break;
1675 }
1676 }
1677
1678 pos += sizeof (*qp);
1679
1680 *curpos = pos;
1681 return s;
1682}
1683
1684/**
1685 * format dns reply data
1686 * verbose > 1, dump everything
1687 * verbose == 1, dump all A and AAAA records
1688 * verbose == 0, dump one A record, and one AAAA record
1689 */
1690
1691u8 *
1692format_dns_reply_data (u8 * s, va_list * args)
1693{
1694 u8 *reply = va_arg (*args, u8 *);
1695 u8 **curpos = va_arg (*args, u8 **);
1696 int verbose = va_arg (*args, int);
1697 int *print_ip4 = va_arg (*args, int *);
1698 int *print_ip6 = va_arg (*args, int *);
1699 int len;
1700 u8 *pos, *pos2;
1701 dns_rr_t *rr;
1702 int i;
1703 int initial_pointer_chase = 0;
1704 u16 *tp;
Dave Barachd2080152017-10-20 09:21:35 -04001705 u16 rrtype_host_byte_order;
Dave Barach65457162017-10-10 17:53:14 -04001706
1707 pos = pos2 = *curpos;
1708
1709 if (verbose > 1)
1710 s = format (s, " ");
1711
1712 /* chase pointer? almost always yes here... */
1713 if (pos2[0] == 0xc0)
1714 {
1715 pos2 = reply + pos2[1];
1716 pos += 2;
1717 initial_pointer_chase = 1;
1718 }
1719
1720 len = *pos2++;
1721
1722 while (len)
1723 {
1724 for (i = 0; i < len; i++)
1725 {
1726 if (verbose > 1)
1727 vec_add1 (s, *pos2);
1728 pos2++;
1729 }
1730 len = *pos2++;
1731 if (len)
1732 {
1733 if (verbose > 1)
1734 vec_add1 (s, '.');
1735 }
1736 else
1737 {
1738 if (verbose > 1)
1739 vec_add1 (s, ' ');
1740 }
1741 }
1742
1743 if (initial_pointer_chase == 0)
1744 pos = pos2;
1745
1746 rr = (dns_rr_t *) pos;
Dave Barachd2080152017-10-20 09:21:35 -04001747 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
Dave Barach65457162017-10-10 17:53:14 -04001748
Dave Barachd2080152017-10-20 09:21:35 -04001749 switch (rrtype_host_byte_order)
Dave Barach65457162017-10-10 17:53:14 -04001750 {
1751 case DNS_TYPE_A:
1752 if (verbose > 1)
1753 {
1754 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1755 format_ip4_address, rr->rdata);
1756 }
1757 else
1758 {
1759 if (*print_ip4)
1760 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1761 clib_net_to_host_u32 (rr->ttl));
1762 if (verbose == 0)
1763 *print_ip4 = 0;
1764
1765 }
1766 pos += sizeof (*rr) + 4;
1767 break;
1768
1769 case DNS_TYPE_AAAA:
1770 if (verbose > 1)
1771 {
1772 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1773 format_ip6_address, rr->rdata);
1774 }
1775 else
1776 {
1777 if (*print_ip6)
1778 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1779 clib_net_to_host_u32 (rr->ttl));
1780 if (verbose == 0)
1781 *print_ip6 = 0;
1782 }
1783 pos += sizeof (*rr) + 16;
1784 break;
1785
1786 case DNS_TYPE_TEXT:
1787 if (verbose > 1)
1788 {
1789 s = format (s, "TEXT: ");
1790 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1791 vec_add1 (s, rr->rdata[i]);
1792 vec_add1 (s, '\n');
1793 }
1794 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1795 break;
1796
Dave Barach0cb01bd2017-10-16 14:39:52 -04001797 case DNS_TYPE_HINFO:
1798 {
1799 /* Two counted strings. DGMS */
1800 u8 *len;
1801 u8 *curpos;
1802 int i;
1803 if (verbose > 1)
1804 {
1805 s = format (s, "HINFO: ");
1806 len = rr->rdata;
1807 curpos = len + 1;
1808 for (i = 0; i < *len; i++)
1809 vec_add1 (s, *curpos++);
1810
1811 vec_add1 (s, ' ');
1812 len = curpos++;
1813 for (i = 0; i < *len; i++)
1814 vec_add1 (s, *curpos++);
1815
1816 vec_add1 (s, '\n');
1817 }
1818 }
1819 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1820 break;
1821
Dave Barach65457162017-10-10 17:53:14 -04001822 case DNS_TYPE_NAMESERVER:
1823 if (verbose > 1)
1824 {
1825 s = format (s, "Nameserver: ");
1826 pos2 = rr->rdata;
1827
1828 /* chase pointer? */
1829 if (pos2[0] == 0xc0)
1830 pos2 = reply + pos2[1];
1831
1832 len = *pos2++;
1833
1834 while (len)
1835 {
1836 for (i = 0; i < len; i++)
1837 vec_add1 (s, *pos2++);
1838
1839 /* chase pointer, typically to offset 12... */
1840 if (pos2[0] == 0xC0)
1841 pos2 = reply + pos2[1];
1842
1843 len = *pos2++;
1844 if (len)
1845 vec_add1 (s, '.');
1846 else
1847 vec_add1 (s, '\n');
1848 }
1849 }
1850 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1851 break;
1852
1853 case DNS_TYPE_MAIL_EXCHANGE:
1854 if (verbose > 1)
1855 {
1856 tp = (u16 *) rr->rdata;
1857
1858 s = format (s, "Mail Exchange: Preference %d ", (u32)
1859 clib_net_to_host_u16 (*tp));
1860
1861 pos2 = rr->rdata + 2;
1862
1863 /* chase pointer? */
1864 if (pos2[0] == 0xc0)
1865 pos2 = reply + pos2[1];
1866
1867 len = *pos2++;
1868
1869 while (len)
1870 {
1871 for (i = 0; i < len; i++)
1872 vec_add1 (s, *pos2++);
1873
1874 /* chase pointer */
1875 if (pos2[0] == 0xC0)
1876 pos2 = reply + pos2[1];
1877
1878 len = *pos2++;
1879 if (len)
1880 vec_add1 (s, '.');
1881 else
1882 vec_add1 (s, '\n');
1883 }
1884 }
1885
1886 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1887 break;
1888
Dave Barachd2080152017-10-20 09:21:35 -04001889 case DNS_TYPE_PTR:
Dave Barach65457162017-10-10 17:53:14 -04001890 case DNS_TYPE_CNAME:
1891 if (verbose > 1)
1892 {
1893 tp = (u16 *) rr->rdata;
1894
Dave Barachd2080152017-10-20 09:21:35 -04001895 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
1896 s = format (s, "CNAME: ");
1897 else
1898 s = format (s, "PTR: ");
Dave Barach65457162017-10-10 17:53:14 -04001899
1900 pos2 = rr->rdata;
1901
1902 /* chase pointer? */
1903 if (pos2[0] == 0xc0)
1904 pos2 = reply + pos2[1];
1905
1906 len = *pos2++;
1907
1908 while (len)
1909 {
1910 for (i = 0; i < len; i++)
1911 vec_add1 (s, *pos2++);
1912
1913 /* chase pointer */
1914 if (pos2[0] == 0xC0)
1915 pos2 = reply + pos2[1];
1916
1917 len = *pos2++;
1918 if (len)
1919 vec_add1 (s, '.');
1920 else
1921 vec_add1 (s, '\n');
1922 }
1923 }
1924 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1925 break;
1926
1927 default:
1928 if (verbose > 1)
1929 s = format (s, "type %d: len %d\n",
1930 (int) clib_net_to_host_u16 (rr->type),
1931 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
1932 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1933 break;
1934 }
1935
1936 *curpos = pos;
1937
1938 return s;
1939}
1940
1941u8 *
1942format_dns_reply (u8 * s, va_list * args)
1943{
1944 u8 *reply_as_u8 = va_arg (*args, u8 *);
1945 int verbose = va_arg (*args, int);
1946 dns_header_t *h;
1947 u16 id, flags;
1948 u8 *curpos;
1949 int i;
1950 int print_ip4 = 1;
1951 int print_ip6 = 1;
1952
1953 h = (dns_header_t *) reply_as_u8;
1954 id = clib_net_to_host_u16 (h->id);
1955 flags = clib_net_to_host_u16 (h->flags);
1956
1957 if (verbose > 1)
1958 {
1959 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
1960 id);
1961 s = format (s, " %s %s %s %s\n",
1962 (flags & DNS_RA) ? "recur" : "no-recur",
1963 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
1964 (flags & DNS_TC) ? "trunc" : "no-trunc",
1965 (flags & DNS_AA) ? "auth" : "non-auth");
1966 s = format (s, " %d queries, %d answers, %d name-servers,"
1967 " %d add'l recs\n",
1968 clib_net_to_host_u16 (h->qdcount),
1969 clib_net_to_host_u16 (h->anscount),
1970 clib_net_to_host_u16 (h->nscount),
1971 clib_net_to_host_u16 (h->arcount));
1972 }
1973
1974 curpos = (u8 *) (h + 1);
1975
1976 if (h->qdcount)
1977 {
1978 if (verbose > 1)
1979 s = format (s, " Queries:\n");
1980 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1981 {
1982 /* The query is variable-length, so curpos is a value-result parm */
1983 s = format (s, "%U", format_dns_query, &curpos, verbose);
1984 }
1985 }
1986 if (h->anscount)
1987 {
1988 if (verbose > 1)
1989 s = format (s, " Replies:\n");
1990
1991 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1992 {
1993 /* curpos is a value-result parm */
1994 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
1995 verbose, &print_ip4, &print_ip6);
1996 }
1997 }
1998 return s;
1999}
2000
2001u8 *
2002format_dns_cache (u8 * s, va_list * args)
2003{
2004 dns_main_t *dm = va_arg (*args, dns_main_t *);
2005 f64 now = va_arg (*args, f64);
2006 int verbose = va_arg (*args, int);
2007 u8 *name = va_arg (*args, u8 *);
2008 dns_cache_entry_t *ep;
2009 char *ss;
2010 uword *p;
2011
2012 if (dm->is_enabled == 0)
2013 {
2014 s = format (s, "The DNS cache is disabled...");
2015 return s;
2016 }
2017
2018 if (pool_elts (dm->entries) == 0)
2019 {
2020 s = format (s, "The DNS cache is empty...");
2021 return s;
2022 }
2023
2024 dns_cache_lock (dm);
2025
2026 if (name)
2027 {
2028 p = hash_get_mem (dm->cache_entry_by_name, name);
2029 if (!p)
2030 {
2031 s = format (s, "%s is not in the cache...", name);
2032 dns_cache_unlock (dm);
2033 return (s);
2034 }
2035
2036 ep = pool_elt_at_index (dm->entries, p[0]);
2037 /* Magic to spit out a C-initializer to research hemorrhoids... */
2038 if (verbose == 3)
2039 {
2040 int i, j;
2041 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2042 s = format (s, "{\n");
2043 j = 0;
2044 for (i = 0; i < vec_len (ep->dns_response); i++)
2045 {
2046 if (j++ == 8)
2047 {
2048 j = 0;
2049 vec_add1 (s, '\n');
2050 }
2051 s = format (s, "0x%02x, ", ep->dns_response[i]);
2052 }
2053 s = format (s, "};\n");
2054 }
2055 else
2056 {
2057 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2058 {
2059 ASSERT (ep->dns_response);
2060 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2061 ss = "[S] ";
2062 else
2063 ss = " ";
2064
Dave Barach0cb01bd2017-10-16 14:39:52 -04002065 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2066 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2067 else
2068 s = format (s, "%s%s -> %U", ss, ep->name,
2069 format_dns_reply, ep->dns_response, verbose);
Dave Barach65457162017-10-10 17:53:14 -04002070 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2071 {
2072 f64 time_left = ep->expiration_time - now;
2073 if (time_left > 0.0)
2074 s = format (s, " TTL left %.1f", time_left);
2075 else
2076 s = format (s, " EXPIRED");
2077 }
2078 }
2079 else
2080 {
2081 ASSERT (ep->dns_request);
2082 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2083 verbose);
2084 }
2085 vec_add1 (s, '\n');
2086 }
2087 return s;
2088 }
2089
2090 /* *INDENT-OFF* */
2091 pool_foreach (ep, dm->entries,
2092 ({
2093 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2094 {
2095 ASSERT (ep->dns_response);
2096 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2097 ss = "[S] ";
2098 else
2099 ss = " ";
2100
Dave Barach0cb01bd2017-10-16 14:39:52 -04002101 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2102 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2103 else
2104 s = format (s, "%s%s -> %U", ss, ep->name,
2105 format_dns_reply,
2106 ep->dns_response,
2107 verbose);
Dave Barach65457162017-10-10 17:53:14 -04002108 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2109 {
2110 f64 time_left = ep->expiration_time - now;
2111 if (time_left > 0.0)
2112 s = format (s, " TTL left %.1f", time_left);
2113 else
2114 s = format (s, " EXPIRED");
Dave Barach0cb01bd2017-10-16 14:39:52 -04002115
2116 if (verbose > 2)
2117 s = format (s, " %d client notifications pending\n",
Dave Barach97494502017-11-04 09:44:38 -04002118 vec_len(ep->pending_requests));
Dave Barach65457162017-10-10 17:53:14 -04002119 }
2120 }
2121 else
2122 {
2123 ASSERT (ep->dns_request);
2124 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2125 verbose);
2126 }
2127 vec_add1 (s, '\n');
2128 }));
2129 /* *INDENT-ON* */
2130
2131 dns_cache_unlock (dm);
2132
2133 return s;
2134}
2135
2136static clib_error_t *
2137show_dns_cache_command_fn (vlib_main_t * vm,
2138 unformat_input_t * input, vlib_cli_command_t * cmd)
2139{
2140 dns_main_t *dm = &dns_main;
2141 int verbose = 0;
2142 u8 *name = 0;
2143 f64 now = vlib_time_now (vm);
2144
2145 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2146 {
2147 if (unformat (input, "verbose %d", &verbose))
2148 ;
2149 else if (unformat (input, "verbose"))
2150 verbose = 1;
2151 else if (unformat (input, "name %s", &name))
2152 ;
2153 else
2154 return clib_error_return (0, "unknown input `%U'",
2155 format_unformat_error, input);
2156 }
2157
2158 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2159
2160 return 0;
2161}
2162
2163/* *INDENT-OFF* */
2164VLIB_CLI_COMMAND (show_dns_cache_command) =
2165{
2166 .path = "show dns cache",
2167 .short_help = "show dns cache [verbose [nn]]",
2168 .function = show_dns_cache_command_fn,
2169};
2170/* *INDENT-ON* */
2171
2172static clib_error_t *
2173dns_cache_add_del_command_fn (vlib_main_t * vm,
2174 unformat_input_t * input,
2175 vlib_cli_command_t * cmd)
2176{
2177 dns_main_t *dm = &dns_main;
2178 u8 *dns_reply_data;
2179 u8 *name;
2180 int is_add = -1;
2181 int is_clear = -1;
2182 int rv;
2183 clib_error_t *error;
2184
2185 if (unformat (input, "add"))
2186 is_add = 1;
2187 if (unformat (input, "del"))
2188 is_add = 0;
2189 if (unformat (input, "clear"))
2190 is_clear = 1;
2191
2192 if (is_add == -1 && is_clear == -1)
2193 return clib_error_return (0, "add / del / clear required...");
2194
2195 if (is_clear == 1)
2196 {
2197 rv = dns_cache_clear (dm);
2198 switch (rv)
2199 {
2200 case 0:
2201 return 0;
2202
2203 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2204 error = clib_error_return (0, "Name resolution not enabled");
2205 return error;
2206 }
2207 }
2208
2209 /* Delete (by name)? */
2210 if (is_add == 0)
2211 {
2212 if (unformat (input, "%v", &name))
2213 {
2214 rv = dns_delete_by_name (dm, name);
2215 switch (rv)
2216 {
2217 case VNET_API_ERROR_NO_SUCH_ENTRY:
2218 error = clib_error_return (0, "%v not in the cache...", name);
2219 vec_free (name);
2220 return error;
2221
2222 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2223 error = clib_error_return (0, "Name resolution not enabled");
2224 vec_free (name);
2225 return error;
2226
2227 case 0:
2228 vec_free (name);
2229 return 0;
2230
2231 default:
2232 error = clib_error_return (0, "dns_delete_by_name returned %d",
2233 rv);
2234 vec_free (name);
2235 return error;
2236 }
2237 }
2238 return clib_error_return (0, "unknown input `%U'",
2239 format_unformat_error, input);
2240 }
2241
2242 /* Note: dns_add_static_entry consumes the name vector if OK... */
2243 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2244 {
2245 rv = dns_add_static_entry (dm, name, dns_reply_data);
2246 switch (rv)
2247 {
2248 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2249 vec_free (name);
2250 vec_free (dns_reply_data);
2251 return clib_error_return (0, "%v already in the cache...", name);
2252 case 0:
2253 return 0;
2254
2255 default:
2256 return clib_error_return (0, "dns_add_static_entry returned %d",
2257 rv);
2258 }
2259 }
2260
2261 return 0;
2262}
2263
2264/* *INDENT-OFF* */
2265VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2266{
2267 .path = "dns cache",
2268 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2269 .function = dns_cache_add_del_command_fn,
2270};
2271/* *INDENT-ON* */
2272
2273#define DNS_FORMAT_TEST 1
2274
2275#if DNS_FORMAT_TEST > 0
2276#if 0
2277/* yahoo.com */
2278static u8 dns_reply_data_initializer[] =
2279 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2280 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2281 0x0, /* null lbl */
2282 0x0, 0xff, /* type ALL */
2283 0x0, 0x1, /* class IN */
2284 0xc0, 0xc, /* pointer to yahoo.com name */
2285 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2286 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2287 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2288 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2289 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2290 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2291 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2292 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2293 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2294 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2295 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2296 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2297 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2298 0x6e,
2299 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2300 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2301 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2302 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2303 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2304 0x0,
2305 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2306 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2307 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2308 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2309 0x0,
2310 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2311 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2312 0x0,
2313 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2314 0x0,
2315 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2316 0x0,
2317 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2318 0x6f,
2319 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2320 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2321 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2322 0x2, 0x58
2323};
2324
2325/* www.cisco.com, has no addresses in reply */
2326static u8 dns_reply_data_initializer[] = {
2327 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2328 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2329 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2330
2331 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2332 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2333 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2334 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2335 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2336};
2337#else
2338/* google.com */
2339static u8 dns_reply_data_initializer[] =
2340 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2341 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2342 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2343 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2344 0x2b,
2345 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2346 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2347 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2348 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2349 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2350 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2351 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2352 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2353 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2354 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2355 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2356 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2357 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2358 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2359 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2360 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2361 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2362 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2363 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2364 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2365 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2366 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2367 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2368 0x57,
2369 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2370};
2371#endif
2372
2373static clib_error_t *
2374test_dns_fmt_command_fn (vlib_main_t * vm,
2375 unformat_input_t * input, vlib_cli_command_t * cmd)
2376{
2377 u8 *dns_reply_data = 0;
2378 int verbose = 0;
2379 int rv;
2380 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2381
2382 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2383 {
2384 if (unformat (input, "verbose %d", &verbose))
2385 ;
2386 else if (unformat (input, "verbose"))
2387 verbose = 1;
2388 else
2389 return clib_error_return (0, "unknown input `%U'",
2390 format_unformat_error, input);
2391 }
2392
2393 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2394
2395 memcpy (dns_reply_data, dns_reply_data_initializer,
2396 ARRAY_LEN (dns_reply_data_initializer));
2397
2398 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2399
2400 memset (rmp, 0, sizeof (*rmp));
2401
2402 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2403
2404 switch (rv)
2405 {
2406 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2407 vlib_cli_output (vm, "no addresses found...");
2408 break;
2409
2410 default:
2411 vlib_cli_output (vm, "response to reply returned %d", rv);
2412 break;
2413
2414 case 0:
2415 if (rmp->ip4_set)
2416 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2417 (ip4_address_t *) rmp->ip4_address);
2418 if (rmp->ip6_set)
2419 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2420 (ip6_address_t *) rmp->ip6_address);
2421 break;
2422 }
2423
2424 vec_free (dns_reply_data);
2425
2426 return 0;
2427}
2428
2429
2430/* *INDENT-OFF* */
2431VLIB_CLI_COMMAND (test_dns_fmt_command) =
2432{
2433 .path = "test dns format",
2434 .short_help = "test dns format",
2435 .function = test_dns_fmt_command_fn,
2436};
2437/* *INDENT-ON* */
2438
2439static clib_error_t *
2440test_dns_unfmt_command_fn (vlib_main_t * vm,
2441 unformat_input_t * input, vlib_cli_command_t * cmd)
2442{
2443 u8 *dns_reply_data = 0;
2444 int verbose = 0;
2445 int reply_set = 0;
2446
2447 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2448 {
2449 if (unformat (input, "verbose %d", &verbose))
2450 ;
2451 else if (unformat (input, "verbose"))
2452 verbose = 1;
2453 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2454 reply_set = 1;
2455 else
2456 return clib_error_return (0, "unknown input `%U'",
2457 format_unformat_error, input);
2458 }
2459
2460 if (reply_set == 0)
2461 return clib_error_return (0, "dns data not set...");
2462
2463 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2464
2465 vec_free (dns_reply_data);
2466
2467 return 0;
2468}
2469
2470/* *INDENT-OFF* */
2471VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2472{
2473 .path = "test dns unformat",
2474 .short_help = "test dns unformat <name> [ip4][ip6]",
2475 .function = test_dns_unfmt_command_fn,
2476};
2477/* *INDENT-ON* */
Dave Barach0cb01bd2017-10-16 14:39:52 -04002478
2479static clib_error_t *
2480test_dns_expire_command_fn (vlib_main_t * vm,
2481 unformat_input_t * input,
2482 vlib_cli_command_t * cmd)
2483{
2484 dns_main_t *dm = &dns_main;
2485 u8 *name;
2486 uword *p;
2487 clib_error_t *e;
2488 dns_cache_entry_t *ep;
2489
2490 if (unformat (input, "%v", &name))
2491 {
2492 vec_add1 (name, 0);
2493 _vec_len (name) -= 1;
2494 }
2495
2496 dns_cache_lock (dm);
2497
2498 p = hash_get_mem (dm->cache_entry_by_name, name);
2499 if (!p)
2500 {
2501 dns_cache_unlock (dm);
2502 e = clib_error_return (0, "%s is not in the cache...", name);
2503 vec_free (name);
2504 return e;
2505 }
2506
2507 ep = pool_elt_at_index (dm->entries, p[0]);
2508
2509 ep->expiration_time = 0;
2510
2511 return 0;
2512}
2513
2514/* *INDENT-OFF* */
2515VLIB_CLI_COMMAND (test_dns_expire_command) =
2516{
2517 .path = "test dns expire",
2518 .short_help = "test dns expire <name>",
2519 .function = test_dns_expire_command_fn,
2520};
2521/* *INDENT-ON* */
Dave Barach65457162017-10-10 17:53:14 -04002522#endif
2523
Dave Barach97494502017-11-04 09:44:38 -04002524void
2525vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
2526 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2527{
2528 clib_warning ("Unimplemented...");
2529}
2530
2531
2532void
2533vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
2534 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2535{
2536 vlib_main_t *vm = dm->vlib_main;
2537 u32 bi;
2538 fib_prefix_t prefix;
2539 fib_node_index_t fei;
2540 u32 sw_if_index, fib_index;
2541 ip4_main_t *im4 = &ip4_main;
2542 ip_lookup_main_t *lm4 = &im4->lookup_main;
2543 ip_interface_address_t *ia = 0;
2544 ip4_address_t *src_address;
2545 ip4_header_t *ip;
2546 udp_header_t *udp;
2547 dns_header_t *dh;
2548 vlib_frame_t *f;
2549 u32 *to_next;
2550 u8 *dns_response;
2551 u8 *reply;
2552 vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2553 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2554 u32 ttl, tmp;
2555 u32 qp_offset;
2556 dns_query_t *qp;
2557 dns_rr_t *rr;
2558 u8 *rrptr;
2559 int is_fail = 0;
2560
2561 ASSERT (ep && ep->dns_response);
2562
2563 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2564 {
2565 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2566 memset (rnr, 0, sizeof (*rnr));
2567 if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2568 {
2569 /* clib_warning ("response_to_reply failed..."); */
2570 is_fail = 1;
2571 }
2572 if (rnr->ip4_set == 0)
2573 {
2574 /* clib_warning ("No A-record..."); */
2575 is_fail = 1;
2576 }
2577 }
2578 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2579 {
2580 memset (rir, 0, sizeof (*rir));
2581 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2582 {
2583 /* clib_warning ("response_to_name failed..."); */
2584 is_fail = 1;
2585 }
2586 }
2587 else
2588 {
2589 clib_warning ("Unknown request type %d", pr->request_type);
2590 return;
2591 }
2592
2593 /* Initialize a buffer */
2594 if (b0 == 0)
2595 {
2596 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2597 return;
2598 b0 = vlib_get_buffer (vm, bi);
2599 }
2600
2601 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2602 vlib_buffer_free_one (vm, b0->next_buffer);
2603
2604 /*
2605 * Reset the buffer. We recycle the DNS request packet in the cache
2606 * hit case, and reply immediately from the request node.
2607 *
2608 * In the resolution-required / deferred case, resetting a freshly-allocated
2609 * buffer won't hurt. We hope.
2610 */
2611 b0->flags &= VLIB_BUFFER_FREE_LIST_INDEX_MASK;
2612 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2613 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2614 b0->current_data = 0;
2615 b0->current_length = 0;
2616 b0->total_length_not_including_first_buffer = 0;
2617 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2618 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2619
2620 /* Find a FIB path to the peer we're trying to answer */
2621 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2622 prefix.fp_proto = FIB_PROTOCOL_IP4;
2623 prefix.fp_len = 32;
2624
2625 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2626 if (fib_index == (u32) ~ 0)
2627 {
2628 clib_warning ("no fib table");
2629 return;
2630 }
2631
2632 fei = fib_table_lookup (fib_index, &prefix);
2633
2634 /* Couldn't find route to destination. Bail out. */
2635 if (fei == FIB_NODE_INDEX_INVALID)
2636 {
2637 clib_warning ("no route to DNS server");
2638 return;
2639 }
2640
2641 sw_if_index = fib_entry_get_resolving_interface (fei);
2642
2643 if (sw_if_index == ~0)
2644 {
2645 clib_warning
2646 ("route to %U exists, fei %d, get_resolving_interface returned"
2647 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2648 return;
2649 }
2650
2651 /* *INDENT-OFF* */
2652 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnummbered */,
2653 ({
2654 src_address = ip_interface_address_get_address (lm4, ia);
2655 goto found_src_address;
2656 }));
2657 /* *INDENT-ON* */
2658
2659 clib_warning ("FIB BUG");
2660 return;
2661
2662found_src_address:
2663
2664 ip = vlib_buffer_get_current (b0);
2665 udp = (udp_header_t *) (ip + 1);
2666 dns_response = (u8 *) (udp + 1);
2667 memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2668
2669 /*
2670 * Start with the variadic portion of the exercise.
2671 * Turn the name into a set of DNS "labels". Max length
2672 * per label is 63, enforce that.
2673 */
2674 reply = name_to_labels (pr->name);
2675 vec_free (pr->name);
2676
2677 qp_offset = vec_len (reply);
2678
2679 /* Add space for the query header */
2680 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2681
2682 qp = (dns_query_t *) (reply + qp_offset);
2683
2684 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2685 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2686 else
2687 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2688
2689 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2690
2691 /* Punch in space for the dns_header_t */
2692 vec_insert (reply, sizeof (dns_header_t), 0);
2693
2694 dh = (dns_header_t *) reply;
2695
2696 /* Transaction ID = pool index */
2697 dh->id = pr->id;
2698
2699 /* Announce that we did a recursive lookup */
2700 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2701 if (is_fail)
2702 tmp |= DNS_RCODE_NAME_ERROR;
2703 dh->flags = clib_host_to_net_u16 (tmp);
2704 dh->qdcount = clib_host_to_net_u16 (1);
2705 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2706 dh->nscount = 0;
2707 dh->arcount = 0;
2708
2709 /* If the name resolution worked, cough up an appropriate RR */
2710 if (is_fail == 0)
2711 {
2712 /* Add the answer. First, a name pointer (0xC00C) */
2713 vec_add1 (reply, 0xC0);
2714 vec_add1 (reply, 0x0C);
2715
2716 /* Now, add single A-rec RR */
2717 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2718 {
2719 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2720 rr = (dns_rr_t *) rrptr;
2721
2722 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2723 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2724 rr->ttl = clib_host_to_net_u32 (ttl);
2725 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2726 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2727 }
2728 else
2729 {
2730 /* Or a single PTR RR */
2731 u8 *vecname = format (0, "%s", rir->name);
2732 u8 *label_vec = name_to_labels (vecname);
2733 vec_free (vecname);
2734
2735 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2736 rr = (dns_rr_t *) rrptr;
2737 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2738 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2739 rr->ttl = clib_host_to_net_u32 (ttl);
2740 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2741 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2742 vec_free (label_vec);
2743 }
2744 }
2745 clib_memcpy (dns_response, reply, vec_len (reply));
2746
2747 /* Set the packet length */
2748 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2749
2750 /* IP header */
2751 ip->ip_version_and_header_length = 0x45;
2752 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2753 ip->ttl = 255;
2754 ip->protocol = IP_PROTOCOL_UDP;
2755 ip->src_address.as_u32 = src_address->as_u32;
2756 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2757 sizeof (ip4_address_t));
2758 ip->checksum = ip4_header_checksum (ip);
2759
2760 /* UDP header */
2761 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2762 udp->dst_port = pr->dst_port;
2763 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2764 vec_len (reply));
2765 udp->checksum = 0;
2766 vec_free (reply);
2767
2768 /* Ship it to ip4_lookup */
2769 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2770 to_next = vlib_frame_vector_args (f);
2771 to_next[0] = bi;
2772 f->n_vectors = 1;
2773 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2774}
2775
Dave Barach65457162017-10-10 17:53:14 -04002776/*
2777 * fd.io coding-style-patch-verification: ON
2778 *
2779 * Local Variables:
2780 * eval: (c-set-style "gnu")
2781 * End:
2782 */