5603371db52459a30945af6cb039b73a241fca8a
[vpp.git] / src / vnet / dns / resolver_process.c
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/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 #include <vnet/vnet_msg_enum.h>
24
25 #define vl_typedefs             /* define message structures */
26 #include <vnet/vnet_all_api_h.h>
27 #undef vl_typedefs
28
29 #define vl_endianfun            /* define message structures */
30 #include <vnet/vnet_all_api_h.h>
31 #undef vl_endianfun
32
33 /* instantiate all the print functions we know about */
34 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
35 #define vl_printfun
36 #include <vnet/vnet_all_api_h.h>
37 #undef vl_printfun
38
39 #include <vlibapi/api_helper_macros.h>
40
41 vlib_node_registration_t dns_resolver_node;
42
43 extern int
44 vnet_dns_response_to_reply (u8 * response,
45                             vl_api_dns_resolve_name_reply_t * rmp,
46                             u32 * min_ttlp);
47
48 static void
49 resolve_event (dns_main_t * dm, f64 now, u8 * reply)
50 {
51   vlib_main_t *vm = dm->vlib_main;
52   dns_header_t *d;
53   u32 pool_index;
54   dns_cache_entry_t *ep;
55   u32 min_ttl;
56   u16 flags;
57   u16 rcode;
58   int i;
59   int rv = 0;
60
61   d = (dns_header_t *) reply;
62   flags = clib_net_to_host_u16 (d->flags);
63   rcode = flags & DNS_RCODE_MASK;
64
65   /* $$$ u16 limits cache to 65K entries, fix later multiple dst ports */
66   pool_index = clib_net_to_host_u16 (d->id);
67   dns_cache_lock (dm);
68
69   if (pool_is_free_index (dm->entries, pool_index))
70     {
71       vec_free (reply);
72       vlib_node_increment_counter (vm, dns46_reply_node.index,
73                                    DNS46_REPLY_ERROR_NO_ELT, 1);
74       dns_cache_unlock (dm);
75       return;
76     }
77
78   ep = pool_elt_at_index (dm->entries, pool_index);
79
80   if (ep->dns_response)
81     vec_free (ep->dns_response);
82
83   /* Handle [sic] recursion AKA CNAME indirection */
84   if (vnet_dns_cname_indirection_nolock (dm, pool_index, reply))
85     {
86       dns_cache_unlock (dm);
87       return;
88     }
89
90   /* Save the response */
91   ep->dns_response = reply;
92   /* Pick some sensible default. */
93   ep->expiration_time = now + 600.0;
94   if (vec_len (ep->dns_response))
95     ep->flags |= DNS_CACHE_ENTRY_FLAG_VALID;
96
97   /* Most likely, send 1 message */
98   for (i = 0; i < vec_len (ep->api_clients_to_notify); i++)
99     {
100       vl_api_registration_t *regp;
101       vl_api_dns_resolve_name_reply_t *rmp;
102
103       regp = vl_api_client_index_to_registration
104         (ep->api_clients_to_notify[i]);
105
106       if (regp == 0)
107         continue;
108
109       rmp = vl_msg_api_alloc (sizeof (*rmp) + vec_len (ep->dns_response));
110       rmp->_vl_msg_id = clib_host_to_net_u16 (VL_API_DNS_RESOLVE_NAME_REPLY);
111       rmp->context = ep->api_client_contexts[i];
112       min_ttl = ~0;
113       rv = vnet_dns_response_to_reply (ep->dns_response, rmp, &min_ttl);
114       if (min_ttl != ~0)
115         ep->expiration_time = now + min_ttl;
116       rmp->retval = clib_host_to_net_u32 (rv);
117       vl_msg_api_send (regp, (u8 *) rmp);
118     }
119   vec_free (ep->api_clients_to_notify);
120   vec_free (ep->api_client_contexts);
121
122   /* $$$ Add ip4/ip6 reply code */
123   vec_free (ep->ip4_peers_to_notify);
124   vec_free (ep->ip6_peers_to_notify);
125
126   for (i = 0; i < vec_len (dm->unresolved_entries); i++)
127     {
128       if (dm->unresolved_entries[i] == pool_index)
129         {
130           vec_delete (dm->unresolved_entries, 1, i);
131           goto found;
132         }
133     }
134   clib_warning ("pool index %d AWOL from unresolved vector", pool_index);
135
136 found:
137   /* Deal with bogus names, server issues, etc. */
138   switch (rcode)
139     {
140     default:
141     case DNS_RCODE_NO_ERROR:
142       break;
143
144     case DNS_RCODE_SERVER_FAILURE:
145     case DNS_RCODE_NOT_IMPLEMENTED:
146     case DNS_RCODE_REFUSED:
147       if (ep->server_af == 0)
148         clib_warning ("name server %U backfire",
149                       format_ip4_address,
150                       dm->ip4_name_servers + ep->server_rotor);
151       else
152         clib_warning ("name server %U backfire",
153                       format_ip6_address,
154                       dm->ip6_name_servers + ep->server_rotor);
155       /* FALLTHROUGH */
156     case DNS_RCODE_NAME_ERROR:
157     case DNS_RCODE_FORMAT_ERROR:
158       /* remove trash from the cache... */
159       vnet_dns_delete_entry_by_index_nolock (dm, ep - dm->entries);
160       break;
161     }
162
163   dns_cache_unlock (dm);
164   return;
165 }
166
167 static void
168 retry_scan (dns_main_t * dm, f64 now)
169 {
170   int i;
171   dns_cache_entry_t *ep;
172
173   for (i = 0; i < vec_len (dm->unresolved_entries); i++)
174     {
175       dns_cache_lock (dm);
176       ep = pool_elt_at_index (dm->entries, dm->unresolved_entries[i]);
177
178       ASSERT ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID) == 0);
179       vnet_send_dns_request (dm, ep);
180       dns_cache_unlock (dm);
181     }
182 }
183
184 static uword
185 dns_resolver_process (vlib_main_t * vm,
186                       vlib_node_runtime_t * rt, vlib_frame_t * f)
187 {
188   dns_main_t *dm = &dns_main;
189   f64 now;
190   f64 timeout = 1000.0;
191   uword *event_data = 0;
192   uword event_type;
193   int i;
194
195   while (1)
196     {
197       vlib_process_wait_for_event_or_clock (vm, timeout);
198
199       now = vlib_time_now (vm);
200
201       event_type = vlib_process_get_events (vm, (uword **) & event_data);
202
203       switch (event_type)
204         {
205           /* Send one of these when a resolution is pending */
206         case DNS_RESOLVER_EVENT_PENDING:
207           timeout = 2.0;
208           break;
209
210         case DNS_RESOLVER_EVENT_RESOLVED:
211           for (i = 0; i < vec_len (event_data); i++)
212             resolve_event (dm, now, (u8 *) event_data[i]);
213           break;
214
215         case ~0:                /* timeout */
216           retry_scan (dm, now);
217           break;
218         }
219       vec_reset_length (event_data);
220
221       /* No work? Back to slow timeout mode... */
222       if (vec_len (dm->unresolved_entries) == 0)
223         timeout = 1000.0;
224     }
225   return 0;                     /* or not */
226 }
227
228 /* *INDENT-OFF* */
229 VLIB_REGISTER_NODE (dns_resolver_node) =
230 {
231   .function = dns_resolver_process,
232   .type = VLIB_NODE_TYPE_PROCESS,
233   .name = "dns-resolver-process",
234 };
235 /* *INDENT-ON* */
236
237
238 /*
239  * fd.io coding-style-patch-verification: ON
240  *
241  * Local Variables:
242  * eval: (c-set-style "gnu")
243  * End:
244  */