xref: /openbsd/usr.sbin/acme-client/dnsproc.c (revision 4cfece93)
1 /*	$Id: dnsproc.c,v 1.11 2020/05/10 15:06:07 florian 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
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 		break;
106 	}
107 
108 	freeaddrinfo(res0);
109 	return vecsz;
110 }
111 
112 int
113 dnsproc(int nfd)
114 {
115 	char		*look = NULL, *last = NULL;
116 	struct addr	 v[MAX_SERVERS_DNS];
117 	int		 rc = 0, cc;
118 	long		 lval;
119 	ssize_t		 vsz = 0;
120 	size_t		 i;
121 	enum dnsop	 op;
122 
123 	if (pledge("stdio dns", NULL) == -1) {
124 		warn("pledge");
125 		goto out;
126 	}
127 
128 	/*
129 	 * This is simple: just loop on a request operation, and each
130 	 * time we write back zero or more entries.
131 	 * Also do a simple trick and cache the last lookup.
132 	 */
133 
134 	for (;;) {
135 		op = DNS__MAX;
136 		if ((lval = readop(nfd, COMM_DNS)) == 0)
137 			op = DNS_STOP;
138 		else if (lval == DNS_LOOKUP)
139 			op = lval;
140 
141 		if (op == DNS__MAX) {
142 			warnx("unknown operation from netproc");
143 			goto out;
144 		} else if (op == DNS_STOP)
145 			break;
146 
147 		if ((look = readstr(nfd, COMM_DNSQ)) == NULL)
148 			goto out;
149 
150 		/*
151 		 * Check if we're asked to repeat the lookup.
152 		 * If not, request it from host_dns().
153 		 */
154 
155 		if (last == NULL || strcmp(look, last)) {
156 			if ((vsz = host_dns(look, v)) < 0)
157 				goto out;
158 
159 			free(last);
160 			last = look;
161 			look = NULL;
162 		} else {
163 			free(look);
164 			look = NULL;
165 		}
166 
167 		if ((cc = writeop(nfd, COMM_DNSLEN, vsz)) == 0)
168 			break;
169 		else if (cc < 0)
170 			goto out;
171 		for (i = 0; i < (size_t)vsz; i++) {
172 			if (writeop(nfd, COMM_DNSF, v[i].family) <= 0)
173 				goto out;
174 			if (writestr(nfd, COMM_DNSA, v[i].ip) <= 0)
175 				goto out;
176 		}
177 	}
178 
179 	rc = 1;
180 out:
181 	close(nfd);
182 	free(look);
183 	free(last);
184 	return rc;
185 }
186