xref: /openbsd/usr.sbin/acme-client/dnsproc.c (revision 9b7c3dbb)
1 /*	$Id: dnsproc.c,v 1.4 2016/09/01 00:35:21 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 	/* ntpd MUST NOT use AI_ADDRCONFIG here */
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 	     NULL != res && 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 (AF_INET == res->ai_family) {
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 	int		 rc, cc;
116 	char		*look, *last;
117 	struct addr	 v[MAX_SERVERS_DNS];
118 	long		 lval;
119 	size_t		 i;
120 	ssize_t		 vsz;
121 	enum dnsop	 op;
122 
123 	rc = 0;
124 	look = last = NULL;
125 	vsz = 0;
126 
127 	if (pledge("stdio dns", NULL) == -1) {
128 		warn("pledge");
129 		goto out;
130 	}
131 
132 	/*
133 	 * This is simple: just loop on a request operation, and each
134 	 * time we write back zero or more entries.
135 	 * Also do a simple trick and cache the last lookup.
136 	 */
137 
138 	for (;;) {
139 		op = DNS__MAX;
140 		if (0 == (lval = readop(nfd, COMM_DNS)))
141 			op = DNS_STOP;
142 		else if (DNS_LOOKUP == lval)
143 			op = lval;
144 
145 		if (DNS__MAX == op) {
146 			warnx("unknown operation from netproc");
147 			goto out;
148 		} else if (DNS_STOP == op)
149 			break;
150 
151 		if (NULL == (look = readstr(nfd, COMM_DNSQ)))
152 			goto out;
153 
154 		/*
155 		 * Check if we're asked to repeat the lookup.
156 		 * If not, request it from host_dns().
157 		 */
158 
159 		if (NULL == last || strcmp(look, last)) {
160 			if ((vsz = host_dns(look, v)) < 0)
161 				goto out;
162 
163 			free(last);
164 			last = look;
165 			look = NULL;
166 		} else {
167 			doddbg("%s: cached", look);
168 			free(look);
169 			look = NULL;
170 		}
171 
172 		if (0 == (cc = writeop(nfd, COMM_DNSLEN, vsz)))
173 			break;
174 		else if (cc < 0)
175 			goto out;
176 		for (i = 0; i < (size_t)vsz; i++) {
177 			if (writeop(nfd, COMM_DNSF, v[i].family) <= 0)
178 				goto out;
179 			if (writestr(nfd, COMM_DNSA, v[i].ip) <= 0)
180 				goto out;
181 		}
182 	}
183 
184 	rc = 1;
185 out:
186 	close(nfd);
187 	free(look);
188 	free(last);
189 	return(rc);
190 }
191