blob: 24cd5969aa7268aa3b98fb683f00d200a4d48fcd [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
Dave Barach580eda72018-01-09 17:00:00 -0500200void
201vnet_dns_send_dns4_request (dns_main_t * dm,
202 dns_cache_entry_t * ep, ip4_address_t * server)
Dave Barach65457162017-10-10 17:53:14 -0400203{
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"
Dave Barach580eda72018-01-09 17:00:00 -0500250 " ~0", format_ip4_address, &prefix.fp_addr, fei);
Dave Barach65457162017-10-10 17:53:14 -0400251 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
Dave Barach580eda72018-01-09 17:00:00 -0500316void
317vnet_dns_send_dns6_request (dns_main_t * dm,
318 dns_cache_entry_t * ep, ip6_address_t * server)
Dave Barach65457162017-10-10 17:53:14 -0400319{
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;
Dave Barach580eda72018-01-09 17:00:00 -0500520 u8 *request, *name_copy;
Dave Barach65457162017-10-10 17:53:14 -0400521 u32 qp_offset;
522
Dave Barach0cb01bd2017-10-16 14:39:52 -0400523 /* This can easily happen if sitting in GDB, etc. */
Dave Barach580eda72018-01-09 17:00:00 -0500524 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID || ep->server_fails > 1)
Dave Barach0cb01bd2017-10-16 14:39:52 -0400525 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);
Dave Barach580eda72018-01-09 17:00:00 -0500536 name_copy = vec_dup (request);
Dave Barach65457162017-10-10 17:53:14 -0400537 qp_offset = vec_len (request);
538
Dave Barach580eda72018-01-09 17:00:00 -0500539 /*
540 * At least when testing against "known good" DNS servers:
541 * it turns out that sending 2x requests - one for an A-record
542 * and another for a AAAA-record - seems to work better than
543 * sending a DNS_TYPE_ALL request.
544 */
545
Dave Barach65457162017-10-10 17:53:14 -0400546 /* Add space for the query header */
Dave Barach580eda72018-01-09 17:00:00 -0500547 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
Dave Barach65457162017-10-10 17:53:14 -0400548
549 qp = (dns_query_t *) (request + qp_offset);
550
Dave Barach580eda72018-01-09 17:00:00 -0500551 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
552 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
553 qp++;
554 clib_memcpy (qp, name_copy, vec_len (name_copy));
555 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
556 vec_free (name_copy);
557
558 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
Dave Barach65457162017-10-10 17:53:14 -0400559 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
560
561 /* Punch in space for the dns_header_t */
562 vec_insert (request, sizeof (dns_header_t), 0);
563
564 h = (dns_header_t *) request;
565
566 /* Transaction ID = pool index */
567 h->id = clib_host_to_net_u16 (ep - dm->entries);
568
569 /* Ask for a recursive lookup */
570 tmp = DNS_RD | DNS_OPCODE_QUERY;
571 h->flags = clib_host_to_net_u16 (tmp);
Dave Barach580eda72018-01-09 17:00:00 -0500572 h->qdcount = clib_host_to_net_u16 (2);
Dave Barach65457162017-10-10 17:53:14 -0400573 h->nscount = 0;
574 h->arcount = 0;
575
576 ep->dns_request = request;
577 }
578
579 /* Work out which server / address family we're going to use */
580
581 /* Retry using current server */
582 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
583 {
584 if (ep->server_af == 1 /* ip6 */ )
585 {
586 if (vec_len (dm->ip6_name_servers))
587 {
Dave Barach580eda72018-01-09 17:00:00 -0500588 vnet_dns_send_dns6_request
589 (dm, ep, dm->ip6_name_servers + ep->server_rotor);
Dave Barach65457162017-10-10 17:53:14 -0400590 goto out;
591 }
592 else
593 ep->server_af = 0;
594 }
595 if (vec_len (dm->ip4_name_servers))
596 {
Dave Barach580eda72018-01-09 17:00:00 -0500597 vnet_dns_send_dns4_request
598 (dm, ep, dm->ip4_name_servers + ep->server_rotor);
Dave Barach65457162017-10-10 17:53:14 -0400599 goto out;
600 }
601 }
602 else /* switch to a new server */
603 {
604 ep->retry_count = 1;
605 ep->server_rotor++;
606 if (ep->server_af == 1 /* ip6 */ )
607 {
608 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
609 {
610 ep->server_rotor = 0;
611 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
612 }
613 }
614 else
615 {
616 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
617 {
618 ep->server_rotor = 0;
619 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
620 }
621 }
622 }
623
624 if (ep->server_af == 1 /* ip6 */ )
Dave Barach580eda72018-01-09 17:00:00 -0500625 vnet_dns_send_dns6_request
626 (dm, ep, dm->ip6_name_servers + ep->server_rotor);
Dave Barach65457162017-10-10 17:53:14 -0400627 else
Dave Barach580eda72018-01-09 17:00:00 -0500628 vnet_dns_send_dns4_request
629 (dm, ep, dm->ip4_name_servers + ep->server_rotor);
Dave Barach65457162017-10-10 17:53:14 -0400630
631out:
632
633 vlib_process_signal_event_mt (dm->vlib_main, dns_resolver_node.index,
634 DNS_RESOLVER_EVENT_PENDING, 0);
635}
636
637int
638vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
639{
640 dns_cache_entry_t *ep;
641 int i;
642
643 if (dm->is_enabled == 0)
644 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
645
646 if (pool_is_free_index (dm->entries, index))
647 return VNET_API_ERROR_NO_SUCH_ENTRY;
648
649 ep = pool_elt_at_index (dm->entries, index);
Dave Barach65457162017-10-10 17:53:14 -0400650 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
651 {
652 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
653 if (index == dm->unresolved_entries[i])
654 {
655 vec_delete (dm->unresolved_entries, 1, i);
656 goto found;
657 }
658 clib_warning ("pool elt %d supposedly pending, but not found...",
659 index);
660 }
661
662found:
663 hash_unset_mem (dm->cache_entry_by_name, ep->name);
664 vec_free (ep->name);
Dave Barach97494502017-11-04 09:44:38 -0400665 vec_free (ep->pending_requests);
Dave Barach65457162017-10-10 17:53:14 -0400666 pool_put (dm->entries, ep);
667
668 return 0;
669}
670
671static int
672dns_delete_by_name (dns_main_t * dm, u8 * name)
673{
674 int rv;
675 uword *p;
676
677 if (dm->is_enabled == 0)
678 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
679
680 dns_cache_lock (dm);
681 p = hash_get_mem (dm->cache_entry_by_name, name);
682 if (!p)
683 {
684 dns_cache_unlock (dm);
685 return VNET_API_ERROR_NO_SUCH_ENTRY;
686 }
687 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
688
689 dns_cache_unlock (dm);
690
691 return rv;
692}
693
694static int
695delete_random_entry (dns_main_t * dm)
696{
697 int rv;
698 u32 victim_index, start_index, i;
699 u32 limit;
700 dns_cache_entry_t *ep;
701
702 if (dm->is_enabled == 0)
703 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
704
Dave Barachb9f2cf02017-10-17 13:13:42 -0400705 /*
706 * Silence spurious coverity warning. We know pool_elts >> 0, or
707 * we wouldn't be here...
708 */
709#ifdef __COVERITY__
710 if (pool_elts (dm->entries) == 0)
711 return VNET_API_ERROR_UNSPECIFIED;
712#endif
713
Dave Barach65457162017-10-10 17:53:14 -0400714 dns_cache_lock (dm);
715 limit = pool_elts (dm->entries);
716 start_index = random_u32 (&dm->random_seed) % limit;
717
718 for (i = 0; i < limit; i++)
719 {
720 victim_index = (start_index + i) % limit;
721
722 if (!pool_is_free_index (dm->entries, victim_index))
723 {
724 ep = pool_elt_at_index (dm->entries, victim_index);
725 /* Delete only valid, non-static entries */
726 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
727 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
728 {
729 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
730 dns_cache_unlock (dm);
731 return rv;
732 }
733 }
734 }
735 dns_cache_unlock (dm);
736
737 clib_warning ("Couldn't find an entry to delete?");
738 return VNET_API_ERROR_UNSPECIFIED;
739}
740
741static int
742dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
743{
744 dns_cache_entry_t *ep;
745 uword *p;
746 int rv;
747
748 if (dm->is_enabled == 0)
749 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
750
751 dns_cache_lock (dm);
752 p = hash_get_mem (dm->cache_entry_by_name, name);
753 if (p)
754 {
755 dns_cache_unlock (dm);
756 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
757 }
758
759 if (pool_elts (dm->entries) == dm->name_cache_size)
760 {
761 /* Will only fail if the cache is totally filled w/ static entries... */
762 rv = delete_random_entry (dm);
763 if (rv)
764 {
765 dns_cache_unlock (dm);
766 return rv;
767 }
768 }
769
770 pool_get (dm->entries, ep);
771 memset (ep, 0, sizeof (*ep));
772
773 /* Note: consumes the name vector */
774 ep->name = name;
775 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
776 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
777 ep->dns_response = dns_reply_data;
778
779 dns_cache_unlock (dm);
780 return 0;
781}
782
Dave Barach97494502017-11-04 09:44:38 -0400783int
784vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t,
785 dns_cache_entry_t ** retp)
Dave Barach65457162017-10-10 17:53:14 -0400786{
787 dns_cache_entry_t *ep;
788 int rv;
789 f64 now;
790 uword *p;
Dave Barach97494502017-11-04 09:44:38 -0400791 dns_pending_request_t *pr;
792 int count;
Dave Barach65457162017-10-10 17:53:14 -0400793
794 now = vlib_time_now (dm->vlib_main);
795
796 /* In case we can't actually answer the question right now... */
797 *retp = 0;
798
799 dns_cache_lock (dm);
Dave Barach0cb01bd2017-10-16 14:39:52 -0400800search_again:
Dave Barach65457162017-10-10 17:53:14 -0400801 p = hash_get_mem (dm->cache_entry_by_name, name);
802 if (p)
803 {
804 ep = pool_elt_at_index (dm->entries, p[0]);
805 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
806 {
807 /* Has the entry expired? */
808 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
809 && (now > ep->expiration_time))
810 {
Dave Barach0cb01bd2017-10-16 14:39:52 -0400811 int i;
812 u32 *indices_to_delete = 0;
813
814 /*
815 * Take out the rest of the resolution chain
816 * This isn't optimal, but it won't happen very often.
817 */
818 while (ep)
819 {
820 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
821 {
822 vec_add1 (indices_to_delete, ep - dm->entries);
823
824 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
825 if (!p)
826 break;
827 ep = pool_elt_at_index (dm->entries, p[0]);
828 }
829 else
830 {
831 vec_add1 (indices_to_delete, ep - dm->entries);
832 break;
833 }
834 }
835 for (i = 0; i < vec_len (indices_to_delete); i++)
836 {
837 /* Reenable to watch re-resolutions */
838 if (0)
839 {
840 ep = pool_elt_at_index (dm->entries,
841 indices_to_delete[i]);
842 clib_warning ("Re-resolve %s", ep->name);
843 }
844
845 vnet_dns_delete_entry_by_index_nolock
846 (dm, indices_to_delete[i]);
847 }
848 vec_free (indices_to_delete);
Dave Barach65457162017-10-10 17:53:14 -0400849 /* Yes, kill it... */
Dave Barach65457162017-10-10 17:53:14 -0400850 goto re_resolve;
851 }
852
Dave Barach0cb01bd2017-10-16 14:39:52 -0400853 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
854 {
855 name = ep->cname;
856 goto search_again;
857 }
858
Dave Barach65457162017-10-10 17:53:14 -0400859 /* Note: caller must drop the lock! */
860 *retp = ep;
861 return (0);
862 }
Dave Barach0cb01bd2017-10-16 14:39:52 -0400863 else
864 {
865 /*
Dave Barachd2080152017-10-20 09:21:35 -0400866 * Resolution pending. Add request to the pending vector
Dave Barach97494502017-11-04 09:44:38 -0400867 * by copying the template request
Dave Barachd2080152017-10-20 09:21:35 -0400868 */
Dave Barach97494502017-11-04 09:44:38 -0400869 vec_add2 (ep->pending_requests, pr, 1);
870 memcpy (pr, t, sizeof (*pr));
Dave Barach0cb01bd2017-10-16 14:39:52 -0400871 dns_cache_unlock (dm);
872 return (0);
873 }
Dave Barach65457162017-10-10 17:53:14 -0400874 }
875
Dave Barach0cb01bd2017-10-16 14:39:52 -0400876re_resolve:
Dave Barach65457162017-10-10 17:53:14 -0400877 if (pool_elts (dm->entries) == dm->name_cache_size)
878 {
879 /* Will only fail if the cache is totally filled w/ static entries... */
880 rv = delete_random_entry (dm);
881 if (rv)
882 {
883 dns_cache_unlock (dm);
884 return rv;
885 }
886 }
887
Dave Barach65457162017-10-10 17:53:14 -0400888 /* add new hash table entry */
889 pool_get (dm->entries, ep);
890 memset (ep, 0, sizeof (*ep));
891
892 ep->name = format (0, "%s%c", name, 0);
893 _vec_len (ep->name) = vec_len (ep->name) - 1;
894
895 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
896
897 vec_add1 (dm->unresolved_entries, ep - dm->entries);
Dave Barach97494502017-11-04 09:44:38 -0400898 vec_add2 (ep->pending_requests, pr, 1);
899
900 pr->request_type = t->request_type;
901
902 /* Remember details so we can reply later... */
903 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
904 t->request_type == DNS_API_PENDING_IP_TO_NAME)
905 {
906 pr->client_index = t->client_index;
907 pr->client_context = t->client_context;
908 }
909 else
910 {
911 pr->client_index = ~0;
912 pr->is_ip6 = t->is_ip6;
913 pr->dst_port = t->dst_port;
914 pr->id = t->id;
915 pr->name = t->name;
916 if (t->is_ip6)
917 count = 16;
918 else
919 count = 4;
920 clib_memcpy (pr->dst_address, t->dst_address, count);
921 }
922
Dave Barach65457162017-10-10 17:53:14 -0400923 vnet_send_dns_request (dm, ep);
924 dns_cache_unlock (dm);
Dave Barach65457162017-10-10 17:53:14 -0400925 return 0;
926}
927
Dave Barach0cb01bd2017-10-16 14:39:52 -0400928#define foreach_notification_to_move \
Dave Barach97494502017-11-04 09:44:38 -0400929_(pending_requests)
Dave Barach0cb01bd2017-10-16 14:39:52 -0400930
Dave Barach65457162017-10-10 17:53:14 -0400931/**
932 * Handle cname indirection. JFC. Called with the cache locked.
933 * returns 0 if the reply is not a CNAME.
934 */
935
936int
Dave Barach0cb01bd2017-10-16 14:39:52 -0400937vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
Dave Barach65457162017-10-10 17:53:14 -0400938{
939 dns_header_t *h;
940 dns_query_t *qp;
941 dns_rr_t *rr;
942 u8 *curpos;
943 u8 *pos, *pos2;
Dave Barachc6372eb2018-01-10 18:18:59 -0500944 u8 *cname_pos = 0;
Dave Barach65457162017-10-10 17:53:14 -0400945 int len, i;
946 u8 *cname = 0;
947 u8 *request = 0;
Dave Barachc6372eb2018-01-10 18:18:59 -0500948 u8 *name_copy;
Dave Barach65457162017-10-10 17:53:14 -0400949 u32 qp_offset;
950 u16 flags;
951 u16 rcode;
Dave Barach0cb01bd2017-10-16 14:39:52 -0400952 dns_cache_entry_t *ep, *next_ep;
953 f64 now;
Dave Barach65457162017-10-10 17:53:14 -0400954
955 h = (dns_header_t *) reply;
956 flags = clib_net_to_host_u16 (h->flags);
957 rcode = flags & DNS_RCODE_MASK;
958
959 /* See if the response is OK */
960 switch (rcode)
961 {
962 case DNS_RCODE_NO_ERROR:
963 break;
964
965 case DNS_RCODE_NAME_ERROR:
966 case DNS_RCODE_FORMAT_ERROR:
967 case DNS_RCODE_SERVER_FAILURE:
968 case DNS_RCODE_NOT_IMPLEMENTED:
969 case DNS_RCODE_REFUSED:
Dave Barach580eda72018-01-09 17:00:00 -0500970 return -1;
Dave Barach65457162017-10-10 17:53:14 -0400971 }
972
973 curpos = (u8 *) (h + 1);
974 pos = curpos;
975 len = *pos++;
976
977 /* Skip the questions */
978 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
979 {
980 while (len)
981 {
982 pos += len;
983 len = *pos++;
984 }
Dave Barachb9f2cf02017-10-17 13:13:42 -0400985 pos += sizeof (dns_query_t);
Dave Barach65457162017-10-10 17:53:14 -0400986 }
987 pos2 = pos;
988 /* expect a pointer chase here for a CNAME record */
989 if ((pos2[0] & 0xC0) == 0xC0)
990 pos += 2;
991 else
992 return 0;
993
Dave Barach580eda72018-01-09 17:00:00 -0500994 /* Walk the answer(s) to see what to do next */
995 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
996 {
997 rr = (dns_rr_t *) pos;
998 switch (clib_net_to_host_u16 (rr->type))
999 {
1000 /* Real address record? Done.. */
1001 case DNS_TYPE_A:
1002 case DNS_TYPE_AAAA:
1003 return 0;
Dave Barachc6372eb2018-01-10 18:18:59 -05001004 /*
1005 * Maybe chase a CNAME pointer?
1006 * It's not unheard-of for name-servers to return
1007 * both CNAME and A/AAAA records...
1008 */
Dave Barach580eda72018-01-09 17:00:00 -05001009 case DNS_TYPE_CNAME:
Dave Barachc6372eb2018-01-10 18:18:59 -05001010 cname_pos = pos;
1011 break;
Dave Barach65457162017-10-10 17:53:14 -04001012
Dave Barach580eda72018-01-09 17:00:00 -05001013 /* Some other junk, e.g. a nameserver... */
1014 default:
1015 break;
1016 }
1017 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
Dave Barachc6372eb2018-01-10 18:18:59 -05001018 /* Skip name... */
1019 if ((pos2[0] & 0xc0) == 0xc0)
1020 pos += 2;
Dave Barach580eda72018-01-09 17:00:00 -05001021 }
Dave Barach65457162017-10-10 17:53:14 -04001022
Dave Barach580eda72018-01-09 17:00:00 -05001023 /* Neither a CNAME nor a real address. Try another server */
Dave Barachc6372eb2018-01-10 18:18:59 -05001024 if (cname_pos == 0)
1025 {
1026 flags &= ~DNS_RCODE_MASK;
1027 flags |= DNS_RCODE_NAME_ERROR;
1028 h->flags = clib_host_to_net_u16 (flags);
1029 return -1;
1030 }
Dave Barach580eda72018-01-09 17:00:00 -05001031
Dave Barach0cb01bd2017-10-16 14:39:52 -04001032 /* This is a CNAME record, chase the name chain. */
Dave Barachc6372eb2018-01-10 18:18:59 -05001033 pos = cname_pos;
Dave Barach65457162017-10-10 17:53:14 -04001034
Dave Barach0cb01bd2017-10-16 14:39:52 -04001035 /* The last request is no longer pending.. */
1036 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
1037 if (ep_index == dm->unresolved_entries[i])
1038 {
1039 vec_delete (dm->unresolved_entries, 1, i);
1040 goto found_last_request;
1041 }
1042 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
1043
1044found_last_request:
1045
1046 now = vlib_time_now (dm->vlib_main);
Dave Barach97494502017-11-04 09:44:38 -04001047 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
Dave Barach0cb01bd2017-10-16 14:39:52 -04001048 /* Save the cname */
1049 vec_add1 (cname, 0);
1050 _vec_len (cname) -= 1;
1051 ep = pool_elt_at_index (dm->entries, ep_index);
1052 ep->cname = cname;
1053 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1054 /* Save the response */
Dave Barach580eda72018-01-09 17:00:00 -05001055 if (ep->dns_response)
1056 vec_free (ep->dns_response);
Dave Barach0cb01bd2017-10-16 14:39:52 -04001057 ep->dns_response = reply;
1058 /* Set up expiration time */
1059 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1060
1061 pool_get (dm->entries, next_ep);
1062
1063 /* Need to recompute ep post pool-get */
1064 ep = pool_elt_at_index (dm->entries, ep_index);
1065
1066 memset (next_ep, 0, sizeof (*next_ep));
1067 next_ep->name = vec_dup (cname);
1068 vec_add1 (next_ep->name, 0);
1069 _vec_len (next_ep->name) -= 1;
1070
1071 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1072 next_ep - dm->entries);
1073
1074 /* Use the same server */
1075 next_ep->server_rotor = ep->server_rotor;
1076 next_ep->server_af = ep->server_af;
1077
1078 /* Move notification data to the next name in the chain */
1079#define _(a) next_ep->a = ep->a; ep->a = 0;
1080 foreach_notification_to_move;
1081#undef _
1082
Dave Barach65457162017-10-10 17:53:14 -04001083 request = name_to_labels (cname);
Dave Barachc6372eb2018-01-10 18:18:59 -05001084 name_copy = vec_dup (request);
Dave Barach65457162017-10-10 17:53:14 -04001085
1086 qp_offset = vec_len (request);
1087
1088 /* Add space for the query header */
Dave Barachc6372eb2018-01-10 18:18:59 -05001089 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
Dave Barach65457162017-10-10 17:53:14 -04001090
1091 qp = (dns_query_t *) (request + qp_offset);
1092
Dave Barachc6372eb2018-01-10 18:18:59 -05001093 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1094 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1095 clib_memcpy (qp, name_copy, vec_len (name_copy));
1096 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1097 vec_free (name_copy);
1098
1099 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
Dave Barach65457162017-10-10 17:53:14 -04001100 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1101
1102 /* Punch in space for the dns_header_t */
1103 vec_insert (request, sizeof (dns_header_t), 0);
1104
1105 h = (dns_header_t *) request;
1106
1107 /* Transaction ID = pool index */
Dave Barach0cb01bd2017-10-16 14:39:52 -04001108 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
Dave Barach65457162017-10-10 17:53:14 -04001109
1110 /* Ask for a recursive lookup */
1111 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
Dave Barachc6372eb2018-01-10 18:18:59 -05001112 h->qdcount = clib_host_to_net_u16 (2);
Dave Barach65457162017-10-10 17:53:14 -04001113 h->nscount = 0;
1114 h->arcount = 0;
1115
Dave Barach0cb01bd2017-10-16 14:39:52 -04001116 next_ep->dns_request = request;
1117 next_ep->retry_timer = now + 2.0;
1118 next_ep->retry_count = 0;
Dave Barach65457162017-10-10 17:53:14 -04001119
1120 /*
1121 * Enable this to watch recursive resolution happen...
1122 * fformat (stdout, "%U", format_dns_reply, request, 2);
1123 */
1124
Dave Barach0cb01bd2017-10-16 14:39:52 -04001125 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1126 vnet_send_dns_request (dm, next_ep);
Dave Barach65457162017-10-10 17:53:14 -04001127 return (1);
1128}
1129
1130int
1131vnet_dns_response_to_reply (u8 * response,
1132 vl_api_dns_resolve_name_reply_t * rmp,
1133 u32 * min_ttlp)
1134{
1135 dns_header_t *h;
1136 dns_query_t *qp;
1137 dns_rr_t *rr;
1138 int i, limit;
1139 u8 len;
Dave Barach52925382017-11-16 10:01:12 -05001140 u8 *curpos, *pos, *pos2;
Dave Barach65457162017-10-10 17:53:14 -04001141 u16 flags;
1142 u16 rcode;
1143 u32 ttl;
Dave Barach52925382017-11-16 10:01:12 -05001144 int pointer_chase;
Dave Barach65457162017-10-10 17:53:14 -04001145
1146 h = (dns_header_t *) response;
1147 flags = clib_net_to_host_u16 (h->flags);
1148 rcode = flags & DNS_RCODE_MASK;
1149
1150 /* See if the response is OK, etc. */
1151 switch (rcode)
1152 {
1153 default:
1154 case DNS_RCODE_NO_ERROR:
1155 break;
1156
1157 case DNS_RCODE_NAME_ERROR:
1158 case DNS_RCODE_FORMAT_ERROR:
1159 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1160
1161 case DNS_RCODE_SERVER_FAILURE:
1162 case DNS_RCODE_NOT_IMPLEMENTED:
1163 case DNS_RCODE_REFUSED:
1164 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1165 }
1166
1167 /* No answers? Loser... */
1168 if (clib_net_to_host_u16 (h->anscount) < 1)
1169 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1170
1171 curpos = (u8 *) (h + 1);
1172
1173 /* Skip the name we asked about */
1174 pos = curpos;
1175 len = *pos++;
1176 /* Should never happen, but stil... */
1177 if ((len & 0xC0) == 0xC0)
1178 curpos += 2;
1179 else
1180 {
1181 /* skip the name / label-set */
1182 while (len)
1183 {
1184 pos += len;
1185 len = *pos++;
1186 }
1187 curpos = pos;
1188 }
1189 /* Skip queries */
1190 limit = clib_net_to_host_u16 (h->qdcount);
1191 qp = (dns_query_t *) curpos;
1192 qp += limit;
1193 curpos = (u8 *) qp;
1194
1195 /* Parse answers */
1196 limit = clib_net_to_host_u16 (h->anscount);
1197
1198 for (i = 0; i < limit; i++)
1199 {
Dave Barach52925382017-11-16 10:01:12 -05001200 pos = pos2 = curpos;
1201 pointer_chase = 0;
Dave Barach65457162017-10-10 17:53:14 -04001202
1203 /* Expect pointer chases in the answer section... */
Dave Barach52925382017-11-16 10:01:12 -05001204 if ((pos2[0] & 0xC0) == 0xC0)
Dave Barach65457162017-10-10 17:53:14 -04001205 {
Dave Barach52925382017-11-16 10:01:12 -05001206 pos = pos2 + 2;
1207 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1208 pointer_chase = 1;
Dave Barach65457162017-10-10 17:53:14 -04001209 }
1210
Dave Barach52925382017-11-16 10:01:12 -05001211 len = *pos2++;
1212
1213 while (len)
1214 {
1215 pos2 += len;
1216 if ((pos2[0] & 0xc0) == 0xc0)
1217 {
1218 /*
1219 * If we've already done one pointer chase,
1220 * do not move the pos pointer.
1221 */
1222 if (pointer_chase == 0)
1223 pos = pos2 + 2;
1224 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1225 len = *pos2++;
1226 pointer_chase = 1;
1227 }
1228 else
1229 len = *pos2++;
1230 }
1231
1232 if (pointer_chase == 0)
1233 pos = pos2;
1234
1235 rr = (dns_rr_t *) pos;
Dave Barach65457162017-10-10 17:53:14 -04001236
1237 switch (clib_net_to_host_u16 (rr->type))
1238 {
1239 case DNS_TYPE_A:
1240 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1241 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1242 rmp->ip4_set = 1;
1243 ttl = clib_net_to_host_u32 (rr->ttl);
1244 if (min_ttlp && *min_ttlp > ttl)
1245 *min_ttlp = ttl;
1246 break;
1247 case DNS_TYPE_AAAA:
1248 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1249 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1250 ttl = clib_net_to_host_u32 (rr->ttl);
1251 if (min_ttlp && *min_ttlp > ttl)
1252 *min_ttlp = ttl;
1253 rmp->ip6_set = 1;
1254 break;
Dave Barach52925382017-11-16 10:01:12 -05001255
Dave Barach65457162017-10-10 17:53:14 -04001256 default:
1257 break;
1258 }
1259 /* Might as well stop ASAP */
1260 if (rmp->ip4_set && rmp->ip6_set)
1261 break;
Dave Barach52925382017-11-16 10:01:12 -05001262 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1263 curpos = pos;
Dave Barach65457162017-10-10 17:53:14 -04001264 }
1265
1266 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1267 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1268 return 0;
1269}
1270
Dave Barachd2080152017-10-20 09:21:35 -04001271int
1272vnet_dns_response_to_name (u8 * response,
1273 vl_api_dns_resolve_ip_reply_t * rmp,
1274 u32 * min_ttlp)
1275{
1276 dns_header_t *h;
1277 dns_query_t *qp;
1278 dns_rr_t *rr;
1279 int i, limit;
1280 u8 len;
Dave Barach52925382017-11-16 10:01:12 -05001281 u8 *curpos, *pos, *pos2;
Dave Barachd2080152017-10-20 09:21:35 -04001282 u16 flags;
1283 u16 rcode;
1284 u8 *name;
1285 u32 ttl;
1286 u8 *junk __attribute__ ((unused));
1287 int name_set = 0;
Dave Barach52925382017-11-16 10:01:12 -05001288 int pointer_chase;
Dave Barachd2080152017-10-20 09:21:35 -04001289
1290 h = (dns_header_t *) response;
1291 flags = clib_net_to_host_u16 (h->flags);
1292 rcode = flags & DNS_RCODE_MASK;
1293
1294 /* See if the response is OK, etc. */
1295 switch (rcode)
1296 {
1297 default:
1298 case DNS_RCODE_NO_ERROR:
1299 break;
1300
1301 case DNS_RCODE_NAME_ERROR:
1302 case DNS_RCODE_FORMAT_ERROR:
1303 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1304
1305 case DNS_RCODE_SERVER_FAILURE:
1306 case DNS_RCODE_NOT_IMPLEMENTED:
1307 case DNS_RCODE_REFUSED:
1308 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1309 }
1310
1311 /* No answers? Loser... */
1312 if (clib_net_to_host_u16 (h->anscount) < 1)
1313 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1314
1315 curpos = (u8 *) (h + 1);
1316
1317 /* Skip the name we asked about */
1318 pos = curpos;
1319 len = *pos++;
1320 /* Should never happen, but stil... */
1321 if ((len & 0xC0) == 0xC0)
1322 curpos += 2;
1323 else
1324 {
1325 /* skip the name / label-set */
1326 while (len)
1327 {
1328 pos += len;
1329 len = *pos++;
1330 }
1331 curpos = pos;
1332 }
1333 /* Skip queries */
1334 limit = clib_net_to_host_u16 (h->qdcount);
1335 qp = (dns_query_t *) curpos;
1336 qp += limit;
1337 curpos = (u8 *) qp;
1338
1339 /* Parse answers */
1340 limit = clib_net_to_host_u16 (h->anscount);
1341
1342 for (i = 0; i < limit; i++)
1343 {
Dave Barach52925382017-11-16 10:01:12 -05001344 pos = pos2 = curpos;
1345 pointer_chase = 0;
Dave Barachd2080152017-10-20 09:21:35 -04001346
1347 /* Expect pointer chases in the answer section... */
Dave Barach52925382017-11-16 10:01:12 -05001348 if ((pos2[0] & 0xC0) == 0xC0)
Dave Barachd2080152017-10-20 09:21:35 -04001349 {
Dave Barach52925382017-11-16 10:01:12 -05001350 pos = pos2 + 2;
1351 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1352 pointer_chase = 1;
Dave Barachd2080152017-10-20 09:21:35 -04001353 }
1354
Dave Barach52925382017-11-16 10:01:12 -05001355 len = *pos2++;
1356
1357 while (len)
1358 {
1359 pos2 += len;
1360 if ((pos2[0] & 0xc0) == 0xc0)
1361 {
1362 /*
1363 * If we've already done one pointer chase,
1364 * do not move the pos pointer.
1365 */
1366 if (pointer_chase == 0)
1367 pos = pos2 + 2;
1368 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1369 len = *pos2++;
1370 pointer_chase = 1;
1371 }
1372 else
1373 len = *pos2++;
1374 }
1375
1376 if (pointer_chase == 0)
1377 pos = pos2;
1378
1379 rr = (dns_rr_t *) pos;
Dave Barachd2080152017-10-20 09:21:35 -04001380
1381 switch (clib_net_to_host_u16 (rr->type))
1382 {
1383 case DNS_TYPE_PTR:
Dave Barach97494502017-11-04 09:44:38 -04001384 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
Dave Barachd2080152017-10-20 09:21:35 -04001385 memcpy (rmp->name, name, vec_len (name));
1386 ttl = clib_net_to_host_u32 (rr->ttl);
Dave Barach52925382017-11-16 10:01:12 -05001387 if (min_ttlp)
Dave Barachd2080152017-10-20 09:21:35 -04001388 *min_ttlp = ttl;
1389 rmp->name[vec_len (name)] = 0;
1390 name_set = 1;
1391 break;
1392 default:
1393 break;
1394 }
1395 /* Might as well stop ASAP */
1396 if (name_set == 1)
1397 break;
Dave Barach52925382017-11-16 10:01:12 -05001398 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1399 curpos = pos;
Dave Barachd2080152017-10-20 09:21:35 -04001400 }
1401
1402 if (name_set == 0)
1403 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1404 return 0;
1405}
1406
Dave Barach65457162017-10-10 17:53:14 -04001407static void
1408vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1409{
1410 dns_main_t *dm = &dns_main;
1411 vl_api_dns_resolve_name_reply_t *rmp;
1412 dns_cache_entry_t *ep;
Dave Barach97494502017-11-04 09:44:38 -04001413 dns_pending_request_t _t0, *t0 = &_t0;
Dave Barach65457162017-10-10 17:53:14 -04001414 int rv;
1415
1416 /* Sanitize the name slightly */
1417 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1418
Dave Barach97494502017-11-04 09:44:38 -04001419 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1420 t0->client_index = mp->client_index;
1421 t0->client_context = mp->context;
1422
1423 rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
Dave Barach65457162017-10-10 17:53:14 -04001424
1425 /* Error, e.g. not enabled? Tell the user */
1426 if (rv < 0)
1427 {
1428 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1429 return;
1430 }
1431
1432 /* Resolution pending? Don't reply... */
1433 if (ep == 0)
1434 return;
1435
1436 /* *INDENT-OFF* */
1437 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1438 ({
1439 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1440 rmp->retval = clib_host_to_net_u32 (rv);
1441 }));
1442 /* *INDENT-ON* */
1443
1444 /*
1445 * dns_resolve_name leaves the cache locked when it returns
1446 * a cached result, so unlock it here.
1447 */
1448 dns_cache_unlock (dm);
1449}
1450
Dave Barachd2080152017-10-20 09:21:35 -04001451static void
1452vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1453{
1454 dns_main_t *dm = &dns_main;
1455 vl_api_dns_resolve_ip_reply_t *rmp;
1456 dns_cache_entry_t *ep;
1457 int rv;
1458 int i, len;
1459 u8 *lookup_name = 0;
1460 u8 digit, nybble;
Dave Barach97494502017-11-04 09:44:38 -04001461 dns_pending_request_t _t0, *t0 = &_t0;
Dave Barachd2080152017-10-20 09:21:35 -04001462
1463 if (mp->is_ip6)
1464 {
1465 for (i = 15; i >= 0; i--)
1466 {
1467 digit = mp->address[i];
1468 nybble = (digit & 0x0F);
1469 if (nybble > 9)
1470 vec_add1 (lookup_name, (nybble - 10) + 'a');
1471 else
1472 vec_add1 (lookup_name, nybble + '0');
1473 vec_add1 (lookup_name, '.');
1474 nybble = (digit & 0xF0) >> 4;
1475 if (nybble > 9)
1476 vec_add1 (lookup_name, (nybble - 10) + 'a');
1477 else
1478 vec_add1 (lookup_name, nybble + '0');
1479 vec_add1 (lookup_name, '.');
1480 }
1481 len = vec_len (lookup_name);
1482 vec_validate (lookup_name, len + 8);
1483 memcpy (lookup_name + len, "ip6.arpa", 8);
1484 }
1485 else
1486 {
1487 for (i = 3; i >= 0; i--)
1488 {
1489 digit = mp->address[i];
1490 lookup_name = format (lookup_name, "%d.", digit);
1491 }
1492 lookup_name = format (lookup_name, "in-addr.arpa");
1493 }
1494
1495 vec_add1 (lookup_name, 0);
1496
Dave Barach97494502017-11-04 09:44:38 -04001497 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1498 t0->client_index = mp->client_index;
1499 t0->client_context = mp->context;
1500
1501 rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
Dave Barachd2080152017-10-20 09:21:35 -04001502
1503 vec_free (lookup_name);
1504
1505 /* Error, e.g. not enabled? Tell the user */
1506 if (rv < 0)
1507 {
1508 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1509 return;
1510 }
1511
1512 /* Resolution pending? Don't reply... */
1513 if (ep == 0)
1514 return;
1515
1516 /* *INDENT-OFF* */
1517 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1518 ({
1519 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1520 rmp->retval = clib_host_to_net_u32 (rv);
1521 }));
1522 /* *INDENT-ON* */
1523
1524 /*
Dave Barach97494502017-11-04 09:44:38 -04001525 * vnet_dns_resolve_name leaves the cache locked when it returns
Dave Barachd2080152017-10-20 09:21:35 -04001526 * a cached result, so unlock it here.
1527 */
1528 dns_cache_unlock (dm);
1529}
1530
Dave Barach65457162017-10-10 17:53:14 -04001531#define vl_msg_name_crc_list
1532#include <vpp/api/vpe_all_api_h.h>
1533#undef vl_msg_name_crc_list
1534
1535static void
1536setup_message_id_table (api_main_t * am)
1537{
1538#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1539 foreach_vl_msg_name_crc_dns;
1540#undef _
1541}
1542
1543#define foreach_dns_api_msg \
1544_(DNS_ENABLE_DISABLE, dns_enable_disable) \
1545_(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
Dave Barachd2080152017-10-20 09:21:35 -04001546_(DNS_RESOLVE_NAME, dns_resolve_name) \
1547_(DNS_RESOLVE_IP, dns_resolve_ip)
Dave Barach65457162017-10-10 17:53:14 -04001548
1549static clib_error_t *
1550dns_api_hookup (vlib_main_t * vm)
1551{
1552#define _(N,n) \
1553 vl_msg_api_set_handlers(VL_API_##N, #n, \
1554 vl_api_##n##_t_handler, \
1555 vl_noop_handler, \
1556 vl_api_##n##_t_endian, \
1557 vl_api_##n##_t_print, \
1558 sizeof(vl_api_##n##_t), 1);
1559 foreach_dns_api_msg;
1560#undef _
1561
1562 setup_message_id_table (&api_main);
1563 return 0;
1564}
1565
1566VLIB_API_INIT_FUNCTION (dns_api_hookup);
1567
1568
1569static clib_error_t *
1570dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1571{
1572 dns_main_t *dm = &dns_main;
1573
1574 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1575 {
1576 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1577 ;
1578 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1579 ;
1580 else
1581 return clib_error_return (0, "unknown input `%U'",
1582 format_unformat_error, input);
1583 }
1584 return 0;
1585}
1586
1587VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1588
1589static clib_error_t *
1590dns_init (vlib_main_t * vm)
1591{
1592 dns_main_t *dm = &dns_main;
1593
1594 dm->vlib_main = vm;
1595 dm->vnet_main = vnet_get_main ();
1596 dm->name_cache_size = 65535;
1597 dm->max_ttl_in_seconds = 86400;
1598 dm->random_seed = 0xDEADDABE;
1599
1600 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply, dns46_reply_node.index,
1601 1 /* is_ip4 */ );
1602
1603 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6, dns46_reply_node.index,
1604 0 /* is_ip4 */ );
1605
Dave Barach65457162017-10-10 17:53:14 -04001606 udp_register_dst_port (vm, UDP_DST_PORT_dns, dns4_request_node.index,
1607 1 /* is_ip4 */ );
Dave Barach97494502017-11-04 09:44:38 -04001608
Dave Barach65457162017-10-10 17:53:14 -04001609 udp_register_dst_port (vm, UDP_DST_PORT_dns6, dns6_request_node.index,
1610 0 /* is_ip4 */ );
Dave Barach65457162017-10-10 17:53:14 -04001611 return 0;
1612}
1613
1614VLIB_INIT_FUNCTION (dns_init);
1615
1616uword
1617unformat_dns_reply (unformat_input_t * input, va_list * args)
1618{
1619 u8 **result = va_arg (*args, u8 **);
1620 u8 **namep = va_arg (*args, u8 **);
1621 ip4_address_t a4;
1622 ip6_address_t a6;
1623 int a4_set = 0;
1624 int a6_set = 0;
1625 u8 *name;
1626 int name_set = 0;
1627 u8 *ce;
1628 u32 qp_offset;
1629 dns_header_t *h;
1630 dns_query_t *qp;
1631 dns_rr_t *rr;
1632 u8 *rru8;
1633
1634 if (unformat (input, "%v", &name))
1635 name_set = 1;
1636
1637 if (unformat (input, "%U", unformat_ip4_address, &a4))
1638 {
1639 a4_set = 1;
1640 if (unformat (input, "%U", unformat_ip6_address, &a6))
1641 a6_set = 1;
1642 }
1643
1644 if (unformat (input, "%U", unformat_ip6_address, &a6))
1645 {
1646 a6_set = 1;
1647 if (unformat (input, "%U", unformat_ip4_address, &a6))
1648 a4_set = 1;
1649 }
1650
1651 /* Must have a name */
1652 if (!name_set)
1653 return 0;
1654
1655 /* Must have at least one address */
1656 if (!(a4_set + a6_set))
1657 return 0;
1658
1659 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1660 ce = name_to_labels (name);
1661 qp_offset = vec_len (ce);
1662
1663 /* Add space for the query header */
1664 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1665 qp = (dns_query_t *) (ce + qp_offset);
1666
1667 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1668 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1669
1670 /* Punch in space for the dns_header_t */
1671 vec_insert (ce, sizeof (dns_header_t), 0);
1672
1673 h = (dns_header_t *) ce;
1674
1675 /* Fake Transaction ID */
1676 h->id = 0xFFFF;
1677
1678 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1679 h->qdcount = clib_host_to_net_u16 (1);
1680 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1681 h->nscount = 0;
1682 h->arcount = 0;
1683
1684 /* Now append one or two A/AAAA RR's... */
1685 if (a4_set)
1686 {
1687 /* Pointer to the name (DGMS) */
1688 vec_add1 (ce, 0xC0);
1689 vec_add1 (ce, 0x0C);
1690 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1691 rr = (void *) rru8;
1692 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1693 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1694 rr->ttl = clib_host_to_net_u32 (86400);
1695 rr->rdlength = clib_host_to_net_u16 (4);
1696 memcpy (rr->rdata, &a4, sizeof (a4));
1697 }
1698 if (a6_set)
1699 {
1700 /* Pointer to the name (DGMS) */
1701 vec_add1 (ce, 0xC0);
1702 vec_add1 (ce, 0x0C);
1703 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1704 rr = (void *) rru8;
1705 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1706 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1707 rr->ttl = clib_host_to_net_u32 (86400);
1708 rr->rdlength = clib_host_to_net_u16 (16);
1709 memcpy (rr->rdata, &a6, sizeof (a6));
1710 }
1711 *result = ce;
1712 if (namep)
1713 *namep = name;
1714 else
1715 vec_free (name);
1716
1717 return 1;
1718}
1719
1720u8 *
1721format_dns_query (u8 * s, va_list * args)
1722{
1723 u8 **curpos = va_arg (*args, u8 **);
1724 int verbose = va_arg (*args, int);
1725 u8 *pos;
1726 dns_query_t *qp;
1727 int len, i;
1728 if (verbose > 1)
1729 s = format (s, " Name: ");
1730
1731 /* Unwind execrated counted-label sheit */
1732 pos = *curpos;
1733 len = *pos++;
1734
1735 while (len)
1736 {
1737 for (i = 0; i < len; i++)
1738 vec_add1 (s, *pos++);
1739
1740 len = *pos++;
1741 if (len)
1742 vec_add1 (s, '.');
1743 else
1744 {
1745 vec_add1 (s, ':');
1746 vec_add1 (s, ' ');
1747 }
1748 }
1749
1750 qp = (dns_query_t *) pos;
1751 if (verbose > 1)
1752 {
1753 switch (clib_net_to_host_u16 (qp->type))
1754 {
1755 case DNS_TYPE_A:
1756 s = format (s, "type A\n");
1757 break;
1758 case DNS_TYPE_AAAA:
1759 s = format (s, "type AAAA\n");
1760 break;
1761 case DNS_TYPE_ALL:
1762 s = format (s, "type ALL\n");
1763 break;
1764
1765 default:
1766 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1767 break;
1768 }
1769 }
1770
1771 pos += sizeof (*qp);
1772
1773 *curpos = pos;
1774 return s;
1775}
1776
1777/**
1778 * format dns reply data
1779 * verbose > 1, dump everything
1780 * verbose == 1, dump all A and AAAA records
1781 * verbose == 0, dump one A record, and one AAAA record
1782 */
1783
1784u8 *
1785format_dns_reply_data (u8 * s, va_list * args)
1786{
1787 u8 *reply = va_arg (*args, u8 *);
1788 u8 **curpos = va_arg (*args, u8 **);
1789 int verbose = va_arg (*args, int);
1790 int *print_ip4 = va_arg (*args, int *);
1791 int *print_ip6 = va_arg (*args, int *);
1792 int len;
1793 u8 *pos, *pos2;
1794 dns_rr_t *rr;
1795 int i;
Dave Barach52925382017-11-16 10:01:12 -05001796 int pointer_chase = 0;
Dave Barach65457162017-10-10 17:53:14 -04001797 u16 *tp;
Dave Barachd2080152017-10-20 09:21:35 -04001798 u16 rrtype_host_byte_order;
Dave Barach65457162017-10-10 17:53:14 -04001799
1800 pos = pos2 = *curpos;
1801
1802 if (verbose > 1)
1803 s = format (s, " ");
1804
1805 /* chase pointer? almost always yes here... */
Dave Barach52925382017-11-16 10:01:12 -05001806 if ((pos2[0] & 0xc0) == 0xc0)
Dave Barach65457162017-10-10 17:53:14 -04001807 {
Dave Barach52925382017-11-16 10:01:12 -05001808 pos = pos2 + 2;
1809 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1810 pointer_chase = 1;
Dave Barach65457162017-10-10 17:53:14 -04001811 }
1812
1813 len = *pos2++;
1814
1815 while (len)
1816 {
1817 for (i = 0; i < len; i++)
1818 {
1819 if (verbose > 1)
1820 vec_add1 (s, *pos2);
1821 pos2++;
1822 }
Dave Barach52925382017-11-16 10:01:12 -05001823 if ((pos2[0] & 0xc0) == 0xc0)
1824 {
1825 /*
1826 * If we've already done one pointer chase,
1827 * do not move the pos pointer.
1828 */
1829 if (pointer_chase == 0)
1830 pos = pos2 + 2;
1831 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1832 len = *pos2++;
1833 pointer_chase = 1;
1834 }
1835 else
1836 len = *pos2++;
Dave Barach65457162017-10-10 17:53:14 -04001837 if (len)
1838 {
1839 if (verbose > 1)
1840 vec_add1 (s, '.');
1841 }
1842 else
1843 {
1844 if (verbose > 1)
1845 vec_add1 (s, ' ');
1846 }
1847 }
1848
Dave Barach52925382017-11-16 10:01:12 -05001849 if (pointer_chase == 0)
Dave Barach65457162017-10-10 17:53:14 -04001850 pos = pos2;
1851
1852 rr = (dns_rr_t *) pos;
Dave Barachd2080152017-10-20 09:21:35 -04001853 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
Dave Barach65457162017-10-10 17:53:14 -04001854
Dave Barachd2080152017-10-20 09:21:35 -04001855 switch (rrtype_host_byte_order)
Dave Barach65457162017-10-10 17:53:14 -04001856 {
1857 case DNS_TYPE_A:
1858 if (verbose > 1)
1859 {
1860 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1861 format_ip4_address, rr->rdata);
1862 }
1863 else
1864 {
1865 if (*print_ip4)
1866 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1867 clib_net_to_host_u32 (rr->ttl));
1868 if (verbose == 0)
1869 *print_ip4 = 0;
1870
1871 }
1872 pos += sizeof (*rr) + 4;
1873 break;
1874
1875 case DNS_TYPE_AAAA:
1876 if (verbose > 1)
1877 {
1878 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1879 format_ip6_address, rr->rdata);
1880 }
1881 else
1882 {
1883 if (*print_ip6)
1884 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1885 clib_net_to_host_u32 (rr->ttl));
1886 if (verbose == 0)
1887 *print_ip6 = 0;
1888 }
1889 pos += sizeof (*rr) + 16;
1890 break;
1891
1892 case DNS_TYPE_TEXT:
1893 if (verbose > 1)
1894 {
1895 s = format (s, "TEXT: ");
1896 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1897 vec_add1 (s, rr->rdata[i]);
1898 vec_add1 (s, '\n');
1899 }
1900 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1901 break;
1902
Dave Barach0cb01bd2017-10-16 14:39:52 -04001903 case DNS_TYPE_HINFO:
1904 {
1905 /* Two counted strings. DGMS */
1906 u8 *len;
1907 u8 *curpos;
1908 int i;
1909 if (verbose > 1)
1910 {
1911 s = format (s, "HINFO: ");
1912 len = rr->rdata;
1913 curpos = len + 1;
1914 for (i = 0; i < *len; i++)
1915 vec_add1 (s, *curpos++);
1916
1917 vec_add1 (s, ' ');
1918 len = curpos++;
1919 for (i = 0; i < *len; i++)
1920 vec_add1 (s, *curpos++);
1921
1922 vec_add1 (s, '\n');
1923 }
1924 }
1925 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1926 break;
1927
Dave Barach65457162017-10-10 17:53:14 -04001928 case DNS_TYPE_NAMESERVER:
1929 if (verbose > 1)
1930 {
1931 s = format (s, "Nameserver: ");
1932 pos2 = rr->rdata;
1933
1934 /* chase pointer? */
Dave Barach52925382017-11-16 10:01:12 -05001935 if ((pos2[0] & 0xc0) == 0xc0)
1936 {
1937 pos = pos2 + 2;
1938 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1939 }
Dave Barach65457162017-10-10 17:53:14 -04001940
1941 len = *pos2++;
1942
1943 while (len)
1944 {
1945 for (i = 0; i < len; i++)
1946 vec_add1 (s, *pos2++);
1947
1948 /* chase pointer, typically to offset 12... */
1949 if (pos2[0] == 0xC0)
1950 pos2 = reply + pos2[1];
1951
1952 len = *pos2++;
1953 if (len)
1954 vec_add1 (s, '.');
1955 else
1956 vec_add1 (s, '\n');
1957 }
1958 }
1959 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1960 break;
1961
1962 case DNS_TYPE_MAIL_EXCHANGE:
1963 if (verbose > 1)
1964 {
1965 tp = (u16 *) rr->rdata;
1966
1967 s = format (s, "Mail Exchange: Preference %d ", (u32)
1968 clib_net_to_host_u16 (*tp));
1969
1970 pos2 = rr->rdata + 2;
1971
1972 /* chase pointer? */
1973 if (pos2[0] == 0xc0)
1974 pos2 = reply + pos2[1];
1975
1976 len = *pos2++;
1977
1978 while (len)
1979 {
1980 for (i = 0; i < len; i++)
1981 vec_add1 (s, *pos2++);
1982
1983 /* chase pointer */
1984 if (pos2[0] == 0xC0)
1985 pos2 = reply + pos2[1];
1986
1987 len = *pos2++;
1988 if (len)
1989 vec_add1 (s, '.');
1990 else
1991 vec_add1 (s, '\n');
1992 }
1993 }
1994
1995 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1996 break;
1997
Dave Barachd2080152017-10-20 09:21:35 -04001998 case DNS_TYPE_PTR:
Dave Barach65457162017-10-10 17:53:14 -04001999 case DNS_TYPE_CNAME:
2000 if (verbose > 1)
2001 {
2002 tp = (u16 *) rr->rdata;
2003
Dave Barachd2080152017-10-20 09:21:35 -04002004 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
2005 s = format (s, "CNAME: ");
2006 else
2007 s = format (s, "PTR: ");
Dave Barach65457162017-10-10 17:53:14 -04002008
2009 pos2 = rr->rdata;
2010
2011 /* chase pointer? */
2012 if (pos2[0] == 0xc0)
2013 pos2 = reply + pos2[1];
2014
2015 len = *pos2++;
2016
2017 while (len)
2018 {
2019 for (i = 0; i < len; i++)
2020 vec_add1 (s, *pos2++);
2021
2022 /* chase pointer */
2023 if (pos2[0] == 0xC0)
2024 pos2 = reply + pos2[1];
2025
2026 len = *pos2++;
2027 if (len)
2028 vec_add1 (s, '.');
2029 else
2030 vec_add1 (s, '\n');
2031 }
2032 }
2033 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2034 break;
2035
2036 default:
2037 if (verbose > 1)
2038 s = format (s, "type %d: len %d\n",
2039 (int) clib_net_to_host_u16 (rr->type),
2040 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
2041 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2042 break;
2043 }
2044
2045 *curpos = pos;
2046
2047 return s;
2048}
2049
2050u8 *
2051format_dns_reply (u8 * s, va_list * args)
2052{
2053 u8 *reply_as_u8 = va_arg (*args, u8 *);
2054 int verbose = va_arg (*args, int);
2055 dns_header_t *h;
2056 u16 id, flags;
2057 u8 *curpos;
2058 int i;
2059 int print_ip4 = 1;
2060 int print_ip6 = 1;
2061
2062 h = (dns_header_t *) reply_as_u8;
2063 id = clib_net_to_host_u16 (h->id);
2064 flags = clib_net_to_host_u16 (h->flags);
2065
2066 if (verbose > 1)
2067 {
2068 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2069 id);
2070 s = format (s, " %s %s %s %s\n",
2071 (flags & DNS_RA) ? "recur" : "no-recur",
2072 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2073 (flags & DNS_TC) ? "trunc" : "no-trunc",
2074 (flags & DNS_AA) ? "auth" : "non-auth");
2075 s = format (s, " %d queries, %d answers, %d name-servers,"
2076 " %d add'l recs\n",
2077 clib_net_to_host_u16 (h->qdcount),
2078 clib_net_to_host_u16 (h->anscount),
2079 clib_net_to_host_u16 (h->nscount),
2080 clib_net_to_host_u16 (h->arcount));
2081 }
2082
2083 curpos = (u8 *) (h + 1);
2084
2085 if (h->qdcount)
2086 {
2087 if (verbose > 1)
2088 s = format (s, " Queries:\n");
2089 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2090 {
2091 /* The query is variable-length, so curpos is a value-result parm */
2092 s = format (s, "%U", format_dns_query, &curpos, verbose);
2093 }
2094 }
2095 if (h->anscount)
2096 {
2097 if (verbose > 1)
2098 s = format (s, " Replies:\n");
2099
2100 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2101 {
2102 /* curpos is a value-result parm */
2103 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2104 verbose, &print_ip4, &print_ip6);
2105 }
2106 }
2107 return s;
2108}
2109
2110u8 *
2111format_dns_cache (u8 * s, va_list * args)
2112{
2113 dns_main_t *dm = va_arg (*args, dns_main_t *);
2114 f64 now = va_arg (*args, f64);
2115 int verbose = va_arg (*args, int);
2116 u8 *name = va_arg (*args, u8 *);
2117 dns_cache_entry_t *ep;
2118 char *ss;
2119 uword *p;
2120
2121 if (dm->is_enabled == 0)
2122 {
2123 s = format (s, "The DNS cache is disabled...");
2124 return s;
2125 }
2126
2127 if (pool_elts (dm->entries) == 0)
2128 {
2129 s = format (s, "The DNS cache is empty...");
2130 return s;
2131 }
2132
2133 dns_cache_lock (dm);
2134
2135 if (name)
2136 {
2137 p = hash_get_mem (dm->cache_entry_by_name, name);
2138 if (!p)
2139 {
2140 s = format (s, "%s is not in the cache...", name);
2141 dns_cache_unlock (dm);
2142 return (s);
2143 }
2144
2145 ep = pool_elt_at_index (dm->entries, p[0]);
2146 /* Magic to spit out a C-initializer to research hemorrhoids... */
2147 if (verbose == 3)
2148 {
2149 int i, j;
2150 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2151 s = format (s, "{\n");
2152 j = 0;
2153 for (i = 0; i < vec_len (ep->dns_response); i++)
2154 {
2155 if (j++ == 8)
2156 {
2157 j = 0;
2158 vec_add1 (s, '\n');
2159 }
2160 s = format (s, "0x%02x, ", ep->dns_response[i]);
2161 }
2162 s = format (s, "};\n");
2163 }
2164 else
2165 {
2166 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2167 {
2168 ASSERT (ep->dns_response);
2169 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2170 ss = "[S] ";
2171 else
2172 ss = " ";
2173
Dave Barach0cb01bd2017-10-16 14:39:52 -04002174 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2175 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2176 else
2177 s = format (s, "%s%s -> %U", ss, ep->name,
2178 format_dns_reply, ep->dns_response, verbose);
Dave Barach65457162017-10-10 17:53:14 -04002179 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2180 {
2181 f64 time_left = ep->expiration_time - now;
2182 if (time_left > 0.0)
2183 s = format (s, " TTL left %.1f", time_left);
2184 else
2185 s = format (s, " EXPIRED");
2186 }
2187 }
2188 else
2189 {
2190 ASSERT (ep->dns_request);
2191 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2192 verbose);
2193 }
2194 vec_add1 (s, '\n');
2195 }
2196 return s;
2197 }
2198
2199 /* *INDENT-OFF* */
2200 pool_foreach (ep, dm->entries,
2201 ({
2202 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2203 {
2204 ASSERT (ep->dns_response);
2205 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2206 ss = "[S] ";
2207 else
2208 ss = " ";
2209
Dave Barach0cb01bd2017-10-16 14:39:52 -04002210 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2211 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2212 else
2213 s = format (s, "%s%s -> %U", ss, ep->name,
2214 format_dns_reply,
2215 ep->dns_response,
2216 verbose);
Dave Barach65457162017-10-10 17:53:14 -04002217 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2218 {
2219 f64 time_left = ep->expiration_time - now;
2220 if (time_left > 0.0)
2221 s = format (s, " TTL left %.1f", time_left);
2222 else
2223 s = format (s, " EXPIRED");
Dave Barach0cb01bd2017-10-16 14:39:52 -04002224
2225 if (verbose > 2)
2226 s = format (s, " %d client notifications pending\n",
Dave Barach97494502017-11-04 09:44:38 -04002227 vec_len(ep->pending_requests));
Dave Barach65457162017-10-10 17:53:14 -04002228 }
2229 }
2230 else
2231 {
2232 ASSERT (ep->dns_request);
2233 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2234 verbose);
2235 }
2236 vec_add1 (s, '\n');
2237 }));
2238 /* *INDENT-ON* */
2239
2240 dns_cache_unlock (dm);
2241
2242 return s;
2243}
2244
2245static clib_error_t *
2246show_dns_cache_command_fn (vlib_main_t * vm,
2247 unformat_input_t * input, vlib_cli_command_t * cmd)
2248{
2249 dns_main_t *dm = &dns_main;
2250 int verbose = 0;
2251 u8 *name = 0;
2252 f64 now = vlib_time_now (vm);
2253
2254 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2255 {
2256 if (unformat (input, "verbose %d", &verbose))
2257 ;
2258 else if (unformat (input, "verbose"))
2259 verbose = 1;
2260 else if (unformat (input, "name %s", &name))
2261 ;
2262 else
2263 return clib_error_return (0, "unknown input `%U'",
2264 format_unformat_error, input);
2265 }
2266
2267 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2268
2269 return 0;
2270}
2271
2272/* *INDENT-OFF* */
2273VLIB_CLI_COMMAND (show_dns_cache_command) =
2274{
2275 .path = "show dns cache",
2276 .short_help = "show dns cache [verbose [nn]]",
2277 .function = show_dns_cache_command_fn,
2278};
2279/* *INDENT-ON* */
2280
2281static clib_error_t *
2282dns_cache_add_del_command_fn (vlib_main_t * vm,
2283 unformat_input_t * input,
2284 vlib_cli_command_t * cmd)
2285{
2286 dns_main_t *dm = &dns_main;
2287 u8 *dns_reply_data;
2288 u8 *name;
2289 int is_add = -1;
2290 int is_clear = -1;
2291 int rv;
2292 clib_error_t *error;
2293
2294 if (unformat (input, "add"))
2295 is_add = 1;
2296 if (unformat (input, "del"))
2297 is_add = 0;
2298 if (unformat (input, "clear"))
2299 is_clear = 1;
2300
2301 if (is_add == -1 && is_clear == -1)
2302 return clib_error_return (0, "add / del / clear required...");
2303
2304 if (is_clear == 1)
2305 {
2306 rv = dns_cache_clear (dm);
2307 switch (rv)
2308 {
2309 case 0:
2310 return 0;
2311
2312 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2313 error = clib_error_return (0, "Name resolution not enabled");
2314 return error;
2315 }
2316 }
2317
2318 /* Delete (by name)? */
2319 if (is_add == 0)
2320 {
2321 if (unformat (input, "%v", &name))
2322 {
2323 rv = dns_delete_by_name (dm, name);
2324 switch (rv)
2325 {
2326 case VNET_API_ERROR_NO_SUCH_ENTRY:
2327 error = clib_error_return (0, "%v not in the cache...", name);
2328 vec_free (name);
2329 return error;
2330
2331 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2332 error = clib_error_return (0, "Name resolution not enabled");
2333 vec_free (name);
2334 return error;
2335
2336 case 0:
2337 vec_free (name);
2338 return 0;
2339
2340 default:
2341 error = clib_error_return (0, "dns_delete_by_name returned %d",
2342 rv);
2343 vec_free (name);
2344 return error;
2345 }
2346 }
2347 return clib_error_return (0, "unknown input `%U'",
2348 format_unformat_error, input);
2349 }
2350
2351 /* Note: dns_add_static_entry consumes the name vector if OK... */
2352 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2353 {
2354 rv = dns_add_static_entry (dm, name, dns_reply_data);
2355 switch (rv)
2356 {
2357 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2358 vec_free (name);
2359 vec_free (dns_reply_data);
2360 return clib_error_return (0, "%v already in the cache...", name);
2361 case 0:
2362 return 0;
2363
2364 default:
2365 return clib_error_return (0, "dns_add_static_entry returned %d",
2366 rv);
2367 }
2368 }
2369
2370 return 0;
2371}
2372
2373/* *INDENT-OFF* */
2374VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2375{
2376 .path = "dns cache",
2377 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2378 .function = dns_cache_add_del_command_fn,
2379};
2380/* *INDENT-ON* */
2381
Dave Barach580eda72018-01-09 17:00:00 -05002382#define DNS_FORMAT_TEST 1
Dave Barach65457162017-10-10 17:53:14 -04002383
2384#if DNS_FORMAT_TEST > 0
2385#if 0
2386/* yahoo.com */
2387static u8 dns_reply_data_initializer[] =
2388 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2389 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2390 0x0, /* null lbl */
2391 0x0, 0xff, /* type ALL */
2392 0x0, 0x1, /* class IN */
2393 0xc0, 0xc, /* pointer to yahoo.com name */
2394 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2395 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2396 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2397 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2398 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2399 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2400 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2401 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2402 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2403 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2404 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2405 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2406 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2407 0x6e,
2408 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2409 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2410 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2411 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2412 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2413 0x0,
2414 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2415 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2416 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2417 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2418 0x0,
2419 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2420 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2421 0x0,
2422 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2423 0x0,
2424 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2425 0x0,
2426 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2427 0x6f,
2428 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2429 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2430 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2431 0x2, 0x58
2432};
2433
2434/* www.cisco.com, has no addresses in reply */
2435static u8 dns_reply_data_initializer[] = {
2436 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2437 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2438 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2439
2440 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2441 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2442 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2443 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2444 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2445};
Dave Barach52925382017-11-16 10:01:12 -05002446
2447/* bind8 (linux widget, w/ nasty double pointer chasees */
2448static u8 dns_reply_data_initializer[] = {
2449 /* 0 */
2450 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2451 /* 8 */
2452 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2453 /* 16 */
2454 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2455 /* 24 */
2456 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2457 /* 32 */
2458 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2459 /* 40 */
2460 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2461 /* 48 */
2462 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2463
2464 /* 56 */
2465 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2466
2467 /* 64 */
2468 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2469 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2470 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2471 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2472 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2473 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2474 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2475 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2476 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2477 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2478 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2479 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2480 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2481 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2482 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2483 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2484 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2485 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2486 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2487 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2488 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2489 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2490 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2491 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2492 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2493 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2494 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2495 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2496 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2497 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2498 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2499 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2500 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2501 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2502 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2503 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2504 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2505 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2506 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2507 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2508 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2509 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2510 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2511 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2512 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2513 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2514 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2515 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2516};
2517
Dave Barach65457162017-10-10 17:53:14 -04002518/* google.com */
2519static u8 dns_reply_data_initializer[] =
2520 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2521 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2522 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2523 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2524 0x2b,
2525 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2526 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2527 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2528 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2529 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2530 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2531 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2532 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2533 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2534 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2535 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2536 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2537 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2538 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2539 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2540 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2541 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2542 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2543 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2544 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2545 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2546 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2547 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2548 0x57,
2549 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2550};
Dave Barach580eda72018-01-09 17:00:00 -05002551
2552#else
2553/* www.weatherlink.com */
2554static u8 dns_reply_data_initializer[] = {
2555 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2556 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2557 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2558 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2559 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2560 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2561 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2562 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2563 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2564};
2565
Dave Barach65457162017-10-10 17:53:14 -04002566#endif
2567
2568static clib_error_t *
2569test_dns_fmt_command_fn (vlib_main_t * vm,
2570 unformat_input_t * input, vlib_cli_command_t * cmd)
2571{
2572 u8 *dns_reply_data = 0;
2573 int verbose = 0;
2574 int rv;
2575 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2576
2577 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2578 {
2579 if (unformat (input, "verbose %d", &verbose))
2580 ;
2581 else if (unformat (input, "verbose"))
2582 verbose = 1;
2583 else
2584 return clib_error_return (0, "unknown input `%U'",
2585 format_unformat_error, input);
2586 }
2587
2588 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2589
2590 memcpy (dns_reply_data, dns_reply_data_initializer,
2591 ARRAY_LEN (dns_reply_data_initializer));
2592
2593 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2594
2595 memset (rmp, 0, sizeof (*rmp));
2596
2597 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2598
2599 switch (rv)
2600 {
2601 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2602 vlib_cli_output (vm, "no addresses found...");
2603 break;
2604
2605 default:
2606 vlib_cli_output (vm, "response to reply returned %d", rv);
2607 break;
2608
2609 case 0:
2610 if (rmp->ip4_set)
2611 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2612 (ip4_address_t *) rmp->ip4_address);
2613 if (rmp->ip6_set)
2614 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2615 (ip6_address_t *) rmp->ip6_address);
2616 break;
2617 }
2618
2619 vec_free (dns_reply_data);
2620
2621 return 0;
2622}
2623
2624
2625/* *INDENT-OFF* */
2626VLIB_CLI_COMMAND (test_dns_fmt_command) =
2627{
2628 .path = "test dns format",
2629 .short_help = "test dns format",
2630 .function = test_dns_fmt_command_fn,
2631};
2632/* *INDENT-ON* */
2633
2634static clib_error_t *
2635test_dns_unfmt_command_fn (vlib_main_t * vm,
2636 unformat_input_t * input, vlib_cli_command_t * cmd)
2637{
2638 u8 *dns_reply_data = 0;
2639 int verbose = 0;
2640 int reply_set = 0;
2641
2642 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2643 {
2644 if (unformat (input, "verbose %d", &verbose))
2645 ;
2646 else if (unformat (input, "verbose"))
2647 verbose = 1;
2648 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2649 reply_set = 1;
2650 else
2651 return clib_error_return (0, "unknown input `%U'",
2652 format_unformat_error, input);
2653 }
2654
2655 if (reply_set == 0)
2656 return clib_error_return (0, "dns data not set...");
2657
2658 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2659
2660 vec_free (dns_reply_data);
2661
2662 return 0;
2663}
2664
2665/* *INDENT-OFF* */
2666VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2667{
2668 .path = "test dns unformat",
2669 .short_help = "test dns unformat <name> [ip4][ip6]",
2670 .function = test_dns_unfmt_command_fn,
2671};
2672/* *INDENT-ON* */
Dave Barach0cb01bd2017-10-16 14:39:52 -04002673
2674static clib_error_t *
2675test_dns_expire_command_fn (vlib_main_t * vm,
2676 unformat_input_t * input,
2677 vlib_cli_command_t * cmd)
2678{
2679 dns_main_t *dm = &dns_main;
2680 u8 *name;
2681 uword *p;
2682 clib_error_t *e;
2683 dns_cache_entry_t *ep;
2684
2685 if (unformat (input, "%v", &name))
2686 {
2687 vec_add1 (name, 0);
2688 _vec_len (name) -= 1;
2689 }
2690
2691 dns_cache_lock (dm);
2692
2693 p = hash_get_mem (dm->cache_entry_by_name, name);
2694 if (!p)
2695 {
2696 dns_cache_unlock (dm);
2697 e = clib_error_return (0, "%s is not in the cache...", name);
2698 vec_free (name);
2699 return e;
2700 }
2701
2702 ep = pool_elt_at_index (dm->entries, p[0]);
2703
2704 ep->expiration_time = 0;
2705
2706 return 0;
2707}
2708
2709/* *INDENT-OFF* */
2710VLIB_CLI_COMMAND (test_dns_expire_command) =
2711{
2712 .path = "test dns expire",
2713 .short_help = "test dns expire <name>",
2714 .function = test_dns_expire_command_fn,
2715};
2716/* *INDENT-ON* */
Dave Barach65457162017-10-10 17:53:14 -04002717#endif
2718
Dave Barach97494502017-11-04 09:44:38 -04002719void
2720vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
2721 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2722{
2723 clib_warning ("Unimplemented...");
2724}
2725
2726
2727void
2728vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
2729 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2730{
2731 vlib_main_t *vm = dm->vlib_main;
Damjan Marionc8a26c62017-11-24 20:15:23 +01002732 u32 bi = 0;
Dave Barach97494502017-11-04 09:44:38 -04002733 fib_prefix_t prefix;
2734 fib_node_index_t fei;
2735 u32 sw_if_index, fib_index;
2736 ip4_main_t *im4 = &ip4_main;
2737 ip_lookup_main_t *lm4 = &im4->lookup_main;
2738 ip_interface_address_t *ia = 0;
2739 ip4_address_t *src_address;
2740 ip4_header_t *ip;
2741 udp_header_t *udp;
2742 dns_header_t *dh;
2743 vlib_frame_t *f;
2744 u32 *to_next;
2745 u8 *dns_response;
2746 u8 *reply;
2747 vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2748 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2749 u32 ttl, tmp;
2750 u32 qp_offset;
2751 dns_query_t *qp;
2752 dns_rr_t *rr;
2753 u8 *rrptr;
2754 int is_fail = 0;
2755
2756 ASSERT (ep && ep->dns_response);
2757
2758 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2759 {
2760 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2761 memset (rnr, 0, sizeof (*rnr));
2762 if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2763 {
2764 /* clib_warning ("response_to_reply failed..."); */
2765 is_fail = 1;
2766 }
2767 if (rnr->ip4_set == 0)
2768 {
2769 /* clib_warning ("No A-record..."); */
2770 is_fail = 1;
2771 }
2772 }
2773 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2774 {
2775 memset (rir, 0, sizeof (*rir));
2776 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2777 {
2778 /* clib_warning ("response_to_name failed..."); */
2779 is_fail = 1;
2780 }
2781 }
2782 else
2783 {
2784 clib_warning ("Unknown request type %d", pr->request_type);
2785 return;
2786 }
2787
2788 /* Initialize a buffer */
2789 if (b0 == 0)
2790 {
2791 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2792 return;
2793 b0 = vlib_get_buffer (vm, bi);
2794 }
2795
2796 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2797 vlib_buffer_free_one (vm, b0->next_buffer);
2798
2799 /*
2800 * Reset the buffer. We recycle the DNS request packet in the cache
2801 * hit case, and reply immediately from the request node.
2802 *
2803 * In the resolution-required / deferred case, resetting a freshly-allocated
2804 * buffer won't hurt. We hope.
2805 */
2806 b0->flags &= VLIB_BUFFER_FREE_LIST_INDEX_MASK;
2807 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2808 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2809 b0->current_data = 0;
2810 b0->current_length = 0;
2811 b0->total_length_not_including_first_buffer = 0;
2812 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2813 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2814
2815 /* Find a FIB path to the peer we're trying to answer */
2816 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2817 prefix.fp_proto = FIB_PROTOCOL_IP4;
2818 prefix.fp_len = 32;
2819
2820 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2821 if (fib_index == (u32) ~ 0)
2822 {
2823 clib_warning ("no fib table");
2824 return;
2825 }
2826
2827 fei = fib_table_lookup (fib_index, &prefix);
2828
2829 /* Couldn't find route to destination. Bail out. */
2830 if (fei == FIB_NODE_INDEX_INVALID)
2831 {
2832 clib_warning ("no route to DNS server");
2833 return;
2834 }
2835
2836 sw_if_index = fib_entry_get_resolving_interface (fei);
2837
2838 if (sw_if_index == ~0)
2839 {
2840 clib_warning
2841 ("route to %U exists, fei %d, get_resolving_interface returned"
2842 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2843 return;
2844 }
2845
2846 /* *INDENT-OFF* */
2847 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnummbered */,
2848 ({
2849 src_address = ip_interface_address_get_address (lm4, ia);
2850 goto found_src_address;
2851 }));
2852 /* *INDENT-ON* */
2853
2854 clib_warning ("FIB BUG");
2855 return;
2856
2857found_src_address:
2858
2859 ip = vlib_buffer_get_current (b0);
2860 udp = (udp_header_t *) (ip + 1);
2861 dns_response = (u8 *) (udp + 1);
2862 memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2863
2864 /*
2865 * Start with the variadic portion of the exercise.
2866 * Turn the name into a set of DNS "labels". Max length
2867 * per label is 63, enforce that.
2868 */
2869 reply = name_to_labels (pr->name);
2870 vec_free (pr->name);
2871
2872 qp_offset = vec_len (reply);
2873
2874 /* Add space for the query header */
2875 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2876
2877 qp = (dns_query_t *) (reply + qp_offset);
2878
2879 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2880 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2881 else
2882 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2883
2884 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2885
2886 /* Punch in space for the dns_header_t */
2887 vec_insert (reply, sizeof (dns_header_t), 0);
2888
2889 dh = (dns_header_t *) reply;
2890
2891 /* Transaction ID = pool index */
2892 dh->id = pr->id;
2893
2894 /* Announce that we did a recursive lookup */
2895 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2896 if (is_fail)
2897 tmp |= DNS_RCODE_NAME_ERROR;
2898 dh->flags = clib_host_to_net_u16 (tmp);
2899 dh->qdcount = clib_host_to_net_u16 (1);
2900 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2901 dh->nscount = 0;
2902 dh->arcount = 0;
2903
2904 /* If the name resolution worked, cough up an appropriate RR */
2905 if (is_fail == 0)
2906 {
2907 /* Add the answer. First, a name pointer (0xC00C) */
2908 vec_add1 (reply, 0xC0);
2909 vec_add1 (reply, 0x0C);
2910
2911 /* Now, add single A-rec RR */
2912 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2913 {
2914 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2915 rr = (dns_rr_t *) rrptr;
2916
2917 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2918 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2919 rr->ttl = clib_host_to_net_u32 (ttl);
2920 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2921 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2922 }
2923 else
2924 {
2925 /* Or a single PTR RR */
2926 u8 *vecname = format (0, "%s", rir->name);
2927 u8 *label_vec = name_to_labels (vecname);
2928 vec_free (vecname);
2929
2930 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2931 rr = (dns_rr_t *) rrptr;
2932 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2933 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2934 rr->ttl = clib_host_to_net_u32 (ttl);
2935 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2936 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2937 vec_free (label_vec);
2938 }
2939 }
2940 clib_memcpy (dns_response, reply, vec_len (reply));
2941
2942 /* Set the packet length */
2943 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2944
2945 /* IP header */
2946 ip->ip_version_and_header_length = 0x45;
2947 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2948 ip->ttl = 255;
2949 ip->protocol = IP_PROTOCOL_UDP;
2950 ip->src_address.as_u32 = src_address->as_u32;
2951 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2952 sizeof (ip4_address_t));
2953 ip->checksum = ip4_header_checksum (ip);
2954
2955 /* UDP header */
2956 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2957 udp->dst_port = pr->dst_port;
2958 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2959 vec_len (reply));
2960 udp->checksum = 0;
2961 vec_free (reply);
2962
2963 /* Ship it to ip4_lookup */
2964 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2965 to_next = vlib_frame_vector_args (f);
2966 to_next[0] = bi;
2967 f->n_vectors = 1;
2968 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2969}
2970
Dave Barach65457162017-10-10 17:53:14 -04002971/*
2972 * fd.io coding-style-patch-verification: ON
2973 *
2974 * Local Variables:
2975 * eval: (c-set-style "gnu")
2976 * End:
2977 */