blob: cf76439ac8e406a8fe9139fac1b4f028ad7d85b0 [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;
Dave Barach52925382017-11-16 10:01:12 -05001078 u8 *curpos, *pos, *pos2;
Dave Barach65457162017-10-10 17:53:14 -04001079 u16 flags;
1080 u16 rcode;
1081 u32 ttl;
Dave Barach52925382017-11-16 10:01:12 -05001082 int pointer_chase;
Dave Barach65457162017-10-10 17:53:14 -04001083
1084 h = (dns_header_t *) response;
1085 flags = clib_net_to_host_u16 (h->flags);
1086 rcode = flags & DNS_RCODE_MASK;
1087
1088 /* See if the response is OK, etc. */
1089 switch (rcode)
1090 {
1091 default:
1092 case DNS_RCODE_NO_ERROR:
1093 break;
1094
1095 case DNS_RCODE_NAME_ERROR:
1096 case DNS_RCODE_FORMAT_ERROR:
1097 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1098
1099 case DNS_RCODE_SERVER_FAILURE:
1100 case DNS_RCODE_NOT_IMPLEMENTED:
1101 case DNS_RCODE_REFUSED:
1102 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1103 }
1104
1105 /* No answers? Loser... */
1106 if (clib_net_to_host_u16 (h->anscount) < 1)
1107 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1108
1109 curpos = (u8 *) (h + 1);
1110
1111 /* Skip the name we asked about */
1112 pos = curpos;
1113 len = *pos++;
1114 /* Should never happen, but stil... */
1115 if ((len & 0xC0) == 0xC0)
1116 curpos += 2;
1117 else
1118 {
1119 /* skip the name / label-set */
1120 while (len)
1121 {
1122 pos += len;
1123 len = *pos++;
1124 }
1125 curpos = pos;
1126 }
1127 /* Skip queries */
1128 limit = clib_net_to_host_u16 (h->qdcount);
1129 qp = (dns_query_t *) curpos;
1130 qp += limit;
1131 curpos = (u8 *) qp;
1132
1133 /* Parse answers */
1134 limit = clib_net_to_host_u16 (h->anscount);
1135
1136 for (i = 0; i < limit; i++)
1137 {
Dave Barach52925382017-11-16 10:01:12 -05001138 pos = pos2 = curpos;
1139 pointer_chase = 0;
Dave Barach65457162017-10-10 17:53:14 -04001140
1141 /* Expect pointer chases in the answer section... */
Dave Barach52925382017-11-16 10:01:12 -05001142 if ((pos2[0] & 0xC0) == 0xC0)
Dave Barach65457162017-10-10 17:53:14 -04001143 {
Dave Barach52925382017-11-16 10:01:12 -05001144 pos = pos2 + 2;
1145 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1146 pointer_chase = 1;
Dave Barach65457162017-10-10 17:53:14 -04001147 }
1148
Dave Barach52925382017-11-16 10:01:12 -05001149 len = *pos2++;
1150
1151 while (len)
1152 {
1153 pos2 += len;
1154 if ((pos2[0] & 0xc0) == 0xc0)
1155 {
1156 /*
1157 * If we've already done one pointer chase,
1158 * do not move the pos pointer.
1159 */
1160 if (pointer_chase == 0)
1161 pos = pos2 + 2;
1162 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1163 len = *pos2++;
1164 pointer_chase = 1;
1165 }
1166 else
1167 len = *pos2++;
1168 }
1169
1170 if (pointer_chase == 0)
1171 pos = pos2;
1172
1173 rr = (dns_rr_t *) pos;
Dave Barach65457162017-10-10 17:53:14 -04001174
1175 switch (clib_net_to_host_u16 (rr->type))
1176 {
1177 case DNS_TYPE_A:
1178 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1179 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1180 rmp->ip4_set = 1;
1181 ttl = clib_net_to_host_u32 (rr->ttl);
1182 if (min_ttlp && *min_ttlp > ttl)
1183 *min_ttlp = ttl;
1184 break;
1185 case DNS_TYPE_AAAA:
1186 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1187 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1188 ttl = clib_net_to_host_u32 (rr->ttl);
1189 if (min_ttlp && *min_ttlp > ttl)
1190 *min_ttlp = ttl;
1191 rmp->ip6_set = 1;
1192 break;
Dave Barach52925382017-11-16 10:01:12 -05001193
Dave Barach65457162017-10-10 17:53:14 -04001194 default:
1195 break;
1196 }
1197 /* Might as well stop ASAP */
1198 if (rmp->ip4_set && rmp->ip6_set)
1199 break;
Dave Barach52925382017-11-16 10:01:12 -05001200 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1201 curpos = pos;
Dave Barach65457162017-10-10 17:53:14 -04001202 }
1203
1204 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1205 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1206 return 0;
1207}
1208
Dave Barachd2080152017-10-20 09:21:35 -04001209int
1210vnet_dns_response_to_name (u8 * response,
1211 vl_api_dns_resolve_ip_reply_t * rmp,
1212 u32 * min_ttlp)
1213{
1214 dns_header_t *h;
1215 dns_query_t *qp;
1216 dns_rr_t *rr;
1217 int i, limit;
1218 u8 len;
Dave Barach52925382017-11-16 10:01:12 -05001219 u8 *curpos, *pos, *pos2;
Dave Barachd2080152017-10-20 09:21:35 -04001220 u16 flags;
1221 u16 rcode;
1222 u8 *name;
1223 u32 ttl;
1224 u8 *junk __attribute__ ((unused));
1225 int name_set = 0;
Dave Barach52925382017-11-16 10:01:12 -05001226 int pointer_chase;
Dave Barachd2080152017-10-20 09:21:35 -04001227
1228 h = (dns_header_t *) response;
1229 flags = clib_net_to_host_u16 (h->flags);
1230 rcode = flags & DNS_RCODE_MASK;
1231
1232 /* See if the response is OK, etc. */
1233 switch (rcode)
1234 {
1235 default:
1236 case DNS_RCODE_NO_ERROR:
1237 break;
1238
1239 case DNS_RCODE_NAME_ERROR:
1240 case DNS_RCODE_FORMAT_ERROR:
1241 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1242
1243 case DNS_RCODE_SERVER_FAILURE:
1244 case DNS_RCODE_NOT_IMPLEMENTED:
1245 case DNS_RCODE_REFUSED:
1246 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1247 }
1248
1249 /* No answers? Loser... */
1250 if (clib_net_to_host_u16 (h->anscount) < 1)
1251 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1252
1253 curpos = (u8 *) (h + 1);
1254
1255 /* Skip the name we asked about */
1256 pos = curpos;
1257 len = *pos++;
1258 /* Should never happen, but stil... */
1259 if ((len & 0xC0) == 0xC0)
1260 curpos += 2;
1261 else
1262 {
1263 /* skip the name / label-set */
1264 while (len)
1265 {
1266 pos += len;
1267 len = *pos++;
1268 }
1269 curpos = pos;
1270 }
1271 /* Skip queries */
1272 limit = clib_net_to_host_u16 (h->qdcount);
1273 qp = (dns_query_t *) curpos;
1274 qp += limit;
1275 curpos = (u8 *) qp;
1276
1277 /* Parse answers */
1278 limit = clib_net_to_host_u16 (h->anscount);
1279
1280 for (i = 0; i < limit; i++)
1281 {
Dave Barach52925382017-11-16 10:01:12 -05001282 pos = pos2 = curpos;
1283 pointer_chase = 0;
Dave Barachd2080152017-10-20 09:21:35 -04001284
1285 /* Expect pointer chases in the answer section... */
Dave Barach52925382017-11-16 10:01:12 -05001286 if ((pos2[0] & 0xC0) == 0xC0)
Dave Barachd2080152017-10-20 09:21:35 -04001287 {
Dave Barach52925382017-11-16 10:01:12 -05001288 pos = pos2 + 2;
1289 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1290 pointer_chase = 1;
Dave Barachd2080152017-10-20 09:21:35 -04001291 }
1292
Dave Barach52925382017-11-16 10:01:12 -05001293 len = *pos2++;
1294
1295 while (len)
1296 {
1297 pos2 += len;
1298 if ((pos2[0] & 0xc0) == 0xc0)
1299 {
1300 /*
1301 * If we've already done one pointer chase,
1302 * do not move the pos pointer.
1303 */
1304 if (pointer_chase == 0)
1305 pos = pos2 + 2;
1306 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1307 len = *pos2++;
1308 pointer_chase = 1;
1309 }
1310 else
1311 len = *pos2++;
1312 }
1313
1314 if (pointer_chase == 0)
1315 pos = pos2;
1316
1317 rr = (dns_rr_t *) pos;
Dave Barachd2080152017-10-20 09:21:35 -04001318
1319 switch (clib_net_to_host_u16 (rr->type))
1320 {
1321 case DNS_TYPE_PTR:
Dave Barach97494502017-11-04 09:44:38 -04001322 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
Dave Barachd2080152017-10-20 09:21:35 -04001323 memcpy (rmp->name, name, vec_len (name));
1324 ttl = clib_net_to_host_u32 (rr->ttl);
Dave Barach52925382017-11-16 10:01:12 -05001325 if (min_ttlp)
Dave Barachd2080152017-10-20 09:21:35 -04001326 *min_ttlp = ttl;
1327 rmp->name[vec_len (name)] = 0;
1328 name_set = 1;
1329 break;
1330 default:
1331 break;
1332 }
1333 /* Might as well stop ASAP */
1334 if (name_set == 1)
1335 break;
Dave Barach52925382017-11-16 10:01:12 -05001336 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1337 curpos = pos;
Dave Barachd2080152017-10-20 09:21:35 -04001338 }
1339
1340 if (name_set == 0)
1341 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1342 return 0;
1343}
1344
Dave Barach65457162017-10-10 17:53:14 -04001345static void
1346vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1347{
1348 dns_main_t *dm = &dns_main;
1349 vl_api_dns_resolve_name_reply_t *rmp;
1350 dns_cache_entry_t *ep;
Dave Barach97494502017-11-04 09:44:38 -04001351 dns_pending_request_t _t0, *t0 = &_t0;
Dave Barach65457162017-10-10 17:53:14 -04001352 int rv;
1353
1354 /* Sanitize the name slightly */
1355 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1356
Dave Barach97494502017-11-04 09:44:38 -04001357 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1358 t0->client_index = mp->client_index;
1359 t0->client_context = mp->context;
1360
1361 rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
Dave Barach65457162017-10-10 17:53:14 -04001362
1363 /* Error, e.g. not enabled? Tell the user */
1364 if (rv < 0)
1365 {
1366 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1367 return;
1368 }
1369
1370 /* Resolution pending? Don't reply... */
1371 if (ep == 0)
1372 return;
1373
1374 /* *INDENT-OFF* */
1375 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1376 ({
1377 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1378 rmp->retval = clib_host_to_net_u32 (rv);
1379 }));
1380 /* *INDENT-ON* */
1381
1382 /*
1383 * dns_resolve_name leaves the cache locked when it returns
1384 * a cached result, so unlock it here.
1385 */
1386 dns_cache_unlock (dm);
1387}
1388
Dave Barachd2080152017-10-20 09:21:35 -04001389static void
1390vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1391{
1392 dns_main_t *dm = &dns_main;
1393 vl_api_dns_resolve_ip_reply_t *rmp;
1394 dns_cache_entry_t *ep;
1395 int rv;
1396 int i, len;
1397 u8 *lookup_name = 0;
1398 u8 digit, nybble;
Dave Barach97494502017-11-04 09:44:38 -04001399 dns_pending_request_t _t0, *t0 = &_t0;
Dave Barachd2080152017-10-20 09:21:35 -04001400
1401 if (mp->is_ip6)
1402 {
1403 for (i = 15; i >= 0; i--)
1404 {
1405 digit = mp->address[i];
1406 nybble = (digit & 0x0F);
1407 if (nybble > 9)
1408 vec_add1 (lookup_name, (nybble - 10) + 'a');
1409 else
1410 vec_add1 (lookup_name, nybble + '0');
1411 vec_add1 (lookup_name, '.');
1412 nybble = (digit & 0xF0) >> 4;
1413 if (nybble > 9)
1414 vec_add1 (lookup_name, (nybble - 10) + 'a');
1415 else
1416 vec_add1 (lookup_name, nybble + '0');
1417 vec_add1 (lookup_name, '.');
1418 }
1419 len = vec_len (lookup_name);
1420 vec_validate (lookup_name, len + 8);
1421 memcpy (lookup_name + len, "ip6.arpa", 8);
1422 }
1423 else
1424 {
1425 for (i = 3; i >= 0; i--)
1426 {
1427 digit = mp->address[i];
1428 lookup_name = format (lookup_name, "%d.", digit);
1429 }
1430 lookup_name = format (lookup_name, "in-addr.arpa");
1431 }
1432
1433 vec_add1 (lookup_name, 0);
1434
Dave Barach97494502017-11-04 09:44:38 -04001435 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1436 t0->client_index = mp->client_index;
1437 t0->client_context = mp->context;
1438
1439 rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
Dave Barachd2080152017-10-20 09:21:35 -04001440
1441 vec_free (lookup_name);
1442
1443 /* Error, e.g. not enabled? Tell the user */
1444 if (rv < 0)
1445 {
1446 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1447 return;
1448 }
1449
1450 /* Resolution pending? Don't reply... */
1451 if (ep == 0)
1452 return;
1453
1454 /* *INDENT-OFF* */
1455 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1456 ({
1457 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1458 rmp->retval = clib_host_to_net_u32 (rv);
1459 }));
1460 /* *INDENT-ON* */
1461
1462 /*
Dave Barach97494502017-11-04 09:44:38 -04001463 * vnet_dns_resolve_name leaves the cache locked when it returns
Dave Barachd2080152017-10-20 09:21:35 -04001464 * a cached result, so unlock it here.
1465 */
1466 dns_cache_unlock (dm);
1467}
1468
Dave Barach65457162017-10-10 17:53:14 -04001469#define vl_msg_name_crc_list
1470#include <vpp/api/vpe_all_api_h.h>
1471#undef vl_msg_name_crc_list
1472
1473static void
1474setup_message_id_table (api_main_t * am)
1475{
1476#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1477 foreach_vl_msg_name_crc_dns;
1478#undef _
1479}
1480
1481#define foreach_dns_api_msg \
1482_(DNS_ENABLE_DISABLE, dns_enable_disable) \
1483_(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
Dave Barachd2080152017-10-20 09:21:35 -04001484_(DNS_RESOLVE_NAME, dns_resolve_name) \
1485_(DNS_RESOLVE_IP, dns_resolve_ip)
Dave Barach65457162017-10-10 17:53:14 -04001486
1487static clib_error_t *
1488dns_api_hookup (vlib_main_t * vm)
1489{
1490#define _(N,n) \
1491 vl_msg_api_set_handlers(VL_API_##N, #n, \
1492 vl_api_##n##_t_handler, \
1493 vl_noop_handler, \
1494 vl_api_##n##_t_endian, \
1495 vl_api_##n##_t_print, \
1496 sizeof(vl_api_##n##_t), 1);
1497 foreach_dns_api_msg;
1498#undef _
1499
1500 setup_message_id_table (&api_main);
1501 return 0;
1502}
1503
1504VLIB_API_INIT_FUNCTION (dns_api_hookup);
1505
1506
1507static clib_error_t *
1508dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1509{
1510 dns_main_t *dm = &dns_main;
1511
1512 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1513 {
1514 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1515 ;
1516 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1517 ;
1518 else
1519 return clib_error_return (0, "unknown input `%U'",
1520 format_unformat_error, input);
1521 }
1522 return 0;
1523}
1524
1525VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1526
1527static clib_error_t *
1528dns_init (vlib_main_t * vm)
1529{
1530 dns_main_t *dm = &dns_main;
1531
1532 dm->vlib_main = vm;
1533 dm->vnet_main = vnet_get_main ();
1534 dm->name_cache_size = 65535;
1535 dm->max_ttl_in_seconds = 86400;
1536 dm->random_seed = 0xDEADDABE;
1537
1538 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply, dns46_reply_node.index,
1539 1 /* is_ip4 */ );
1540
1541 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6, dns46_reply_node.index,
1542 0 /* is_ip4 */ );
1543
Dave Barach65457162017-10-10 17:53:14 -04001544 udp_register_dst_port (vm, UDP_DST_PORT_dns, dns4_request_node.index,
1545 1 /* is_ip4 */ );
Dave Barach97494502017-11-04 09:44:38 -04001546
Dave Barach65457162017-10-10 17:53:14 -04001547 udp_register_dst_port (vm, UDP_DST_PORT_dns6, dns6_request_node.index,
1548 0 /* is_ip4 */ );
Dave Barach65457162017-10-10 17:53:14 -04001549 return 0;
1550}
1551
1552VLIB_INIT_FUNCTION (dns_init);
1553
1554uword
1555unformat_dns_reply (unformat_input_t * input, va_list * args)
1556{
1557 u8 **result = va_arg (*args, u8 **);
1558 u8 **namep = va_arg (*args, u8 **);
1559 ip4_address_t a4;
1560 ip6_address_t a6;
1561 int a4_set = 0;
1562 int a6_set = 0;
1563 u8 *name;
1564 int name_set = 0;
1565 u8 *ce;
1566 u32 qp_offset;
1567 dns_header_t *h;
1568 dns_query_t *qp;
1569 dns_rr_t *rr;
1570 u8 *rru8;
1571
1572 if (unformat (input, "%v", &name))
1573 name_set = 1;
1574
1575 if (unformat (input, "%U", unformat_ip4_address, &a4))
1576 {
1577 a4_set = 1;
1578 if (unformat (input, "%U", unformat_ip6_address, &a6))
1579 a6_set = 1;
1580 }
1581
1582 if (unformat (input, "%U", unformat_ip6_address, &a6))
1583 {
1584 a6_set = 1;
1585 if (unformat (input, "%U", unformat_ip4_address, &a6))
1586 a4_set = 1;
1587 }
1588
1589 /* Must have a name */
1590 if (!name_set)
1591 return 0;
1592
1593 /* Must have at least one address */
1594 if (!(a4_set + a6_set))
1595 return 0;
1596
1597 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1598 ce = name_to_labels (name);
1599 qp_offset = vec_len (ce);
1600
1601 /* Add space for the query header */
1602 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1603 qp = (dns_query_t *) (ce + qp_offset);
1604
1605 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1606 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1607
1608 /* Punch in space for the dns_header_t */
1609 vec_insert (ce, sizeof (dns_header_t), 0);
1610
1611 h = (dns_header_t *) ce;
1612
1613 /* Fake Transaction ID */
1614 h->id = 0xFFFF;
1615
1616 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1617 h->qdcount = clib_host_to_net_u16 (1);
1618 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1619 h->nscount = 0;
1620 h->arcount = 0;
1621
1622 /* Now append one or two A/AAAA RR's... */
1623 if (a4_set)
1624 {
1625 /* Pointer to the name (DGMS) */
1626 vec_add1 (ce, 0xC0);
1627 vec_add1 (ce, 0x0C);
1628 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1629 rr = (void *) rru8;
1630 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1631 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1632 rr->ttl = clib_host_to_net_u32 (86400);
1633 rr->rdlength = clib_host_to_net_u16 (4);
1634 memcpy (rr->rdata, &a4, sizeof (a4));
1635 }
1636 if (a6_set)
1637 {
1638 /* Pointer to the name (DGMS) */
1639 vec_add1 (ce, 0xC0);
1640 vec_add1 (ce, 0x0C);
1641 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1642 rr = (void *) rru8;
1643 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1644 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1645 rr->ttl = clib_host_to_net_u32 (86400);
1646 rr->rdlength = clib_host_to_net_u16 (16);
1647 memcpy (rr->rdata, &a6, sizeof (a6));
1648 }
1649 *result = ce;
1650 if (namep)
1651 *namep = name;
1652 else
1653 vec_free (name);
1654
1655 return 1;
1656}
1657
1658u8 *
1659format_dns_query (u8 * s, va_list * args)
1660{
1661 u8 **curpos = va_arg (*args, u8 **);
1662 int verbose = va_arg (*args, int);
1663 u8 *pos;
1664 dns_query_t *qp;
1665 int len, i;
1666 if (verbose > 1)
1667 s = format (s, " Name: ");
1668
1669 /* Unwind execrated counted-label sheit */
1670 pos = *curpos;
1671 len = *pos++;
1672
1673 while (len)
1674 {
1675 for (i = 0; i < len; i++)
1676 vec_add1 (s, *pos++);
1677
1678 len = *pos++;
1679 if (len)
1680 vec_add1 (s, '.');
1681 else
1682 {
1683 vec_add1 (s, ':');
1684 vec_add1 (s, ' ');
1685 }
1686 }
1687
1688 qp = (dns_query_t *) pos;
1689 if (verbose > 1)
1690 {
1691 switch (clib_net_to_host_u16 (qp->type))
1692 {
1693 case DNS_TYPE_A:
1694 s = format (s, "type A\n");
1695 break;
1696 case DNS_TYPE_AAAA:
1697 s = format (s, "type AAAA\n");
1698 break;
1699 case DNS_TYPE_ALL:
1700 s = format (s, "type ALL\n");
1701 break;
1702
1703 default:
1704 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1705 break;
1706 }
1707 }
1708
1709 pos += sizeof (*qp);
1710
1711 *curpos = pos;
1712 return s;
1713}
1714
1715/**
1716 * format dns reply data
1717 * verbose > 1, dump everything
1718 * verbose == 1, dump all A and AAAA records
1719 * verbose == 0, dump one A record, and one AAAA record
1720 */
1721
1722u8 *
1723format_dns_reply_data (u8 * s, va_list * args)
1724{
1725 u8 *reply = va_arg (*args, u8 *);
1726 u8 **curpos = va_arg (*args, u8 **);
1727 int verbose = va_arg (*args, int);
1728 int *print_ip4 = va_arg (*args, int *);
1729 int *print_ip6 = va_arg (*args, int *);
1730 int len;
1731 u8 *pos, *pos2;
1732 dns_rr_t *rr;
1733 int i;
Dave Barach52925382017-11-16 10:01:12 -05001734 int pointer_chase = 0;
Dave Barach65457162017-10-10 17:53:14 -04001735 u16 *tp;
Dave Barachd2080152017-10-20 09:21:35 -04001736 u16 rrtype_host_byte_order;
Dave Barach65457162017-10-10 17:53:14 -04001737
1738 pos = pos2 = *curpos;
1739
1740 if (verbose > 1)
1741 s = format (s, " ");
1742
1743 /* chase pointer? almost always yes here... */
Dave Barach52925382017-11-16 10:01:12 -05001744 if ((pos2[0] & 0xc0) == 0xc0)
Dave Barach65457162017-10-10 17:53:14 -04001745 {
Dave Barach52925382017-11-16 10:01:12 -05001746 pos = pos2 + 2;
1747 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1748 pointer_chase = 1;
Dave Barach65457162017-10-10 17:53:14 -04001749 }
1750
1751 len = *pos2++;
1752
1753 while (len)
1754 {
1755 for (i = 0; i < len; i++)
1756 {
1757 if (verbose > 1)
1758 vec_add1 (s, *pos2);
1759 pos2++;
1760 }
Dave Barach52925382017-11-16 10:01:12 -05001761 if ((pos2[0] & 0xc0) == 0xc0)
1762 {
1763 /*
1764 * If we've already done one pointer chase,
1765 * do not move the pos pointer.
1766 */
1767 if (pointer_chase == 0)
1768 pos = pos2 + 2;
1769 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1770 len = *pos2++;
1771 pointer_chase = 1;
1772 }
1773 else
1774 len = *pos2++;
Dave Barach65457162017-10-10 17:53:14 -04001775 if (len)
1776 {
1777 if (verbose > 1)
1778 vec_add1 (s, '.');
1779 }
1780 else
1781 {
1782 if (verbose > 1)
1783 vec_add1 (s, ' ');
1784 }
1785 }
1786
Dave Barach52925382017-11-16 10:01:12 -05001787 if (pointer_chase == 0)
Dave Barach65457162017-10-10 17:53:14 -04001788 pos = pos2;
1789
1790 rr = (dns_rr_t *) pos;
Dave Barachd2080152017-10-20 09:21:35 -04001791 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
Dave Barach65457162017-10-10 17:53:14 -04001792
Dave Barachd2080152017-10-20 09:21:35 -04001793 switch (rrtype_host_byte_order)
Dave Barach65457162017-10-10 17:53:14 -04001794 {
1795 case DNS_TYPE_A:
1796 if (verbose > 1)
1797 {
1798 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1799 format_ip4_address, rr->rdata);
1800 }
1801 else
1802 {
1803 if (*print_ip4)
1804 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1805 clib_net_to_host_u32 (rr->ttl));
1806 if (verbose == 0)
1807 *print_ip4 = 0;
1808
1809 }
1810 pos += sizeof (*rr) + 4;
1811 break;
1812
1813 case DNS_TYPE_AAAA:
1814 if (verbose > 1)
1815 {
1816 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1817 format_ip6_address, rr->rdata);
1818 }
1819 else
1820 {
1821 if (*print_ip6)
1822 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1823 clib_net_to_host_u32 (rr->ttl));
1824 if (verbose == 0)
1825 *print_ip6 = 0;
1826 }
1827 pos += sizeof (*rr) + 16;
1828 break;
1829
1830 case DNS_TYPE_TEXT:
1831 if (verbose > 1)
1832 {
1833 s = format (s, "TEXT: ");
1834 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1835 vec_add1 (s, rr->rdata[i]);
1836 vec_add1 (s, '\n');
1837 }
1838 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1839 break;
1840
Dave Barach0cb01bd2017-10-16 14:39:52 -04001841 case DNS_TYPE_HINFO:
1842 {
1843 /* Two counted strings. DGMS */
1844 u8 *len;
1845 u8 *curpos;
1846 int i;
1847 if (verbose > 1)
1848 {
1849 s = format (s, "HINFO: ");
1850 len = rr->rdata;
1851 curpos = len + 1;
1852 for (i = 0; i < *len; i++)
1853 vec_add1 (s, *curpos++);
1854
1855 vec_add1 (s, ' ');
1856 len = curpos++;
1857 for (i = 0; i < *len; i++)
1858 vec_add1 (s, *curpos++);
1859
1860 vec_add1 (s, '\n');
1861 }
1862 }
1863 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1864 break;
1865
Dave Barach65457162017-10-10 17:53:14 -04001866 case DNS_TYPE_NAMESERVER:
1867 if (verbose > 1)
1868 {
1869 s = format (s, "Nameserver: ");
1870 pos2 = rr->rdata;
1871
1872 /* chase pointer? */
Dave Barach52925382017-11-16 10:01:12 -05001873 if ((pos2[0] & 0xc0) == 0xc0)
1874 {
1875 pos = pos2 + 2;
1876 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1877 }
Dave Barach65457162017-10-10 17:53:14 -04001878
1879 len = *pos2++;
1880
1881 while (len)
1882 {
1883 for (i = 0; i < len; i++)
1884 vec_add1 (s, *pos2++);
1885
1886 /* chase pointer, typically to offset 12... */
1887 if (pos2[0] == 0xC0)
1888 pos2 = reply + pos2[1];
1889
1890 len = *pos2++;
1891 if (len)
1892 vec_add1 (s, '.');
1893 else
1894 vec_add1 (s, '\n');
1895 }
1896 }
1897 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1898 break;
1899
1900 case DNS_TYPE_MAIL_EXCHANGE:
1901 if (verbose > 1)
1902 {
1903 tp = (u16 *) rr->rdata;
1904
1905 s = format (s, "Mail Exchange: Preference %d ", (u32)
1906 clib_net_to_host_u16 (*tp));
1907
1908 pos2 = rr->rdata + 2;
1909
1910 /* chase pointer? */
1911 if (pos2[0] == 0xc0)
1912 pos2 = reply + pos2[1];
1913
1914 len = *pos2++;
1915
1916 while (len)
1917 {
1918 for (i = 0; i < len; i++)
1919 vec_add1 (s, *pos2++);
1920
1921 /* chase pointer */
1922 if (pos2[0] == 0xC0)
1923 pos2 = reply + pos2[1];
1924
1925 len = *pos2++;
1926 if (len)
1927 vec_add1 (s, '.');
1928 else
1929 vec_add1 (s, '\n');
1930 }
1931 }
1932
1933 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1934 break;
1935
Dave Barachd2080152017-10-20 09:21:35 -04001936 case DNS_TYPE_PTR:
Dave Barach65457162017-10-10 17:53:14 -04001937 case DNS_TYPE_CNAME:
1938 if (verbose > 1)
1939 {
1940 tp = (u16 *) rr->rdata;
1941
Dave Barachd2080152017-10-20 09:21:35 -04001942 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
1943 s = format (s, "CNAME: ");
1944 else
1945 s = format (s, "PTR: ");
Dave Barach65457162017-10-10 17:53:14 -04001946
1947 pos2 = rr->rdata;
1948
1949 /* chase pointer? */
1950 if (pos2[0] == 0xc0)
1951 pos2 = reply + pos2[1];
1952
1953 len = *pos2++;
1954
1955 while (len)
1956 {
1957 for (i = 0; i < len; i++)
1958 vec_add1 (s, *pos2++);
1959
1960 /* chase pointer */
1961 if (pos2[0] == 0xC0)
1962 pos2 = reply + pos2[1];
1963
1964 len = *pos2++;
1965 if (len)
1966 vec_add1 (s, '.');
1967 else
1968 vec_add1 (s, '\n');
1969 }
1970 }
1971 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1972 break;
1973
1974 default:
1975 if (verbose > 1)
1976 s = format (s, "type %d: len %d\n",
1977 (int) clib_net_to_host_u16 (rr->type),
1978 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
1979 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1980 break;
1981 }
1982
1983 *curpos = pos;
1984
1985 return s;
1986}
1987
1988u8 *
1989format_dns_reply (u8 * s, va_list * args)
1990{
1991 u8 *reply_as_u8 = va_arg (*args, u8 *);
1992 int verbose = va_arg (*args, int);
1993 dns_header_t *h;
1994 u16 id, flags;
1995 u8 *curpos;
1996 int i;
1997 int print_ip4 = 1;
1998 int print_ip6 = 1;
1999
2000 h = (dns_header_t *) reply_as_u8;
2001 id = clib_net_to_host_u16 (h->id);
2002 flags = clib_net_to_host_u16 (h->flags);
2003
2004 if (verbose > 1)
2005 {
2006 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2007 id);
2008 s = format (s, " %s %s %s %s\n",
2009 (flags & DNS_RA) ? "recur" : "no-recur",
2010 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2011 (flags & DNS_TC) ? "trunc" : "no-trunc",
2012 (flags & DNS_AA) ? "auth" : "non-auth");
2013 s = format (s, " %d queries, %d answers, %d name-servers,"
2014 " %d add'l recs\n",
2015 clib_net_to_host_u16 (h->qdcount),
2016 clib_net_to_host_u16 (h->anscount),
2017 clib_net_to_host_u16 (h->nscount),
2018 clib_net_to_host_u16 (h->arcount));
2019 }
2020
2021 curpos = (u8 *) (h + 1);
2022
2023 if (h->qdcount)
2024 {
2025 if (verbose > 1)
2026 s = format (s, " Queries:\n");
2027 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2028 {
2029 /* The query is variable-length, so curpos is a value-result parm */
2030 s = format (s, "%U", format_dns_query, &curpos, verbose);
2031 }
2032 }
2033 if (h->anscount)
2034 {
2035 if (verbose > 1)
2036 s = format (s, " Replies:\n");
2037
2038 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2039 {
2040 /* curpos is a value-result parm */
2041 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2042 verbose, &print_ip4, &print_ip6);
2043 }
2044 }
2045 return s;
2046}
2047
2048u8 *
2049format_dns_cache (u8 * s, va_list * args)
2050{
2051 dns_main_t *dm = va_arg (*args, dns_main_t *);
2052 f64 now = va_arg (*args, f64);
2053 int verbose = va_arg (*args, int);
2054 u8 *name = va_arg (*args, u8 *);
2055 dns_cache_entry_t *ep;
2056 char *ss;
2057 uword *p;
2058
2059 if (dm->is_enabled == 0)
2060 {
2061 s = format (s, "The DNS cache is disabled...");
2062 return s;
2063 }
2064
2065 if (pool_elts (dm->entries) == 0)
2066 {
2067 s = format (s, "The DNS cache is empty...");
2068 return s;
2069 }
2070
2071 dns_cache_lock (dm);
2072
2073 if (name)
2074 {
2075 p = hash_get_mem (dm->cache_entry_by_name, name);
2076 if (!p)
2077 {
2078 s = format (s, "%s is not in the cache...", name);
2079 dns_cache_unlock (dm);
2080 return (s);
2081 }
2082
2083 ep = pool_elt_at_index (dm->entries, p[0]);
2084 /* Magic to spit out a C-initializer to research hemorrhoids... */
2085 if (verbose == 3)
2086 {
2087 int i, j;
2088 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2089 s = format (s, "{\n");
2090 j = 0;
2091 for (i = 0; i < vec_len (ep->dns_response); i++)
2092 {
2093 if (j++ == 8)
2094 {
2095 j = 0;
2096 vec_add1 (s, '\n');
2097 }
2098 s = format (s, "0x%02x, ", ep->dns_response[i]);
2099 }
2100 s = format (s, "};\n");
2101 }
2102 else
2103 {
2104 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2105 {
2106 ASSERT (ep->dns_response);
2107 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2108 ss = "[S] ";
2109 else
2110 ss = " ";
2111
Dave Barach0cb01bd2017-10-16 14:39:52 -04002112 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2113 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2114 else
2115 s = format (s, "%s%s -> %U", ss, ep->name,
2116 format_dns_reply, ep->dns_response, verbose);
Dave Barach65457162017-10-10 17:53:14 -04002117 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2118 {
2119 f64 time_left = ep->expiration_time - now;
2120 if (time_left > 0.0)
2121 s = format (s, " TTL left %.1f", time_left);
2122 else
2123 s = format (s, " EXPIRED");
2124 }
2125 }
2126 else
2127 {
2128 ASSERT (ep->dns_request);
2129 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2130 verbose);
2131 }
2132 vec_add1 (s, '\n');
2133 }
2134 return s;
2135 }
2136
2137 /* *INDENT-OFF* */
2138 pool_foreach (ep, dm->entries,
2139 ({
2140 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2141 {
2142 ASSERT (ep->dns_response);
2143 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2144 ss = "[S] ";
2145 else
2146 ss = " ";
2147
Dave Barach0cb01bd2017-10-16 14:39:52 -04002148 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2149 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2150 else
2151 s = format (s, "%s%s -> %U", ss, ep->name,
2152 format_dns_reply,
2153 ep->dns_response,
2154 verbose);
Dave Barach65457162017-10-10 17:53:14 -04002155 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2156 {
2157 f64 time_left = ep->expiration_time - now;
2158 if (time_left > 0.0)
2159 s = format (s, " TTL left %.1f", time_left);
2160 else
2161 s = format (s, " EXPIRED");
Dave Barach0cb01bd2017-10-16 14:39:52 -04002162
2163 if (verbose > 2)
2164 s = format (s, " %d client notifications pending\n",
Dave Barach97494502017-11-04 09:44:38 -04002165 vec_len(ep->pending_requests));
Dave Barach65457162017-10-10 17:53:14 -04002166 }
2167 }
2168 else
2169 {
2170 ASSERT (ep->dns_request);
2171 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2172 verbose);
2173 }
2174 vec_add1 (s, '\n');
2175 }));
2176 /* *INDENT-ON* */
2177
2178 dns_cache_unlock (dm);
2179
2180 return s;
2181}
2182
2183static clib_error_t *
2184show_dns_cache_command_fn (vlib_main_t * vm,
2185 unformat_input_t * input, vlib_cli_command_t * cmd)
2186{
2187 dns_main_t *dm = &dns_main;
2188 int verbose = 0;
2189 u8 *name = 0;
2190 f64 now = vlib_time_now (vm);
2191
2192 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2193 {
2194 if (unformat (input, "verbose %d", &verbose))
2195 ;
2196 else if (unformat (input, "verbose"))
2197 verbose = 1;
2198 else if (unformat (input, "name %s", &name))
2199 ;
2200 else
2201 return clib_error_return (0, "unknown input `%U'",
2202 format_unformat_error, input);
2203 }
2204
2205 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2206
2207 return 0;
2208}
2209
2210/* *INDENT-OFF* */
2211VLIB_CLI_COMMAND (show_dns_cache_command) =
2212{
2213 .path = "show dns cache",
2214 .short_help = "show dns cache [verbose [nn]]",
2215 .function = show_dns_cache_command_fn,
2216};
2217/* *INDENT-ON* */
2218
2219static clib_error_t *
2220dns_cache_add_del_command_fn (vlib_main_t * vm,
2221 unformat_input_t * input,
2222 vlib_cli_command_t * cmd)
2223{
2224 dns_main_t *dm = &dns_main;
2225 u8 *dns_reply_data;
2226 u8 *name;
2227 int is_add = -1;
2228 int is_clear = -1;
2229 int rv;
2230 clib_error_t *error;
2231
2232 if (unformat (input, "add"))
2233 is_add = 1;
2234 if (unformat (input, "del"))
2235 is_add = 0;
2236 if (unformat (input, "clear"))
2237 is_clear = 1;
2238
2239 if (is_add == -1 && is_clear == -1)
2240 return clib_error_return (0, "add / del / clear required...");
2241
2242 if (is_clear == 1)
2243 {
2244 rv = dns_cache_clear (dm);
2245 switch (rv)
2246 {
2247 case 0:
2248 return 0;
2249
2250 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2251 error = clib_error_return (0, "Name resolution not enabled");
2252 return error;
2253 }
2254 }
2255
2256 /* Delete (by name)? */
2257 if (is_add == 0)
2258 {
2259 if (unformat (input, "%v", &name))
2260 {
2261 rv = dns_delete_by_name (dm, name);
2262 switch (rv)
2263 {
2264 case VNET_API_ERROR_NO_SUCH_ENTRY:
2265 error = clib_error_return (0, "%v not in the cache...", name);
2266 vec_free (name);
2267 return error;
2268
2269 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2270 error = clib_error_return (0, "Name resolution not enabled");
2271 vec_free (name);
2272 return error;
2273
2274 case 0:
2275 vec_free (name);
2276 return 0;
2277
2278 default:
2279 error = clib_error_return (0, "dns_delete_by_name returned %d",
2280 rv);
2281 vec_free (name);
2282 return error;
2283 }
2284 }
2285 return clib_error_return (0, "unknown input `%U'",
2286 format_unformat_error, input);
2287 }
2288
2289 /* Note: dns_add_static_entry consumes the name vector if OK... */
2290 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2291 {
2292 rv = dns_add_static_entry (dm, name, dns_reply_data);
2293 switch (rv)
2294 {
2295 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2296 vec_free (name);
2297 vec_free (dns_reply_data);
2298 return clib_error_return (0, "%v already in the cache...", name);
2299 case 0:
2300 return 0;
2301
2302 default:
2303 return clib_error_return (0, "dns_add_static_entry returned %d",
2304 rv);
2305 }
2306 }
2307
2308 return 0;
2309}
2310
2311/* *INDENT-OFF* */
2312VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2313{
2314 .path = "dns cache",
2315 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2316 .function = dns_cache_add_del_command_fn,
2317};
2318/* *INDENT-ON* */
2319
Dave Barach52925382017-11-16 10:01:12 -05002320#define DNS_FORMAT_TEST 0
Dave Barach65457162017-10-10 17:53:14 -04002321
2322#if DNS_FORMAT_TEST > 0
2323#if 0
2324/* yahoo.com */
2325static u8 dns_reply_data_initializer[] =
2326 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2327 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2328 0x0, /* null lbl */
2329 0x0, 0xff, /* type ALL */
2330 0x0, 0x1, /* class IN */
2331 0xc0, 0xc, /* pointer to yahoo.com name */
2332 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2333 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2334 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2335 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2336 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2337 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2338 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2339 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2340 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2341 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2342 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2343 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2344 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2345 0x6e,
2346 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2347 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2348 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2349 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2350 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2351 0x0,
2352 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2353 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2354 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2355 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2356 0x0,
2357 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2358 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2359 0x0,
2360 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2361 0x0,
2362 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2363 0x0,
2364 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2365 0x6f,
2366 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2367 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2368 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2369 0x2, 0x58
2370};
2371
2372/* www.cisco.com, has no addresses in reply */
2373static u8 dns_reply_data_initializer[] = {
2374 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2375 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2376 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2377
2378 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2379 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2380 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2381 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2382 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2383};
Dave Barach52925382017-11-16 10:01:12 -05002384
2385/* bind8 (linux widget, w/ nasty double pointer chasees */
2386static u8 dns_reply_data_initializer[] = {
2387 /* 0 */
2388 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2389 /* 8 */
2390 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2391 /* 16 */
2392 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2393 /* 24 */
2394 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2395 /* 32 */
2396 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2397 /* 40 */
2398 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2399 /* 48 */
2400 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2401
2402 /* 56 */
2403 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2404
2405 /* 64 */
2406 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2407 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2408 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2409 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2410 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2411 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2412 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2413 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2414 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2415 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2416 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2417 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2418 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2419 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2420 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2421 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2422 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2423 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2424 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2425 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2426 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2427 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2428 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2429 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2430 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2431 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2432 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2433 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2434 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2435 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2436 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2437 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2438 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2439 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2440 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2441 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2442 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2443 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2444 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2445 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2446 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2447 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2448 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2449 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2450 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2451 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2452 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2453 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2454};
2455
Dave Barach65457162017-10-10 17:53:14 -04002456/* google.com */
Dave Barach52925382017-11-16 10:01:12 -05002457#else
Dave Barach65457162017-10-10 17:53:14 -04002458static u8 dns_reply_data_initializer[] =
2459 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2460 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2461 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2462 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2463 0x2b,
2464 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2465 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2466 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2467 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2468 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2469 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2470 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2471 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2472 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2473 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2474 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2475 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2476 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2477 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2478 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2479 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2480 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2481 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2482 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2483 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2484 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2485 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2486 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2487 0x57,
2488 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2489};
2490#endif
2491
2492static clib_error_t *
2493test_dns_fmt_command_fn (vlib_main_t * vm,
2494 unformat_input_t * input, vlib_cli_command_t * cmd)
2495{
2496 u8 *dns_reply_data = 0;
2497 int verbose = 0;
2498 int rv;
2499 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2500
2501 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2502 {
2503 if (unformat (input, "verbose %d", &verbose))
2504 ;
2505 else if (unformat (input, "verbose"))
2506 verbose = 1;
2507 else
2508 return clib_error_return (0, "unknown input `%U'",
2509 format_unformat_error, input);
2510 }
2511
2512 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2513
2514 memcpy (dns_reply_data, dns_reply_data_initializer,
2515 ARRAY_LEN (dns_reply_data_initializer));
2516
2517 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2518
2519 memset (rmp, 0, sizeof (*rmp));
2520
2521 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2522
2523 switch (rv)
2524 {
2525 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2526 vlib_cli_output (vm, "no addresses found...");
2527 break;
2528
2529 default:
2530 vlib_cli_output (vm, "response to reply returned %d", rv);
2531 break;
2532
2533 case 0:
2534 if (rmp->ip4_set)
2535 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2536 (ip4_address_t *) rmp->ip4_address);
2537 if (rmp->ip6_set)
2538 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2539 (ip6_address_t *) rmp->ip6_address);
2540 break;
2541 }
2542
2543 vec_free (dns_reply_data);
2544
2545 return 0;
2546}
2547
2548
2549/* *INDENT-OFF* */
2550VLIB_CLI_COMMAND (test_dns_fmt_command) =
2551{
2552 .path = "test dns format",
2553 .short_help = "test dns format",
2554 .function = test_dns_fmt_command_fn,
2555};
2556/* *INDENT-ON* */
2557
2558static clib_error_t *
2559test_dns_unfmt_command_fn (vlib_main_t * vm,
2560 unformat_input_t * input, vlib_cli_command_t * cmd)
2561{
2562 u8 *dns_reply_data = 0;
2563 int verbose = 0;
2564 int reply_set = 0;
2565
2566 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2567 {
2568 if (unformat (input, "verbose %d", &verbose))
2569 ;
2570 else if (unformat (input, "verbose"))
2571 verbose = 1;
2572 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2573 reply_set = 1;
2574 else
2575 return clib_error_return (0, "unknown input `%U'",
2576 format_unformat_error, input);
2577 }
2578
2579 if (reply_set == 0)
2580 return clib_error_return (0, "dns data not set...");
2581
2582 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2583
2584 vec_free (dns_reply_data);
2585
2586 return 0;
2587}
2588
2589/* *INDENT-OFF* */
2590VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2591{
2592 .path = "test dns unformat",
2593 .short_help = "test dns unformat <name> [ip4][ip6]",
2594 .function = test_dns_unfmt_command_fn,
2595};
2596/* *INDENT-ON* */
Dave Barach0cb01bd2017-10-16 14:39:52 -04002597
2598static clib_error_t *
2599test_dns_expire_command_fn (vlib_main_t * vm,
2600 unformat_input_t * input,
2601 vlib_cli_command_t * cmd)
2602{
2603 dns_main_t *dm = &dns_main;
2604 u8 *name;
2605 uword *p;
2606 clib_error_t *e;
2607 dns_cache_entry_t *ep;
2608
2609 if (unformat (input, "%v", &name))
2610 {
2611 vec_add1 (name, 0);
2612 _vec_len (name) -= 1;
2613 }
2614
2615 dns_cache_lock (dm);
2616
2617 p = hash_get_mem (dm->cache_entry_by_name, name);
2618 if (!p)
2619 {
2620 dns_cache_unlock (dm);
2621 e = clib_error_return (0, "%s is not in the cache...", name);
2622 vec_free (name);
2623 return e;
2624 }
2625
2626 ep = pool_elt_at_index (dm->entries, p[0]);
2627
2628 ep->expiration_time = 0;
2629
2630 return 0;
2631}
2632
2633/* *INDENT-OFF* */
2634VLIB_CLI_COMMAND (test_dns_expire_command) =
2635{
2636 .path = "test dns expire",
2637 .short_help = "test dns expire <name>",
2638 .function = test_dns_expire_command_fn,
2639};
2640/* *INDENT-ON* */
Dave Barach65457162017-10-10 17:53:14 -04002641#endif
2642
Dave Barach97494502017-11-04 09:44:38 -04002643void
2644vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
2645 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2646{
2647 clib_warning ("Unimplemented...");
2648}
2649
2650
2651void
2652vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
2653 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2654{
2655 vlib_main_t *vm = dm->vlib_main;
2656 u32 bi;
2657 fib_prefix_t prefix;
2658 fib_node_index_t fei;
2659 u32 sw_if_index, fib_index;
2660 ip4_main_t *im4 = &ip4_main;
2661 ip_lookup_main_t *lm4 = &im4->lookup_main;
2662 ip_interface_address_t *ia = 0;
2663 ip4_address_t *src_address;
2664 ip4_header_t *ip;
2665 udp_header_t *udp;
2666 dns_header_t *dh;
2667 vlib_frame_t *f;
2668 u32 *to_next;
2669 u8 *dns_response;
2670 u8 *reply;
2671 vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2672 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2673 u32 ttl, tmp;
2674 u32 qp_offset;
2675 dns_query_t *qp;
2676 dns_rr_t *rr;
2677 u8 *rrptr;
2678 int is_fail = 0;
2679
2680 ASSERT (ep && ep->dns_response);
2681
2682 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2683 {
2684 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2685 memset (rnr, 0, sizeof (*rnr));
2686 if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2687 {
2688 /* clib_warning ("response_to_reply failed..."); */
2689 is_fail = 1;
2690 }
2691 if (rnr->ip4_set == 0)
2692 {
2693 /* clib_warning ("No A-record..."); */
2694 is_fail = 1;
2695 }
2696 }
2697 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2698 {
2699 memset (rir, 0, sizeof (*rir));
2700 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2701 {
2702 /* clib_warning ("response_to_name failed..."); */
2703 is_fail = 1;
2704 }
2705 }
2706 else
2707 {
2708 clib_warning ("Unknown request type %d", pr->request_type);
2709 return;
2710 }
2711
2712 /* Initialize a buffer */
2713 if (b0 == 0)
2714 {
2715 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2716 return;
2717 b0 = vlib_get_buffer (vm, bi);
2718 }
2719
2720 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2721 vlib_buffer_free_one (vm, b0->next_buffer);
2722
2723 /*
2724 * Reset the buffer. We recycle the DNS request packet in the cache
2725 * hit case, and reply immediately from the request node.
2726 *
2727 * In the resolution-required / deferred case, resetting a freshly-allocated
2728 * buffer won't hurt. We hope.
2729 */
2730 b0->flags &= VLIB_BUFFER_FREE_LIST_INDEX_MASK;
2731 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2732 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2733 b0->current_data = 0;
2734 b0->current_length = 0;
2735 b0->total_length_not_including_first_buffer = 0;
2736 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2737 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2738
2739 /* Find a FIB path to the peer we're trying to answer */
2740 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2741 prefix.fp_proto = FIB_PROTOCOL_IP4;
2742 prefix.fp_len = 32;
2743
2744 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2745 if (fib_index == (u32) ~ 0)
2746 {
2747 clib_warning ("no fib table");
2748 return;
2749 }
2750
2751 fei = fib_table_lookup (fib_index, &prefix);
2752
2753 /* Couldn't find route to destination. Bail out. */
2754 if (fei == FIB_NODE_INDEX_INVALID)
2755 {
2756 clib_warning ("no route to DNS server");
2757 return;
2758 }
2759
2760 sw_if_index = fib_entry_get_resolving_interface (fei);
2761
2762 if (sw_if_index == ~0)
2763 {
2764 clib_warning
2765 ("route to %U exists, fei %d, get_resolving_interface returned"
2766 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2767 return;
2768 }
2769
2770 /* *INDENT-OFF* */
2771 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnummbered */,
2772 ({
2773 src_address = ip_interface_address_get_address (lm4, ia);
2774 goto found_src_address;
2775 }));
2776 /* *INDENT-ON* */
2777
2778 clib_warning ("FIB BUG");
2779 return;
2780
2781found_src_address:
2782
2783 ip = vlib_buffer_get_current (b0);
2784 udp = (udp_header_t *) (ip + 1);
2785 dns_response = (u8 *) (udp + 1);
2786 memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2787
2788 /*
2789 * Start with the variadic portion of the exercise.
2790 * Turn the name into a set of DNS "labels". Max length
2791 * per label is 63, enforce that.
2792 */
2793 reply = name_to_labels (pr->name);
2794 vec_free (pr->name);
2795
2796 qp_offset = vec_len (reply);
2797
2798 /* Add space for the query header */
2799 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2800
2801 qp = (dns_query_t *) (reply + qp_offset);
2802
2803 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2804 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2805 else
2806 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2807
2808 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2809
2810 /* Punch in space for the dns_header_t */
2811 vec_insert (reply, sizeof (dns_header_t), 0);
2812
2813 dh = (dns_header_t *) reply;
2814
2815 /* Transaction ID = pool index */
2816 dh->id = pr->id;
2817
2818 /* Announce that we did a recursive lookup */
2819 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2820 if (is_fail)
2821 tmp |= DNS_RCODE_NAME_ERROR;
2822 dh->flags = clib_host_to_net_u16 (tmp);
2823 dh->qdcount = clib_host_to_net_u16 (1);
2824 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2825 dh->nscount = 0;
2826 dh->arcount = 0;
2827
2828 /* If the name resolution worked, cough up an appropriate RR */
2829 if (is_fail == 0)
2830 {
2831 /* Add the answer. First, a name pointer (0xC00C) */
2832 vec_add1 (reply, 0xC0);
2833 vec_add1 (reply, 0x0C);
2834
2835 /* Now, add single A-rec RR */
2836 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2837 {
2838 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2839 rr = (dns_rr_t *) rrptr;
2840
2841 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2842 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2843 rr->ttl = clib_host_to_net_u32 (ttl);
2844 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2845 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2846 }
2847 else
2848 {
2849 /* Or a single PTR RR */
2850 u8 *vecname = format (0, "%s", rir->name);
2851 u8 *label_vec = name_to_labels (vecname);
2852 vec_free (vecname);
2853
2854 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2855 rr = (dns_rr_t *) rrptr;
2856 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2857 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2858 rr->ttl = clib_host_to_net_u32 (ttl);
2859 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2860 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2861 vec_free (label_vec);
2862 }
2863 }
2864 clib_memcpy (dns_response, reply, vec_len (reply));
2865
2866 /* Set the packet length */
2867 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2868
2869 /* IP header */
2870 ip->ip_version_and_header_length = 0x45;
2871 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2872 ip->ttl = 255;
2873 ip->protocol = IP_PROTOCOL_UDP;
2874 ip->src_address.as_u32 = src_address->as_u32;
2875 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2876 sizeof (ip4_address_t));
2877 ip->checksum = ip4_header_checksum (ip);
2878
2879 /* UDP header */
2880 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2881 udp->dst_port = pr->dst_port;
2882 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2883 vec_len (reply));
2884 udp->checksum = 0;
2885 vec_free (reply);
2886
2887 /* Ship it to ip4_lookup */
2888 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2889 to_next = vlib_frame_vector_args (f);
2890 to_next[0] = bi;
2891 f->n_vectors = 1;
2892 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2893}
2894
Dave Barach65457162017-10-10 17:53:14 -04002895/*
2896 * fd.io coding-style-patch-verification: ON
2897 *
2898 * Local Variables:
2899 * eval: (c-set-style "gnu")
2900 * End:
2901 */