Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <errno.h>
4 : #include <poll.h>
5 : #include <pthread.h>
6 : #include <resolv.h>
7 : #include <signal.h>
8 : #include <stdint.h>
9 : #include <stdio.h>
10 : #include <stdlib.h>
11 : #include <string.h>
12 : #include <sys/prctl.h>
13 : #include <unistd.h>
14 :
15 : #include "sd-resolve.h"
16 :
17 : #include "alloc-util.h"
18 : #include "dns-domain.h"
19 : #include "errno-util.h"
20 : #include "fd-util.h"
21 : #include "io-util.h"
22 : #include "list.h"
23 : #include "memory-util.h"
24 : #include "missing.h"
25 : #include "process-util.h"
26 : #include "resolve-private.h"
27 : #include "socket-util.h"
28 :
29 : #define WORKERS_MIN 1U
30 : #define WORKERS_MAX 16U
31 : #define QUERIES_MAX 256U
32 : #define BUFSIZE 10240U
33 :
34 : typedef enum {
35 : REQUEST_ADDRINFO,
36 : RESPONSE_ADDRINFO,
37 : REQUEST_NAMEINFO,
38 : RESPONSE_NAMEINFO,
39 : REQUEST_TERMINATE,
40 : RESPONSE_DIED
41 : } QueryType;
42 :
43 : enum {
44 : REQUEST_RECV_FD,
45 : REQUEST_SEND_FD,
46 : RESPONSE_RECV_FD,
47 : RESPONSE_SEND_FD,
48 : _FD_MAX
49 : };
50 :
51 : struct sd_resolve {
52 : unsigned n_ref;
53 :
54 : bool dead:1;
55 : pid_t original_pid;
56 :
57 : int fds[_FD_MAX];
58 :
59 : pthread_t workers[WORKERS_MAX];
60 : unsigned n_valid_workers;
61 :
62 : unsigned current_id;
63 : sd_resolve_query* query_array[QUERIES_MAX];
64 : unsigned n_queries, n_done, n_outstanding;
65 :
66 : sd_event_source *event_source;
67 : sd_event *event;
68 :
69 : sd_resolve_query *current;
70 :
71 : sd_resolve **default_resolve_ptr;
72 : pid_t tid;
73 :
74 : LIST_HEAD(sd_resolve_query, queries);
75 : };
76 :
77 : struct sd_resolve_query {
78 : unsigned n_ref;
79 :
80 : sd_resolve *resolve;
81 :
82 : QueryType type:4;
83 : bool done:1;
84 : bool floating:1;
85 : unsigned id;
86 :
87 : int ret;
88 : int _errno;
89 : int _h_errno;
90 : struct addrinfo *addrinfo;
91 : char *serv, *host;
92 :
93 : union {
94 : sd_resolve_getaddrinfo_handler_t getaddrinfo_handler;
95 : sd_resolve_getnameinfo_handler_t getnameinfo_handler;
96 : };
97 :
98 : void *userdata;
99 : sd_resolve_destroy_t destroy_callback;
100 :
101 : LIST_FIELDS(sd_resolve_query, queries);
102 : };
103 :
104 : typedef struct RHeader {
105 : QueryType type;
106 : unsigned id;
107 : size_t length;
108 : } RHeader;
109 :
110 : typedef struct AddrInfoRequest {
111 : struct RHeader header;
112 : bool hints_valid;
113 : int ai_flags;
114 : int ai_family;
115 : int ai_socktype;
116 : int ai_protocol;
117 : size_t node_len, service_len;
118 : } AddrInfoRequest;
119 :
120 : typedef struct AddrInfoResponse {
121 : struct RHeader header;
122 : int ret;
123 : int _errno;
124 : int _h_errno;
125 : /* followed by addrinfo_serialization[] */
126 : } AddrInfoResponse;
127 :
128 : typedef struct AddrInfoSerialization {
129 : int ai_flags;
130 : int ai_family;
131 : int ai_socktype;
132 : int ai_protocol;
133 : size_t ai_addrlen;
134 : size_t canonname_len;
135 : /* Followed by ai_addr amd ai_canonname with variable lengths */
136 : } AddrInfoSerialization;
137 :
138 : typedef struct NameInfoRequest {
139 : struct RHeader header;
140 : int flags;
141 : socklen_t sockaddr_len;
142 : bool gethost:1, getserv:1;
143 : } NameInfoRequest;
144 :
145 : typedef struct NameInfoResponse {
146 : struct RHeader header;
147 : size_t hostlen, servlen;
148 : int ret;
149 : int _errno;
150 : int _h_errno;
151 : } NameInfoResponse;
152 :
153 : typedef union Packet {
154 : RHeader rheader;
155 : AddrInfoRequest addrinfo_request;
156 : AddrInfoResponse addrinfo_response;
157 : NameInfoRequest nameinfo_request;
158 : NameInfoResponse nameinfo_response;
159 : } Packet;
160 :
161 : static int getaddrinfo_done(sd_resolve_query* q);
162 : static int getnameinfo_done(sd_resolve_query *q);
163 :
164 : static void resolve_query_disconnect(sd_resolve_query *q);
165 :
166 : #define RESOLVE_DONT_DESTROY(resolve) \
167 : _cleanup_(sd_resolve_unrefp) _unused_ sd_resolve *_dont_destroy_##resolve = sd_resolve_ref(resolve)
168 :
169 3 : static void query_assign_errno(sd_resolve_query *q, int ret, int error, int h_error) {
170 3 : assert(q);
171 :
172 3 : q->ret = ret;
173 3 : q->_errno = abs(error);
174 3 : q->_h_errno = h_error;
175 3 : }
176 :
177 3 : static int send_died(int out_fd) {
178 3 : RHeader rh = {
179 : .type = RESPONSE_DIED,
180 : .length = sizeof(RHeader),
181 : };
182 :
183 3 : assert(out_fd >= 0);
184 :
185 3 : if (send(out_fd, &rh, rh.length, MSG_NOSIGNAL) < 0)
186 0 : return -errno;
187 :
188 3 : return 0;
189 : }
190 :
191 6 : static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) {
192 : AddrInfoSerialization s;
193 : size_t cnl, l;
194 :
195 6 : assert(p);
196 6 : assert(ai);
197 6 : assert(length);
198 6 : assert(*length <= maxlength);
199 :
200 6 : cnl = ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0;
201 6 : l = sizeof(AddrInfoSerialization) + ai->ai_addrlen + cnl;
202 :
203 6 : if (*length + l > maxlength)
204 0 : return NULL;
205 :
206 6 : s = (AddrInfoSerialization) {
207 6 : .ai_flags = ai->ai_flags,
208 6 : .ai_family = ai->ai_family,
209 6 : .ai_socktype = ai->ai_socktype,
210 6 : .ai_protocol = ai->ai_protocol,
211 6 : .ai_addrlen = ai->ai_addrlen,
212 : .canonname_len = cnl,
213 : };
214 :
215 6 : memcpy((uint8_t*) p, &s, sizeof(AddrInfoSerialization));
216 6 : memcpy((uint8_t*) p + sizeof(AddrInfoSerialization), ai->ai_addr, ai->ai_addrlen);
217 6 : memcpy_safe((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen,
218 6 : ai->ai_canonname, cnl);
219 :
220 6 : *length += l;
221 6 : return (uint8_t*) p + l;
222 : }
223 :
224 2 : static int send_addrinfo_reply(
225 : int out_fd,
226 : unsigned id,
227 : int ret,
228 : struct addrinfo *ai,
229 : int _errno,
230 : int _h_errno) {
231 :
232 2 : AddrInfoResponse resp = {};
233 : union {
234 : AddrInfoSerialization ais;
235 : uint8_t space[BUFSIZE];
236 : } buffer;
237 : struct iovec iov[2];
238 : struct msghdr mh;
239 :
240 2 : assert(out_fd >= 0);
241 :
242 2 : resp = (AddrInfoResponse) {
243 : .header.type = RESPONSE_ADDRINFO,
244 : .header.id = id,
245 : .header.length = sizeof(AddrInfoResponse),
246 : .ret = ret,
247 : ._errno = _errno,
248 : ._h_errno = _h_errno,
249 : };
250 :
251 : msan_unpoison(&resp, sizeof(resp));
252 :
253 2 : if (ret == 0 && ai) {
254 2 : void *p = &buffer;
255 : struct addrinfo *k;
256 :
257 8 : for (k = ai; k; k = k->ai_next) {
258 6 : p = serialize_addrinfo(p, k, &resp.header.length, (uint8_t*) &buffer + BUFSIZE - (uint8_t*) p);
259 6 : if (!p) {
260 0 : freeaddrinfo(ai);
261 0 : return -ENOBUFS;
262 : }
263 : }
264 : }
265 :
266 2 : if (ai)
267 2 : freeaddrinfo(ai);
268 :
269 2 : iov[0] = IOVEC_MAKE(&resp, sizeof(AddrInfoResponse));
270 2 : iov[1] = IOVEC_MAKE(&buffer, resp.header.length - sizeof(AddrInfoResponse));
271 :
272 2 : mh = (struct msghdr) {
273 : .msg_iov = iov,
274 : .msg_iovlen = ELEMENTSOF(iov)
275 : };
276 :
277 2 : if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0)
278 0 : return -errno;
279 :
280 2 : return 0;
281 : }
282 :
283 1 : static int send_nameinfo_reply(
284 : int out_fd,
285 : unsigned id,
286 : int ret,
287 : const char *host,
288 : const char *serv,
289 : int _errno,
290 : int _h_errno) {
291 :
292 1 : NameInfoResponse resp = {};
293 : struct iovec iov[3];
294 : struct msghdr mh;
295 : size_t hl, sl;
296 :
297 1 : assert(out_fd >= 0);
298 :
299 1 : sl = serv ? strlen(serv)+1 : 0;
300 1 : hl = host ? strlen(host)+1 : 0;
301 :
302 1 : resp = (NameInfoResponse) {
303 : .header.type = RESPONSE_NAMEINFO,
304 : .header.id = id,
305 1 : .header.length = sizeof(NameInfoResponse) + hl + sl,
306 : .hostlen = hl,
307 : .servlen = sl,
308 : .ret = ret,
309 : ._errno = _errno,
310 : ._h_errno = _h_errno,
311 : };
312 :
313 : msan_unpoison(&resp, sizeof(resp));
314 :
315 1 : iov[0] = IOVEC_MAKE(&resp, sizeof(NameInfoResponse));
316 1 : iov[1] = IOVEC_MAKE((void*) host, hl);
317 1 : iov[2] = IOVEC_MAKE((void*) serv, sl);
318 :
319 1 : mh = (struct msghdr) {
320 : .msg_iov = iov,
321 : .msg_iovlen = ELEMENTSOF(iov)
322 : };
323 :
324 1 : if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0)
325 0 : return -errno;
326 :
327 1 : return 0;
328 : }
329 :
330 6 : static int handle_request(int out_fd, const Packet *packet, size_t length) {
331 : const RHeader *req;
332 :
333 6 : assert(out_fd >= 0);
334 6 : assert(packet);
335 :
336 6 : req = &packet->rheader;
337 :
338 6 : assert_return(length >= sizeof(RHeader), -EIO);
339 6 : assert_return(length == req->length, -EIO);
340 :
341 6 : switch (req->type) {
342 :
343 2 : case REQUEST_ADDRINFO: {
344 2 : const AddrInfoRequest *ai_req = &packet->addrinfo_request;
345 2 : struct addrinfo hints, *result = NULL;
346 : const char *node, *service;
347 : int ret;
348 :
349 2 : assert_return(length >= sizeof(AddrInfoRequest), -EBADMSG);
350 2 : assert_return(length == sizeof(AddrInfoRequest) + ai_req->node_len + ai_req->service_len, -EBADMSG);
351 :
352 2 : hints = (struct addrinfo) {
353 2 : .ai_flags = ai_req->ai_flags,
354 2 : .ai_family = ai_req->ai_family,
355 2 : .ai_socktype = ai_req->ai_socktype,
356 2 : .ai_protocol = ai_req->ai_protocol,
357 : };
358 :
359 : msan_unpoison(&hints, sizeof(hints));
360 :
361 2 : node = ai_req->node_len ? (const char*) ai_req + sizeof(AddrInfoRequest) : NULL;
362 2 : service = ai_req->service_len ? (const char*) ai_req + sizeof(AddrInfoRequest) + ai_req->node_len : NULL;
363 :
364 2 : ret = getaddrinfo(node, service,
365 2 : ai_req->hints_valid ? &hints : NULL,
366 : &result);
367 :
368 : /* send_addrinfo_reply() frees result */
369 2 : return send_addrinfo_reply(out_fd, req->id, ret, result, errno, h_errno);
370 : }
371 :
372 1 : case REQUEST_NAMEINFO: {
373 1 : const NameInfoRequest *ni_req = &packet->nameinfo_request;
374 : char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV];
375 : union sockaddr_union sa;
376 : int ret;
377 :
378 1 : assert_return(length >= sizeof(NameInfoRequest), -EBADMSG);
379 1 : assert_return(length == sizeof(NameInfoRequest) + ni_req->sockaddr_len, -EBADMSG);
380 1 : assert_return(ni_req->sockaddr_len <= sizeof(sa), -EBADMSG);
381 :
382 1 : memcpy(&sa, (const uint8_t *) ni_req + sizeof(NameInfoRequest), ni_req->sockaddr_len);
383 :
384 3 : ret = getnameinfo(&sa.sa, ni_req->sockaddr_len,
385 2 : ni_req->gethost ? hostbuf : NULL, ni_req->gethost ? sizeof(hostbuf) : 0,
386 1 : ni_req->getserv ? servbuf : NULL, ni_req->getserv ? sizeof(servbuf) : 0,
387 : ni_req->flags);
388 :
389 2 : return send_nameinfo_reply(out_fd, req->id, ret,
390 1 : ret == 0 && ni_req->gethost ? hostbuf : NULL,
391 1 : ret == 0 && ni_req->getserv ? servbuf : NULL,
392 1 : errno, h_errno);
393 : }
394 :
395 3 : case REQUEST_TERMINATE:
396 : /* Quit */
397 3 : return -ECONNRESET;
398 :
399 0 : default:
400 0 : assert_not_reached("Unknown request");
401 : }
402 :
403 : return 0;
404 : }
405 :
406 3 : static void* thread_worker(void *p) {
407 3 : sd_resolve *resolve = p;
408 :
409 : /* Assign a pretty name to this thread */
410 3 : (void) pthread_setname_np(pthread_self(), "sd-resolve");
411 :
412 6 : while (!resolve->dead) {
413 : union {
414 : Packet packet;
415 : uint8_t space[BUFSIZE];
416 : } buf;
417 : ssize_t length;
418 :
419 6 : length = recv(resolve->fds[REQUEST_RECV_FD], &buf, sizeof buf, 0);
420 6 : if (length < 0) {
421 0 : if (errno == EINTR)
422 0 : continue;
423 :
424 3 : break;
425 : }
426 6 : if (length == 0)
427 0 : break;
428 :
429 6 : if (handle_request(resolve->fds[RESPONSE_SEND_FD], &buf.packet, (size_t) length) < 0)
430 3 : break;
431 : }
432 :
433 3 : send_died(resolve->fds[RESPONSE_SEND_FD]);
434 :
435 3 : return NULL;
436 : }
437 :
438 3 : static int start_threads(sd_resolve *resolve, unsigned extra) {
439 : sigset_t ss, saved_ss;
440 : unsigned n;
441 : int r, k;
442 :
443 3 : assert_se(sigfillset(&ss) >= 0);
444 :
445 : /* No signals in forked off threads please. We set the mask before forking, so that the threads never exist
446 : * with a different mask than a fully blocked one */
447 3 : r = pthread_sigmask(SIG_BLOCK, &ss, &saved_ss);
448 3 : if (r > 0)
449 0 : return -r;
450 :
451 3 : n = resolve->n_outstanding + extra;
452 3 : n = CLAMP(n, WORKERS_MIN, WORKERS_MAX);
453 :
454 6 : while (resolve->n_valid_workers < n) {
455 3 : r = pthread_create(&resolve->workers[resolve->n_valid_workers], NULL, thread_worker, resolve);
456 3 : if (r > 0) {
457 0 : r = -r;
458 0 : goto finish;
459 : }
460 :
461 3 : resolve->n_valid_workers++;
462 : }
463 :
464 3 : r = 0;
465 :
466 3 : finish:
467 3 : k = pthread_sigmask(SIG_SETMASK, &saved_ss, NULL);
468 3 : if (k > 0 && r >= 0)
469 0 : r = -k;
470 :
471 3 : return r;
472 : }
473 :
474 10 : static bool resolve_pid_changed(sd_resolve *r) {
475 10 : assert(r);
476 :
477 : /* We don't support people creating a resolver and keeping it
478 : * around after fork(). Let's complain. */
479 :
480 10 : return r->original_pid != getpid_cached();
481 : }
482 :
483 3 : _public_ int sd_resolve_new(sd_resolve **ret) {
484 3 : _cleanup_(sd_resolve_unrefp) sd_resolve *resolve = NULL;
485 : int i;
486 :
487 3 : assert_return(ret, -EINVAL);
488 :
489 3 : resolve = new0(sd_resolve, 1);
490 3 : if (!resolve)
491 0 : return -ENOMEM;
492 :
493 3 : resolve->n_ref = 1;
494 3 : resolve->original_pid = getpid_cached();
495 :
496 15 : for (i = 0; i < _FD_MAX; i++)
497 12 : resolve->fds[i] = -1;
498 :
499 3 : if (socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds + REQUEST_RECV_FD) < 0)
500 0 : return -errno;
501 :
502 3 : if (socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds + RESPONSE_RECV_FD) < 0)
503 0 : return -errno;
504 :
505 15 : for (i = 0; i < _FD_MAX; i++)
506 12 : resolve->fds[i] = fd_move_above_stdio(resolve->fds[i]);
507 :
508 3 : (void) fd_inc_sndbuf(resolve->fds[REQUEST_SEND_FD], QUERIES_MAX * BUFSIZE);
509 3 : (void) fd_inc_rcvbuf(resolve->fds[REQUEST_RECV_FD], QUERIES_MAX * BUFSIZE);
510 3 : (void) fd_inc_sndbuf(resolve->fds[RESPONSE_SEND_FD], QUERIES_MAX * BUFSIZE);
511 3 : (void) fd_inc_rcvbuf(resolve->fds[RESPONSE_RECV_FD], QUERIES_MAX * BUFSIZE);
512 :
513 3 : (void) fd_nonblock(resolve->fds[RESPONSE_RECV_FD], true);
514 :
515 3 : *ret = TAKE_PTR(resolve);
516 3 : return 0;
517 : }
518 :
519 3 : _public_ int sd_resolve_default(sd_resolve **ret) {
520 : static thread_local sd_resolve *default_resolve = NULL;
521 3 : sd_resolve *e = NULL;
522 : int r;
523 :
524 3 : if (!ret)
525 0 : return !!default_resolve;
526 :
527 3 : if (default_resolve) {
528 0 : *ret = sd_resolve_ref(default_resolve);
529 0 : return 0;
530 : }
531 :
532 3 : r = sd_resolve_new(&e);
533 3 : if (r < 0)
534 0 : return r;
535 :
536 3 : e->default_resolve_ptr = &default_resolve;
537 3 : e->tid = gettid();
538 3 : default_resolve = e;
539 :
540 3 : *ret = e;
541 3 : return 1;
542 : }
543 :
544 0 : _public_ int sd_resolve_get_tid(sd_resolve *resolve, pid_t *tid) {
545 0 : assert_return(resolve, -EINVAL);
546 0 : assert_return(tid, -EINVAL);
547 0 : assert_return(!resolve_pid_changed(resolve), -ECHILD);
548 :
549 0 : if (resolve->tid != 0) {
550 0 : *tid = resolve->tid;
551 0 : return 0;
552 : }
553 :
554 0 : if (resolve->event)
555 0 : return sd_event_get_tid(resolve->event, tid);
556 :
557 0 : return -ENXIO;
558 : }
559 :
560 3 : static sd_resolve *resolve_free(sd_resolve *resolve) {
561 3 : PROTECT_ERRNO;
562 : sd_resolve_query *q;
563 : unsigned i;
564 :
565 3 : assert(resolve);
566 :
567 3 : while ((q = resolve->queries)) {
568 0 : assert(q->floating);
569 0 : resolve_query_disconnect(q);
570 0 : sd_resolve_query_unref(q);
571 : }
572 :
573 3 : if (resolve->default_resolve_ptr)
574 3 : *(resolve->default_resolve_ptr) = NULL;
575 :
576 3 : resolve->dead = true;
577 :
578 3 : sd_resolve_detach_event(resolve);
579 :
580 3 : if (resolve->fds[REQUEST_SEND_FD] >= 0) {
581 :
582 3 : RHeader req = {
583 : .type = REQUEST_TERMINATE,
584 : .length = sizeof req,
585 : };
586 :
587 : /* Send one termination packet for each worker */
588 6 : for (i = 0; i < resolve->n_valid_workers; i++)
589 3 : (void) send(resolve->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL);
590 : }
591 :
592 : /* Now terminate them and wait until they are gone.
593 : If we get an error than most likely the thread already exited. */
594 6 : for (i = 0; i < resolve->n_valid_workers; i++)
595 3 : (void) pthread_join(resolve->workers[i], NULL);
596 :
597 : /* Close all communication channels */
598 3 : close_many(resolve->fds, _FD_MAX);
599 :
600 3 : return mfree(resolve);
601 : }
602 :
603 17 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_resolve, sd_resolve, resolve_free);
604 :
605 0 : _public_ int sd_resolve_get_fd(sd_resolve *resolve) {
606 0 : assert_return(resolve, -EINVAL);
607 0 : assert_return(!resolve_pid_changed(resolve), -ECHILD);
608 :
609 0 : return resolve->fds[RESPONSE_RECV_FD];
610 : }
611 :
612 0 : _public_ int sd_resolve_get_events(sd_resolve *resolve) {
613 0 : assert_return(resolve, -EINVAL);
614 0 : assert_return(!resolve_pid_changed(resolve), -ECHILD);
615 :
616 0 : return resolve->n_queries > resolve->n_done ? POLLIN : 0;
617 : }
618 :
619 0 : _public_ int sd_resolve_get_timeout(sd_resolve *resolve, uint64_t *usec) {
620 0 : assert_return(resolve, -EINVAL);
621 0 : assert_return(usec, -EINVAL);
622 0 : assert_return(!resolve_pid_changed(resolve), -ECHILD);
623 :
624 0 : *usec = (uint64_t) -1;
625 0 : return 0;
626 : }
627 :
628 3 : static sd_resolve_query *lookup_query(sd_resolve *resolve, unsigned id) {
629 : sd_resolve_query *q;
630 :
631 3 : assert(resolve);
632 :
633 3 : q = resolve->query_array[id % QUERIES_MAX];
634 3 : if (q)
635 3 : if (q->id == id)
636 3 : return q;
637 :
638 0 : return NULL;
639 : }
640 :
641 3 : static int complete_query(sd_resolve *resolve, sd_resolve_query *q) {
642 : int r;
643 :
644 3 : assert(q);
645 3 : assert(!q->done);
646 3 : assert(q->resolve == resolve);
647 :
648 3 : q->done = true;
649 3 : resolve->n_done++;
650 :
651 3 : resolve->current = sd_resolve_query_ref(q);
652 :
653 3 : switch (q->type) {
654 :
655 2 : case REQUEST_ADDRINFO:
656 2 : r = getaddrinfo_done(q);
657 2 : break;
658 :
659 1 : case REQUEST_NAMEINFO:
660 1 : r = getnameinfo_done(q);
661 1 : break;
662 :
663 0 : default:
664 0 : assert_not_reached("Cannot complete unknown query type");
665 : }
666 :
667 3 : resolve->current = NULL;
668 :
669 3 : if (q->floating) {
670 1 : resolve_query_disconnect(q);
671 1 : sd_resolve_query_unref(q);
672 : }
673 :
674 3 : sd_resolve_query_unref(q);
675 :
676 3 : return r;
677 : }
678 :
679 6 : static int unserialize_addrinfo(const void **p, size_t *length, struct addrinfo **ret_ai) {
680 : AddrInfoSerialization s;
681 : struct addrinfo *ai;
682 : size_t l;
683 :
684 6 : assert(p);
685 6 : assert(*p);
686 6 : assert(ret_ai);
687 6 : assert(length);
688 :
689 6 : if (*length < sizeof(AddrInfoSerialization))
690 0 : return -EBADMSG;
691 :
692 6 : memcpy(&s, *p, sizeof(s));
693 :
694 6 : l = sizeof(AddrInfoSerialization) + s.ai_addrlen + s.canonname_len;
695 6 : if (*length < l)
696 0 : return -EBADMSG;
697 :
698 6 : ai = new(struct addrinfo, 1);
699 6 : if (!ai)
700 0 : return -ENOMEM;
701 :
702 6 : *ai = (struct addrinfo) {
703 6 : .ai_flags = s.ai_flags,
704 6 : .ai_family = s.ai_family,
705 6 : .ai_socktype = s.ai_socktype,
706 6 : .ai_protocol = s.ai_protocol,
707 6 : .ai_addrlen = s.ai_addrlen,
708 : };
709 :
710 6 : if (s.ai_addrlen > 0) {
711 6 : ai->ai_addr = memdup((const uint8_t*) *p + sizeof(AddrInfoSerialization), s.ai_addrlen);
712 6 : if (!ai->ai_addr) {
713 0 : free(ai);
714 0 : return -ENOMEM;
715 : }
716 : }
717 :
718 6 : if (s.canonname_len > 0) {
719 1 : ai->ai_canonname = memdup((const uint8_t*) *p + sizeof(AddrInfoSerialization) + s.ai_addrlen, s.canonname_len);
720 1 : if (!ai->ai_canonname) {
721 0 : free(ai->ai_addr);
722 0 : free(ai);
723 0 : return -ENOMEM;
724 : }
725 : }
726 :
727 6 : *length -= l;
728 6 : *ret_ai = ai;
729 6 : *p = ((const uint8_t*) *p) + l;
730 :
731 6 : return 0;
732 : }
733 :
734 3 : static int handle_response(sd_resolve *resolve, const Packet *packet, size_t length) {
735 : const RHeader *resp;
736 : sd_resolve_query *q;
737 : int r;
738 :
739 3 : assert(resolve);
740 3 : assert(packet);
741 :
742 3 : resp = &packet->rheader;
743 3 : assert_return(length >= sizeof(RHeader), -EIO);
744 3 : assert_return(length == resp->length, -EIO);
745 :
746 3 : if (resp->type == RESPONSE_DIED) {
747 0 : resolve->dead = true;
748 0 : return 0;
749 : }
750 :
751 3 : assert(resolve->n_outstanding > 0);
752 3 : resolve->n_outstanding--;
753 :
754 3 : q = lookup_query(resolve, resp->id);
755 3 : if (!q)
756 0 : return 0;
757 :
758 3 : switch (resp->type) {
759 :
760 2 : case RESPONSE_ADDRINFO: {
761 2 : const AddrInfoResponse *ai_resp = &packet->addrinfo_response;
762 : const void *p;
763 : size_t l;
764 2 : struct addrinfo *prev = NULL;
765 :
766 2 : assert_return(length >= sizeof(AddrInfoResponse), -EBADMSG);
767 2 : assert_return(q->type == REQUEST_ADDRINFO, -EBADMSG);
768 :
769 2 : query_assign_errno(q, ai_resp->ret, ai_resp->_errno, ai_resp->_h_errno);
770 :
771 2 : l = length - sizeof(AddrInfoResponse);
772 2 : p = (const uint8_t*) resp + sizeof(AddrInfoResponse);
773 :
774 8 : while (l > 0 && p) {
775 6 : struct addrinfo *ai = NULL;
776 :
777 6 : r = unserialize_addrinfo(&p, &l, &ai);
778 6 : if (r < 0) {
779 0 : query_assign_errno(q, EAI_SYSTEM, r, 0);
780 0 : freeaddrinfo(q->addrinfo);
781 0 : q->addrinfo = NULL;
782 0 : break;
783 : }
784 :
785 6 : if (prev)
786 4 : prev->ai_next = ai;
787 : else
788 2 : q->addrinfo = ai;
789 :
790 6 : prev = ai;
791 : }
792 :
793 2 : return complete_query(resolve, q);
794 : }
795 :
796 1 : case RESPONSE_NAMEINFO: {
797 1 : const NameInfoResponse *ni_resp = &packet->nameinfo_response;
798 :
799 1 : assert_return(length >= sizeof(NameInfoResponse), -EBADMSG);
800 1 : assert_return(q->type == REQUEST_NAMEINFO, -EBADMSG);
801 :
802 1 : if (ni_resp->hostlen > DNS_HOSTNAME_MAX ||
803 1 : ni_resp->servlen > DNS_HOSTNAME_MAX ||
804 1 : sizeof(NameInfoResponse) + ni_resp->hostlen + ni_resp->servlen > length)
805 0 : query_assign_errno(q, EAI_SYSTEM, EIO, 0);
806 : else {
807 1 : query_assign_errno(q, ni_resp->ret, ni_resp->_errno, ni_resp->_h_errno);
808 :
809 1 : if (ni_resp->hostlen > 0) {
810 1 : q->host = strndup((const char*) ni_resp + sizeof(NameInfoResponse),
811 1 : ni_resp->hostlen-1);
812 1 : if (!q->host)
813 0 : query_assign_errno(q, EAI_MEMORY, ENOMEM, 0);
814 : }
815 :
816 1 : if (ni_resp->servlen > 0) {
817 1 : q->serv = strndup((const char*) ni_resp + sizeof(NameInfoResponse) + ni_resp->hostlen,
818 1 : ni_resp->servlen-1);
819 1 : if (!q->serv)
820 0 : query_assign_errno(q, EAI_MEMORY, ENOMEM, 0);
821 : }
822 : }
823 :
824 1 : return complete_query(resolve, q);
825 : }
826 :
827 0 : default:
828 0 : return 0;
829 : }
830 : }
831 :
832 3 : _public_ int sd_resolve_process(sd_resolve *resolve) {
833 6 : RESOLVE_DONT_DESTROY(resolve);
834 :
835 : union {
836 : Packet packet;
837 : uint8_t space[BUFSIZE];
838 : } buf;
839 : ssize_t l;
840 : int r;
841 :
842 3 : assert_return(resolve, -EINVAL);
843 3 : assert_return(!resolve_pid_changed(resolve), -ECHILD);
844 :
845 : /* We don't allow recursively invoking sd_resolve_process(). */
846 3 : assert_return(!resolve->current, -EBUSY);
847 :
848 3 : l = recv(resolve->fds[RESPONSE_RECV_FD], &buf, sizeof buf, 0);
849 3 : if (l < 0) {
850 0 : if (errno == EAGAIN)
851 0 : return 0;
852 :
853 0 : return -errno;
854 : }
855 3 : if (l == 0)
856 0 : return -ECONNREFUSED;
857 :
858 3 : r = handle_response(resolve, &buf.packet, (size_t) l);
859 3 : if (r < 0)
860 0 : return r;
861 :
862 3 : return 1;
863 : }
864 :
865 4 : _public_ int sd_resolve_wait(sd_resolve *resolve, uint64_t timeout_usec) {
866 : int r;
867 :
868 4 : assert_return(resolve, -EINVAL);
869 4 : assert_return(!resolve_pid_changed(resolve), -ECHILD);
870 :
871 4 : if (resolve->n_done >= resolve->n_queries)
872 1 : return 0;
873 :
874 : do {
875 3 : r = fd_wait_for_event(resolve->fds[RESPONSE_RECV_FD], POLLIN, timeout_usec);
876 3 : } while (r == -EINTR);
877 :
878 3 : if (r < 0)
879 0 : return r;
880 3 : if (r == 0)
881 0 : return -ETIMEDOUT;
882 :
883 3 : return sd_resolve_process(resolve);
884 : }
885 :
886 3 : static int alloc_query(sd_resolve *resolve, bool floating, sd_resolve_query **_q) {
887 : sd_resolve_query *q;
888 : int r;
889 :
890 3 : assert(resolve);
891 3 : assert(_q);
892 :
893 3 : if (resolve->n_queries >= QUERIES_MAX)
894 0 : return -ENOBUFS;
895 :
896 3 : r = start_threads(resolve, 1);
897 3 : if (r < 0)
898 0 : return r;
899 :
900 3 : while (resolve->query_array[resolve->current_id % QUERIES_MAX])
901 0 : resolve->current_id++;
902 :
903 3 : q = resolve->query_array[resolve->current_id % QUERIES_MAX] = new0(sd_resolve_query, 1);
904 3 : if (!q)
905 0 : return -ENOMEM;
906 :
907 3 : q->n_ref = 1;
908 3 : q->resolve = resolve;
909 3 : q->floating = floating;
910 3 : q->id = resolve->current_id++;
911 :
912 3 : if (!floating)
913 2 : sd_resolve_ref(resolve);
914 :
915 3 : LIST_PREPEND(queries, resolve->queries, q);
916 3 : resolve->n_queries++;
917 :
918 3 : *_q = q;
919 3 : return 0;
920 : }
921 :
922 2 : int resolve_getaddrinfo_with_destroy_callback(
923 : sd_resolve *resolve,
924 : sd_resolve_query **ret_query,
925 : const char *node, const char *service,
926 : const struct addrinfo *hints,
927 : sd_resolve_getaddrinfo_handler_t callback,
928 : sd_resolve_destroy_t destroy_callback,
929 : void *userdata) {
930 :
931 2 : _cleanup_(sd_resolve_query_unrefp) sd_resolve_query *q = NULL;
932 : size_t node_len, service_len;
933 2 : AddrInfoRequest req = {};
934 : struct iovec iov[3];
935 2 : struct msghdr mh = {};
936 : int r;
937 :
938 2 : assert_return(resolve, -EINVAL);
939 2 : assert_return(node || service, -EINVAL);
940 2 : assert_return(callback, -EINVAL);
941 2 : assert_return(!resolve_pid_changed(resolve), -ECHILD);
942 :
943 2 : r = alloc_query(resolve, !ret_query, &q);
944 2 : if (r < 0)
945 0 : return r;
946 :
947 2 : q->type = REQUEST_ADDRINFO;
948 2 : q->getaddrinfo_handler = callback;
949 2 : q->userdata = userdata;
950 :
951 2 : node_len = node ? strlen(node) + 1 : 0;
952 2 : service_len = service ? strlen(service) + 1 : 0;
953 :
954 4 : req = (AddrInfoRequest) {
955 : .node_len = node_len,
956 : .service_len = service_len,
957 :
958 2 : .header.id = q->id,
959 : .header.type = REQUEST_ADDRINFO,
960 2 : .header.length = sizeof(AddrInfoRequest) + node_len + service_len,
961 :
962 : .hints_valid = hints,
963 2 : .ai_flags = hints ? hints->ai_flags : 0,
964 2 : .ai_family = hints ? hints->ai_family : 0,
965 2 : .ai_socktype = hints ? hints->ai_socktype : 0,
966 2 : .ai_protocol = hints ? hints->ai_protocol : 0,
967 : };
968 :
969 : msan_unpoison(&req, sizeof(req));
970 :
971 2 : iov[mh.msg_iovlen++] = IOVEC_MAKE(&req, sizeof(AddrInfoRequest));
972 2 : if (node)
973 2 : iov[mh.msg_iovlen++] = IOVEC_MAKE((void*) node, req.node_len);
974 2 : if (service)
975 1 : iov[mh.msg_iovlen++] = IOVEC_MAKE((void*) service, req.service_len);
976 2 : mh.msg_iov = iov;
977 :
978 2 : if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0)
979 0 : return -errno;
980 :
981 2 : resolve->n_outstanding++;
982 2 : q->destroy_callback = destroy_callback;
983 :
984 2 : if (ret_query)
985 1 : *ret_query = q;
986 :
987 2 : TAKE_PTR(q);
988 :
989 2 : return 0;
990 : }
991 :
992 2 : _public_ int sd_resolve_getaddrinfo(
993 : sd_resolve *resolve,
994 : sd_resolve_query **ret_query,
995 : const char *node, const char *service,
996 : const struct addrinfo *hints,
997 : sd_resolve_getaddrinfo_handler_t callback,
998 : void *userdata) {
999 :
1000 2 : return resolve_getaddrinfo_with_destroy_callback(resolve, ret_query, node, service, hints, callback, NULL, userdata);
1001 : }
1002 :
1003 2 : static int getaddrinfo_done(sd_resolve_query* q) {
1004 2 : assert(q);
1005 2 : assert(q->done);
1006 2 : assert(q->getaddrinfo_handler);
1007 :
1008 2 : errno = q->_errno;
1009 2 : h_errno = q->_h_errno;
1010 :
1011 2 : return q->getaddrinfo_handler(q, q->ret, q->addrinfo, q->userdata);
1012 : }
1013 :
1014 1 : int resolve_getnameinfo_with_destroy_callback(
1015 : sd_resolve *resolve,
1016 : sd_resolve_query **ret_query,
1017 : const struct sockaddr *sa, socklen_t salen,
1018 : int flags,
1019 : uint64_t get,
1020 : sd_resolve_getnameinfo_handler_t callback,
1021 : sd_resolve_destroy_t destroy_callback,
1022 : void *userdata) {
1023 :
1024 1 : _cleanup_(sd_resolve_query_unrefp) sd_resolve_query *q = NULL;
1025 1 : NameInfoRequest req = {};
1026 : struct iovec iov[2];
1027 : struct msghdr mh;
1028 : int r;
1029 :
1030 1 : assert_return(resolve, -EINVAL);
1031 1 : assert_return(sa, -EINVAL);
1032 1 : assert_return(salen >= sizeof(struct sockaddr), -EINVAL);
1033 1 : assert_return(salen <= sizeof(union sockaddr_union), -EINVAL);
1034 1 : assert_return((get & ~SD_RESOLVE_GET_BOTH) == 0, -EINVAL);
1035 1 : assert_return(callback, -EINVAL);
1036 1 : assert_return(!resolve_pid_changed(resolve), -ECHILD);
1037 :
1038 1 : r = alloc_query(resolve, !ret_query, &q);
1039 1 : if (r < 0)
1040 0 : return r;
1041 :
1042 1 : q->type = REQUEST_NAMEINFO;
1043 1 : q->getnameinfo_handler = callback;
1044 1 : q->userdata = userdata;
1045 :
1046 1 : req = (NameInfoRequest) {
1047 1 : .header.id = q->id,
1048 : .header.type = REQUEST_NAMEINFO,
1049 1 : .header.length = sizeof(NameInfoRequest) + salen,
1050 :
1051 : .flags = flags,
1052 : .sockaddr_len = salen,
1053 1 : .gethost = !!(get & SD_RESOLVE_GET_HOST),
1054 1 : .getserv = !!(get & SD_RESOLVE_GET_SERVICE),
1055 : };
1056 :
1057 : msan_unpoison(&req, sizeof(req));
1058 :
1059 1 : iov[0] = IOVEC_MAKE(&req, sizeof(NameInfoRequest));
1060 1 : iov[1] = IOVEC_MAKE((void*) sa, salen);
1061 :
1062 1 : mh = (struct msghdr) {
1063 : .msg_iov = iov,
1064 : .msg_iovlen = ELEMENTSOF(iov)
1065 : };
1066 :
1067 1 : if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0)
1068 0 : return -errno;
1069 :
1070 1 : resolve->n_outstanding++;
1071 1 : q->destroy_callback = destroy_callback;
1072 :
1073 1 : if (ret_query)
1074 1 : *ret_query = q;
1075 :
1076 1 : TAKE_PTR(q);
1077 :
1078 1 : return 0;
1079 : }
1080 :
1081 1 : _public_ int sd_resolve_getnameinfo(
1082 : sd_resolve *resolve,
1083 : sd_resolve_query **ret_query,
1084 : const struct sockaddr *sa, socklen_t salen,
1085 : int flags,
1086 : uint64_t get,
1087 : sd_resolve_getnameinfo_handler_t callback,
1088 : void *userdata) {
1089 :
1090 1 : return resolve_getnameinfo_with_destroy_callback(resolve, ret_query, sa, salen, flags, get, callback, NULL, userdata);
1091 : }
1092 :
1093 1 : static int getnameinfo_done(sd_resolve_query *q) {
1094 :
1095 1 : assert(q);
1096 1 : assert(q->done);
1097 1 : assert(q->getnameinfo_handler);
1098 :
1099 1 : errno = q->_errno;
1100 1 : h_errno = q->_h_errno;
1101 :
1102 1 : return q->getnameinfo_handler(q, q->ret, q->host, q->serv, q->userdata);
1103 : }
1104 :
1105 3 : static void resolve_freeaddrinfo(struct addrinfo *ai) {
1106 9 : while (ai) {
1107 6 : struct addrinfo *next = ai->ai_next;
1108 :
1109 6 : free(ai->ai_addr);
1110 6 : free(ai->ai_canonname);
1111 6 : free(ai);
1112 6 : ai = next;
1113 : }
1114 3 : }
1115 :
1116 4 : static void resolve_query_disconnect(sd_resolve_query *q) {
1117 : sd_resolve *resolve;
1118 : unsigned i;
1119 :
1120 4 : assert(q);
1121 :
1122 4 : if (!q->resolve)
1123 1 : return;
1124 :
1125 3 : resolve = q->resolve;
1126 3 : assert(resolve->n_queries > 0);
1127 :
1128 3 : if (q->done) {
1129 3 : assert(resolve->n_done > 0);
1130 3 : resolve->n_done--;
1131 : }
1132 :
1133 3 : i = q->id % QUERIES_MAX;
1134 3 : assert(resolve->query_array[i] == q);
1135 3 : resolve->query_array[i] = NULL;
1136 3 : LIST_REMOVE(queries, resolve->queries, q);
1137 3 : resolve->n_queries--;
1138 :
1139 3 : q->resolve = NULL;
1140 3 : if (!q->floating)
1141 2 : sd_resolve_unref(resolve);
1142 : }
1143 :
1144 3 : static sd_resolve_query *resolve_query_free(sd_resolve_query *q) {
1145 3 : assert(q);
1146 :
1147 3 : resolve_query_disconnect(q);
1148 :
1149 3 : if (q->destroy_callback)
1150 0 : q->destroy_callback(q->userdata);
1151 :
1152 3 : resolve_freeaddrinfo(q->addrinfo);
1153 3 : free(q->host);
1154 3 : free(q->serv);
1155 :
1156 3 : return mfree(q);
1157 : }
1158 :
1159 10 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_resolve_query, sd_resolve_query, resolve_query_free);
1160 :
1161 0 : _public_ int sd_resolve_query_is_done(sd_resolve_query *q) {
1162 0 : assert_return(q, -EINVAL);
1163 0 : assert_return(!resolve_pid_changed(q->resolve), -ECHILD);
1164 :
1165 0 : return q->done;
1166 : }
1167 :
1168 0 : _public_ void* sd_resolve_query_set_userdata(sd_resolve_query *q, void *userdata) {
1169 : void *ret;
1170 :
1171 0 : assert_return(q, NULL);
1172 0 : assert_return(!resolve_pid_changed(q->resolve), NULL);
1173 :
1174 0 : ret = q->userdata;
1175 0 : q->userdata = userdata;
1176 :
1177 0 : return ret;
1178 : }
1179 :
1180 0 : _public_ void* sd_resolve_query_get_userdata(sd_resolve_query *q) {
1181 0 : assert_return(q, NULL);
1182 0 : assert_return(!resolve_pid_changed(q->resolve), NULL);
1183 :
1184 0 : return q->userdata;
1185 : }
1186 :
1187 0 : _public_ sd_resolve *sd_resolve_query_get_resolve(sd_resolve_query *q) {
1188 0 : assert_return(q, NULL);
1189 0 : assert_return(!resolve_pid_changed(q->resolve), NULL);
1190 :
1191 0 : return q->resolve;
1192 : }
1193 :
1194 0 : _public_ int sd_resolve_query_get_destroy_callback(sd_resolve_query *q, sd_resolve_destroy_t *destroy_callback) {
1195 0 : assert_return(q, -EINVAL);
1196 :
1197 0 : if (destroy_callback)
1198 0 : *destroy_callback = q->destroy_callback;
1199 :
1200 0 : return !!q->destroy_callback;
1201 : }
1202 :
1203 0 : _public_ int sd_resolve_query_set_destroy_callback(sd_resolve_query *q, sd_resolve_destroy_t destroy_callback) {
1204 0 : assert_return(q, -EINVAL);
1205 :
1206 0 : q->destroy_callback = destroy_callback;
1207 0 : return 0;
1208 : }
1209 :
1210 0 : _public_ int sd_resolve_query_get_floating(sd_resolve_query *q) {
1211 0 : assert_return(q, -EINVAL);
1212 :
1213 0 : return q->floating;
1214 : }
1215 :
1216 0 : _public_ int sd_resolve_query_set_floating(sd_resolve_query *q, int b) {
1217 0 : assert_return(q, -EINVAL);
1218 :
1219 0 : if (q->floating == !!b)
1220 0 : return 0;
1221 :
1222 0 : if (!q->resolve) /* Already disconnected */
1223 0 : return -ESTALE;
1224 :
1225 0 : q->floating = b;
1226 :
1227 0 : if (b) {
1228 0 : sd_resolve_query_ref(q);
1229 0 : sd_resolve_unref(q->resolve);
1230 : } else {
1231 0 : sd_resolve_ref(q->resolve);
1232 0 : sd_resolve_query_unref(q);
1233 : }
1234 :
1235 0 : return 1;
1236 : }
1237 :
1238 0 : static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
1239 0 : sd_resolve *resolve = userdata;
1240 : int r;
1241 :
1242 0 : assert(resolve);
1243 :
1244 0 : r = sd_resolve_process(resolve);
1245 0 : if (r < 0)
1246 0 : return r;
1247 :
1248 0 : return 1;
1249 : }
1250 :
1251 2 : _public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int64_t priority) {
1252 : int r;
1253 :
1254 2 : assert_return(resolve, -EINVAL);
1255 2 : assert_return(!resolve->event, -EBUSY);
1256 :
1257 2 : assert(!resolve->event_source);
1258 :
1259 2 : if (event)
1260 2 : resolve->event = sd_event_ref(event);
1261 : else {
1262 0 : r = sd_event_default(&resolve->event);
1263 0 : if (r < 0)
1264 0 : return r;
1265 : }
1266 :
1267 2 : r = sd_event_add_io(resolve->event, &resolve->event_source, resolve->fds[RESPONSE_RECV_FD], POLLIN, io_callback, resolve);
1268 2 : if (r < 0)
1269 0 : goto fail;
1270 :
1271 2 : r = sd_event_source_set_priority(resolve->event_source, priority);
1272 2 : if (r < 0)
1273 0 : goto fail;
1274 :
1275 2 : return 0;
1276 :
1277 0 : fail:
1278 0 : sd_resolve_detach_event(resolve);
1279 0 : return r;
1280 : }
1281 :
1282 3 : _public_ int sd_resolve_detach_event(sd_resolve *resolve) {
1283 3 : assert_return(resolve, -EINVAL);
1284 :
1285 3 : if (!resolve->event)
1286 1 : return 0;
1287 :
1288 2 : if (resolve->event_source) {
1289 2 : sd_event_source_set_enabled(resolve->event_source, SD_EVENT_OFF);
1290 2 : resolve->event_source = sd_event_source_unref(resolve->event_source);
1291 : }
1292 :
1293 2 : resolve->event = sd_event_unref(resolve->event);
1294 2 : return 1;
1295 : }
1296 :
1297 0 : _public_ sd_event *sd_resolve_get_event(sd_resolve *resolve) {
1298 0 : assert_return(resolve, NULL);
1299 :
1300 0 : return resolve->event;
1301 : }
|