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