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