sd-dns.c revision e963e3ada17e7592ad499b9d7fbb3355287a05ca
19aadacf92ad86967ffb678e37b2ff9e83cb9480Jan Engelhardt This file is part of libasyncns.
cff452c7e974db5053cdbd0d7bbbab2e3b4c91b9Kay Sievers Copyright 2005-2008 Lennart Poettering
cff452c7e974db5053cdbd0d7bbbab2e3b4c91b9Kay Sievers libasyncns is free software; you can redistribute it and/or modify
f957632b960a0a42999b38ded7089fa602b41745Kay Sievers it under the terms of the GNU Lesser General Public License as
f957632b960a0a42999b38ded7089fa602b41745Kay Sievers published by the Free Software Foundation, either version 2.1 of the
f957632b960a0a42999b38ded7089fa602b41745Kay Sievers License, or (at your option) any later version.
a40593a0d0d740efa387e35411e1e456a6c5aba7Lennart Poettering libasyncns is distributed in the hope that it will be useful, but
20ffc4c4a9226b0e45cc02ad9c0108981626c0bbKay Sievers WITHOUT ANY WARRANTY; without even the implied warranty of
04ac799283f517672a5424e7c5bf066cfa4ca020Zbigniew Jędrzejewski-Szmek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
04ac799283f517672a5424e7c5bf066cfa4ca020Zbigniew Jędrzejewski-Szmek Lesser General Public License for more details.
04ac799283f517672a5424e7c5bf066cfa4ca020Zbigniew Jędrzejewski-Szmek You should have received a copy of the GNU Lesser General Public
d8160f21fd295b451cee9679aa281fedf1cb8e8cZbigniew Jędrzejewski-Szmek License along with libasyncns. If not, see
ef417cfd2211ae017a38b9796c6db29130133e63Zbigniew Jędrzejewski-Szmek asyncns_query_t *done_head, *done_tail;
47c94a96df29080f8b3a97e7362df4e9c6ba3265Lennart Poetteringtypedef struct rheader {
0aafd43d235982510d1c40564079f7bcec0c7c19Lennart Poettering /* followed by addrinfo_serialization[] */
e1b7e7ec9b34ae6ae54a4c8084395cbf2bfe9960Lennart Poettering /* Followed by ai_addr amd ai_canonname with variable lengths */
69af45035913e7119cffd94c542bd3039600e45dZbigniew Jędrzejewski-Szmektypedef struct nameinfo_response {
df98a87ba389bdfc0359beedf47557411f3af434Lennart Poetteringtypedef union packet {
154ff088d371bee5651eaa2bc9bde8a34c185656Lennart Poettering return send(out_fd, &rh, rh.length, MSG_NOSIGNAL);
461bd8e47cafacfcd38389e7558330bfb6e902adLennart Poetteringstatic void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) {
b454b11220e87add6d0f011695c7912b009c853dLennart Poettering cnl = (ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0);
b454b11220e87add6d0f011695c7912b009c853dLennart Poettering l = sizeof(addrinfo_serialization_t) + ai->ai_addrlen + cnl;
fff87a35d9e26c0d4ea41273a963c0eb20e18da4Zbigniew Jędrzejewski-Szmek s.ai_socktype = ai->ai_socktype;
fff87a35d9e26c0d4ea41273a963c0eb20e18da4Zbigniew Jędrzejewski-Szmek s.ai_protocol = ai->ai_protocol;
3df82d5a8cdc510f518fd5e234ccb3233b748719Lennart Poettering memcpy((uint8_t*) p, &s, sizeof(addrinfo_serialization_t));
3df82d5a8cdc510f518fd5e234ccb3233b748719Lennart Poettering memcpy((uint8_t*) p + sizeof(addrinfo_serialization_t), ai->ai_addr, ai->ai_addrlen);
b5c03638d48c07aa0eaf13b5f54000c7133e1883Lennart Poettering strcpy((char*) p + sizeof(addrinfo_serialization_t) + ai->ai_addrlen, ai->ai_canonname);
b5c03638d48c07aa0eaf13b5f54000c7133e1883Lennart Poettering return (uint8_t*) p + l;
eece8c6fb5f4d354dcef6fd369e876c4f3a3f163Lennart Poetteringstatic int send_addrinfo_reply(int out_fd, unsigned id, int ret, struct addrinfo *ai, int _errno, int _h_errno) {
eece8c6fb5f4d354dcef6fd369e876c4f3a3f163Lennart Poettering addrinfo_response_t data[BUFSIZE/sizeof(addrinfo_response_t) + 1] = {};
795607b22308f5b92073b012e43be1892fdd97c0Lennart Poettering resp->header.length = sizeof(addrinfo_response_t);
e5ec62c56963d997edaffa904af5dc45dac23988Lennart Poettering if (!(p = serialize_addrinfo(p, k, &resp->header.length, (char*) data + BUFSIZE - (char*) p))) {
3679d1126bae52e02f6cd60fca196f616b9e660dLennart Poettering return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
cbb7712189527f9f483321607e44c4ead3dd11b8Lennart Poetteringstatic int send_nameinfo_reply(int out_fd, unsigned id, int ret, const char *host, const char *serv, int _errno, int _h_errno) {
d01a73b6396f57792113c1b5df6e8492fc703e5eLennart Poettering nameinfo_response_t data[BUFSIZE/sizeof(nameinfo_response_t) + 1] = {};
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering resp->header.length = sizeof(nameinfo_response_t) + hl + sl;
e9fd44b728ff1fc0d1f24fccb87a767f6865df27Lennart Poettering assert(sizeof(data) >= resp->header.length);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering memcpy((uint8_t *)data + sizeof(nameinfo_response_t), host, hl);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering memcpy((uint8_t *)data + sizeof(nameinfo_response_t) + hl, serv, sl);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poetteringstatic int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret, int _errno, int _h_errno) {
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering res_response_t data[BUFSIZE/sizeof(res_response_t) + 1] = {};
f38afcd0c7f558ca5bf0854b42f8c6954f8ad7f3Lennart Poettering resp->header.length = sizeof(res_response_t) + (ret < 0 ? 0 : ret);
f38afcd0c7f558ca5bf0854b42f8c6954f8ad7f3Lennart Poettering assert(sizeof(data) >= resp->header.length);
e673ad0415d89c322e5b1a121e411f1b1d8075c0Lennart Poettering memcpy((uint8_t *)data + sizeof(res_response_t), answer, ret);
e673ad0415d89c322e5b1a121e411f1b1d8075c0Lennart Poettering return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poetteringstatic int handle_request(int out_fd, const packet_t *packet, size_t length) {
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering const addrinfo_request_t *ai_req = &packet->addrinfo_request;
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering assert(length >= sizeof(addrinfo_request_t));
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering assert(length == sizeof(addrinfo_request_t) + ai_req->node_len + ai_req->service_len);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering node = ai_req->node_len ? (const char*) ai_req + sizeof(addrinfo_request_t) : NULL;
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering service = ai_req->service_len ? (const char*) ai_req + sizeof(addrinfo_request_t) + ai_req->node_len : NULL;
f38afcd0c7f558ca5bf0854b42f8c6954f8ad7f3Lennart Poettering /* send_addrinfo_reply() frees result */
f38afcd0c7f558ca5bf0854b42f8c6954f8ad7f3Lennart Poettering return send_addrinfo_reply(out_fd, req->id, ret, result, errno, h_errno);
f38afcd0c7f558ca5bf0854b42f8c6954f8ad7f3Lennart Poettering const nameinfo_request_t *ni_req = &packet->nameinfo_request;
f38afcd0c7f558ca5bf0854b42f8c6954f8ad7f3Lennart Poettering char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV];
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering assert(length >= sizeof(nameinfo_request_t));
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering assert(length == sizeof(nameinfo_request_t) + ni_req->sockaddr_len);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering memcpy(&sa, (const uint8_t *) ni_req + sizeof(nameinfo_request_t), ni_req->sockaddr_len);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering ret = getnameinfo((struct sockaddr *)&sa, ni_req->sockaddr_len,
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering ni_req->gethost ? hostbuf : NULL, ni_req->gethost ? sizeof(hostbuf) : 0,
eb124a97fb72d076014253b1acde69d428f15ecfLennart Poettering ni_req->getserv ? servbuf : NULL, ni_req->getserv ? sizeof(servbuf) : 0,
f38afcd0c7f558ca5bf0854b42f8c6954f8ad7f3Lennart Poettering return send_nameinfo_reply(out_fd, req->id, ret,
f38afcd0c7f558ca5bf0854b42f8c6954f8ad7f3Lennart Poettering ret == 0 && ni_req->gethost ? hostbuf : NULL,
f38afcd0c7f558ca5bf0854b42f8c6954f8ad7f3Lennart Poettering ret == 0 && ni_req->getserv ? servbuf : NULL,
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering HEADER answer[BUFSIZE/sizeof(HEADER) + 1];
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering const res_request_t *res_req = &packet->res_request;
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering assert(length == sizeof(res_request_t) + res_req->dname_len);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering dname = (const char *) req + sizeof(res_request_t);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering ret = res_query(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE);
f38afcd0c7f558ca5bf0854b42f8c6954f8ad7f3Lennart Poettering ret = res_search(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE);
8b8f259170e35b93e6c6d1757cb8b835bbdaa40cZbigniew Jędrzejewski-Szmek return send_res_reply(out_fd, req->id, (unsigned char *) answer, ret, errno, h_errno);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poetteringstatic void* thread_worker(void *p) {
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering /* No signals in this thread please */
eb124a97fb72d076014253b1acde69d428f15ecfLennart Poettering pthread_sigmask(SIG_BLOCK, &fullset, NULL);
90e071d1d59be05fcba66561439c3ca67c80ee20Lennart Poettering packet_t buf[BUFSIZE/sizeof(packet_t) + 1];
d2e83c23f5f0cdd3b6ec05c5c40209708721e704Kay Sievers length = recv(asyncns->fds[REQUEST_RECV_FD], buf, sizeof(buf), 0);
f6113d42d015ad9f3a9e702a09eb8006511a4424Kay Sievers if (length < 0 && (errno == EAGAIN || errno == EINTR))
59704f3e937c664f7324bfbb08483c358dfbc4c6Lennart Poettering if (handle_request(asyncns->fds[RESPONSE_SEND_FD], buf, (size_t) length) < 0)
e707c49485b8f4f2ec040d3da232d39153e650b9Lennart Poettering send_died(asyncns->fds[RESPONSE_SEND_FD]);
7d8197d1f25c1291855bb6cffc705444978c6d8dKay Sievers for (i = 0; i < MESSAGE_FD_MAX; i++)
9ee58bddeb6eb044753167e0047fe836479ca5dbKay Sievers memset(asyncns->queries, 0, sizeof(asyncns->queries));
71ef24d09573874c0f7bc323c07c3aec2a458707Lennart Poettering if (socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, asyncns->fds) < 0 ||
71ef24d09573874c0f7bc323c07c3aec2a458707Lennart Poettering socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, asyncns->fds+2) < 0) {
1b89884ba31cbe98f159ce2c7d6fac5f6a57698fLennart Poettering /* Try again, without SOCK_CLOEXEC */
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering if (socketpair(PF_UNIX, SOCK_DGRAM, 0, asyncns->fds) < 0 ||
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering socketpair(PF_UNIX, SOCK_DGRAM, 0, asyncns->fds+2) < 0)
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering for (i = 0; i < MESSAGE_FD_MAX; i++)
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering for (asyncns->valid_workers = 0; asyncns->valid_workers < n_proc; asyncns->valid_workers++) {
f801968466fed39d50d410b30ac828c26722cc95Lennart Poettering if ((r = pthread_create(&asyncns->workers[asyncns->valid_workers], NULL, thread_worker, asyncns)) != 0) {
a1cccad1fe88ddd6943e18af97cf7f466296970fLennart Poettering asyncns->current_index = asyncns->current_id = 0;
a1cccad1fe88ddd6943e18af97cf7f466296970fLennart Poettering asyncns->done_head = asyncns->done_tail = NULL;
8556879e0d14925ce897875c6c264368e2d048c2Lennart Poettering fd_nonblock(asyncns->fds[RESPONSE_RECV_FD], true);
68f160039eb78fe122cfe0d4c49695ae91f6f0d1Lennart Poettering if (asyncns->fds[REQUEST_SEND_FD] >= 0) {
8230e26dc954a40d8c9dbc8ddd9376117021f9d2Lennart Poettering /* Send one termination packet for each worker */
4d9909c93e9c58789c71b34555a1908307c6849eLennart Poettering for (p = 0; p < asyncns->valid_workers; p++)
4d9909c93e9c58789c71b34555a1908307c6849eLennart Poettering send(asyncns->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL);
88a6c5894c9d3f85d63b87b040c130366b4006ceKay Sievers /* Now terminate them and wait until they are gone. */
8351ceaea9480d9c2979aa2ff0f4982cfdfef58dLennart Poettering for (p = 0; p < asyncns->valid_workers; p++) {
c66d36e5b5ae81f3c5297d6dacadc13c88c530f6Lennart Poettering if (pthread_join(asyncns->workers[p], NULL) != EINTR)
3471bedc005fab03f40b99bf6599645330adcd9eLennart Poettering /* Close all communication channels */
59cea26a349cfa8db906b520dac72563dd773ff2Lennart Poettering for (i = 0; i < MESSAGE_FD_MAX; i++)
d3a3f22267a7dac426b07a7ed0baa1632f5daf04Kay Sievers for (p = 0; p < MAX_QUERIES; p++)
abd55b16547d0bb0ed1c31e72e16838f0f59f48bKay Sieversstatic asyncns_query_t *lookup_query(asyncns_t *asyncns, unsigned id) {
7f110ff9b8828b477e87de7b28c708cf69a3d008Lennart Poetteringstatic void complete_query(asyncns_t *asyncns, asyncns_query_t *q) {
ad740100d108282d0244d5739d4dcc86fe4c5fdeLennart Poetteringstatic const void *unserialize_addrinfo(const void *p, struct addrinfo **ret_ai, size_t *length) {
ff01d048b4c1455241c894cf7982662c9d28fd34Lennart Poettering if (*length < sizeof(addrinfo_serialization_t))
1d6702e8d3877c0bebf3ac817dc45ff72f5ecfa9Lennart Poettering memcpy(&s, p, sizeof(s));
1d6702e8d3877c0bebf3ac817dc45ff72f5ecfa9Lennart Poettering l = sizeof(addrinfo_serialization_t) + s.ai_addrlen + s.canonname_len;
1258097cd3cdbc5dd3d264850119e553a29c5068Lennart Poettering if (!(ai = malloc(sizeof(struct addrinfo))))
8d0e38a2b966799af884e78a54fd6a2dffa44788Lennart Poettering if (s.ai_addrlen && !(ai->ai_addr = malloc(s.ai_addrlen)))
f28f1daf754a9a07de90e6fc4ada581bf5de677dLennart Poettering if (s.canonname_len && !(ai->ai_canonname = malloc(s.canonname_len)))
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering memcpy(ai->ai_addr, (const uint8_t*) p + sizeof(addrinfo_serialization_t), s.ai_addrlen);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering memcpy(ai->ai_canonname, (const uint8_t*) p + sizeof(addrinfo_serialization_t) + s.ai_addrlen, s.canonname_len);
9534ce54858c67363b841cdbdc315140437bfdb4Lennart Poettering return (const uint8_t*) p + l;
8bbabc447b1d913bd21faf97c7b17d20d315d2b4Lennart Poetteringstatic int handle_response(asyncns_t *asyncns, const packet_t *packet, size_t length) {