1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* C-Ares integration to Quagga mainloop
3 * Copyright (c) 2014-2015 Timo Teräs
11 #include <ares_version.h>
16 #include "lib_errors.h"
24 struct resolver_state
{
26 struct event_loop
*master
;
27 struct event
*timeout
;
30 static struct resolver_state state
;
31 static bool resolver_debug
;
33 /* a FD doesn't necessarily map 1:1 to a request; we could be talking to
34 * multiple caches simultaneously, to see which responds fastest.
35 * Theoretically we could also be using the same fd for multiple lookups,
36 * but the c-ares API guarantees an n:1 mapping for fd => channel.
38 * Either way c-ares makes that decision and we just need to deal with
39 * whatever FDs it gives us.
42 DEFINE_MTYPE_STATIC(LIB
, ARES_FD
, "c-ares (DNS) file descriptor information");
43 PREDECL_HASH(resolver_fds
);
46 struct resolver_fds_item itm
;
49 struct resolver_state
*state
;
50 struct event
*t_read
, *t_write
;
53 static int resolver_fd_cmp(const struct resolver_fd
*a
,
54 const struct resolver_fd
*b
)
56 return numcmp(a
->fd
, b
->fd
);
59 static uint32_t resolver_fd_hash(const struct resolver_fd
*item
)
61 return jhash_1word(item
->fd
, 0xacd04c9e);
64 DECLARE_HASH(resolver_fds
, struct resolver_fd
, itm
, resolver_fd_cmp
,
67 static struct resolver_fds_head resfds
[1] = {INIT_HASH(resfds
[0])};
69 static struct resolver_fd
*resolver_fd_get(int fd
,
70 struct resolver_state
*newstate
)
72 struct resolver_fd ref
= {.fd
= fd
}, *res
;
74 res
= resolver_fds_find(resfds
, &ref
);
75 if (!res
&& newstate
) {
76 res
= XCALLOC(MTYPE_ARES_FD
, sizeof(*res
));
78 res
->state
= newstate
;
79 resolver_fds_add(resfds
, res
);
82 zlog_debug("c-ares registered FD %d", fd
);
87 static void resolver_fd_drop_maybe(struct resolver_fd
*resfd
)
89 if (resfd
->t_read
|| resfd
->t_write
)
93 zlog_debug("c-ares unregistered FD %d", resfd
->fd
);
95 resolver_fds_del(resfds
, resfd
);
96 XFREE(MTYPE_ARES_FD
, resfd
);
99 /* end of FD housekeeping */
101 static void resolver_update_timeouts(struct resolver_state
*r
);
103 static void resolver_cb_timeout(struct event
*t
)
105 struct resolver_state
*r
= EVENT_ARG(t
);
107 ares_process(r
->channel
, NULL
, NULL
);
108 resolver_update_timeouts(r
);
111 static void resolver_cb_socket_readable(struct event
*t
)
113 struct resolver_fd
*resfd
= EVENT_ARG(t
);
114 struct resolver_state
*r
= resfd
->state
;
116 event_add_read(r
->master
, resolver_cb_socket_readable
, resfd
, resfd
->fd
,
118 /* ^ ordering important:
119 * ares_process_fd may transitively call EVENT_OFF(resfd->t_read)
120 * combined with resolver_fd_drop_maybe, so resfd may be free'd after!
122 ares_process_fd(r
->channel
, resfd
->fd
, ARES_SOCKET_BAD
);
123 resolver_update_timeouts(r
);
126 static void resolver_cb_socket_writable(struct event
*t
)
128 struct resolver_fd
*resfd
= EVENT_ARG(t
);
129 struct resolver_state
*r
= resfd
->state
;
131 event_add_write(r
->master
, resolver_cb_socket_writable
, resfd
,
132 resfd
->fd
, &resfd
->t_write
);
133 /* ^ ordering important:
134 * ares_process_fd may transitively call EVENT_OFF(resfd->t_write)
135 * combined with resolver_fd_drop_maybe, so resfd may be free'd after!
137 ares_process_fd(r
->channel
, ARES_SOCKET_BAD
, resfd
->fd
);
138 resolver_update_timeouts(r
);
141 static void resolver_update_timeouts(struct resolver_state
*r
)
143 struct timeval
*tv
, tvbuf
;
145 EVENT_OFF(r
->timeout
);
146 tv
= ares_timeout(r
->channel
, NULL
, &tvbuf
);
148 unsigned int timeoutms
= tv
->tv_sec
* 1000 + tv
->tv_usec
/ 1000;
150 event_add_timer_msec(r
->master
, resolver_cb_timeout
, r
,
151 timeoutms
, &r
->timeout
);
155 static void ares_socket_cb(void *data
, ares_socket_t fd
, int readable
,
158 struct resolver_state
*r
= (struct resolver_state
*)data
;
159 struct resolver_fd
*resfd
;
161 resfd
= resolver_fd_get(fd
, (readable
|| writable
) ? r
: NULL
);
165 assert(resfd
->state
== r
);
168 EVENT_OFF(resfd
->t_read
);
169 else if (!resfd
->t_read
)
170 event_add_read(r
->master
, resolver_cb_socket_readable
, resfd
,
174 EVENT_OFF(resfd
->t_write
);
175 else if (!resfd
->t_write
)
176 event_add_write(r
->master
, resolver_cb_socket_writable
, resfd
,
177 fd
, &resfd
->t_write
);
179 resolver_fd_drop_maybe(resfd
);
183 static void ares_address_cb(void *arg
, int status
, int timeouts
,
186 struct resolver_query
*query
= (struct resolver_query
*)arg
;
187 union sockunion addr
[16];
188 void (*callback
)(struct resolver_query
*, const char *, int,
192 callback
= query
->callback
;
193 query
->callback
= NULL
;
195 if (status
!= ARES_SUCCESS
) {
197 zlog_debug("[%p] Resolving failed (%s)",
198 query
, ares_strerror(status
));
200 callback(query
, ares_strerror(status
), -1, NULL
);
204 for (i
= 0; i
< array_size(addr
) && he
->h_addr_list
[i
] != NULL
; i
++) {
205 memset(&addr
[i
], 0, sizeof(addr
[i
]));
206 addr
[i
].sa
.sa_family
= he
->h_addrtype
;
207 switch (he
->h_addrtype
) {
209 memcpy(&addr
[i
].sin
.sin_addr
,
210 (uint8_t *)he
->h_addr_list
[i
], he
->h_length
);
213 memcpy(&addr
[i
].sin6
.sin6_addr
,
214 (uint8_t *)he
->h_addr_list
[i
], he
->h_length
);
220 zlog_debug("[%p] Resolved with %d results", query
, (int)i
);
222 callback(query
, NULL
, i
, &addr
[0]);
225 static void resolver_cb_literal(struct event
*t
)
227 struct resolver_query
*query
= EVENT_ARG(t
);
228 void (*callback
)(struct resolver_query
*, const char *, int,
231 callback
= query
->callback
;
232 query
->callback
= NULL
;
234 callback(query
, ARES_SUCCESS
, 1, &query
->literal_addr
);
237 void resolver_resolve(struct resolver_query
*query
, int af
, vrf_id_t vrf_id
,
238 const char *hostname
,
239 void (*callback
)(struct resolver_query
*, const char *,
240 int, union sockunion
*))
244 if (hostname
== NULL
)
247 if (query
->callback
!= NULL
) {
250 "Trying to resolve '%s', but previous query was not finished yet",
255 query
->callback
= callback
;
256 query
->literal_cb
= NULL
;
258 ret
= str2sockunion(hostname
, &query
->literal_addr
);
261 zlog_debug("[%p] Resolving '%s' (IP literal)",
264 /* for consistency with proper name lookup, don't call the
265 * callback immediately; defer to thread loop
267 event_add_timer_msec(state
.master
, resolver_cb_literal
, query
,
268 0, &query
->literal_cb
);
273 zlog_debug("[%p] Resolving '%s'", query
, hostname
);
275 ret
= vrf_switch_to_netns(vrf_id
);
277 flog_err_sys(EC_LIB_SOCKET
, "%s: Can't switch to VRF %u (%s)",
278 __func__
, vrf_id
, safe_strerror(errno
));
281 ares_gethostbyname(state
.channel
, hostname
, af
, ares_address_cb
, query
);
282 ret
= vrf_switchback_to_initial();
284 flog_err_sys(EC_LIB_SOCKET
,
285 "%s: Can't switchback from VRF %u (%s)", __func__
,
286 vrf_id
, safe_strerror(errno
));
287 resolver_update_timeouts(&state
);
290 DEFUN(debug_resolver
,
292 "[no] debug resolver",
295 "Debug DNS resolver actions\n")
297 resolver_debug
= (argc
== 2);
301 static int resolver_config_write_debug(struct vty
*vty
);
302 static struct cmd_node resolver_debug_node
= {
303 .name
= "resolver debug",
304 .node
= RESOLVER_DEBUG_NODE
,
306 .config_write
= resolver_config_write_debug
,
309 static int resolver_config_write_debug(struct vty
*vty
)
312 vty_out(vty
, "debug resolver\n");
317 void resolver_init(struct event_loop
*tm
)
319 struct ares_options ares_opts
;
323 ares_opts
= (struct ares_options
){
324 .sock_state_cb
= &ares_socket_cb
,
325 .sock_state_cb_data
= &state
,
330 ares_init_options(&state
.channel
, &ares_opts
,
331 ARES_OPT_SOCK_STATE_CB
| ARES_OPT_TIMEOUT
334 install_node(&resolver_debug_node
);
335 install_element(CONFIG_NODE
, &debug_resolver_cmd
);
336 install_element(ENABLE_NODE
, &debug_resolver_cmd
);