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