1*28f2fbe8Sjca /* $Id: dnsproc.c,v 1.12 2021/12/13 13:30:39 jca Exp $ */
2de579d12Sflorian /*
3de579d12Sflorian * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
4de579d12Sflorian *
5de579d12Sflorian * Permission to use, copy, modify, and distribute this software for any
6de579d12Sflorian * purpose with or without fee is hereby granted, provided that the above
7de579d12Sflorian * copyright notice and this permission notice appear in all copies.
8de579d12Sflorian *
9de579d12Sflorian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
10de579d12Sflorian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11de579d12Sflorian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
12de579d12Sflorian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13de579d12Sflorian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14de579d12Sflorian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15de579d12Sflorian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16de579d12Sflorian */
17de579d12Sflorian
18de579d12Sflorian #include <sys/socket.h>
19de579d12Sflorian #include <arpa/inet.h>
20de579d12Sflorian
21de579d12Sflorian #include <err.h>
22de579d12Sflorian #include <netdb.h>
23de579d12Sflorian #include <stdio.h>
24de579d12Sflorian #include <stdlib.h>
25de579d12Sflorian #include <string.h>
26de579d12Sflorian #include <unistd.h>
27de579d12Sflorian
28de579d12Sflorian #include "extern.h"
29de579d12Sflorian
30de579d12Sflorian struct addr {
31de579d12Sflorian int family; /* 4 for PF_INET, 6 for PF_INET6 */
32de579d12Sflorian char ip[INET6_ADDRSTRLEN];
33de579d12Sflorian };
34de579d12Sflorian
35de579d12Sflorian /*
36de579d12Sflorian * This is a modified version of host_dns in config.c of OpenBSD's ntpd.
37de579d12Sflorian */
38de579d12Sflorian /*
39de579d12Sflorian * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
40de579d12Sflorian *
41de579d12Sflorian * Permission to use, copy, modify, and distribute this software for any
42de579d12Sflorian * purpose with or without fee is hereby granted, provided that the above
43de579d12Sflorian * copyright notice and this permission notice appear in all copies.
44de579d12Sflorian *
45de579d12Sflorian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
46de579d12Sflorian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
47de579d12Sflorian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
48de579d12Sflorian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
49de579d12Sflorian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
50de579d12Sflorian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
51de579d12Sflorian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
52de579d12Sflorian */
53de579d12Sflorian static ssize_t
host_dns(const char * s,struct addr * vec)54de579d12Sflorian host_dns(const char *s, struct addr *vec)
55de579d12Sflorian {
56de579d12Sflorian struct addrinfo hints, *res0, *res;
57de579d12Sflorian int error;
58de579d12Sflorian ssize_t vecsz;
59de579d12Sflorian struct sockaddr *sa;
60de579d12Sflorian
61de579d12Sflorian memset(&hints, 0, sizeof(hints));
62de579d12Sflorian hints.ai_family = PF_UNSPEC;
63de579d12Sflorian hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
64e93086b0Sflorian hints.ai_flags = AI_ADDRCONFIG;
65de579d12Sflorian
66de579d12Sflorian error = getaddrinfo(s, NULL, &hints, &res0);
67de579d12Sflorian
68de579d12Sflorian if (error == EAI_AGAIN ||
69de579d12Sflorian /* FIXME */
70de579d12Sflorian #ifndef __FreeBSD__
71de579d12Sflorian error == EAI_NODATA ||
72de579d12Sflorian #endif
73de579d12Sflorian error == EAI_NONAME)
7434335c11Sjsing return 0;
75de579d12Sflorian
76de579d12Sflorian if (error) {
77de579d12Sflorian warnx("%s: parse error: %s",
78de579d12Sflorian s, gai_strerror(error));
7934335c11Sjsing return -1;
80de579d12Sflorian }
81de579d12Sflorian
82de579d12Sflorian for (vecsz = 0, res = res0;
837cd8f039Sjsing res != NULL && vecsz < MAX_SERVERS_DNS;
84de579d12Sflorian res = res->ai_next) {
85de579d12Sflorian if (res->ai_family != AF_INET &&
86de579d12Sflorian res->ai_family != AF_INET6)
87de579d12Sflorian continue;
88de579d12Sflorian
89de579d12Sflorian sa = res->ai_addr;
90de579d12Sflorian
917cd8f039Sjsing if (res->ai_family == AF_INET) {
92de579d12Sflorian vec[vecsz].family = 4;
93de579d12Sflorian inet_ntop(AF_INET,
94de579d12Sflorian &(((struct sockaddr_in *)sa)->sin_addr),
95de579d12Sflorian vec[vecsz].ip, INET6_ADDRSTRLEN);
96de579d12Sflorian } else {
97de579d12Sflorian vec[vecsz].family = 6;
98de579d12Sflorian inet_ntop(AF_INET6,
99de579d12Sflorian &(((struct sockaddr_in6 *)sa)->sin6_addr),
100de579d12Sflorian vec[vecsz].ip, INET6_ADDRSTRLEN);
101de579d12Sflorian }
102de579d12Sflorian
103de579d12Sflorian dodbg("%s: DNS: %s", s, vec[vecsz].ip);
104de579d12Sflorian vecsz++;
105de579d12Sflorian }
106de579d12Sflorian
107de579d12Sflorian freeaddrinfo(res0);
10834335c11Sjsing return vecsz;
109de579d12Sflorian }
110de579d12Sflorian
111de579d12Sflorian int
dnsproc(int nfd)112de579d12Sflorian dnsproc(int nfd)
113de579d12Sflorian {
1147bce6888Sderaadt char *look = NULL, *last = NULL;
115de579d12Sflorian struct addr v[MAX_SERVERS_DNS];
1167bce6888Sderaadt int rc = 0, cc;
117de579d12Sflorian long lval;
1187bce6888Sderaadt ssize_t vsz = 0;
119de579d12Sflorian size_t i;
120de579d12Sflorian enum dnsop op;
121de579d12Sflorian
122ec0d8c8bSderaadt if (pledge("stdio dns", NULL) == -1) {
123ec0d8c8bSderaadt warn("pledge");
124de579d12Sflorian goto out;
125ec0d8c8bSderaadt }
126de579d12Sflorian
127de579d12Sflorian /*
128de579d12Sflorian * This is simple: just loop on a request operation, and each
129de579d12Sflorian * time we write back zero or more entries.
130de579d12Sflorian * Also do a simple trick and cache the last lookup.
131de579d12Sflorian */
132de579d12Sflorian
133de579d12Sflorian for (;;) {
134de579d12Sflorian op = DNS__MAX;
1357cd8f039Sjsing if ((lval = readop(nfd, COMM_DNS)) == 0)
136de579d12Sflorian op = DNS_STOP;
1377cd8f039Sjsing else if (lval == DNS_LOOKUP)
138de579d12Sflorian op = lval;
139de579d12Sflorian
1404de82fa3Sderaadt if (op == DNS__MAX) {
141de579d12Sflorian warnx("unknown operation from netproc");
142de579d12Sflorian goto out;
1434de82fa3Sderaadt } else if (op == DNS_STOP)
144de579d12Sflorian break;
145de579d12Sflorian
1467cd8f039Sjsing if ((look = readstr(nfd, COMM_DNSQ)) == NULL)
147de579d12Sflorian goto out;
148de579d12Sflorian
149de579d12Sflorian /*
150de579d12Sflorian * Check if we're asked to repeat the lookup.
151de579d12Sflorian * If not, request it from host_dns().
152de579d12Sflorian */
153de579d12Sflorian
1547cd8f039Sjsing if (last == NULL || strcmp(look, last)) {
155de579d12Sflorian if ((vsz = host_dns(look, v)) < 0)
156de579d12Sflorian goto out;
157de579d12Sflorian
158de579d12Sflorian free(last);
159de579d12Sflorian last = look;
160de579d12Sflorian look = NULL;
161de579d12Sflorian } else {
162de579d12Sflorian free(look);
163de579d12Sflorian look = NULL;
164de579d12Sflorian }
165de579d12Sflorian
1667cd8f039Sjsing if ((cc = writeop(nfd, COMM_DNSLEN, vsz)) == 0)
167de579d12Sflorian break;
168de579d12Sflorian else if (cc < 0)
169de579d12Sflorian goto out;
170de579d12Sflorian for (i = 0; i < (size_t)vsz; i++) {
171de579d12Sflorian if (writeop(nfd, COMM_DNSF, v[i].family) <= 0)
172de579d12Sflorian goto out;
173de579d12Sflorian if (writestr(nfd, COMM_DNSA, v[i].ip) <= 0)
174de579d12Sflorian goto out;
175de579d12Sflorian }
176de579d12Sflorian }
177de579d12Sflorian
178de579d12Sflorian rc = 1;
179de579d12Sflorian out:
180de579d12Sflorian close(nfd);
181de579d12Sflorian free(look);
182de579d12Sflorian free(last);
18334335c11Sjsing return rc;
184de579d12Sflorian }
185