1 /* $OpenBSD: resolver.c,v 1.4 2019/04/06 10:35:48 eric Exp $ */
2
3 /*
4 * Copyright (c) 2017-2018 Eric Faurot <eric@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <sys/tree.h>
22 #include <sys/queue.h>
23 #include <netinet/in.h>
24
25 #include <asr.h>
26 #include <ctype.h>
27 #include <errno.h>
28 #include <imsg.h>
29 #include <limits.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35
36 #include "lpd.h"
37
38 #include "log.h"
39 #include "proc.h"
40
41 #define p_resolver p_engine
42
43 struct request {
44 SPLAY_ENTRY(request) entry;
45 uint32_t id;
46 void (*cb_ai)(void *, int, struct addrinfo *);
47 void (*cb_ni)(void *, int, const char *, const char *);
48 void *arg;
49 struct addrinfo *ai;
50 };
51
52 struct session {
53 uint32_t reqid;
54 struct imsgproc *proc;
55 char *host;
56 char *serv;
57 };
58
59 SPLAY_HEAD(reqtree, request);
60
61 static void resolver_init(void);
62 static void resolver_getaddrinfo_cb(struct asr_result *, void *);
63 static void resolver_getnameinfo_cb(struct asr_result *, void *);
64
65 static int request_cmp(struct request *, struct request *);
66 SPLAY_PROTOTYPE(reqtree, request, entry, request_cmp);
67
68 static struct reqtree reqs;
69
70 void
resolver_getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,void (* cb)(void *,int,struct addrinfo *),void * arg)71 resolver_getaddrinfo(const char *hostname, const char *servname,
72 const struct addrinfo *hints, void (*cb)(void *, int, struct addrinfo *),
73 void *arg)
74 {
75 struct request *req;
76
77 resolver_init();
78
79 req = calloc(1, sizeof(*req));
80 if (req == NULL) {
81 cb(arg, EAI_MEMORY, NULL);
82 return;
83 }
84
85 while (req->id == 0 || SPLAY_FIND(reqtree, &reqs, req))
86 req->id = arc4random();
87 req->cb_ai = cb;
88 req->arg = arg;
89
90 SPLAY_INSERT(reqtree, &reqs, req);
91
92 m_create(p_resolver, IMSG_GETADDRINFO, req->id, 0, -1);
93 m_add_int(p_resolver, hints ? hints->ai_flags : 0);
94 m_add_int(p_resolver, hints ? hints->ai_family : 0);
95 m_add_int(p_resolver, hints ? hints->ai_socktype : 0);
96 m_add_int(p_resolver, hints ? hints->ai_protocol : 0);
97 m_add_string(p_resolver, hostname);
98 m_add_string(p_resolver, servname);
99 m_close(p_resolver);
100 }
101
102 void
resolver_getnameinfo(const struct sockaddr * sa,int flags,void (* cb)(void *,int,const char *,const char *),void * arg)103 resolver_getnameinfo(const struct sockaddr *sa, int flags,
104 void(*cb)(void *, int, const char *, const char *), void *arg)
105 {
106 struct request *req;
107
108 resolver_init();
109
110 req = calloc(1, sizeof(*req));
111 if (req == NULL) {
112 cb(arg, EAI_MEMORY, NULL, NULL);
113 return;
114 }
115
116 while (req->id == 0 || SPLAY_FIND(reqtree, &reqs, req))
117 req->id = arc4random();
118 req->cb_ni = cb;
119 req->arg = arg;
120
121 SPLAY_INSERT(reqtree, &reqs, req);
122
123 m_create(p_resolver, IMSG_GETNAMEINFO, req->id, 0, -1);
124 m_add_sockaddr(p_resolver, sa);
125 m_add_int(p_resolver, flags);
126 m_close(p_resolver);
127 }
128
129 void
resolver_dispatch_request(struct imsgproc * proc,struct imsg * imsg)130 resolver_dispatch_request(struct imsgproc *proc, struct imsg *imsg)
131 {
132 const char *hostname, *servname;
133 struct session *s;
134 struct asr_query *q;
135 struct addrinfo hints;
136 struct sockaddr_storage ss;
137 struct sockaddr *sa;
138 uint32_t reqid;
139 int flags, save_errno;
140
141 reqid = imsg->hdr.peerid;
142
143 switch (imsg->hdr.type) {
144
145 case IMSG_GETADDRINFO:
146 servname = NULL;
147 memset(&hints, 0 , sizeof(hints));
148 m_get_int(proc, &hints.ai_flags);
149 m_get_int(proc, &hints.ai_family);
150 m_get_int(proc, &hints.ai_socktype);
151 m_get_int(proc, &hints.ai_protocol);
152 m_get_string(proc, &hostname);
153 m_get_string(proc, &servname);
154 m_end(proc);
155
156 s = NULL;
157 q = NULL;
158 if ((s = calloc(1, sizeof(*s))) &&
159 (q = getaddrinfo_async(hostname, servname, &hints, NULL)) &&
160 (event_asr_run(q, resolver_getaddrinfo_cb, s))) {
161 s->reqid = reqid;
162 s->proc = proc;
163 break;
164 }
165 save_errno = errno;
166
167 if (q)
168 asr_abort(q);
169 if (s)
170 free(s);
171
172 m_create(proc, IMSG_GETADDRINFO_END, reqid, 0, -1);
173 m_add_int(proc, EAI_SYSTEM);
174 m_add_int(proc, save_errno);
175 m_close(proc);
176 break;
177
178 case IMSG_GETNAMEINFO:
179 sa = (struct sockaddr*)&ss;
180 m_get_sockaddr(proc, sa);
181 m_get_int(proc, &flags);
182 m_end(proc);
183
184 s = NULL;
185 q = NULL;
186 if ((s = calloc(1, sizeof(*s))) &&
187 (s->host = malloc(NI_MAXHOST)) &&
188 (s->serv = malloc(NI_MAXSERV)) &&
189 (q = getnameinfo_async(sa, sa->sa_len, s->host, NI_MAXHOST,
190 s->serv, NI_MAXSERV, flags, NULL)) &&
191 (event_asr_run(q, resolver_getnameinfo_cb, s))) {
192 s->reqid = reqid;
193 s->proc = proc;
194 break;
195 }
196 save_errno = errno;
197
198 if (q)
199 asr_abort(q);
200 if (s) {
201 free(s->host);
202 free(s->serv);
203 free(s);
204 }
205
206 m_create(proc, IMSG_GETNAMEINFO, reqid, 0, -1);
207 m_add_int(proc, EAI_SYSTEM);
208 m_add_int(proc, save_errno);
209 m_add_string(proc, NULL);
210 m_add_string(proc, NULL);
211 m_close(proc);
212 break;
213
214 default:
215 fatalx("%s: %s", __func__, log_fmt_imsgtype(imsg->hdr.type));
216 }
217 }
218
219 void
resolver_dispatch_result(struct imsgproc * proc,struct imsg * imsg)220 resolver_dispatch_result(struct imsgproc *proc, struct imsg *imsg)
221 {
222 struct request key, *req;
223 struct sockaddr_storage ss;
224 struct addrinfo *ai;
225 const char *cname, *host, *serv;
226 int gai_errno;
227
228 key.id = imsg->hdr.peerid;
229 req = SPLAY_FIND(reqtree, &reqs, &key);
230 if (req == NULL)
231 fatalx("%s: unknown request %08x", __func__, imsg->hdr.peerid);
232
233 switch (imsg->hdr.type) {
234
235 case IMSG_GETADDRINFO:
236 ai = calloc(1, sizeof(*ai));
237 if (ai == NULL) {
238 log_warn("%s: calloc", __func__);
239 break;
240 }
241 m_get_int(proc, &ai->ai_flags);
242 m_get_int(proc, &ai->ai_family);
243 m_get_int(proc, &ai->ai_socktype);
244 m_get_int(proc, &ai->ai_protocol);
245 m_get_sockaddr(proc, (struct sockaddr *)&ss);
246 m_get_string(proc, &cname);
247 m_end(proc);
248
249 ai->ai_addr = malloc(ss.ss_len);
250 if (ai->ai_addr == NULL) {
251 log_warn("%s: malloc", __func__);
252 free(ai);
253 break;
254 }
255
256 memmove(ai->ai_addr, &ss, ss.ss_len);
257
258 if (cname) {
259 ai->ai_canonname = strdup(cname);
260 if (ai->ai_canonname == NULL) {
261 log_warn("%s: strdup", __func__);
262 free(ai->ai_addr);
263 free(ai);
264 break;
265 }
266 }
267
268 ai->ai_next = req->ai;
269 req->ai = ai;
270 break;
271
272 case IMSG_GETADDRINFO_END:
273 m_get_int(proc, &gai_errno);
274 m_get_int(proc, &errno);
275 m_end(proc);
276
277 SPLAY_REMOVE(reqtree, &reqs, req);
278 req->cb_ai(req->arg, gai_errno, req->ai);
279 free(req);
280 break;
281
282 case IMSG_GETNAMEINFO:
283 m_get_int(proc, &gai_errno);
284 m_get_int(proc, &errno);
285 m_get_string(proc, &host);
286 m_get_string(proc, &serv);
287 m_end(proc);
288
289 SPLAY_REMOVE(reqtree, &reqs, req);
290 req->cb_ni(req->arg, gai_errno, host, serv);
291 free(req);
292 break;
293 }
294 }
295
296 static void
resolver_init(void)297 resolver_init(void)
298 {
299 static int init = 0;
300
301 if (init == 0) {
302 SPLAY_INIT(&reqs);
303 init = 1;
304 }
305 }
306
307 static void
resolver_getaddrinfo_cb(struct asr_result * ar,void * arg)308 resolver_getaddrinfo_cb(struct asr_result *ar, void *arg)
309 {
310 struct session *s = arg;
311 struct addrinfo *ai;
312
313 for (ai = ar->ar_addrinfo; ai; ai = ai->ai_next) {
314 m_create(s->proc, IMSG_GETADDRINFO, s->reqid, 0, -1);
315 m_add_int(s->proc, ai->ai_flags);
316 m_add_int(s->proc, ai->ai_family);
317 m_add_int(s->proc, ai->ai_socktype);
318 m_add_int(s->proc, ai->ai_protocol);
319 m_add_sockaddr(s->proc, ai->ai_addr);
320 m_add_string(s->proc, ai->ai_canonname);
321 m_close(s->proc);
322 }
323
324 m_create(s->proc, IMSG_GETADDRINFO_END, s->reqid, 0, -1);
325 m_add_int(s->proc, ar->ar_gai_errno);
326 m_add_int(s->proc, ar->ar_errno);
327 m_close(s->proc);
328
329 if (ar->ar_addrinfo)
330 freeaddrinfo(ar->ar_addrinfo);
331 free(s);
332 }
333
334 static void
resolver_getnameinfo_cb(struct asr_result * ar,void * arg)335 resolver_getnameinfo_cb(struct asr_result *ar, void *arg)
336 {
337 struct session *s = arg;
338
339 m_create(s->proc, IMSG_GETNAMEINFO, s->reqid, 0, -1);
340 m_add_int(s->proc, ar->ar_gai_errno);
341 m_add_int(s->proc, ar->ar_errno);
342 m_add_string(s->proc, ar->ar_gai_errno ? NULL : s->host);
343 m_add_string(s->proc, ar->ar_gai_errno ? NULL : s->serv);
344 m_close(s->proc);
345
346 free(s->host);
347 free(s->serv);
348 free(s);
349 }
350
351 static int
request_cmp(struct request * a,struct request * b)352 request_cmp(struct request *a, struct request *b)
353 {
354 if (a->id < b->id)
355 return -1;
356 if (a->id > b->id)
357 return 1;
358 return 0;
359 }
360
361 SPLAY_GENERATE(reqtree, request, entry, request_cmp);
362