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