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