1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2005-2008 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include <sys/select.h>
32 #include <sys/types.h>
34 #include <netinet/in.h>
35 #include <arpa/nameser.h>
39 #include <sys/resource.h>
42 #include <sys/prctl.h>
44 #include "sd-resolve.h"
47 #define MAX_WORKERS 16
48 #define MAX_QUERIES 256
49 #define BUFSIZE (10240)
72 int fds[MESSAGE_FD_MAX];
74 pthread_t workers[MAX_WORKERS];
75 unsigned valid_workers;
77 unsigned current_id, current_index;
78 sd_resolve_query* queries[MAX_QUERIES];
80 sd_resolve_query *done_head, *done_tail;
86 struct sd_resolve_query {
91 sd_resolve_query *done_next, *done_prev;
95 struct addrinfo *addrinfo;
100 typedef struct RHeader {
106 typedef struct AddrInfoRequest {
107 struct RHeader header;
113 size_t node_len, service_len;
116 typedef struct AddrInfoResponse {
117 struct RHeader header;
121 /* followed by addrinfo_serialization[] */
124 typedef struct AddrInfoSerialization {
130 size_t canonname_len;
131 /* Followed by ai_addr amd ai_canonname with variable lengths */
132 } AddrInfoSerialization;
134 typedef struct NameInfoRequest {
135 struct RHeader header;
137 socklen_t sockaddr_len;
138 int gethost, getserv;
141 typedef struct NameInfoResponse {
142 struct RHeader header;
143 size_t hostlen, servlen;
149 typedef struct ResRequest {
150 struct RHeader header;
156 typedef struct ResResponse {
157 struct RHeader header;
163 typedef union Packet {
165 AddrInfoRequest addrinfo_request;
166 AddrInfoResponse addrinfo_response;
167 NameInfoRequest nameinfo_request;
168 NameInfoResponse nameinfo_response;
169 ResRequest res_request;
170 ResResponse res_response;
173 static int send_died(int out_fd) {
177 rh.type = RESPONSE_DIED;
179 rh.length = sizeof(rh);
181 return send(out_fd, &rh, rh.length, MSG_NOSIGNAL);
184 static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) {
185 AddrInfoSerialization s;
190 assert(*length <= maxlength);
192 cnl = (ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0);
193 l = sizeof(AddrInfoSerialization) + ai->ai_addrlen + cnl;
195 if (*length + l > maxlength)
198 s.ai_flags = ai->ai_flags;
199 s.ai_family = ai->ai_family;
200 s.ai_socktype = ai->ai_socktype;
201 s.ai_protocol = ai->ai_protocol;
202 s.ai_addrlen = ai->ai_addrlen;
203 s.canonname_len = cnl;
205 memcpy((uint8_t*) p, &s, sizeof(AddrInfoSerialization));
206 memcpy((uint8_t*) p + sizeof(AddrInfoSerialization), ai->ai_addr, ai->ai_addrlen);
208 if (ai->ai_canonname)
209 strcpy((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen, ai->ai_canonname);
212 return (uint8_t*) p + l;
215 static int send_addrinfo_reply(int out_fd, unsigned id, int ret, struct addrinfo *ai, int _errno, int _h_errno) {
216 AddrInfoResponse data[BUFSIZE/sizeof(AddrInfoResponse) + 1] = {};
217 AddrInfoResponse *resp = data;
220 resp->header.type = RESPONSE_ADDRINFO;
221 resp->header.id = id;
222 resp->header.length = sizeof(AddrInfoResponse);
224 resp->_errno = _errno;
225 resp->_h_errno = _h_errno;
227 if (ret == 0 && ai) {
231 for (k = ai; k; k = k->ai_next) {
232 p = serialize_addrinfo(p, k, &resp->header.length, (char*) data + BUFSIZE - (char*) p);
234 resp->ret = EAI_MEMORY;
243 return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
246 static int send_nameinfo_reply(int out_fd, unsigned id, int ret, const char *host, const char *serv, int _errno, int _h_errno) {
247 NameInfoResponse data[BUFSIZE/sizeof(NameInfoResponse) + 1] = {};
249 NameInfoResponse *resp = data;
253 sl = serv ? strlen(serv)+1 : 0;
254 hl = host ? strlen(host)+1 : 0;
256 resp->header.type = RESPONSE_NAMEINFO;
257 resp->header.id = id;
258 resp->header.length = sizeof(NameInfoResponse) + hl + sl;
260 resp->_errno = _errno;
261 resp->_h_errno = _h_errno;
265 assert(sizeof(data) >= resp->header.length);
268 memcpy((uint8_t *)data + sizeof(NameInfoResponse), host, hl);
271 memcpy((uint8_t *)data + sizeof(NameInfoResponse) + hl, serv, sl);
273 return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
276 static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret, int _errno, int _h_errno) {
277 ResResponse data[BUFSIZE/sizeof(ResResponse) + 1] = {};
278 ResResponse *resp = data;
282 resp->header.type = RESPONSE_RES;
283 resp->header.id = id;
284 resp->header.length = sizeof(ResResponse) + (ret < 0 ? 0 : ret);
286 resp->_errno = _errno;
287 resp->_h_errno = _h_errno;
289 assert(sizeof(data) >= resp->header.length);
292 memcpy((uint8_t *)data + sizeof(ResResponse), answer, ret);
294 return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
297 static int handle_request(int out_fd, const Packet *packet, size_t length) {
301 req = &packet->rheader;
303 assert(length >= sizeof(RHeader));
304 assert(length == req->length);
307 case REQUEST_ADDRINFO: {
308 struct addrinfo ai = {}, *result = NULL;
309 const AddrInfoRequest *ai_req = &packet->addrinfo_request;
310 const char *node, *service;
313 assert(length >= sizeof(AddrInfoRequest));
314 assert(length == sizeof(AddrInfoRequest) + ai_req->node_len + ai_req->service_len);
316 ai.ai_flags = ai_req->ai_flags;
317 ai.ai_family = ai_req->ai_family;
318 ai.ai_socktype = ai_req->ai_socktype;
319 ai.ai_protocol = ai_req->ai_protocol;
321 node = ai_req->node_len ? (const char*) ai_req + sizeof(AddrInfoRequest) : NULL;
322 service = ai_req->service_len ? (const char*) ai_req + sizeof(AddrInfoRequest) + ai_req->node_len : NULL;
324 ret = getaddrinfo(node, service,
325 ai_req->hints_is_null ? NULL : &ai,
328 /* send_addrinfo_reply() frees result */
329 return send_addrinfo_reply(out_fd, req->id, ret, result, errno, h_errno);
332 case REQUEST_NAMEINFO: {
334 const NameInfoRequest *ni_req = &packet->nameinfo_request;
335 char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV];
336 struct sockaddr_storage sa;
338 assert(length >= sizeof(NameInfoRequest));
339 assert(length == sizeof(NameInfoRequest) + ni_req->sockaddr_len);
341 memcpy(&sa, (const uint8_t *) ni_req + sizeof(NameInfoRequest), ni_req->sockaddr_len);
343 ret = getnameinfo((struct sockaddr *)&sa, ni_req->sockaddr_len,
344 ni_req->gethost ? hostbuf : NULL, ni_req->gethost ? sizeof(hostbuf) : 0,
345 ni_req->getserv ? servbuf : NULL, ni_req->getserv ? sizeof(servbuf) : 0,
348 return send_nameinfo_reply(out_fd, req->id, ret,
349 ret == 0 && ni_req->gethost ? hostbuf : NULL,
350 ret == 0 && ni_req->getserv ? servbuf : NULL,
354 case REQUEST_RES_QUERY:
355 case REQUEST_RES_SEARCH: {
357 HEADER answer[BUFSIZE/sizeof(HEADER) + 1];
358 const ResRequest *res_req = &packet->res_request;
361 assert(length >= sizeof(ResRequest));
362 assert(length == sizeof(ResRequest) + res_req->dname_len);
364 dname = (const char *) req + sizeof(ResRequest);
366 if (req->type == REQUEST_RES_QUERY)
367 ret = res_query(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE);
369 ret = res_search(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE);
371 return send_res_reply(out_fd, req->id, (unsigned char *) answer, ret, errno, h_errno);
374 case REQUEST_TERMINATE:
385 static void* thread_worker(void *p) {
386 sd_resolve *resolve = p;
389 /* No signals in this thread please */
390 sigfillset(&fullset);
391 pthread_sigmask(SIG_BLOCK, &fullset, NULL);
393 while (!resolve->dead) {
394 Packet buf[BUFSIZE/sizeof(Packet) + 1];
397 length = recv(resolve->fds[REQUEST_RECV_FD], buf, sizeof(buf), 0);
400 if (length < 0 && (errno == EAGAIN || errno == EINTR))
408 if (handle_request(resolve->fds[RESPONSE_SEND_FD], buf, (size_t) length) < 0)
412 send_died(resolve->fds[RESPONSE_SEND_FD]);
417 _public_ sd_resolve* sd_resolve_new(unsigned n_proc) {
418 sd_resolve *resolve = NULL;
423 if (n_proc > MAX_WORKERS)
424 n_proc = MAX_WORKERS;
426 resolve = new(sd_resolve, 1);
433 resolve->valid_workers = 0;
435 for (i = 0; i < MESSAGE_FD_MAX; i++)
436 resolve->fds[i] = -1;
438 memset(resolve->queries, 0, sizeof(resolve->queries));
440 r = socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds);
444 r = socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds+2);
448 for (resolve->valid_workers = 0; resolve->valid_workers < n_proc; resolve->valid_workers++) {
449 r = pthread_create(&resolve->workers[resolve->valid_workers], NULL, thread_worker, resolve);
456 resolve->current_index = resolve->current_id = 0;
457 resolve->done_head = resolve->done_tail = NULL;
458 resolve->n_queries = 0;
460 fd_nonblock(resolve->fds[RESPONSE_RECV_FD], true);
466 sd_resolve_free(resolve);
471 _public_ void sd_resolve_free(sd_resolve *resolve) {
473 int saved_errno = errno;
480 if (resolve->fds[REQUEST_SEND_FD] >= 0) {
483 req.type = REQUEST_TERMINATE;
484 req.length = sizeof(req);
487 /* Send one termination packet for each worker */
488 for (p = 0; p < resolve->valid_workers; p++)
489 send(resolve->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL);
492 /* Now terminate them and wait until they are gone. */
493 for (p = 0; p < resolve->valid_workers; p++) {
495 if (pthread_join(resolve->workers[p], NULL) != EINTR)
500 /* Close all communication channels */
501 for (i = 0; i < MESSAGE_FD_MAX; i++)
502 if (resolve->fds[i] >= 0)
503 close(resolve->fds[i]);
505 for (p = 0; p < MAX_QUERIES; p++)
506 if (resolve->queries[p])
507 sd_resolve_cancel(resolve, resolve->queries[p]);
514 _public_ int sd_resolve_fd(sd_resolve *resolve) {
517 return resolve->fds[RESPONSE_RECV_FD];
520 static sd_resolve_query *lookup_query(sd_resolve *resolve, unsigned id) {
524 q = resolve->queries[id % MAX_QUERIES];
532 static void complete_query(sd_resolve *resolve, sd_resolve_query *q) {
539 if ((q->done_prev = resolve->done_tail))
540 resolve->done_tail->done_next = q;
542 resolve->done_head = q;
544 resolve->done_tail = q;
548 static const void *unserialize_addrinfo(const void *p, struct addrinfo **ret_ai, size_t *length) {
549 AddrInfoSerialization s;
556 if (*length < sizeof(AddrInfoSerialization))
559 memcpy(&s, p, sizeof(s));
561 l = sizeof(AddrInfoSerialization) + s.ai_addrlen + s.canonname_len;
565 ai = new(struct addrinfo, 1);
570 ai->ai_canonname = NULL;
573 if (s.ai_addrlen && !(ai->ai_addr = malloc(s.ai_addrlen)))
576 if (s.canonname_len && !(ai->ai_canonname = malloc(s.canonname_len)))
579 ai->ai_flags = s.ai_flags;
580 ai->ai_family = s.ai_family;
581 ai->ai_socktype = s.ai_socktype;
582 ai->ai_protocol = s.ai_protocol;
583 ai->ai_addrlen = s.ai_addrlen;
586 memcpy(ai->ai_addr, (const uint8_t*) p + sizeof(AddrInfoSerialization), s.ai_addrlen);
588 if (ai->ai_canonname)
589 memcpy(ai->ai_canonname, (const uint8_t*) p + sizeof(AddrInfoSerialization) + s.ai_addrlen, s.canonname_len);
594 return (const uint8_t*) p + l;
599 sd_resolve_freeaddrinfo(ai);
604 static int handle_response(sd_resolve *resolve, const Packet *packet, size_t length) {
610 resp = &packet->rheader;
612 assert(length >= sizeof(RHeader));
613 assert(length == resp->length);
615 if (resp->type == RESPONSE_DIED) {
620 q = lookup_query(resolve, resp->id);
624 switch (resp->type) {
625 case RESPONSE_ADDRINFO: {
626 const AddrInfoResponse *ai_resp = &packet->addrinfo_response;
629 struct addrinfo *prev = NULL;
631 assert(length >= sizeof(AddrInfoResponse));
632 assert(q->type == REQUEST_ADDRINFO);
634 q->ret = ai_resp->ret;
635 q->_errno = ai_resp->_errno;
636 q->_h_errno = ai_resp->_h_errno;
637 l = length - sizeof(AddrInfoResponse);
638 p = (const uint8_t*) resp + sizeof(AddrInfoResponse);
641 struct addrinfo *ai = NULL;
642 p = unserialize_addrinfo(p, &ai, &l);
657 complete_query(resolve, q);
661 case RESPONSE_NAMEINFO: {
662 const NameInfoResponse *ni_resp = &packet->nameinfo_response;
664 assert(length >= sizeof(NameInfoResponse));
665 assert(q->type == REQUEST_NAMEINFO);
667 q->ret = ni_resp->ret;
668 q->_errno = ni_resp->_errno;
669 q->_h_errno = ni_resp->_h_errno;
671 if (ni_resp->hostlen)
672 if (!(q->host = strndup((const char*) ni_resp + sizeof(NameInfoResponse), ni_resp->hostlen-1)))
675 if (ni_resp->servlen)
676 if (!(q->serv = strndup((const char*) ni_resp + sizeof(NameInfoResponse) + ni_resp->hostlen, ni_resp->servlen-1)))
679 complete_query(resolve, q);
684 const ResResponse *res_resp = &packet->res_response;
686 assert(length >= sizeof(ResResponse));
687 assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
689 q->ret = res_resp->ret;
690 q->_errno = res_resp->_errno;
691 q->_h_errno = res_resp->_h_errno;
693 if (res_resp->ret >= 0) {
694 if (!(q->serv = malloc(res_resp->ret))) {
698 memcpy(q->serv, (const char *)resp + sizeof(ResResponse), res_resp->ret);
701 complete_query(resolve, q);
712 _public_ int sd_resolve_wait(sd_resolve *resolve, int block) {
717 Packet buf[BUFSIZE/sizeof(Packet) + 1];
725 l = recv(resolve->fds[RESPONSE_RECV_FD], buf, sizeof(buf), 0);
732 if (!block || handled)
736 FD_SET(resolve->fds[RESPONSE_RECV_FD], &fds);
738 if (select(resolve->fds[RESPONSE_RECV_FD]+1, &fds, NULL, NULL, NULL) < 0)
744 if (handle_response(resolve, buf, (size_t) l) < 0)
751 static sd_resolve_query *alloc_query(sd_resolve *resolve) {
755 if (resolve->n_queries >= MAX_QUERIES) {
760 while (resolve->queries[resolve->current_index]) {
761 resolve->current_index++;
762 resolve->current_id++;
764 while (resolve->current_index >= MAX_QUERIES)
765 resolve->current_index -= MAX_QUERIES;
768 q = resolve->queries[resolve->current_index] = new(sd_resolve_query, 1);
774 resolve->n_queries++;
776 q->resolve = resolve;
778 q->id = resolve->current_id;
779 q->done_next = q->done_prev = NULL;
785 q->host = q->serv = NULL;
790 _public_ sd_resolve_query* sd_resolve_getaddrinfo(sd_resolve *resolve, const char *node, const char *service, const struct addrinfo *hints) {
791 AddrInfoRequest data[BUFSIZE/sizeof(AddrInfoRequest) + 1] = {};
792 AddrInfoRequest *req = data;
795 assert(node || service);
802 q = alloc_query(resolve);
806 req->node_len = node ? strlen(node)+1 : 0;
807 req->service_len = service ? strlen(service)+1 : 0;
809 req->header.id = q->id;
810 req->header.type = q->type = REQUEST_ADDRINFO;
811 req->header.length = sizeof(AddrInfoRequest) + req->node_len + req->service_len;
813 if (req->header.length > BUFSIZE) {
818 if (!(req->hints_is_null = !hints)) {
819 req->ai_flags = hints->ai_flags;
820 req->ai_family = hints->ai_family;
821 req->ai_socktype = hints->ai_socktype;
822 req->ai_protocol = hints->ai_protocol;
826 strcpy((char*) req + sizeof(AddrInfoRequest), node);
829 strcpy((char*) req + sizeof(AddrInfoRequest) + req->node_len, service);
831 if (send(resolve->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
838 sd_resolve_cancel(resolve, q);
843 _public_ int sd_resolve_getaddrinfo_done(sd_resolve *resolve, sd_resolve_query* q, struct addrinfo **ret_res) {
847 assert(q->resolve == resolve);
848 assert(q->type == REQUEST_ADDRINFO);
858 *ret_res = q->addrinfo;
863 if (ret == EAI_SYSTEM)
867 h_errno = q->_h_errno;
869 sd_resolve_cancel(resolve, q);
874 _public_ sd_resolve_query* sd_resolve_getnameinfo(sd_resolve *resolve, const struct sockaddr *sa, socklen_t salen, int flags, int gethost, int getserv) {
875 NameInfoRequest data[BUFSIZE/sizeof(NameInfoRequest) + 1] = {};
876 NameInfoRequest *req = data;
888 q = alloc_query(resolve);
892 req->header.id = q->id;
893 req->header.type = q->type = REQUEST_NAMEINFO;
894 req->header.length = sizeof(NameInfoRequest) + salen;
896 if (req->header.length > BUFSIZE) {
902 req->sockaddr_len = salen;
903 req->gethost = gethost;
904 req->getserv = getserv;
906 memcpy((uint8_t*) req + sizeof(NameInfoRequest), sa, salen);
908 if (send(resolve->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
915 sd_resolve_cancel(resolve, q);
920 _public_ int sd_resolve_getnameinfo_done(sd_resolve *resolve, sd_resolve_query* q, char *ret_host, size_t hostlen, char *ret_serv, size_t servlen) {
924 assert(q->resolve == resolve);
925 assert(q->type == REQUEST_NAMEINFO);
926 assert(!ret_host || hostlen);
927 assert(!ret_serv || servlen);
937 if (ret_host && q->host) {
938 strncpy(ret_host, q->host, hostlen);
939 ret_host[hostlen-1] = 0;
942 if (ret_serv && q->serv) {
943 strncpy(ret_serv, q->serv, servlen);
944 ret_serv[servlen-1] = 0;
949 if (ret == EAI_SYSTEM)
953 h_errno = q->_h_errno;
955 sd_resolve_cancel(resolve, q);
960 static sd_resolve_query * resolve_res(sd_resolve *resolve, QueryType qtype, const char *dname, int class, int type) {
961 ResRequest data[BUFSIZE/sizeof(ResRequest) + 1];
962 ResRequest *req = data;
973 q = alloc_query(resolve);
977 req->dname_len = strlen(dname) + 1;
979 req->header.id = q->id;
980 req->header.type = q->type = qtype;
981 req->header.length = sizeof(ResRequest) + req->dname_len;
983 if (req->header.length > BUFSIZE) {
991 strcpy((char*) req + sizeof(ResRequest), dname);
993 if (send(resolve->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
1000 sd_resolve_cancel(resolve, q);
1005 _public_ sd_resolve_query* sd_resolve_res_query(sd_resolve *resolve, const char *dname, int class, int type) {
1006 return resolve_res(resolve, REQUEST_RES_QUERY, dname, class, type);
1009 _public_ sd_resolve_query* sd_resolve_res_search(sd_resolve *resolve, const char *dname, int class, int type) {
1010 return resolve_res(resolve, REQUEST_RES_SEARCH, dname, class, type);
1013 _public_ int sd_resolve_res_done(sd_resolve *resolve, sd_resolve_query* q, unsigned char **answer) {
1017 assert(q->resolve == resolve);
1018 assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
1021 if (resolve->dead) {
1031 *answer = (unsigned char *)q->serv;
1038 h_errno = q->_h_errno;
1041 sd_resolve_cancel(resolve, q);
1043 return ret < 0 ? -errno : ret;
1046 _public_ sd_resolve_query* sd_resolve_get_next(sd_resolve *resolve) {
1048 return resolve->done_head;
1051 _public_ int sd_resolve_get_n_queries(sd_resolve *resolve) {
1053 return resolve->n_queries;
1056 _public_ void sd_resolve_cancel(sd_resolve *resolve, sd_resolve_query* q) {
1058 int saved_errno = errno;
1062 assert(q->resolve == resolve);
1063 assert(resolve->n_queries > 0);
1068 q->done_prev->done_next = q->done_next;
1070 resolve->done_head = q->done_next;
1073 q->done_next->done_prev = q->done_prev;
1075 resolve->done_tail = q->done_prev;
1078 i = q->id % MAX_QUERIES;
1079 assert(resolve->queries[i] == q);
1080 resolve->queries[i] = NULL;
1082 sd_resolve_freeaddrinfo(q->addrinfo);
1086 resolve->n_queries--;
1089 errno = saved_errno;
1092 _public_ void sd_resolve_freeaddrinfo(struct addrinfo *ai) {
1093 int saved_errno = errno;
1096 struct addrinfo *next = ai->ai_next;
1099 free(ai->ai_canonname);
1105 errno = saved_errno;
1108 _public_ int sd_resolve_isdone(sd_resolve *resolve, sd_resolve_query*q) {
1111 assert(q->resolve == resolve);
1116 _public_ void sd_resolve_setuserdata(sd_resolve *resolve, sd_resolve_query *q, void *userdata) {
1119 assert(q->resolve = resolve);
1121 q->userdata = userdata;
1124 _public_ void* sd_resolve_getuserdata(sd_resolve *resolve, sd_resolve_query *q) {
1127 assert(q->resolve = resolve);