]> git.proxmox.com Git - mirror_frr.git/blame - lib/resolver.c
Merge pull request #9977 from ton31337/fix/documentation_for_rpki_from_packages
[mirror_frr.git] / lib / resolver.c
CommitLineData
2fb975da
TT
1/* C-Ares integration to Quagga mainloop
2 * Copyright (c) 2014-2015 Timo Teräs
3 *
4 * This file is free software: you may copy, redistribute and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
b45ac5f5
DL
10#ifdef HAVE_CONFIG_H
11#include "config.h"
12#endif
13
2fb975da
TT
14#include <ares.h>
15#include <ares_version.h>
16
17#include "vector.h"
18#include "thread.h"
aed07011 19#include "lib_errors.h"
fe9e7b71
DL
20#include "resolver.h"
21#include "command.h"
b2fa8c0f
DL
22#include "xref.h"
23
80413c20 24XREF_SETUP();
2fb975da
TT
25
26struct resolver_state {
27 ares_channel channel;
fe9e7b71 28 struct thread_master *master;
2fb975da
TT
29 struct thread *timeout;
30 vector read_threads, write_threads;
31};
32
33static struct resolver_state state;
fe9e7b71 34static bool resolver_debug;
2fb975da
TT
35
36#define THREAD_RUNNING ((struct thread *)-1)
37
38static void resolver_update_timeouts(struct resolver_state *r);
39
40static int resolver_cb_timeout(struct thread *t)
41{
42 struct resolver_state *r = THREAD_ARG(t);
43
44 r->timeout = THREAD_RUNNING;
45 ares_process(r->channel, NULL, NULL);
46 r->timeout = NULL;
47 resolver_update_timeouts(r);
48
49 return 0;
50}
51
52static int resolver_cb_socket_readable(struct thread *t)
53{
54 struct resolver_state *r = THREAD_ARG(t);
55 int fd = THREAD_FD(t);
72618ba8 56 struct thread **t_ptr;
2fb975da
TT
57
58 vector_set_index(r->read_threads, fd, THREAD_RUNNING);
59 ares_process_fd(r->channel, fd, ARES_SOCKET_BAD);
60 if (vector_lookup(r->read_threads, fd) == THREAD_RUNNING) {
72618ba8 61 t_ptr = (struct thread **)vector_get_index(r->read_threads, fd);
fe9e7b71 62 thread_add_read(r->master, resolver_cb_socket_readable, r, fd,
72618ba8 63 t_ptr);
2fb975da
TT
64 }
65 resolver_update_timeouts(r);
66
67 return 0;
68}
69
70static int resolver_cb_socket_writable(struct thread *t)
71{
72 struct resolver_state *r = THREAD_ARG(t);
73 int fd = THREAD_FD(t);
72618ba8 74 struct thread **t_ptr;
2fb975da
TT
75
76 vector_set_index(r->write_threads, fd, THREAD_RUNNING);
77 ares_process_fd(r->channel, ARES_SOCKET_BAD, fd);
78 if (vector_lookup(r->write_threads, fd) == THREAD_RUNNING) {
72618ba8 79 t_ptr = (struct thread **)vector_get_index(r->write_threads, fd);
fe9e7b71 80 thread_add_write(r->master, resolver_cb_socket_writable, r, fd,
72618ba8 81 t_ptr);
2fb975da
TT
82 }
83 resolver_update_timeouts(r);
84
85 return 0;
86}
87
88static void resolver_update_timeouts(struct resolver_state *r)
89{
90 struct timeval *tv, tvbuf;
91
996c9314
LB
92 if (r->timeout == THREAD_RUNNING)
93 return;
2fb975da
TT
94
95 THREAD_OFF(r->timeout);
96 tv = ares_timeout(r->channel, NULL, &tvbuf);
97 if (tv) {
98 unsigned int timeoutms = tv->tv_sec * 1000 + tv->tv_usec / 1000;
fe9e7b71
DL
99 thread_add_timer_msec(r->master, resolver_cb_timeout, r,
100 timeoutms, &r->timeout);
2fb975da
TT
101 }
102}
103
996c9314
LB
104static void ares_socket_cb(void *data, ares_socket_t fd, int readable,
105 int writable)
2fb975da 106{
996c9314 107 struct resolver_state *r = (struct resolver_state *)data;
72618ba8 108 struct thread *t, **t_ptr;
2fb975da
TT
109
110 if (readable) {
72618ba8 111 t = vector_lookup(r->read_threads, fd);
2fb975da 112 if (!t) {
72618ba8
IR
113 t_ptr = (struct thread **)vector_get_index(
114 r->read_threads, fd);
fe9e7b71 115 thread_add_read(r->master, resolver_cb_socket_readable,
72618ba8 116 r, fd, t_ptr);
2fb975da
TT
117 }
118 } else {
119 t = vector_lookup(r->read_threads, fd);
120 if (t) {
121 if (t != THREAD_RUNNING) {
122 THREAD_OFF(t);
123 }
124 vector_unset(r->read_threads, fd);
125 }
126 }
127
128 if (writable) {
72618ba8 129 t = vector_lookup(r->write_threads, fd);
2fb975da 130 if (!t) {
72618ba8
IR
131 t_ptr = (struct thread **)vector_get_index(
132 r->write_threads, fd);
fe9e7b71 133 thread_add_read(r->master, resolver_cb_socket_writable,
72618ba8 134 r, fd, t_ptr);
2fb975da
TT
135 }
136 } else {
137 t = vector_lookup(r->write_threads, fd);
138 if (t) {
139 if (t != THREAD_RUNNING) {
140 THREAD_OFF(t);
141 }
142 vector_unset(r->write_threads, fd);
143 }
144 }
145}
146
2fb975da 147
996c9314
LB
148static void ares_address_cb(void *arg, int status, int timeouts,
149 struct hostent *he)
2fb975da 150{
996c9314 151 struct resolver_query *query = (struct resolver_query *)arg;
2fb975da 152 union sockunion addr[16];
3286ca07
DL
153 void (*callback)(struct resolver_query *, const char *, int,
154 union sockunion *);
2fb975da
TT
155 size_t i;
156
50cdb6cf
DL
157 callback = query->callback;
158 query->callback = NULL;
159
2fb975da 160 if (status != ARES_SUCCESS) {
fe9e7b71 161 if (resolver_debug)
3286ca07
DL
162 zlog_debug("[%p] Resolving failed (%s)",
163 query, ares_strerror(status));
fe9e7b71 164
3286ca07 165 callback(query, ares_strerror(status), -1, NULL);
2fb975da
TT
166 return;
167 }
168
7e3a1ec7 169 for (i = 0; i < array_size(addr) && he->h_addr_list[i] != NULL; i++) {
2fb975da
TT
170 memset(&addr[i], 0, sizeof(addr[i]));
171 addr[i].sa.sa_family = he->h_addrtype;
172 switch (he->h_addrtype) {
173 case AF_INET:
996c9314
LB
174 memcpy(&addr[i].sin.sin_addr,
175 (uint8_t *)he->h_addr_list[i], he->h_length);
2fb975da
TT
176 break;
177 case AF_INET6:
996c9314
LB
178 memcpy(&addr[i].sin6.sin6_addr,
179 (uint8_t *)he->h_addr_list[i], he->h_length);
2fb975da
TT
180 break;
181 }
182 }
183
fe9e7b71
DL
184 if (resolver_debug)
185 zlog_debug("[%p] Resolved with %d results", query, (int)i);
186
3286ca07 187 callback(query, NULL, i, &addr[0]);
2fb975da
TT
188}
189
125dc952
DL
190static int resolver_cb_literal(struct thread *t)
191{
192 struct resolver_query *query = THREAD_ARG(t);
3286ca07
DL
193 void (*callback)(struct resolver_query *, const char *, int,
194 union sockunion *);
125dc952
DL
195
196 callback = query->callback;
197 query->callback = NULL;
198
3286ca07 199 callback(query, ARES_SUCCESS, 1, &query->literal_addr);
125dc952
DL
200 return 0;
201}
202
996c9314
LB
203void resolver_resolve(struct resolver_query *query, int af,
204 const char *hostname,
3286ca07
DL
205 void (*callback)(struct resolver_query *, const char *,
206 int, union sockunion *))
2fb975da 207{
125dc952
DL
208 int ret;
209
2fb975da 210 if (query->callback != NULL) {
1c50c1c0 211 flog_err(
fe9e7b71 212 EC_LIB_RESOLVER,
1c50c1c0
QY
213 "Trying to resolve '%s', but previous query was not finished yet",
214 hostname);
2fb975da
TT
215 return;
216 }
217
125dc952
DL
218 query->callback = callback;
219 query->literal_cb = NULL;
220
221 ret = str2sockunion(hostname, &query->literal_addr);
222 if (ret == 0) {
223 if (resolver_debug)
224 zlog_debug("[%p] Resolving '%s' (IP literal)",
225 query, hostname);
226
227 /* for consistency with proper name lookup, don't call the
228 * callback immediately; defer to thread loop
229 */
230 thread_add_timer_msec(state.master, resolver_cb_literal,
231 query, 0, &query->literal_cb);
232 return;
233 }
234
fe9e7b71
DL
235 if (resolver_debug)
236 zlog_debug("[%p] Resolving '%s'", query, hostname);
2fb975da 237
2fb975da
TT
238 ares_gethostbyname(state.channel, hostname, af, ares_address_cb, query);
239 resolver_update_timeouts(&state);
240}
fe9e7b71
DL
241
242DEFUN(debug_resolver,
243 debug_resolver_cmd,
244 "[no] debug resolver",
245 NO_STR
246 DEBUG_STR
247 "Debug DNS resolver actions\n")
248{
249 resolver_debug = (argc == 2);
250 return CMD_SUCCESS;
251}
252
612c2c15 253static int resolver_config_write_debug(struct vty *vty);
62b346ee 254static struct cmd_node resolver_debug_node = {
f4b8291f 255 .name = "resolver debug",
62b346ee
DL
256 .node = RESOLVER_DEBUG_NODE,
257 .prompt = "",
612c2c15 258 .config_write = resolver_config_write_debug,
62b346ee 259};
fe9e7b71
DL
260
261static int resolver_config_write_debug(struct vty *vty)
262{
263 if (resolver_debug)
264 vty_out(vty, "debug resolver\n");
265 return 1;
266}
267
268
269void resolver_init(struct thread_master *tm)
270{
271 struct ares_options ares_opts;
272
273 state.master = tm;
274 state.read_threads = vector_init(1);
275 state.write_threads = vector_init(1);
276
277 ares_opts = (struct ares_options){
278 .sock_state_cb = &ares_socket_cb,
279 .sock_state_cb_data = &state,
280 .timeout = 2,
281 .tries = 3,
282 };
283
284 ares_init_options(&state.channel, &ares_opts,
285 ARES_OPT_SOCK_STATE_CB | ARES_OPT_TIMEOUT
286 | ARES_OPT_TRIES);
287
612c2c15 288 install_node(&resolver_debug_node);
fe9e7b71
DL
289 install_element(CONFIG_NODE, &debug_resolver_cmd);
290 install_element(ENABLE_NODE, &debug_resolver_cmd);
291}