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