blob: 90079e17e99952461ccde995e456b3514c9c4831 [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);
58 vec_free (ep->api_clients_to_notify);
59 vec_free (ep->api_client_contexts);
60 vec_free (ep->ip4_peers_to_notify);
61 vec_free (ep->ip6_peers_to_notify);
62 }));
63 /* *INDENT-ON* */
64
65 pool_free (dm->entries);
66 hash_free (dm->cache_entry_by_name);
67 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
68 vec_free (dm->unresolved_entries);
69 dns_cache_unlock (dm);
70 return 0;
71}
72
73static int
74dns_enable_disable (dns_main_t * dm, int is_enable)
75{
76 vlib_thread_main_t *tm = &vlib_thread_main;
77 u32 n_vlib_mains = tm->n_vlib_mains;
78
79 if (is_enable)
80 {
81 if (vec_len (dm->ip4_name_servers) == 0
82 && (vec_len (dm->ip6_name_servers) == 0))
83 return VNET_API_ERROR_NO_NAME_SERVERS;
84
85 if (dm->cache_entry_by_name == 0)
86 {
87 if (n_vlib_mains > 1)
88 dm->cache_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
89 CLIB_CACHE_LINE_BYTES);
90
91 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
92 }
93
94 dm->is_enabled = 1;
95 }
96 else
97 {
98 dns_cache_clear (dm);
99 dm->is_enabled = 0;
100 }
101 return 0;
102}
103
104static void vl_api_dns_enable_disable_t_handler
105 (vl_api_dns_enable_disable_t * mp)
106{
107 vl_api_dns_enable_disable_reply_t *rmp;
108 dns_main_t *dm = &dns_main;
109 int rv;
110
111 rv = dns_enable_disable (dm, mp->enable);
112
113 REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
114}
115
116static int
117dns6_name_server_add_del (dns_main_t * dm,
118 u8 * server_address_as_u8, int is_add)
119{
120 int i;
121 ip6_address_t *ap;
122
123 if (is_add)
124 {
125 /* Already there? done... */
126 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
127 {
128 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
129 sizeof (ip6_address_t)))
130 return 0;
131 }
132
133 vec_add2 (dm->ip6_name_servers, ap, 1);
134 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
135 }
136 else
137 {
138 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
139 {
140 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
141 sizeof (ip6_address_t)))
142 {
143 vec_delete (dm->ip6_name_servers, 1, i);
144 return 0;
145 }
146 }
147 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
148 }
149 return 0;
150}
151
152static int
153dns4_name_server_add_del (dns_main_t * dm,
154 u8 * server_address_as_u8, int is_add)
155{
156 int i;
157 ip4_address_t *ap;
158
159 if (is_add)
160 {
161 /* Already there? done... */
162 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
163 {
164 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
165 sizeof (ip4_address_t)))
166 return 0;
167 }
168
169 vec_add2 (dm->ip4_name_servers, ap, 1);
170 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
171 }
172 else
173 {
174 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
175 {
176 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
177 sizeof (ip4_address_t)))
178 {
179 vec_delete (dm->ip4_name_servers, 1, i);
180 return 0;
181 }
182 }
183 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
184 }
185 return 0;
186}
187
188static void vl_api_dns_name_server_add_del_t_handler
189 (vl_api_dns_name_server_add_del_t * mp)
190{
191 dns_main_t *dm = &dns_main;
192 vl_api_dns_name_server_add_del_reply_t *rmp;
193 int rv;
194
195 if (mp->is_ip6)
196 rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
197 else
198 rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
199
200 REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
201}
202
203static void
204send_dns4_request (dns_main_t * dm,
205 dns_cache_entry_t * ep, ip4_address_t * server)
206{
207 vlib_main_t *vm = dm->vlib_main;
208 f64 now = vlib_time_now (vm);
209 u32 bi;
210 vlib_buffer_t *b;
211 ip4_header_t *ip;
212 fib_prefix_t prefix;
213 fib_node_index_t fei;
214 u32 sw_if_index, fib_index;
215 udp_header_t *udp;
216 ip4_main_t *im4 = &ip4_main;
217 ip_lookup_main_t *lm4 = &im4->lookup_main;
218 ip_interface_address_t *ia = 0;
219 ip4_address_t *src_address;
220 u8 *dns_request;
221 vlib_frame_t *f;
222 u32 *to_next;
223
224 ASSERT (ep->dns_request);
225
226 /* Find a FIB path to the server */
227 clib_memcpy (&prefix.fp_addr.ip4, server, sizeof (*server));
228 prefix.fp_proto = FIB_PROTOCOL_IP4;
229 prefix.fp_len = 32;
230
231 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
232 if (fib_index == (u32) ~ 0)
233 {
234 clib_warning ("no fib table");
235 return;
236 }
237
238 fei = fib_table_lookup (fib_index, &prefix);
239
240 /* Couldn't find route to destination. Bail out. */
241 if (fei == FIB_NODE_INDEX_INVALID)
242 {
243 clib_warning ("no route to DNS server");
244 return;
245 }
246
247 sw_if_index = fib_entry_get_resolving_interface (fei);
248
249 if (sw_if_index == ~0)
250 {
251 clib_warning
252 ("route to %U exists, fei %d, get_resolving_interface returned"
253 " ~0", fei, format_ip4_address, &prefix.fp_addr);
254 return;
255 }
256
257 /* *INDENT-OFF* */
258 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnummbered */,
259 ({
260 src_address = ip_interface_address_get_address (lm4, ia);
261 goto found_src_address;
262 }));
263 /* *INDENT-ON* */
264
265 clib_warning ("FIB BUG");
266 return;
267
268found_src_address:
269
270 /* Go get a buffer */
271 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
272 return;
273
274 b = vlib_get_buffer (vm, bi);
275 b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
276 vec_len (ep->dns_request);
277 b->total_length_not_including_first_buffer = 0;
278 b->flags =
279 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
280 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
281 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
282
283 ip = vlib_buffer_get_current (b);
284 memset (ip, 0, sizeof (*ip));
285 udp = (udp_header_t *) (ip + 1);
286 memset (udp, 0, sizeof (*udp));
287
288 dns_request = (u8 *) (udp + 1);
289
290 /* IP header */
291 ip->ip_version_and_header_length = 0x45;
292 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
293 ip->ttl = 255;
294 ip->protocol = IP_PROTOCOL_UDP;
295 ip->src_address.as_u32 = src_address->as_u32;
296 ip->dst_address.as_u32 = server->as_u32;
297 ip->checksum = ip4_header_checksum (ip);
298
299 /* UDP header */
300 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
301 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
302 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
303 vec_len (ep->dns_request));
304 udp->checksum = 0;
305
306 /* The actual DNS request */
307 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
308
309 /* Ship it to ip4_lookup */
310 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
311 to_next = vlib_frame_vector_args (f);
312 to_next[0] = bi;
313 f->n_vectors = 1;
314 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
315
316 ep->retry_timer = now + 2.0;
317}
318
319static void
320send_dns6_request (dns_main_t * dm,
321 dns_cache_entry_t * ep, ip6_address_t * server)
322{
323 vlib_main_t *vm = dm->vlib_main;
324 f64 now = vlib_time_now (vm);
325 u32 bi;
326 vlib_buffer_t *b;
327 ip6_header_t *ip;
328 fib_prefix_t prefix;
329 fib_node_index_t fei;
330 u32 sw_if_index, fib_index;
331 udp_header_t *udp;
332 ip6_main_t *im6 = &ip6_main;
333 ip_lookup_main_t *lm6 = &im6->lookup_main;
334 ip_interface_address_t *ia = 0;
335 ip6_address_t *src_address;
336 u8 *dns_request;
337 vlib_frame_t *f;
338 u32 *to_next;
339 int junk __attribute__ ((unused));
340
341 ASSERT (ep->dns_request);
342
343 /* Find a FIB path to the server */
344 clib_memcpy (&prefix.fp_addr, server, sizeof (*server));
345 prefix.fp_proto = FIB_PROTOCOL_IP6;
346 prefix.fp_len = 32;
347
348 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
349 if (fib_index == (u32) ~ 0)
350 {
351 clib_warning ("no fib table");
352 return;
353 }
354
355 fei = fib_table_lookup (fib_index, &prefix);
356
357 /* Couldn't find route to destination. Bail out. */
358 if (fei == FIB_NODE_INDEX_INVALID)
359 {
360 clib_warning ("no route to DNS server");
361 }
362
363 sw_if_index = fib_entry_get_resolving_interface (fei);
364
365 /* *INDENT-OFF* */
366 foreach_ip_interface_address(lm6, ia, sw_if_index, 1 /* honor unnummbered */,
367 ({
368 src_address = ip_interface_address_get_address (lm6, ia);
369 goto found_src_address;
370 }));
371 /* *INDENT-ON* */
372
373 clib_warning ("FIB BUG");
374 return;
375
376found_src_address:
377
378 /* Go get a buffer */
379 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
380 return;
381
382 b = vlib_get_buffer (vm, bi);
383 b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
384 vec_len (ep->dns_request);
385 b->total_length_not_including_first_buffer = 0;
386 b->flags =
387 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
388
389 ip = vlib_buffer_get_current (b);
390 memset (ip, 0, sizeof (*ip));
391 udp = (udp_header_t *) (ip + 1);
392 memset (udp, 0, sizeof (*udp));
393
394 dns_request = (u8 *) (udp + 1);
395
396 /* IP header */
397 ip->ip_version_traffic_class_and_flow_label =
398 clib_host_to_net_u32 (0x6 << 28);
399
400 ip->payload_length =
401 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
402 - sizeof (ip6_header_t));
403 ip->hop_limit = 255;
404 ip->protocol = IP_PROTOCOL_UDP;
405 clib_memcpy (&ip->src_address, src_address, sizeof (ip6_address_t));
406 clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
407
408 /* UDP header */
409 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
410 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
411 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
412 vec_len (ep->dns_request));
413 udp->checksum = 0;
414 udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
415
416 /* The actual DNS request */
417 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
418
419 /* Ship it to ip6_lookup */
420 f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
421 to_next = vlib_frame_vector_args (f);
422 to_next[0] = bi;
423 f->n_vectors = 1;
424
425 ep->retry_timer = now + 2.0;
426}
427
428/**
429 * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
430 * A historical / hysterical micro-TLV scheme. DGMS.
431 */
432u8 *
433name_to_labels (u8 * name)
434{
435 int i;
436 int last_label_index;
437 u8 *rv;
438
439 rv = vec_dup (name);
440
441 /* punch in space for the first length */
442 vec_insert (rv, 1, 0);
443 last_label_index = 0;
444 i = 1;
445
446 while (i < vec_len (rv))
447 {
448 if (rv[i] == '.')
449 {
450 rv[last_label_index] = (i - last_label_index) - 1;
451 if ((i - last_label_index) > 63)
452 clib_warning ("stupid name, label length %d",
453 i - last_label_index);
454 last_label_index = i;
455 rv[i] = 0;
456 }
457 i++;
458 }
459 /* Set the last real label length */
460 rv[last_label_index] = (i - last_label_index) - 1;
461
462 /*
463 * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
464 * where to stop.
465 */
466 vec_add1 (rv, 0);
467 return rv;
468}
469
470/**
471 * arc-function for the above.
472 * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
473 * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
474 */
475u8 *
476labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
477{
478 u8 *reply = 0;
479 u16 offset;
480 u8 len;
481 int i;
482
483 *parse_from_here = 0;
484
485 /* chase initial pointer? */
486 if ((label[0] & 0xC0) == 0xC0)
487 {
488 *parse_from_here = label + 2;
489 offset = ((label[0] & 0x3f) << 8) + label[1];
490 label = full_text + offset;
491 }
492
493 len = *label++;
494
495 while (len)
496 {
497 for (i = 0; i < len; i++)
498 vec_add1 (reply, *label++);
499
500 /* chase pointer? */
501 if ((label[0] & 0xC0) == 0xC0)
502 {
503 *parse_from_here = label + 2;
504 offset = ((label[0] & 0x3f) << 8) + label[1];
505 label = full_text + offset;
506 }
507
508 len = *label++;
509 if (len)
510 vec_add1 (reply, '.');
511 }
512 if (*parse_from_here == 0)
513 *parse_from_here = label;
514 return reply;
515}
516
517void
518vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep)
519{
520 dns_header_t *h;
521 dns_query_t *qp;
522 u16 tmp;
523 u8 *request;
524 u32 qp_offset;
525
526 /* Construct the dns request, if we haven't been here already */
527 if (vec_len (ep->dns_request) == 0)
528 {
529 /*
530 * Start with the variadic portion of the exercise.
531 * Turn the name into a set of DNS "labels". Max length
532 * per label is 63, enforce that.
533 */
534 request = name_to_labels (ep->name);
535 qp_offset = vec_len (request);
536
537 /* Add space for the query header */
538 vec_validate (request, qp_offset + sizeof (dns_query_t) - 1);
539
540 qp = (dns_query_t *) (request + qp_offset);
541
542 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
543 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
544
545 /* Punch in space for the dns_header_t */
546 vec_insert (request, sizeof (dns_header_t), 0);
547
548 h = (dns_header_t *) request;
549
550 /* Transaction ID = pool index */
551 h->id = clib_host_to_net_u16 (ep - dm->entries);
552
553 /* Ask for a recursive lookup */
554 tmp = DNS_RD | DNS_OPCODE_QUERY;
555 h->flags = clib_host_to_net_u16 (tmp);
556 h->qdcount = clib_host_to_net_u16 (1);
557 h->nscount = 0;
558 h->arcount = 0;
559
560 ep->dns_request = request;
561 }
562
563 /* Work out which server / address family we're going to use */
564
565 /* Retry using current server */
566 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
567 {
568 if (ep->server_af == 1 /* ip6 */ )
569 {
570 if (vec_len (dm->ip6_name_servers))
571 {
572 send_dns6_request (dm, ep,
573 dm->ip6_name_servers + ep->server_rotor);
574 goto out;
575 }
576 else
577 ep->server_af = 0;
578 }
579 if (vec_len (dm->ip4_name_servers))
580 {
581 send_dns4_request (dm, ep, dm->ip4_name_servers + ep->server_rotor);
582 goto out;
583 }
584 }
585 else /* switch to a new server */
586 {
587 ep->retry_count = 1;
588 ep->server_rotor++;
589 if (ep->server_af == 1 /* ip6 */ )
590 {
591 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
592 {
593 ep->server_rotor = 0;
594 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
595 }
596 }
597 else
598 {
599 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
600 {
601 ep->server_rotor = 0;
602 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
603 }
604 }
605 }
606
607 if (ep->server_af == 1 /* ip6 */ )
608 send_dns6_request (dm, ep, dm->ip6_name_servers + ep->server_rotor);
609 else
610 send_dns4_request (dm, ep, dm->ip4_name_servers + ep->server_rotor);
611
612out:
613
614 vlib_process_signal_event_mt (dm->vlib_main, dns_resolver_node.index,
615 DNS_RESOLVER_EVENT_PENDING, 0);
616}
617
618int
619vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
620{
621 dns_cache_entry_t *ep;
622 int i;
623
624 if (dm->is_enabled == 0)
625 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
626
627 if (pool_is_free_index (dm->entries, index))
628 return VNET_API_ERROR_NO_SUCH_ENTRY;
629
630 ep = pool_elt_at_index (dm->entries, index);
631
632 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);
647 vec_free (ep->api_clients_to_notify);
648 vec_free (ep->api_client_contexts);
649 vec_free (ep->ip4_peers_to_notify);
650 vec_free (ep->ip6_peers_to_notify);
651 pool_put (dm->entries, ep);
652
653 return 0;
654}
655
656static int
657dns_delete_by_name (dns_main_t * dm, u8 * name)
658{
659 int rv;
660 uword *p;
661
662 if (dm->is_enabled == 0)
663 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
664
665 dns_cache_lock (dm);
666 p = hash_get_mem (dm->cache_entry_by_name, name);
667 if (!p)
668 {
669 dns_cache_unlock (dm);
670 return VNET_API_ERROR_NO_SUCH_ENTRY;
671 }
672 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
673
674 dns_cache_unlock (dm);
675
676 return rv;
677}
678
679static int
680delete_random_entry (dns_main_t * dm)
681{
682 int rv;
683 u32 victim_index, start_index, i;
684 u32 limit;
685 dns_cache_entry_t *ep;
686
687 if (dm->is_enabled == 0)
688 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
689
690 dns_cache_lock (dm);
691 limit = pool_elts (dm->entries);
692 start_index = random_u32 (&dm->random_seed) % limit;
693
694 for (i = 0; i < limit; i++)
695 {
696 victim_index = (start_index + i) % limit;
697
698 if (!pool_is_free_index (dm->entries, victim_index))
699 {
700 ep = pool_elt_at_index (dm->entries, victim_index);
701 /* Delete only valid, non-static entries */
702 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
703 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
704 {
705 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
706 dns_cache_unlock (dm);
707 return rv;
708 }
709 }
710 }
711 dns_cache_unlock (dm);
712
713 clib_warning ("Couldn't find an entry to delete?");
714 return VNET_API_ERROR_UNSPECIFIED;
715}
716
717static int
718dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
719{
720 dns_cache_entry_t *ep;
721 uword *p;
722 int rv;
723
724 if (dm->is_enabled == 0)
725 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
726
727 dns_cache_lock (dm);
728 p = hash_get_mem (dm->cache_entry_by_name, name);
729 if (p)
730 {
731 dns_cache_unlock (dm);
732 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
733 }
734
735 if (pool_elts (dm->entries) == dm->name_cache_size)
736 {
737 /* Will only fail if the cache is totally filled w/ static entries... */
738 rv = delete_random_entry (dm);
739 if (rv)
740 {
741 dns_cache_unlock (dm);
742 return rv;
743 }
744 }
745
746 pool_get (dm->entries, ep);
747 memset (ep, 0, sizeof (*ep));
748
749 /* Note: consumes the name vector */
750 ep->name = name;
751 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
752 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
753 ep->dns_response = dns_reply_data;
754
755 dns_cache_unlock (dm);
756 return 0;
757}
758
759static int
760dns_resolve_name (dns_main_t * dm,
761 u8 * name, u32 client_index, u32 client_context,
762 dns_cache_entry_t ** retp)
763{
764 dns_cache_entry_t *ep;
765 int rv;
766 f64 now;
767 uword *p;
768
769 now = vlib_time_now (dm->vlib_main);
770
771 /* In case we can't actually answer the question right now... */
772 *retp = 0;
773
774 dns_cache_lock (dm);
775 p = hash_get_mem (dm->cache_entry_by_name, name);
776 if (p)
777 {
778 ep = pool_elt_at_index (dm->entries, p[0]);
779 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
780 {
781 /* Has the entry expired? */
782 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
783 && (now > ep->expiration_time))
784 {
785 clib_warning ("Re-resolve %s", name);
786 /* Yes, kill it... */
787 vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
788 goto re_resolve;
789 }
790
791 /* Note: caller must drop the lock! */
792 *retp = ep;
793 return (0);
794 }
795 }
796
797 if (pool_elts (dm->entries) == dm->name_cache_size)
798 {
799 /* Will only fail if the cache is totally filled w/ static entries... */
800 rv = delete_random_entry (dm);
801 if (rv)
802 {
803 dns_cache_unlock (dm);
804 return rv;
805 }
806 }
807
808re_resolve:
809 /* add new hash table entry */
810 pool_get (dm->entries, ep);
811 memset (ep, 0, sizeof (*ep));
812
813 ep->name = format (0, "%s%c", name, 0);
814 _vec_len (ep->name) = vec_len (ep->name) - 1;
815
816 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
817
818 vec_add1 (dm->unresolved_entries, ep - dm->entries);
819 vec_add1 (ep->api_clients_to_notify, client_index);
820 vec_add1 (ep->api_client_contexts, client_context);
821 vnet_send_dns_request (dm, ep);
822 dns_cache_unlock (dm);
823
824 return 0;
825}
826
827/**
828 * Handle cname indirection. JFC. Called with the cache locked.
829 * returns 0 if the reply is not a CNAME.
830 */
831
832int
833vnet_dns_cname_indirection_nolock (dns_main_t * dm, dns_cache_entry_t * ep,
834 u8 * reply)
835{
836 dns_header_t *h;
837 dns_query_t *qp;
838 dns_rr_t *rr;
839 u8 *curpos;
840 u8 *pos, *pos2;
841 int len, i;
842 u8 *cname = 0;
843 u8 *request = 0;
844 u32 qp_offset;
845 u16 flags;
846 u16 rcode;
847
848 h = (dns_header_t *) reply;
849 flags = clib_net_to_host_u16 (h->flags);
850 rcode = flags & DNS_RCODE_MASK;
851
852 /* See if the response is OK */
853 switch (rcode)
854 {
855 case DNS_RCODE_NO_ERROR:
856 break;
857
858 case DNS_RCODE_NAME_ERROR:
859 case DNS_RCODE_FORMAT_ERROR:
860 case DNS_RCODE_SERVER_FAILURE:
861 case DNS_RCODE_NOT_IMPLEMENTED:
862 case DNS_RCODE_REFUSED:
863 return 0;
864 }
865
866 curpos = (u8 *) (h + 1);
867 pos = curpos;
868 len = *pos++;
869
870 /* Skip the questions */
871 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
872 {
873 while (len)
874 {
875 pos += len;
876 len = *pos++;
877 }
878 qp = (dns_query_t *) pos;
879 pos += sizeof (*qp);
880 }
881 pos2 = pos;
882 /* expect a pointer chase here for a CNAME record */
883 if ((pos2[0] & 0xC0) == 0xC0)
884 pos += 2;
885 else
886 return 0;
887
888 rr = (dns_rr_t *) pos;
889
890 /* This is a real record, not a CNAME record */
891 if (clib_net_to_host_u16 (rr->type) != DNS_TYPE_CNAME)
892 return 0;
893
894 /* Crap. Chase the CNAME name chain. */
895
896 cname = labels_to_name (rr->rdata, reply, &pos2);
897 request = name_to_labels (cname);
898 vec_free (cname);
899
900 qp_offset = vec_len (request);
901
902 /* Add space for the query header */
903 vec_validate (request, qp_offset + sizeof (dns_query_t) - 1);
904
905 qp = (dns_query_t *) (request + qp_offset);
906
907 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
908 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
909
910 /* Punch in space for the dns_header_t */
911 vec_insert (request, sizeof (dns_header_t), 0);
912
913 h = (dns_header_t *) request;
914
915 /* Transaction ID = pool index */
916 h->id = clib_host_to_net_u16 (ep - dm->entries);
917
918 /* Ask for a recursive lookup */
919 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
920 h->qdcount = clib_host_to_net_u16 (1);
921 h->nscount = 0;
922 h->arcount = 0;
923
924 vec_free (ep->dns_request);
925 ep->dns_request = request;
926 ep->retry_timer = vlib_time_now (dm->vlib_main) + 2.0;
927 ep->retry_count = 0;
928
929 /*
930 * Enable this to watch recursive resolution happen...
931 * fformat (stdout, "%U", format_dns_reply, request, 2);
932 */
933
934 if (ep->server_af == 1 /* ip6 */ )
935 send_dns6_request (dm, ep, dm->ip6_name_servers + ep->server_rotor);
936 else
937 send_dns4_request (dm, ep, dm->ip4_name_servers + ep->server_rotor);
938
939 vec_free (reply);
940 return (1);
941}
942
943int
944vnet_dns_response_to_reply (u8 * response,
945 vl_api_dns_resolve_name_reply_t * rmp,
946 u32 * min_ttlp)
947{
948 dns_header_t *h;
949 dns_query_t *qp;
950 dns_rr_t *rr;
951 int i, limit;
952 u8 len;
953 u8 *curpos, *pos;
954 u16 flags;
955 u16 rcode;
956 u32 ttl;
957
958 h = (dns_header_t *) response;
959 flags = clib_net_to_host_u16 (h->flags);
960 rcode = flags & DNS_RCODE_MASK;
961
962 /* See if the response is OK, etc. */
963 switch (rcode)
964 {
965 default:
966 case DNS_RCODE_NO_ERROR:
967 break;
968
969 case DNS_RCODE_NAME_ERROR:
970 case DNS_RCODE_FORMAT_ERROR:
971 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
972
973 case DNS_RCODE_SERVER_FAILURE:
974 case DNS_RCODE_NOT_IMPLEMENTED:
975 case DNS_RCODE_REFUSED:
976 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
977 }
978
979 /* No answers? Loser... */
980 if (clib_net_to_host_u16 (h->anscount) < 1)
981 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
982
983 curpos = (u8 *) (h + 1);
984
985 /* Skip the name we asked about */
986 pos = curpos;
987 len = *pos++;
988 /* Should never happen, but stil... */
989 if ((len & 0xC0) == 0xC0)
990 curpos += 2;
991 else
992 {
993 /* skip the name / label-set */
994 while (len)
995 {
996 pos += len;
997 len = *pos++;
998 }
999 curpos = pos;
1000 }
1001 /* Skip queries */
1002 limit = clib_net_to_host_u16 (h->qdcount);
1003 qp = (dns_query_t *) curpos;
1004 qp += limit;
1005 curpos = (u8 *) qp;
1006
1007 /* Parse answers */
1008 limit = clib_net_to_host_u16 (h->anscount);
1009
1010 for (i = 0; i < limit; i++)
1011 {
1012 pos = curpos;
1013
1014 /* Expect pointer chases in the answer section... */
1015 if ((pos[0] & 0xC0) == 0xC0)
1016 curpos += 2;
1017 else
1018 {
1019 len = *pos++;
1020 while (len)
1021 {
1022 if ((pos[0] & 0xC0) == 0xC0)
1023 {
1024 curpos = pos + 2;
1025 break;
1026 }
1027 pos += len;
1028 len = *pos++;
1029 }
1030 curpos = pos;
1031 }
1032
1033 rr = (dns_rr_t *) curpos;
1034
1035 switch (clib_net_to_host_u16 (rr->type))
1036 {
1037 case DNS_TYPE_A:
1038 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1039 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1040 rmp->ip4_set = 1;
1041 ttl = clib_net_to_host_u32 (rr->ttl);
1042 if (min_ttlp && *min_ttlp > ttl)
1043 *min_ttlp = ttl;
1044 break;
1045 case DNS_TYPE_AAAA:
1046 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1047 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1048 ttl = clib_net_to_host_u32 (rr->ttl);
1049 if (min_ttlp && *min_ttlp > ttl)
1050 *min_ttlp = ttl;
1051 rmp->ip6_set = 1;
1052 break;
1053 default:
1054 break;
1055 }
1056 /* Might as well stop ASAP */
1057 if (rmp->ip4_set && rmp->ip6_set)
1058 break;
1059 curpos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1060 }
1061
1062 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1063 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1064 return 0;
1065}
1066
1067static void
1068vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1069{
1070 dns_main_t *dm = &dns_main;
1071 vl_api_dns_resolve_name_reply_t *rmp;
1072 dns_cache_entry_t *ep;
1073 int rv;
1074
1075 /* Sanitize the name slightly */
1076 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1077
1078 rv = dns_resolve_name (dm, mp->name, mp->client_index, mp->context, &ep);
1079
1080 /* Error, e.g. not enabled? Tell the user */
1081 if (rv < 0)
1082 {
1083 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1084 return;
1085 }
1086
1087 /* Resolution pending? Don't reply... */
1088 if (ep == 0)
1089 return;
1090
1091 /* *INDENT-OFF* */
1092 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1093 ({
1094 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1095 rmp->retval = clib_host_to_net_u32 (rv);
1096 }));
1097 /* *INDENT-ON* */
1098
1099 /*
1100 * dns_resolve_name leaves the cache locked when it returns
1101 * a cached result, so unlock it here.
1102 */
1103 dns_cache_unlock (dm);
1104}
1105
1106#define vl_msg_name_crc_list
1107#include <vpp/api/vpe_all_api_h.h>
1108#undef vl_msg_name_crc_list
1109
1110static void
1111setup_message_id_table (api_main_t * am)
1112{
1113#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1114 foreach_vl_msg_name_crc_dns;
1115#undef _
1116}
1117
1118#define foreach_dns_api_msg \
1119_(DNS_ENABLE_DISABLE, dns_enable_disable) \
1120_(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
1121_(DNS_RESOLVE_NAME, dns_resolve_name)
1122
1123static clib_error_t *
1124dns_api_hookup (vlib_main_t * vm)
1125{
1126#define _(N,n) \
1127 vl_msg_api_set_handlers(VL_API_##N, #n, \
1128 vl_api_##n##_t_handler, \
1129 vl_noop_handler, \
1130 vl_api_##n##_t_endian, \
1131 vl_api_##n##_t_print, \
1132 sizeof(vl_api_##n##_t), 1);
1133 foreach_dns_api_msg;
1134#undef _
1135
1136 setup_message_id_table (&api_main);
1137 return 0;
1138}
1139
1140VLIB_API_INIT_FUNCTION (dns_api_hookup);
1141
1142
1143static clib_error_t *
1144dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1145{
1146 dns_main_t *dm = &dns_main;
1147
1148 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1149 {
1150 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1151 ;
1152 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1153 ;
1154 else
1155 return clib_error_return (0, "unknown input `%U'",
1156 format_unformat_error, input);
1157 }
1158 return 0;
1159}
1160
1161VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1162
1163static clib_error_t *
1164dns_init (vlib_main_t * vm)
1165{
1166 dns_main_t *dm = &dns_main;
1167
1168 dm->vlib_main = vm;
1169 dm->vnet_main = vnet_get_main ();
1170 dm->name_cache_size = 65535;
1171 dm->max_ttl_in_seconds = 86400;
1172 dm->random_seed = 0xDEADDABE;
1173
1174 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply, dns46_reply_node.index,
1175 1 /* is_ip4 */ );
1176
1177 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6, dns46_reply_node.index,
1178 0 /* is_ip4 */ );
1179
1180#if 0
1181 udp_register_dst_port (vm, UDP_DST_PORT_dns, dns4_request_node.index,
1182 1 /* is_ip4 */ );
1183 udp_register_dst_port (vm, UDP_DST_PORT_dns6, dns6_request_node.index,
1184 0 /* is_ip4 */ );
1185#endif
1186
1187 return 0;
1188}
1189
1190VLIB_INIT_FUNCTION (dns_init);
1191
1192uword
1193unformat_dns_reply (unformat_input_t * input, va_list * args)
1194{
1195 u8 **result = va_arg (*args, u8 **);
1196 u8 **namep = va_arg (*args, u8 **);
1197 ip4_address_t a4;
1198 ip6_address_t a6;
1199 int a4_set = 0;
1200 int a6_set = 0;
1201 u8 *name;
1202 int name_set = 0;
1203 u8 *ce;
1204 u32 qp_offset;
1205 dns_header_t *h;
1206 dns_query_t *qp;
1207 dns_rr_t *rr;
1208 u8 *rru8;
1209
1210 if (unformat (input, "%v", &name))
1211 name_set = 1;
1212
1213 if (unformat (input, "%U", unformat_ip4_address, &a4))
1214 {
1215 a4_set = 1;
1216 if (unformat (input, "%U", unformat_ip6_address, &a6))
1217 a6_set = 1;
1218 }
1219
1220 if (unformat (input, "%U", unformat_ip6_address, &a6))
1221 {
1222 a6_set = 1;
1223 if (unformat (input, "%U", unformat_ip4_address, &a6))
1224 a4_set = 1;
1225 }
1226
1227 /* Must have a name */
1228 if (!name_set)
1229 return 0;
1230
1231 /* Must have at least one address */
1232 if (!(a4_set + a6_set))
1233 return 0;
1234
1235 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1236 ce = name_to_labels (name);
1237 qp_offset = vec_len (ce);
1238
1239 /* Add space for the query header */
1240 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1241 qp = (dns_query_t *) (ce + qp_offset);
1242
1243 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1244 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1245
1246 /* Punch in space for the dns_header_t */
1247 vec_insert (ce, sizeof (dns_header_t), 0);
1248
1249 h = (dns_header_t *) ce;
1250
1251 /* Fake Transaction ID */
1252 h->id = 0xFFFF;
1253
1254 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1255 h->qdcount = clib_host_to_net_u16 (1);
1256 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1257 h->nscount = 0;
1258 h->arcount = 0;
1259
1260 /* Now append one or two A/AAAA RR's... */
1261 if (a4_set)
1262 {
1263 /* Pointer to the name (DGMS) */
1264 vec_add1 (ce, 0xC0);
1265 vec_add1 (ce, 0x0C);
1266 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1267 rr = (void *) rru8;
1268 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1269 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1270 rr->ttl = clib_host_to_net_u32 (86400);
1271 rr->rdlength = clib_host_to_net_u16 (4);
1272 memcpy (rr->rdata, &a4, sizeof (a4));
1273 }
1274 if (a6_set)
1275 {
1276 /* Pointer to the name (DGMS) */
1277 vec_add1 (ce, 0xC0);
1278 vec_add1 (ce, 0x0C);
1279 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1280 rr = (void *) rru8;
1281 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1282 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1283 rr->ttl = clib_host_to_net_u32 (86400);
1284 rr->rdlength = clib_host_to_net_u16 (16);
1285 memcpy (rr->rdata, &a6, sizeof (a6));
1286 }
1287 *result = ce;
1288 if (namep)
1289 *namep = name;
1290 else
1291 vec_free (name);
1292
1293 return 1;
1294}
1295
1296u8 *
1297format_dns_query (u8 * s, va_list * args)
1298{
1299 u8 **curpos = va_arg (*args, u8 **);
1300 int verbose = va_arg (*args, int);
1301 u8 *pos;
1302 dns_query_t *qp;
1303 int len, i;
1304 if (verbose > 1)
1305 s = format (s, " Name: ");
1306
1307 /* Unwind execrated counted-label sheit */
1308 pos = *curpos;
1309 len = *pos++;
1310
1311 while (len)
1312 {
1313 for (i = 0; i < len; i++)
1314 vec_add1 (s, *pos++);
1315
1316 len = *pos++;
1317 if (len)
1318 vec_add1 (s, '.');
1319 else
1320 {
1321 vec_add1 (s, ':');
1322 vec_add1 (s, ' ');
1323 }
1324 }
1325
1326 qp = (dns_query_t *) pos;
1327 if (verbose > 1)
1328 {
1329 switch (clib_net_to_host_u16 (qp->type))
1330 {
1331 case DNS_TYPE_A:
1332 s = format (s, "type A\n");
1333 break;
1334 case DNS_TYPE_AAAA:
1335 s = format (s, "type AAAA\n");
1336 break;
1337 case DNS_TYPE_ALL:
1338 s = format (s, "type ALL\n");
1339 break;
1340
1341 default:
1342 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1343 break;
1344 }
1345 }
1346
1347 pos += sizeof (*qp);
1348
1349 *curpos = pos;
1350 return s;
1351}
1352
1353/**
1354 * format dns reply data
1355 * verbose > 1, dump everything
1356 * verbose == 1, dump all A and AAAA records
1357 * verbose == 0, dump one A record, and one AAAA record
1358 */
1359
1360u8 *
1361format_dns_reply_data (u8 * s, va_list * args)
1362{
1363 u8 *reply = va_arg (*args, u8 *);
1364 u8 **curpos = va_arg (*args, u8 **);
1365 int verbose = va_arg (*args, int);
1366 int *print_ip4 = va_arg (*args, int *);
1367 int *print_ip6 = va_arg (*args, int *);
1368 int len;
1369 u8 *pos, *pos2;
1370 dns_rr_t *rr;
1371 int i;
1372 int initial_pointer_chase = 0;
1373 u16 *tp;
1374
1375 pos = pos2 = *curpos;
1376
1377 if (verbose > 1)
1378 s = format (s, " ");
1379
1380 /* chase pointer? almost always yes here... */
1381 if (pos2[0] == 0xc0)
1382 {
1383 pos2 = reply + pos2[1];
1384 pos += 2;
1385 initial_pointer_chase = 1;
1386 }
1387
1388 len = *pos2++;
1389
1390 while (len)
1391 {
1392 for (i = 0; i < len; i++)
1393 {
1394 if (verbose > 1)
1395 vec_add1 (s, *pos2);
1396 pos2++;
1397 }
1398 len = *pos2++;
1399 if (len)
1400 {
1401 if (verbose > 1)
1402 vec_add1 (s, '.');
1403 }
1404 else
1405 {
1406 if (verbose > 1)
1407 vec_add1 (s, ' ');
1408 }
1409 }
1410
1411 if (initial_pointer_chase == 0)
1412 pos = pos2;
1413
1414 rr = (dns_rr_t *) pos;
1415
1416 switch (clib_net_to_host_u16 (rr->type))
1417 {
1418 case DNS_TYPE_A:
1419 if (verbose > 1)
1420 {
1421 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1422 format_ip4_address, rr->rdata);
1423 }
1424 else
1425 {
1426 if (*print_ip4)
1427 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1428 clib_net_to_host_u32 (rr->ttl));
1429 if (verbose == 0)
1430 *print_ip4 = 0;
1431
1432 }
1433 pos += sizeof (*rr) + 4;
1434 break;
1435
1436 case DNS_TYPE_AAAA:
1437 if (verbose > 1)
1438 {
1439 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1440 format_ip6_address, rr->rdata);
1441 }
1442 else
1443 {
1444 if (*print_ip6)
1445 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1446 clib_net_to_host_u32 (rr->ttl));
1447 if (verbose == 0)
1448 *print_ip6 = 0;
1449 }
1450 pos += sizeof (*rr) + 16;
1451 break;
1452
1453 case DNS_TYPE_TEXT:
1454 if (verbose > 1)
1455 {
1456 s = format (s, "TEXT: ");
1457 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1458 vec_add1 (s, rr->rdata[i]);
1459 vec_add1 (s, '\n');
1460 }
1461 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1462 break;
1463
1464 case DNS_TYPE_NAMESERVER:
1465 if (verbose > 1)
1466 {
1467 s = format (s, "Nameserver: ");
1468 pos2 = rr->rdata;
1469
1470 /* chase pointer? */
1471 if (pos2[0] == 0xc0)
1472 pos2 = reply + pos2[1];
1473
1474 len = *pos2++;
1475
1476 while (len)
1477 {
1478 for (i = 0; i < len; i++)
1479 vec_add1 (s, *pos2++);
1480
1481 /* chase pointer, typically to offset 12... */
1482 if (pos2[0] == 0xC0)
1483 pos2 = reply + pos2[1];
1484
1485 len = *pos2++;
1486 if (len)
1487 vec_add1 (s, '.');
1488 else
1489 vec_add1 (s, '\n');
1490 }
1491 }
1492 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1493 break;
1494
1495 case DNS_TYPE_MAIL_EXCHANGE:
1496 if (verbose > 1)
1497 {
1498 tp = (u16 *) rr->rdata;
1499
1500 s = format (s, "Mail Exchange: Preference %d ", (u32)
1501 clib_net_to_host_u16 (*tp));
1502
1503 pos2 = rr->rdata + 2;
1504
1505 /* chase pointer? */
1506 if (pos2[0] == 0xc0)
1507 pos2 = reply + pos2[1];
1508
1509 len = *pos2++;
1510
1511 while (len)
1512 {
1513 for (i = 0; i < len; i++)
1514 vec_add1 (s, *pos2++);
1515
1516 /* chase pointer */
1517 if (pos2[0] == 0xC0)
1518 pos2 = reply + pos2[1];
1519
1520 len = *pos2++;
1521 if (len)
1522 vec_add1 (s, '.');
1523 else
1524 vec_add1 (s, '\n');
1525 }
1526 }
1527
1528 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1529 break;
1530
1531 case DNS_TYPE_CNAME:
1532 if (verbose > 1)
1533 {
1534 tp = (u16 *) rr->rdata;
1535
1536 s = format (s, "CNAME: ");
1537
1538 pos2 = rr->rdata;
1539
1540 /* chase pointer? */
1541 if (pos2[0] == 0xc0)
1542 pos2 = reply + pos2[1];
1543
1544 len = *pos2++;
1545
1546 while (len)
1547 {
1548 for (i = 0; i < len; i++)
1549 vec_add1 (s, *pos2++);
1550
1551 /* chase pointer */
1552 if (pos2[0] == 0xC0)
1553 pos2 = reply + pos2[1];
1554
1555 len = *pos2++;
1556 if (len)
1557 vec_add1 (s, '.');
1558 else
1559 vec_add1 (s, '\n');
1560 }
1561 }
1562 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1563 break;
1564
1565 default:
1566 if (verbose > 1)
1567 s = format (s, "type %d: len %d\n",
1568 (int) clib_net_to_host_u16 (rr->type),
1569 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
1570 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1571 break;
1572 }
1573
1574 *curpos = pos;
1575
1576 return s;
1577}
1578
1579u8 *
1580format_dns_reply (u8 * s, va_list * args)
1581{
1582 u8 *reply_as_u8 = va_arg (*args, u8 *);
1583 int verbose = va_arg (*args, int);
1584 dns_header_t *h;
1585 u16 id, flags;
1586 u8 *curpos;
1587 int i;
1588 int print_ip4 = 1;
1589 int print_ip6 = 1;
1590
1591 h = (dns_header_t *) reply_as_u8;
1592 id = clib_net_to_host_u16 (h->id);
1593 flags = clib_net_to_host_u16 (h->flags);
1594
1595 if (verbose > 1)
1596 {
1597 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
1598 id);
1599 s = format (s, " %s %s %s %s\n",
1600 (flags & DNS_RA) ? "recur" : "no-recur",
1601 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
1602 (flags & DNS_TC) ? "trunc" : "no-trunc",
1603 (flags & DNS_AA) ? "auth" : "non-auth");
1604 s = format (s, " %d queries, %d answers, %d name-servers,"
1605 " %d add'l recs\n",
1606 clib_net_to_host_u16 (h->qdcount),
1607 clib_net_to_host_u16 (h->anscount),
1608 clib_net_to_host_u16 (h->nscount),
1609 clib_net_to_host_u16 (h->arcount));
1610 }
1611
1612 curpos = (u8 *) (h + 1);
1613
1614 if (h->qdcount)
1615 {
1616 if (verbose > 1)
1617 s = format (s, " Queries:\n");
1618 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1619 {
1620 /* The query is variable-length, so curpos is a value-result parm */
1621 s = format (s, "%U", format_dns_query, &curpos, verbose);
1622 }
1623 }
1624 if (h->anscount)
1625 {
1626 if (verbose > 1)
1627 s = format (s, " Replies:\n");
1628
1629 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1630 {
1631 /* curpos is a value-result parm */
1632 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
1633 verbose, &print_ip4, &print_ip6);
1634 }
1635 }
1636 return s;
1637}
1638
1639u8 *
1640format_dns_cache (u8 * s, va_list * args)
1641{
1642 dns_main_t *dm = va_arg (*args, dns_main_t *);
1643 f64 now = va_arg (*args, f64);
1644 int verbose = va_arg (*args, int);
1645 u8 *name = va_arg (*args, u8 *);
1646 dns_cache_entry_t *ep;
1647 char *ss;
1648 uword *p;
1649
1650 if (dm->is_enabled == 0)
1651 {
1652 s = format (s, "The DNS cache is disabled...");
1653 return s;
1654 }
1655
1656 if (pool_elts (dm->entries) == 0)
1657 {
1658 s = format (s, "The DNS cache is empty...");
1659 return s;
1660 }
1661
1662 dns_cache_lock (dm);
1663
1664 if (name)
1665 {
1666 p = hash_get_mem (dm->cache_entry_by_name, name);
1667 if (!p)
1668 {
1669 s = format (s, "%s is not in the cache...", name);
1670 dns_cache_unlock (dm);
1671 return (s);
1672 }
1673
1674 ep = pool_elt_at_index (dm->entries, p[0]);
1675 /* Magic to spit out a C-initializer to research hemorrhoids... */
1676 if (verbose == 3)
1677 {
1678 int i, j;
1679 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
1680 s = format (s, "{\n");
1681 j = 0;
1682 for (i = 0; i < vec_len (ep->dns_response); i++)
1683 {
1684 if (j++ == 8)
1685 {
1686 j = 0;
1687 vec_add1 (s, '\n');
1688 }
1689 s = format (s, "0x%02x, ", ep->dns_response[i]);
1690 }
1691 s = format (s, "};\n");
1692 }
1693 else
1694 {
1695 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
1696 {
1697 ASSERT (ep->dns_response);
1698 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
1699 ss = "[S] ";
1700 else
1701 ss = " ";
1702
1703 s = format (s, "%s%s -> %U", ss, ep->name,
1704 format_dns_reply, ep->dns_response, verbose);
1705 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
1706 {
1707 f64 time_left = ep->expiration_time - now;
1708 if (time_left > 0.0)
1709 s = format (s, " TTL left %.1f", time_left);
1710 else
1711 s = format (s, " EXPIRED");
1712 }
1713 }
1714 else
1715 {
1716 ASSERT (ep->dns_request);
1717 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
1718 verbose);
1719 }
1720 vec_add1 (s, '\n');
1721 }
1722 return s;
1723 }
1724
1725 /* *INDENT-OFF* */
1726 pool_foreach (ep, dm->entries,
1727 ({
1728 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
1729 {
1730 ASSERT (ep->dns_response);
1731 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
1732 ss = "[S] ";
1733 else
1734 ss = " ";
1735
1736 s = format (s, "%s%s -> %U", ss, ep->name,
1737 format_dns_reply,
1738 ep->dns_response,
1739 verbose);
1740 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
1741 {
1742 f64 time_left = ep->expiration_time - now;
1743 if (time_left > 0.0)
1744 s = format (s, " TTL left %.1f", time_left);
1745 else
1746 s = format (s, " EXPIRED");
1747 }
1748 }
1749 else
1750 {
1751 ASSERT (ep->dns_request);
1752 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
1753 verbose);
1754 }
1755 vec_add1 (s, '\n');
1756 }));
1757 /* *INDENT-ON* */
1758
1759 dns_cache_unlock (dm);
1760
1761 return s;
1762}
1763
1764static clib_error_t *
1765show_dns_cache_command_fn (vlib_main_t * vm,
1766 unformat_input_t * input, vlib_cli_command_t * cmd)
1767{
1768 dns_main_t *dm = &dns_main;
1769 int verbose = 0;
1770 u8 *name = 0;
1771 f64 now = vlib_time_now (vm);
1772
1773 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1774 {
1775 if (unformat (input, "verbose %d", &verbose))
1776 ;
1777 else if (unformat (input, "verbose"))
1778 verbose = 1;
1779 else if (unformat (input, "name %s", &name))
1780 ;
1781 else
1782 return clib_error_return (0, "unknown input `%U'",
1783 format_unformat_error, input);
1784 }
1785
1786 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
1787
1788 return 0;
1789}
1790
1791/* *INDENT-OFF* */
1792VLIB_CLI_COMMAND (show_dns_cache_command) =
1793{
1794 .path = "show dns cache",
1795 .short_help = "show dns cache [verbose [nn]]",
1796 .function = show_dns_cache_command_fn,
1797};
1798/* *INDENT-ON* */
1799
1800static clib_error_t *
1801dns_cache_add_del_command_fn (vlib_main_t * vm,
1802 unformat_input_t * input,
1803 vlib_cli_command_t * cmd)
1804{
1805 dns_main_t *dm = &dns_main;
1806 u8 *dns_reply_data;
1807 u8 *name;
1808 int is_add = -1;
1809 int is_clear = -1;
1810 int rv;
1811 clib_error_t *error;
1812
1813 if (unformat (input, "add"))
1814 is_add = 1;
1815 if (unformat (input, "del"))
1816 is_add = 0;
1817 if (unformat (input, "clear"))
1818 is_clear = 1;
1819
1820 if (is_add == -1 && is_clear == -1)
1821 return clib_error_return (0, "add / del / clear required...");
1822
1823 if (is_clear == 1)
1824 {
1825 rv = dns_cache_clear (dm);
1826 switch (rv)
1827 {
1828 case 0:
1829 return 0;
1830
1831 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
1832 error = clib_error_return (0, "Name resolution not enabled");
1833 return error;
1834 }
1835 }
1836
1837 /* Delete (by name)? */
1838 if (is_add == 0)
1839 {
1840 if (unformat (input, "%v", &name))
1841 {
1842 rv = dns_delete_by_name (dm, name);
1843 switch (rv)
1844 {
1845 case VNET_API_ERROR_NO_SUCH_ENTRY:
1846 error = clib_error_return (0, "%v not in the cache...", name);
1847 vec_free (name);
1848 return error;
1849
1850 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
1851 error = clib_error_return (0, "Name resolution not enabled");
1852 vec_free (name);
1853 return error;
1854
1855 case 0:
1856 vec_free (name);
1857 return 0;
1858
1859 default:
1860 error = clib_error_return (0, "dns_delete_by_name returned %d",
1861 rv);
1862 vec_free (name);
1863 return error;
1864 }
1865 }
1866 return clib_error_return (0, "unknown input `%U'",
1867 format_unformat_error, input);
1868 }
1869
1870 /* Note: dns_add_static_entry consumes the name vector if OK... */
1871 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
1872 {
1873 rv = dns_add_static_entry (dm, name, dns_reply_data);
1874 switch (rv)
1875 {
1876 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
1877 vec_free (name);
1878 vec_free (dns_reply_data);
1879 return clib_error_return (0, "%v already in the cache...", name);
1880 case 0:
1881 return 0;
1882
1883 default:
1884 return clib_error_return (0, "dns_add_static_entry returned %d",
1885 rv);
1886 }
1887 }
1888
1889 return 0;
1890}
1891
1892/* *INDENT-OFF* */
1893VLIB_CLI_COMMAND (dns_cache_add_del_command) =
1894{
1895 .path = "dns cache",
1896 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
1897 .function = dns_cache_add_del_command_fn,
1898};
1899/* *INDENT-ON* */
1900
1901#define DNS_FORMAT_TEST 1
1902
1903#if DNS_FORMAT_TEST > 0
1904#if 0
1905/* yahoo.com */
1906static u8 dns_reply_data_initializer[] =
1907 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
1908 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
1909 0x0, /* null lbl */
1910 0x0, 0xff, /* type ALL */
1911 0x0, 0x1, /* class IN */
1912 0xc0, 0xc, /* pointer to yahoo.com name */
1913 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
1914 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
1915 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
1916 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
1917 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
1918 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
1919 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
1920 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
1921 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
1922 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
1923 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
1924 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
1925 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
1926 0x6e,
1927 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
1928 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
1929 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
1930 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
1931 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
1932 0x0,
1933 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
1934 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
1935 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
1936 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
1937 0x0,
1938 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
1939 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
1940 0x0,
1941 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
1942 0x0,
1943 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
1944 0x0,
1945 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
1946 0x6f,
1947 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
1948 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
1949 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
1950 0x2, 0x58
1951};
1952
1953/* www.cisco.com, has no addresses in reply */
1954static u8 dns_reply_data_initializer[] = {
1955 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
1956 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
1957 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
1958
1959 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
1960 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
1961 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
1962 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
1963 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
1964};
1965#else
1966/* google.com */
1967static u8 dns_reply_data_initializer[] =
1968 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
1969 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
1970 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
1971 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
1972 0x2b,
1973 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
1974 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
1975 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
1976 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
1977 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
1978 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
1979 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
1980 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
1981 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
1982 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
1983 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
1984 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
1985 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
1986 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
1987 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
1988 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
1989 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
1990 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
1991 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
1992 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
1993 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
1994 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
1995 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
1996 0x57,
1997 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
1998};
1999#endif
2000
2001static clib_error_t *
2002test_dns_fmt_command_fn (vlib_main_t * vm,
2003 unformat_input_t * input, vlib_cli_command_t * cmd)
2004{
2005 u8 *dns_reply_data = 0;
2006 int verbose = 0;
2007 int rv;
2008 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2009
2010 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2011 {
2012 if (unformat (input, "verbose %d", &verbose))
2013 ;
2014 else if (unformat (input, "verbose"))
2015 verbose = 1;
2016 else
2017 return clib_error_return (0, "unknown input `%U'",
2018 format_unformat_error, input);
2019 }
2020
2021 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2022
2023 memcpy (dns_reply_data, dns_reply_data_initializer,
2024 ARRAY_LEN (dns_reply_data_initializer));
2025
2026 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2027
2028 memset (rmp, 0, sizeof (*rmp));
2029
2030 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2031
2032 switch (rv)
2033 {
2034 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2035 vlib_cli_output (vm, "no addresses found...");
2036 break;
2037
2038 default:
2039 vlib_cli_output (vm, "response to reply returned %d", rv);
2040 break;
2041
2042 case 0:
2043 if (rmp->ip4_set)
2044 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2045 (ip4_address_t *) rmp->ip4_address);
2046 if (rmp->ip6_set)
2047 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2048 (ip6_address_t *) rmp->ip6_address);
2049 break;
2050 }
2051
2052 vec_free (dns_reply_data);
2053
2054 return 0;
2055}
2056
2057
2058/* *INDENT-OFF* */
2059VLIB_CLI_COMMAND (test_dns_fmt_command) =
2060{
2061 .path = "test dns format",
2062 .short_help = "test dns format",
2063 .function = test_dns_fmt_command_fn,
2064};
2065/* *INDENT-ON* */
2066
2067static clib_error_t *
2068test_dns_unfmt_command_fn (vlib_main_t * vm,
2069 unformat_input_t * input, vlib_cli_command_t * cmd)
2070{
2071 u8 *dns_reply_data = 0;
2072 int verbose = 0;
2073 int reply_set = 0;
2074
2075 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2076 {
2077 if (unformat (input, "verbose %d", &verbose))
2078 ;
2079 else if (unformat (input, "verbose"))
2080 verbose = 1;
2081 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2082 reply_set = 1;
2083 else
2084 return clib_error_return (0, "unknown input `%U'",
2085 format_unformat_error, input);
2086 }
2087
2088 if (reply_set == 0)
2089 return clib_error_return (0, "dns data not set...");
2090
2091 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2092
2093 vec_free (dns_reply_data);
2094
2095 return 0;
2096}
2097
2098/* *INDENT-OFF* */
2099VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2100{
2101 .path = "test dns unformat",
2102 .short_help = "test dns unformat <name> [ip4][ip6]",
2103 .function = test_dns_unfmt_command_fn,
2104};
2105/* *INDENT-ON* */
2106#endif
2107
2108/*
2109 * fd.io coding-style-patch-verification: ON
2110 *
2111 * Local Variables:
2112 * eval: (c-set-style "gnu")
2113 * End:
2114 */