FD.io VPP  v20.05.1-6-gf53edbc3b
Vector Packet Processing
resolver_process.c
Go to the documentation of this file.
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 <dns/dns.h>
17 #include <vlibapi/api.h>
18 #include <vlibmemory/api.h>
19 
20 #include <vlib/vlib.h>
21 #include <vnet/vnet.h>
22 
23 /* define message IDs */
24 #include <dns/dns.api_enum.h>
25 #include <dns/dns.api_types.h>
26 
28 
29 int
30 vnet_dns_response_to_reply (u8 * response,
32  u32 * min_ttlp);
33 int
34 vnet_dns_response_to_name (u8 * response,
36  u32 * min_ttlp);
37 
38 static void
39 resolve_event (dns_main_t * dm, f64 now, u8 * reply)
40 {
41  vlib_main_t *vm = dm->vlib_main;
43  dns_header_t *d;
44  u32 pool_index;
46  u32 min_ttl;
47  u16 flags;
48  u16 rcode;
49  int i;
50  int entry_was_valid;
51  int remove_count;
52  int rv = 0;
53 
54  d = (dns_header_t *) reply;
55  flags = clib_net_to_host_u16 (d->flags);
56  rcode = flags & DNS_RCODE_MASK;
57 
58  /* $$$ u16 limits cache to 65K entries, fix later multiple dst ports */
59  pool_index = clib_net_to_host_u16 (d->id);
60  dns_cache_lock (dm, 10);
61 
62  if (pool_is_free_index (dm->entries, pool_index))
63  {
64  vec_free (reply);
65  if (0)
66  clib_warning ("pool index %d is free", pool_index);
68  DNS46_REPLY_ERROR_NO_ELT, 1);
69  dns_cache_unlock (dm);
70  return;
71  }
72 
73  ep = pool_elt_at_index (dm->entries, pool_index);
74 
75  if (ep->dns_response)
76  vec_free (ep->dns_response);
77 
78  /* Handle [sic] recursion AKA CNAME indirection */
79  rv = vnet_dns_cname_indirection_nolock (dm, pool_index, reply);
80 
81  /* CNAME found, further resolution pending, we're done here */
82  if (rv > 0)
83  {
84  dns_cache_unlock (dm);
85  return;
86  }
87  /* Server backfire: refused to answer, or sent zero replies */
88  if (rv < 0)
89  {
90  /* Try a different server */
91  if (ep->server_af /* ip6 */ )
92  {
93  if (0)
94  clib_warning ("Server %U failed to resolve '%s'",
96  dm->ip6_name_servers + ep->server_rotor, ep->name);
97  /* Any more servers to try? */
98  if (ep->server_fails > 1 || vec_len (dm->ip6_name_servers) <= 1)
99  {
100  /* No, tell the client to go away */
101  goto reply;
102  }
103  ep->retry_count = 0;
104  ep->server_rotor++;
105  ep->server_fails++;
106  if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
107  ep->server_rotor = 0;
108  if (0)
109  clib_warning ("Try server %U", format_ip6_address,
110  dm->ip6_name_servers + ep->server_rotor);
112  (dm, ep, dm->ip6_name_servers + ep->server_rotor);
113  }
114  else
115  {
116  if (0)
117  clib_warning ("Server %U failed to resolve '%s'",
119  dm->ip4_name_servers + ep->server_rotor, ep->name);
120 
121  if (ep->server_fails > 1 || vec_len (dm->ip4_name_servers) <= 1)
122  {
123  /* No, tell the client to go away */
124  goto reply;
125  }
126  ep->retry_count = 0;
127  ep->server_rotor++;
128  ep->server_fails++;
129  if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
130  ep->server_rotor = 0;
131  if (0)
132  clib_warning ("Try server %U", format_ip4_address,
133  dm->ip4_name_servers + ep->server_rotor);
135  (dm, ep, dm->ip4_name_servers + ep->server_rotor);
136  }
137  dns_cache_unlock (dm);
138  return;
139  }
140 
141 reply:
142  /* Save the response */
143  ep->dns_response = reply;
144 
145  /*
146  * Pick a sensible default cache entry expiration time.
147  * We don't play the 10-second timeout game.
148  */
149  ep->expiration_time = now + 600.0;
150 
151  if (0)
152  clib_warning ("resolving '%s', was %s valid",
153  ep->name, (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID) ?
154  "already" : "not");
155  /*
156  * The world is a mess. A single DNS request sent to e.g. 8.8.8.8
157  * may yield multiple, subtly different responses - all with the same
158  * DNS protocol-level ID.
159  *
160  * Last response wins in terms of what ends up in the cache.
161  * First response wins in terms of the response sent to the client.
162  */
163 
164  /* Strong hint that we may not find a pending resolution entry */
165  entry_was_valid = (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID) ? 1 : 0;
166 
167  if (vec_len (ep->dns_response))
169 
170  /* Most likely, send 1 message */
171  for (i = 0; i < vec_len (ep->pending_requests); i++)
172  {
173  vl_api_registration_t *regp;
174 
175  pr = vec_elt_at_index (ep->pending_requests, i);
176 
177  switch (pr->request_type)
178  {
180  {
183  if (regp == 0)
184  continue;
185 
186  rmp = vl_msg_api_alloc (sizeof (*rmp));
187  rmp->_vl_msg_id =
188  clib_host_to_net_u16 (VL_API_DNS_RESOLVE_NAME_REPLY
189  + dm->msg_id_base);
190  rmp->context = pr->client_context;
191  min_ttl = ~0;
192  rv = vnet_dns_response_to_reply (ep->dns_response, rmp, &min_ttl);
193  if (min_ttl != ~0)
194  ep->expiration_time = now + min_ttl;
195  rmp->retval = clib_host_to_net_u32 (rv);
196  vl_api_send_msg (regp, (u8 *) rmp);
197  }
198  break;
199 
201  {
203 
205  if (regp == 0)
206  continue;
207 
208  rmp = vl_msg_api_alloc (sizeof (*rmp));
209  rmp->_vl_msg_id =
210  clib_host_to_net_u16 (VL_API_DNS_RESOLVE_IP_REPLY
211  + dm->msg_id_base);
212  rmp->context = pr->client_context;
213  min_ttl = ~0;
214  rv = vnet_dns_response_to_name (ep->dns_response, rmp, &min_ttl);
215  if (min_ttl != ~0)
216  ep->expiration_time = now + min_ttl;
217  rmp->retval = clib_host_to_net_u32 (rv);
218  vl_api_send_msg (regp, (u8 *) rmp);
219  }
220  break;
221 
224  if (pr->is_ip6)
225  vnet_send_dns6_reply (dm, pr, ep, 0 /* allocate a buffer */ );
226  else
227  vnet_send_dns4_reply (dm, pr, ep, 0 /* allocate a buffer */ );
228  break;
229  default:
230  clib_warning ("request type %d unknown", pr->request_type);
231  break;
232  }
233  }
235 
236  remove_count = 0;
237  for (i = 0; i < vec_len (dm->unresolved_entries); i++)
238  {
239  if (dm->unresolved_entries[i] == pool_index)
240  {
241  vec_delete (dm->unresolved_entries, 1, i);
242  remove_count++;
243  i--;
244  }
245  }
246  /* See multiple response comment above... */
247  if (remove_count == 0)
248  {
249  u32 error_code = entry_was_valid ? DNS46_REPLY_ERROR_MULTIPLE_REPLY :
250  DNS46_REPLY_ERROR_NO_UNRESOLVED_ENTRY;
251 
252  vlib_node_increment_counter (vm, dns46_reply_node.index, error_code, 1);
253  dns_cache_unlock (dm);
254  return;
255  }
256 
257  /* Deal with bogus names, server issues, etc. */
258  switch (rcode)
259  {
260  default:
261  case DNS_RCODE_NO_ERROR:
262  break;
263 
266  case DNS_RCODE_REFUSED:
267  if (ep->server_af == 0)
268  clib_warning ("name server %U can't resolve '%s'",
270  dm->ip4_name_servers + ep->server_rotor, ep->name);
271  else
272  clib_warning ("name server %U can't resolve '%s'",
274  dm->ip6_name_servers + ep->server_rotor, ep->name);
275  /* FALLTHROUGH */
278  /* remove trash from the cache... */
280  break;
281  }
282 
283 
284  dns_cache_unlock (dm);
285  return;
286 }
287 
288 static void
290 {
291  int i;
292  dns_cache_entry_t *ep;
293 
294  for (i = 0; i < vec_len (dm->unresolved_entries); i++)
295  {
296  dns_cache_lock (dm, 11);
297  ep = pool_elt_at_index (dm->entries, dm->unresolved_entries[i]);
298 
299  ASSERT ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID) == 0);
300  vnet_send_dns_request (dm, ep);
301  dns_cache_unlock (dm);
302  }
303 }
304 
305 static uword
308 {
309  dns_main_t *dm = &dns_main;
310  f64 now;
311  f64 timeout = 1000.0;
312  uword *event_data = 0;
313  uword event_type;
314  int i;
315 
316  while (1)
317  {
319 
320  now = vlib_time_now (vm);
321 
322  event_type = vlib_process_get_events (vm, (uword **) & event_data);
323 
324  switch (event_type)
325  {
326  /* Send one of these when a resolution is pending */
328  timeout = 2.0;
329  break;
330 
332  for (i = 0; i < vec_len (event_data); i++)
333  resolve_event (dm, now, (u8 *) event_data[i]);
334  break;
335 
336  case ~0: /* timeout */
337  retry_scan (dm, now);
338  break;
339  }
340  vec_reset_length (event_data);
341 
342  /* No work? Back to slow timeout mode... */
343  if (vec_len (dm->unresolved_entries) == 0)
344  timeout = 1000.0;
345  }
346  return 0; /* or not */
347 }
348 
349 void
351 {
352  /* Already created the resolver process? */
353  if (dm->resolver_process_node_index > 0)
354  return;
355 
356  /* No, create it now and make a note of the node index */
358  (dm->vlib_main, "dns-resolver-process",
359  dns_resolver_process, 16 /* log2_n_stack_bytes */ );
360 }
361 
362 /*
363  * fd.io coding-style-patch-verification: ON
364  *
365  * Local Variables:
366  * eval: (c-set-style "gnu")
367  * End:
368  */
Definition: dns.h:50
ip6_address_t * ip6_name_servers
Definition: dns.h:112
static f64 vlib_process_wait_for_event_or_clock(vlib_main_t *vm, f64 dt)
Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds...
Definition: node_funcs.h:673
#define DNS_CACHE_ENTRY_FLAG_VALID
we have Actual Data
Definition: dns.h:81
vlib_node_registration_t dns46_reply_node
(constructor) VLIB_REGISTER_NODE (dns46_reply_node)
Definition: reply_node.c:42
int vnet_dns_cname_indirection_nolock(dns_main_t *dm, u32 ep_index, u8 *reply)
Handle cname indirection.
Definition: dns.c:967
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:291
#define DNS_RCODE_REFUSED
Definition: dns_packet.h:40
static void vl_api_send_msg(vl_api_registration_t *rp, u8 *elem)
Definition: api.h:35
#define DNS_RCODE_NO_ERROR
Definition: dns_packet.h:35
u8 * dns_response
Cached dns response.
Definition: dns.h:75
int vnet_dns_delete_entry_by_index_nolock(dns_main_t *dm, u32 index)
Definition: dns.c:663
int retry_count
Retry parameters.
Definition: dns.h:68
for(i=1;i<=collision_buckets;i++)
static void retry_scan(dns_main_t *dm, f64 now)
static void resolve_event(dns_main_t *dm, f64 now, u8 *reply)
u32 client_context
Definition: dns.h:33
void * vl_msg_api_alloc(int nbytes)
void vnet_dns_create_resolver_process(dns_main_t *dm)
#define DNS_RCODE_NOT_IMPLEMENTED
Definition: dns_packet.h:39
unsigned char u8
Definition: types.h:56
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
double f64
Definition: types.h:142
vlib_main_t * vlib_main
Definition: dns.h:126
format_function_t format_ip4_address
Definition: format.h:73
dns_main_t dns_main
Definition: dns.c:42
void vnet_send_dns_request(dns_main_t *dm, dns_cache_entry_t *ep)
Definition: dns.c:539
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type...
Definition: node_funcs.h:516
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
u32 * unresolved_entries
Pool indices of unresolved entries.
Definition: dns.h:97
#define DNS_RCODE_MASK
Definition: dns_packet.h:34
unsigned int u32
Definition: types.h:88
void vnet_send_dns4_reply(dns_main_t *dm, dns_pending_request_t *pr, dns_cache_entry_t *ep, vlib_buffer_t *b0)
Definition: dns.c:2739
u32 resolver_process_node_index
resolver process node index
Definition: dns.h:115
dns_pending_request_t * pending_requests
Clients / peers awaiting responses.
Definition: dns.h:78
ip4_address_t * ip4_name_servers
upstream name servers, e.g.
Definition: dns.h:111
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:534
u8 * name
The name in "normal human being" notation, e.g.
Definition: dns.h:56
#define DNS_RCODE_SERVER_FAILURE
Definition: dns_packet.h:37
unsigned short u16
Definition: types.h:57
u32 vlib_process_create(vlib_main_t *vm, char *name, vlib_node_function_t *f, u32 log2_n_stack_bytes)
Create a vlib process.
Definition: node.c:769
DNS ip->name resolution reply.
Definition: dns.api:102
vlib_main_t * vm
Definition: in2out_ed.c:1599
int server_rotor
Definition: dns.h:69
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1150
An API client registration, only in vpp/vlib.
Definition: api_common.h:47
u32 flags
Definition: vhost_user.h:248
format_function_t format_ip6_address
Definition: format.h:91
static void dns_cache_unlock(dns_main_t *dm)
Definition: dns.h:214
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:380
int vnet_dns_response_to_name(u8 *response, vl_api_dns_resolve_ip_reply_t *rmp, u32 *min_ttlp)
Definition: dns.c:1303
#define clib_warning(format, args...)
Definition: error.h:59
u16 msg_id_base
message-ID base
Definition: dns.h:123
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:299
static vl_api_registration_t * vl_api_client_index_to_registration(u32 index)
Definition: api.h:57
#define ASSERT(truth)
volatile u8 flags
flags
Definition: dns.h:53
#define DNS_RCODE_FORMAT_ERROR
Definition: dns_packet.h:36
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:852
#define DNS_RESOLVER_EVENT_RESOLVED
Definition: dns.h:87
static void dns_cache_lock(dns_main_t *dm, int tag)
Definition: dns.h:202
static uword dns_resolver_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
#define DNS_RCODE_NAME_ERROR
Definition: dns_packet.h:38
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
void vnet_send_dns6_reply(dns_main_t *dm, dns_pending_request_t *pr, dns_cache_entry_t *ep, vlib_buffer_t *b0)
Definition: dns.c:2731
void vnet_dns_send_dns6_request(dns_main_t *dm, dns_cache_entry_t *ep, ip6_address_t *server)
Definition: dns.c:340
u64 uword
Definition: types.h:112
Definition: dns.h:91
int server_fails
Definition: dns.h:71
int vnet_dns_response_to_reply(u8 *response, vl_api_dns_resolve_name_reply_t *rmp, u32 *min_ttlp)
Definition: dns.c:1162
void vnet_dns_send_dns4_request(dns_main_t *dm, dns_cache_entry_t *ep, ip4_address_t *server)
Definition: dns.c:221
int server_af
Definition: dns.h:70
f64 expiration_time
Expiration time.
Definition: dns.h:62
DNS name resolution reply.
Definition: dns.api:71
#define DNS_RESOLVER_EVENT_PENDING
Definition: dns.h:88
dns_cache_entry_t * entries
Pool of cache entries.
Definition: dns.h:94