xref: /freebsd/contrib/unbound/util/net_help.c (revision 8f76bb7dad48538c6832c2fb466a433d2a3f8cd5)
1b7579f77SDag-Erling Smørgrav /*
2b7579f77SDag-Erling Smørgrav  * util/net_help.c - implementation of the network helper code
3b7579f77SDag-Erling Smørgrav  *
4b7579f77SDag-Erling Smørgrav  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5b7579f77SDag-Erling Smørgrav  *
6b7579f77SDag-Erling Smørgrav  * This software is open source.
7b7579f77SDag-Erling Smørgrav  *
8b7579f77SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
9b7579f77SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
10b7579f77SDag-Erling Smørgrav  * are met:
11b7579f77SDag-Erling Smørgrav  *
12b7579f77SDag-Erling Smørgrav  * Redistributions of source code must retain the above copyright notice,
13b7579f77SDag-Erling Smørgrav  * this list of conditions and the following disclaimer.
14b7579f77SDag-Erling Smørgrav  *
15b7579f77SDag-Erling Smørgrav  * Redistributions in binary form must reproduce the above copyright notice,
16b7579f77SDag-Erling Smørgrav  * this list of conditions and the following disclaimer in the documentation
17b7579f77SDag-Erling Smørgrav  * and/or other materials provided with the distribution.
18b7579f77SDag-Erling Smørgrav  *
19b7579f77SDag-Erling Smørgrav  * Neither the name of the NLNET LABS nor the names of its contributors may
20b7579f77SDag-Erling Smørgrav  * be used to endorse or promote products derived from this software without
21b7579f77SDag-Erling Smørgrav  * specific prior written permission.
22b7579f77SDag-Erling Smørgrav  *
23b7579f77SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2417d15b25SDag-Erling Smørgrav  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2517d15b25SDag-Erling Smørgrav  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2617d15b25SDag-Erling Smørgrav  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2717d15b25SDag-Erling Smørgrav  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2817d15b25SDag-Erling Smørgrav  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
2917d15b25SDag-Erling Smørgrav  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3017d15b25SDag-Erling Smørgrav  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3117d15b25SDag-Erling Smørgrav  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3217d15b25SDag-Erling Smørgrav  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3317d15b25SDag-Erling Smørgrav  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34b7579f77SDag-Erling Smørgrav  */
35b7579f77SDag-Erling Smørgrav /**
36b7579f77SDag-Erling Smørgrav  * \file
37b7579f77SDag-Erling Smørgrav  * Implementation of net_help.h.
38b7579f77SDag-Erling Smørgrav  */
39b7579f77SDag-Erling Smørgrav 
40b7579f77SDag-Erling Smørgrav #include "config.h"
4124e36522SCy Schubert #ifdef HAVE_SYS_TYPES_H
4224e36522SCy Schubert #  include <sys/types.h>
4324e36522SCy Schubert #endif
4424e36522SCy Schubert #ifdef HAVE_NET_IF_H
4524e36522SCy Schubert #include <net/if.h>
4624e36522SCy Schubert #endif
479cf5bc93SCy Schubert #ifdef HAVE_NETIOAPI_H
489cf5bc93SCy Schubert #include <netioapi.h>
499cf5bc93SCy Schubert #endif
50b7579f77SDag-Erling Smørgrav #include "util/net_help.h"
51b7579f77SDag-Erling Smørgrav #include "util/log.h"
52b7579f77SDag-Erling Smørgrav #include "util/data/dname.h"
53b7579f77SDag-Erling Smørgrav #include "util/module.h"
54b7579f77SDag-Erling Smørgrav #include "util/regional.h"
55e86b9096SDag-Erling Smørgrav #include "util/config_file.h"
5609a3aaf3SDag-Erling Smørgrav #include "sldns/parseutil.h"
5709a3aaf3SDag-Erling Smørgrav #include "sldns/wire2str.h"
589cf5bc93SCy Schubert #include "sldns/str2wire.h"
59b7579f77SDag-Erling Smørgrav #include <fcntl.h>
608ed2b524SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_SSL_H
61b7579f77SDag-Erling Smørgrav #include <openssl/ssl.h>
62e86b9096SDag-Erling Smørgrav #include <openssl/evp.h>
63e86b9096SDag-Erling Smørgrav #include <openssl/rand.h>
648ed2b524SDag-Erling Smørgrav #endif
658ed2b524SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_ERR_H
66b7579f77SDag-Erling Smørgrav #include <openssl/err.h>
678ed2b524SDag-Erling Smørgrav #endif
6825039b37SCy Schubert #ifdef HAVE_OPENSSL_CORE_NAMES_H
6925039b37SCy Schubert #include <openssl/core_names.h>
7025039b37SCy Schubert #endif
713bd4df0aSDag-Erling Smørgrav #ifdef USE_WINSOCK
723bd4df0aSDag-Erling Smørgrav #include <wincrypt.h>
733bd4df0aSDag-Erling Smørgrav #endif
74c0caa2e2SCy Schubert #ifdef HAVE_NGHTTP2_NGHTTP2_H
75c0caa2e2SCy Schubert #include <nghttp2/nghttp2.h>
76c0caa2e2SCy Schubert #endif
77b7579f77SDag-Erling Smørgrav 
78b7579f77SDag-Erling Smørgrav /** max length of an IP address (the address portion) that we allow */
79b7579f77SDag-Erling Smørgrav #define MAX_ADDR_STRLEN 128 /* characters */
80b7579f77SDag-Erling Smørgrav /** default value for EDNS ADVERTISED size */
81b7579f77SDag-Erling Smørgrav uint16_t EDNS_ADVERTISED_SIZE = 4096;
82b7579f77SDag-Erling Smørgrav 
83b7579f77SDag-Erling Smørgrav /** minimal responses when positive answer: default is no */
84b7579f77SDag-Erling Smørgrav int MINIMAL_RESPONSES = 0;
85b7579f77SDag-Erling Smørgrav 
8625039b37SCy Schubert /** rrset order roundrobin: default is yes */
8725039b37SCy Schubert int RRSET_ROUNDROBIN = 1;
88b7579f77SDag-Erling Smørgrav 
89e86b9096SDag-Erling Smørgrav /** log tag queries with name instead of 'info' for filtering */
90e86b9096SDag-Erling Smørgrav int LOG_TAG_QUERYREPLY = 0;
91e86b9096SDag-Erling Smørgrav 
92e86b9096SDag-Erling Smørgrav static struct tls_session_ticket_key {
93e86b9096SDag-Erling Smørgrav 	unsigned char *key_name;
94e86b9096SDag-Erling Smørgrav 	unsigned char *aes_key;
95e86b9096SDag-Erling Smørgrav 	unsigned char *hmac_key;
96e86b9096SDag-Erling Smørgrav } *ticket_keys;
97e86b9096SDag-Erling Smørgrav 
98c0caa2e2SCy Schubert #ifdef HAVE_SSL
9925039b37SCy Schubert /**
10025039b37SCy Schubert  * callback TLS session ticket encrypt and decrypt
10125039b37SCy Schubert  * For use with SSL_CTX_set_tlsext_ticket_key_cb or
10225039b37SCy Schubert  * SSL_CTX_set_tlsext_ticket_key_evp_cb
10325039b37SCy Schubert  * @param s: the SSL_CTX to use (from connect_sslctx_create())
10425039b37SCy Schubert  * @param key_name: secret name, 16 bytes
10525039b37SCy Schubert  * @param iv: up to EVP_MAX_IV_LENGTH.
10625039b37SCy Schubert  * @param evp_ctx: the evp cipher context, function sets this.
10725039b37SCy Schubert  * @param hmac_ctx: the hmac context, function sets this.
10825039b37SCy Schubert  * 	with ..key_cb it is of type HMAC_CTX*
10925039b37SCy Schubert  * 	with ..key_evp_cb it is of type EVP_MAC_CTX*
11025039b37SCy Schubert  * @param enc: 1 is encrypt, 0 is decrypt
11125039b37SCy Schubert  * @return 0 on no ticket, 1 for okay, and 2 for okay but renew the ticket
11225039b37SCy Schubert  * 	(the ticket is decrypt only). and <0 for failures.
11325039b37SCy Schubert  */
11425039b37SCy Schubert int tls_session_ticket_key_cb(SSL *s, unsigned char* key_name,
11525039b37SCy Schubert 	unsigned char* iv, EVP_CIPHER_CTX *evp_ctx,
11625039b37SCy Schubert #ifdef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
11725039b37SCy Schubert 	EVP_MAC_CTX *hmac_ctx,
11825039b37SCy Schubert #else
11925039b37SCy Schubert 	HMAC_CTX* hmac_ctx,
12025039b37SCy Schubert #endif
12125039b37SCy Schubert 	int enc);
12225039b37SCy Schubert #endif /* HAVE_SSL */
12325039b37SCy Schubert 
124b7579f77SDag-Erling Smørgrav /* returns true is string addr is an ip6 specced address */
125b7579f77SDag-Erling Smørgrav int
126b7579f77SDag-Erling Smørgrav str_is_ip6(const char* str)
127b7579f77SDag-Erling Smørgrav {
128b7579f77SDag-Erling Smørgrav 	if(strchr(str, ':'))
129b7579f77SDag-Erling Smørgrav 		return 1;
130b7579f77SDag-Erling Smørgrav 	else    return 0;
131b7579f77SDag-Erling Smørgrav }
132b7579f77SDag-Erling Smørgrav 
133b7579f77SDag-Erling Smørgrav int
134b7579f77SDag-Erling Smørgrav fd_set_nonblock(int s)
135b7579f77SDag-Erling Smørgrav {
136b7579f77SDag-Erling Smørgrav #ifdef HAVE_FCNTL
137b7579f77SDag-Erling Smørgrav 	int flag;
138b7579f77SDag-Erling Smørgrav 	if((flag = fcntl(s, F_GETFL)) == -1) {
139b7579f77SDag-Erling Smørgrav 		log_err("can't fcntl F_GETFL: %s", strerror(errno));
140b7579f77SDag-Erling Smørgrav 		flag = 0;
141b7579f77SDag-Erling Smørgrav 	}
142b7579f77SDag-Erling Smørgrav 	flag |= O_NONBLOCK;
143b7579f77SDag-Erling Smørgrav 	if(fcntl(s, F_SETFL, flag) == -1) {
144b7579f77SDag-Erling Smørgrav 		log_err("can't fcntl F_SETFL: %s", strerror(errno));
145b7579f77SDag-Erling Smørgrav 		return 0;
146b7579f77SDag-Erling Smørgrav 	}
147b7579f77SDag-Erling Smørgrav #elif defined(HAVE_IOCTLSOCKET)
148b7579f77SDag-Erling Smørgrav 	unsigned long on = 1;
149b7579f77SDag-Erling Smørgrav 	if(ioctlsocket(s, FIONBIO, &on) != 0) {
150b7579f77SDag-Erling Smørgrav 		log_err("can't ioctlsocket FIONBIO on: %s",
151b7579f77SDag-Erling Smørgrav 			wsa_strerror(WSAGetLastError()));
152b7579f77SDag-Erling Smørgrav 	}
153b7579f77SDag-Erling Smørgrav #endif
154b7579f77SDag-Erling Smørgrav 	return 1;
155b7579f77SDag-Erling Smørgrav }
156b7579f77SDag-Erling Smørgrav 
157b7579f77SDag-Erling Smørgrav int
158b7579f77SDag-Erling Smørgrav fd_set_block(int s)
159b7579f77SDag-Erling Smørgrav {
160b7579f77SDag-Erling Smørgrav #ifdef HAVE_FCNTL
161b7579f77SDag-Erling Smørgrav 	int flag;
162b7579f77SDag-Erling Smørgrav 	if((flag = fcntl(s, F_GETFL)) == -1) {
163b7579f77SDag-Erling Smørgrav 		log_err("cannot fcntl F_GETFL: %s", strerror(errno));
164b7579f77SDag-Erling Smørgrav 		flag = 0;
165b7579f77SDag-Erling Smørgrav 	}
166b7579f77SDag-Erling Smørgrav 	flag &= ~O_NONBLOCK;
167b7579f77SDag-Erling Smørgrav 	if(fcntl(s, F_SETFL, flag) == -1) {
168b7579f77SDag-Erling Smørgrav 		log_err("cannot fcntl F_SETFL: %s", strerror(errno));
169b7579f77SDag-Erling Smørgrav 		return 0;
170b7579f77SDag-Erling Smørgrav 	}
171b7579f77SDag-Erling Smørgrav #elif defined(HAVE_IOCTLSOCKET)
172b7579f77SDag-Erling Smørgrav 	unsigned long off = 0;
173b7579f77SDag-Erling Smørgrav 	if(ioctlsocket(s, FIONBIO, &off) != 0) {
174971980c3SDag-Erling Smørgrav 		if(WSAGetLastError() != WSAEINVAL || verbosity >= 4)
175b7579f77SDag-Erling Smørgrav 			log_err("can't ioctlsocket FIONBIO off: %s",
176b7579f77SDag-Erling Smørgrav 				wsa_strerror(WSAGetLastError()));
177b7579f77SDag-Erling Smørgrav 	}
178b7579f77SDag-Erling Smørgrav #endif
179b7579f77SDag-Erling Smørgrav 	return 1;
180b7579f77SDag-Erling Smørgrav }
181b7579f77SDag-Erling Smørgrav 
182b7579f77SDag-Erling Smørgrav int
183b7579f77SDag-Erling Smørgrav is_pow2(size_t num)
184b7579f77SDag-Erling Smørgrav {
185b7579f77SDag-Erling Smørgrav 	if(num == 0) return 1;
186b7579f77SDag-Erling Smørgrav 	return (num & (num-1)) == 0;
187b7579f77SDag-Erling Smørgrav }
188b7579f77SDag-Erling Smørgrav 
189b7579f77SDag-Erling Smørgrav void*
190b7579f77SDag-Erling Smørgrav memdup(void* data, size_t len)
191b7579f77SDag-Erling Smørgrav {
192b7579f77SDag-Erling Smørgrav 	void* d;
193b7579f77SDag-Erling Smørgrav 	if(!data) return NULL;
194b7579f77SDag-Erling Smørgrav 	if(len == 0) return NULL;
195b7579f77SDag-Erling Smørgrav 	d = malloc(len);
196b7579f77SDag-Erling Smørgrav 	if(!d) return NULL;
197b7579f77SDag-Erling Smørgrav 	memcpy(d, data, len);
198b7579f77SDag-Erling Smørgrav 	return d;
199b7579f77SDag-Erling Smørgrav }
200b7579f77SDag-Erling Smørgrav 
201b7579f77SDag-Erling Smørgrav void
202b7579f77SDag-Erling Smørgrav log_addr(enum verbosity_value v, const char* str,
203b7579f77SDag-Erling Smørgrav 	struct sockaddr_storage* addr, socklen_t addrlen)
204b7579f77SDag-Erling Smørgrav {
205b7579f77SDag-Erling Smørgrav 	uint16_t port;
206b7579f77SDag-Erling Smørgrav 	const char* family = "unknown";
207b7579f77SDag-Erling Smørgrav 	char dest[100];
208b7579f77SDag-Erling Smørgrav 	int af = (int)((struct sockaddr_in*)addr)->sin_family;
209b7579f77SDag-Erling Smørgrav 	void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
210b7579f77SDag-Erling Smørgrav 	if(verbosity < v)
211b7579f77SDag-Erling Smørgrav 		return;
212b7579f77SDag-Erling Smørgrav 	switch(af) {
213b7579f77SDag-Erling Smørgrav 		case AF_INET: family="ip4"; break;
214b7579f77SDag-Erling Smørgrav 		case AF_INET6: family="ip6";
215b7579f77SDag-Erling Smørgrav 			sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
216b7579f77SDag-Erling Smørgrav 			break;
2176480faa8SDag-Erling Smørgrav 		case AF_LOCAL:
2186480faa8SDag-Erling Smørgrav 			dest[0]=0;
2196480faa8SDag-Erling Smørgrav 			(void)inet_ntop(af, sinaddr, dest,
2206480faa8SDag-Erling Smørgrav 				(socklen_t)sizeof(dest));
2216480faa8SDag-Erling Smørgrav 			verbose(v, "%s local %s", str, dest);
2226480faa8SDag-Erling Smørgrav 			return; /* do not continue and try to get port */
223b7579f77SDag-Erling Smørgrav 		default: break;
224b7579f77SDag-Erling Smørgrav 	}
225b7579f77SDag-Erling Smørgrav 	if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
22617d15b25SDag-Erling Smørgrav 		(void)strlcpy(dest, "(inet_ntop error)", sizeof(dest));
227b7579f77SDag-Erling Smørgrav 	}
228b7579f77SDag-Erling Smørgrav 	dest[sizeof(dest)-1] = 0;
229b7579f77SDag-Erling Smørgrav 	port = ntohs(((struct sockaddr_in*)addr)->sin_port);
230b7579f77SDag-Erling Smørgrav 	if(verbosity >= 4)
231b7579f77SDag-Erling Smørgrav 		verbose(v, "%s %s %s port %d (len %d)", str, family, dest,
232b7579f77SDag-Erling Smørgrav 			(int)port, (int)addrlen);
233b7579f77SDag-Erling Smørgrav 	else	verbose(v, "%s %s port %d", str, dest, (int)port);
234b7579f77SDag-Erling Smørgrav }
235b7579f77SDag-Erling Smørgrav 
236b7579f77SDag-Erling Smørgrav int
237b7579f77SDag-Erling Smørgrav extstrtoaddr(const char* str, struct sockaddr_storage* addr,
238865f46b2SCy Schubert 	socklen_t* addrlen, int port)
239b7579f77SDag-Erling Smørgrav {
240b7579f77SDag-Erling Smørgrav 	char* s;
241b7579f77SDag-Erling Smørgrav 	if((s=strchr(str, '@'))) {
242b7579f77SDag-Erling Smørgrav 		char buf[MAX_ADDR_STRLEN];
243b7579f77SDag-Erling Smørgrav 		if(s-str >= MAX_ADDR_STRLEN) {
244b7579f77SDag-Erling Smørgrav 			return 0;
245b7579f77SDag-Erling Smørgrav 		}
24617d15b25SDag-Erling Smørgrav 		(void)strlcpy(buf, str, sizeof(buf));
247b7579f77SDag-Erling Smørgrav 		buf[s-str] = 0;
248b7579f77SDag-Erling Smørgrav 		port = atoi(s+1);
249b7579f77SDag-Erling Smørgrav 		if(port == 0 && strcmp(s+1,"0")!=0) {
250b7579f77SDag-Erling Smørgrav 			return 0;
251b7579f77SDag-Erling Smørgrav 		}
252b7579f77SDag-Erling Smørgrav 		return ipstrtoaddr(buf, port, addr, addrlen);
253b7579f77SDag-Erling Smørgrav 	}
254b7579f77SDag-Erling Smørgrav 	return ipstrtoaddr(str, port, addr, addrlen);
255b7579f77SDag-Erling Smørgrav }
256b7579f77SDag-Erling Smørgrav 
257b7579f77SDag-Erling Smørgrav int
258b7579f77SDag-Erling Smørgrav ipstrtoaddr(const char* ip, int port, struct sockaddr_storage* addr,
259b7579f77SDag-Erling Smørgrav 	socklen_t* addrlen)
260b7579f77SDag-Erling Smørgrav {
261b7579f77SDag-Erling Smørgrav 	uint16_t p;
262b7579f77SDag-Erling Smørgrav 	if(!ip) return 0;
263b7579f77SDag-Erling Smørgrav 	p = (uint16_t) port;
264b7579f77SDag-Erling Smørgrav 	if(str_is_ip6(ip)) {
265b7579f77SDag-Erling Smørgrav 		char buf[MAX_ADDR_STRLEN];
266b7579f77SDag-Erling Smørgrav 		char* s;
267b7579f77SDag-Erling Smørgrav 		struct sockaddr_in6* sa = (struct sockaddr_in6*)addr;
268b7579f77SDag-Erling Smørgrav 		*addrlen = (socklen_t)sizeof(struct sockaddr_in6);
269b7579f77SDag-Erling Smørgrav 		memset(sa, 0, *addrlen);
270b7579f77SDag-Erling Smørgrav 		sa->sin6_family = AF_INET6;
271b7579f77SDag-Erling Smørgrav 		sa->sin6_port = (in_port_t)htons(p);
272b7579f77SDag-Erling Smørgrav 		if((s=strchr(ip, '%'))) { /* ip6%interface, rfc 4007 */
273b7579f77SDag-Erling Smørgrav 			if(s-ip >= MAX_ADDR_STRLEN)
274b7579f77SDag-Erling Smørgrav 				return 0;
27517d15b25SDag-Erling Smørgrav 			(void)strlcpy(buf, ip, sizeof(buf));
276b7579f77SDag-Erling Smørgrav 			buf[s-ip]=0;
27724e36522SCy Schubert #ifdef HAVE_IF_NAMETOINDEX
27824e36522SCy Schubert 			if (!(sa->sin6_scope_id = if_nametoindex(s+1)))
27924e36522SCy Schubert #endif /* HAVE_IF_NAMETOINDEX */
280b7579f77SDag-Erling Smørgrav 				sa->sin6_scope_id = (uint32_t)atoi(s+1);
281b7579f77SDag-Erling Smørgrav 			ip = buf;
282b7579f77SDag-Erling Smørgrav 		}
283b7579f77SDag-Erling Smørgrav 		if(inet_pton((int)sa->sin6_family, ip, &sa->sin6_addr) <= 0) {
284b7579f77SDag-Erling Smørgrav 			return 0;
285b7579f77SDag-Erling Smørgrav 		}
286b7579f77SDag-Erling Smørgrav 	} else { /* ip4 */
287b7579f77SDag-Erling Smørgrav 		struct sockaddr_in* sa = (struct sockaddr_in*)addr;
288b7579f77SDag-Erling Smørgrav 		*addrlen = (socklen_t)sizeof(struct sockaddr_in);
289b7579f77SDag-Erling Smørgrav 		memset(sa, 0, *addrlen);
290b7579f77SDag-Erling Smørgrav 		sa->sin_family = AF_INET;
291b7579f77SDag-Erling Smørgrav 		sa->sin_port = (in_port_t)htons(p);
292b7579f77SDag-Erling Smørgrav 		if(inet_pton((int)sa->sin_family, ip, &sa->sin_addr) <= 0) {
293b7579f77SDag-Erling Smørgrav 			return 0;
294b7579f77SDag-Erling Smørgrav 		}
295b7579f77SDag-Erling Smørgrav 	}
296b7579f77SDag-Erling Smørgrav 	return 1;
297b7579f77SDag-Erling Smørgrav }
298b7579f77SDag-Erling Smørgrav 
299b7579f77SDag-Erling Smørgrav int netblockstrtoaddr(const char* str, int port, struct sockaddr_storage* addr,
300b7579f77SDag-Erling Smørgrav         socklen_t* addrlen, int* net)
301b7579f77SDag-Erling Smørgrav {
3020fb34990SDag-Erling Smørgrav 	char buf[64];
3030fb34990SDag-Erling Smørgrav 	char* s;
304b7579f77SDag-Erling Smørgrav 	*net = (str_is_ip6(str)?128:32);
305b7579f77SDag-Erling Smørgrav 	if((s=strchr(str, '/'))) {
306b7579f77SDag-Erling Smørgrav 		if(atoi(s+1) > *net) {
307b7579f77SDag-Erling Smørgrav 			log_err("netblock too large: %s", str);
308b7579f77SDag-Erling Smørgrav 			return 0;
309b7579f77SDag-Erling Smørgrav 		}
310b7579f77SDag-Erling Smørgrav 		*net = atoi(s+1);
311b7579f77SDag-Erling Smørgrav 		if(*net == 0 && strcmp(s+1, "0") != 0) {
312b7579f77SDag-Erling Smørgrav 			log_err("cannot parse netblock: '%s'", str);
313b7579f77SDag-Erling Smørgrav 			return 0;
314b7579f77SDag-Erling Smørgrav 		}
3150fb34990SDag-Erling Smørgrav 		strlcpy(buf, str, sizeof(buf));
3160fb34990SDag-Erling Smørgrav 		s = strchr(buf, '/');
3170fb34990SDag-Erling Smørgrav 		if(s) *s = 0;
3180fb34990SDag-Erling Smørgrav 		s = buf;
319b7579f77SDag-Erling Smørgrav 	}
320b7579f77SDag-Erling Smørgrav 	if(!ipstrtoaddr(s?s:str, port, addr, addrlen)) {
321b7579f77SDag-Erling Smørgrav 		log_err("cannot parse ip address: '%s'", str);
322b7579f77SDag-Erling Smørgrav 		return 0;
323b7579f77SDag-Erling Smørgrav 	}
324b7579f77SDag-Erling Smørgrav 	if(s) {
325b7579f77SDag-Erling Smørgrav 		addr_mask(addr, *addrlen, *net);
326b7579f77SDag-Erling Smørgrav 	}
327b7579f77SDag-Erling Smørgrav 	return 1;
328b7579f77SDag-Erling Smørgrav }
329b7579f77SDag-Erling Smørgrav 
330091e9e46SCy Schubert /* RPZ format address dname to network byte order address */
331091e9e46SCy Schubert static int ipdnametoaddr(uint8_t* dname, size_t dnamelen,
332091e9e46SCy Schubert 	struct sockaddr_storage* addr, socklen_t* addrlen, int* af)
333091e9e46SCy Schubert {
334091e9e46SCy Schubert 	uint8_t* ia;
335f44e67d1SCy Schubert 	int dnamelabs = dname_count_labels(dname);
336091e9e46SCy Schubert 	uint8_t lablen;
337091e9e46SCy Schubert 	char* e = NULL;
338091e9e46SCy Schubert 	int z = 0;
339091e9e46SCy Schubert 	size_t len = 0;
340091e9e46SCy Schubert 	int i;
341091e9e46SCy Schubert 	*af = AF_INET;
342091e9e46SCy Schubert 
343091e9e46SCy Schubert 	/* need 1 byte for label length */
344091e9e46SCy Schubert 	if(dnamelen < 1)
345091e9e46SCy Schubert 		return 0;
346091e9e46SCy Schubert 
347091e9e46SCy Schubert 	if(dnamelabs > 6 ||
348091e9e46SCy Schubert 		dname_has_label(dname, dnamelen, (uint8_t*)"\002zz")) {
349091e9e46SCy Schubert 		*af = AF_INET6;
350091e9e46SCy Schubert 	}
351091e9e46SCy Schubert 	len = *dname;
352091e9e46SCy Schubert 	lablen = *dname++;
353091e9e46SCy Schubert 	i = (*af == AF_INET) ? 3 : 15;
354091e9e46SCy Schubert 	if(*af == AF_INET6) {
355091e9e46SCy Schubert 		struct sockaddr_in6* sa = (struct sockaddr_in6*)addr;
356091e9e46SCy Schubert 		*addrlen = (socklen_t)sizeof(struct sockaddr_in6);
357091e9e46SCy Schubert 		memset(sa, 0, *addrlen);
358091e9e46SCy Schubert 		sa->sin6_family = AF_INET6;
359091e9e46SCy Schubert 		ia = (uint8_t*)&sa->sin6_addr;
360091e9e46SCy Schubert 	} else { /* ip4 */
361091e9e46SCy Schubert 		struct sockaddr_in* sa = (struct sockaddr_in*)addr;
362091e9e46SCy Schubert 		*addrlen = (socklen_t)sizeof(struct sockaddr_in);
363091e9e46SCy Schubert 		memset(sa, 0, *addrlen);
364091e9e46SCy Schubert 		sa->sin_family = AF_INET;
365091e9e46SCy Schubert 		ia = (uint8_t*)&sa->sin_addr;
366091e9e46SCy Schubert 	}
367091e9e46SCy Schubert 	while(lablen && i >= 0 && len <= dnamelen) {
368091e9e46SCy Schubert 		char buff[LDNS_MAX_LABELLEN+1];
369091e9e46SCy Schubert 		uint16_t chunk; /* big enough to not overflow on IPv6 hextet */
370091e9e46SCy Schubert 		if((*af == AF_INET && (lablen > 3 || dnamelabs > 6)) ||
371091e9e46SCy Schubert 			(*af == AF_INET6 && (lablen > 4 || dnamelabs > 10))) {
372091e9e46SCy Schubert 			return 0;
373091e9e46SCy Schubert 		}
374091e9e46SCy Schubert 		if(memcmp(dname, "zz", 2) == 0 && *af == AF_INET6) {
375091e9e46SCy Schubert 			/* Add one or more 0 labels. Address is initialised at
376091e9e46SCy Schubert 			 * 0, so just skip the zero part. */
377091e9e46SCy Schubert 			int zl = 11 - dnamelabs;
378091e9e46SCy Schubert 			if(z || zl < 0)
379091e9e46SCy Schubert 				return 0;
380091e9e46SCy Schubert 			z = 1;
381091e9e46SCy Schubert 			i -= (zl*2);
382091e9e46SCy Schubert 		} else {
383091e9e46SCy Schubert 			memcpy(buff, dname, lablen);
384091e9e46SCy Schubert 			buff[lablen] = '\0';
385091e9e46SCy Schubert 			chunk = strtol(buff, &e, (*af == AF_INET) ? 10 : 16);
386091e9e46SCy Schubert 			if(!e || *e != '\0' || (*af == AF_INET && chunk > 255))
387091e9e46SCy Schubert 				return 0;
388091e9e46SCy Schubert 			if(*af == AF_INET) {
389091e9e46SCy Schubert 				log_assert(i < 4 && i >= 0);
390091e9e46SCy Schubert 				ia[i] = (uint8_t)chunk;
391091e9e46SCy Schubert 				i--;
392091e9e46SCy Schubert 			} else {
393091e9e46SCy Schubert 				log_assert(i < 16 && i >= 1);
394091e9e46SCy Schubert 				/* ia in network byte order */
395091e9e46SCy Schubert 				ia[i-1] = (uint8_t)(chunk >> 8);
396091e9e46SCy Schubert 				ia[i] = (uint8_t)(chunk & 0x00FF);
397091e9e46SCy Schubert 				i -= 2;
398091e9e46SCy Schubert 			}
399091e9e46SCy Schubert 		}
400091e9e46SCy Schubert 		dname += lablen;
401091e9e46SCy Schubert 		lablen = *dname++;
402091e9e46SCy Schubert 		len += lablen;
403091e9e46SCy Schubert 	}
404091e9e46SCy Schubert 	if(i != -1)
405091e9e46SCy Schubert 		/* input too short */
406091e9e46SCy Schubert 		return 0;
407091e9e46SCy Schubert 	return 1;
408091e9e46SCy Schubert }
409091e9e46SCy Schubert 
410091e9e46SCy Schubert int netblockdnametoaddr(uint8_t* dname, size_t dnamelen,
411091e9e46SCy Schubert 	struct sockaddr_storage* addr, socklen_t* addrlen, int* net, int* af)
412091e9e46SCy Schubert {
413091e9e46SCy Schubert 	char buff[3 /* 3 digit netblock */ + 1];
414091e9e46SCy Schubert 	size_t nlablen;
415091e9e46SCy Schubert 	if(dnamelen < 1 || *dname > 3)
416091e9e46SCy Schubert 		/* netblock invalid */
417091e9e46SCy Schubert 		return 0;
418091e9e46SCy Schubert 	nlablen = *dname;
419091e9e46SCy Schubert 
420091e9e46SCy Schubert 	if(dnamelen < 1 + nlablen)
421091e9e46SCy Schubert 		return 0;
422091e9e46SCy Schubert 
423091e9e46SCy Schubert 	memcpy(buff, dname+1, nlablen);
424091e9e46SCy Schubert 	buff[nlablen] = '\0';
425091e9e46SCy Schubert 	*net = atoi(buff);
426091e9e46SCy Schubert 	if(*net == 0 && strcmp(buff, "0") != 0)
427091e9e46SCy Schubert 		return 0;
428091e9e46SCy Schubert 	dname += nlablen;
429091e9e46SCy Schubert 	dname++;
430091e9e46SCy Schubert 	if(!ipdnametoaddr(dname, dnamelen-1-nlablen, addr, addrlen, af))
431091e9e46SCy Schubert 		return 0;
432091e9e46SCy Schubert 	if((*af == AF_INET6 && *net > 128) || (*af == AF_INET && *net > 32))
433091e9e46SCy Schubert 		return 0;
434091e9e46SCy Schubert 	return 1;
435091e9e46SCy Schubert }
436091e9e46SCy Schubert 
4370fb34990SDag-Erling Smørgrav int authextstrtoaddr(char* str, struct sockaddr_storage* addr,
4380fb34990SDag-Erling Smørgrav 	socklen_t* addrlen, char** auth_name)
4390fb34990SDag-Erling Smørgrav {
4400fb34990SDag-Erling Smørgrav 	char* s;
4410fb34990SDag-Erling Smørgrav 	int port = UNBOUND_DNS_PORT;
4420fb34990SDag-Erling Smørgrav 	if((s=strchr(str, '@'))) {
4430fb34990SDag-Erling Smørgrav 		char buf[MAX_ADDR_STRLEN];
4440fb34990SDag-Erling Smørgrav 		size_t len = (size_t)(s-str);
4450fb34990SDag-Erling Smørgrav 		char* hash = strchr(s+1, '#');
4460fb34990SDag-Erling Smørgrav 		if(hash) {
4470fb34990SDag-Erling Smørgrav 			*auth_name = hash+1;
4480fb34990SDag-Erling Smørgrav 		} else {
4490fb34990SDag-Erling Smørgrav 			*auth_name = NULL;
4500fb34990SDag-Erling Smørgrav 		}
4510fb34990SDag-Erling Smørgrav 		if(len >= MAX_ADDR_STRLEN) {
4520fb34990SDag-Erling Smørgrav 			return 0;
4530fb34990SDag-Erling Smørgrav 		}
4540fb34990SDag-Erling Smørgrav 		(void)strlcpy(buf, str, sizeof(buf));
4550fb34990SDag-Erling Smørgrav 		buf[len] = 0;
4560fb34990SDag-Erling Smørgrav 		port = atoi(s+1);
4570fb34990SDag-Erling Smørgrav 		if(port == 0) {
4580fb34990SDag-Erling Smørgrav 			if(!hash && strcmp(s+1,"0")!=0)
4590fb34990SDag-Erling Smørgrav 				return 0;
4600fb34990SDag-Erling Smørgrav 			if(hash && strncmp(s+1,"0#",2)!=0)
4610fb34990SDag-Erling Smørgrav 				return 0;
4620fb34990SDag-Erling Smørgrav 		}
4630fb34990SDag-Erling Smørgrav 		return ipstrtoaddr(buf, port, addr, addrlen);
4640fb34990SDag-Erling Smørgrav 	}
4650fb34990SDag-Erling Smørgrav 	if((s=strchr(str, '#'))) {
4660fb34990SDag-Erling Smørgrav 		char buf[MAX_ADDR_STRLEN];
4670fb34990SDag-Erling Smørgrav 		size_t len = (size_t)(s-str);
4680fb34990SDag-Erling Smørgrav 		if(len >= MAX_ADDR_STRLEN) {
4690fb34990SDag-Erling Smørgrav 			return 0;
4700fb34990SDag-Erling Smørgrav 		}
4710fb34990SDag-Erling Smørgrav 		(void)strlcpy(buf, str, sizeof(buf));
4720fb34990SDag-Erling Smørgrav 		buf[len] = 0;
4730fb34990SDag-Erling Smørgrav 		port = UNBOUND_DNS_OVER_TLS_PORT;
4740fb34990SDag-Erling Smørgrav 		*auth_name = s+1;
4750fb34990SDag-Erling Smørgrav 		return ipstrtoaddr(buf, port, addr, addrlen);
4760fb34990SDag-Erling Smørgrav 	}
4770fb34990SDag-Erling Smørgrav 	*auth_name = NULL;
4780fb34990SDag-Erling Smørgrav 	return ipstrtoaddr(str, port, addr, addrlen);
4790fb34990SDag-Erling Smørgrav }
4800fb34990SDag-Erling Smørgrav 
4819cf5bc93SCy Schubert uint8_t* authextstrtodname(char* str, int* port, char** auth_name)
4829cf5bc93SCy Schubert {
4839cf5bc93SCy Schubert 	char* s;
4849cf5bc93SCy Schubert 	uint8_t* dname;
4859cf5bc93SCy Schubert 	size_t dname_len;
4869cf5bc93SCy Schubert 	*port = UNBOUND_DNS_PORT;
4879cf5bc93SCy Schubert 	*auth_name = NULL;
4889cf5bc93SCy Schubert 	if((s=strchr(str, '@'))) {
4899cf5bc93SCy Schubert 		char* hash = strchr(s+1, '#');
4909cf5bc93SCy Schubert 		if(hash) {
4919cf5bc93SCy Schubert 			*auth_name = hash+1;
4929cf5bc93SCy Schubert 		} else {
4939cf5bc93SCy Schubert 			*auth_name = NULL;
4949cf5bc93SCy Schubert 		}
4959cf5bc93SCy Schubert 		*port = atoi(s+1);
4969cf5bc93SCy Schubert 		if(*port == 0) {
4979cf5bc93SCy Schubert 			if(!hash && strcmp(s+1,"0")!=0)
4989cf5bc93SCy Schubert 				return 0;
4999cf5bc93SCy Schubert 			if(hash && strncmp(s+1,"0#",2)!=0)
5009cf5bc93SCy Schubert 				return 0;
5019cf5bc93SCy Schubert 		}
5029cf5bc93SCy Schubert 		*s = 0;
5039cf5bc93SCy Schubert 		dname = sldns_str2wire_dname(str, &dname_len);
5049cf5bc93SCy Schubert 		*s = '@';
5059cf5bc93SCy Schubert 	} else if((s=strchr(str, '#'))) {
5069cf5bc93SCy Schubert 		*port = UNBOUND_DNS_OVER_TLS_PORT;
5079cf5bc93SCy Schubert 		*auth_name = s+1;
5089cf5bc93SCy Schubert 		*s = 0;
5099cf5bc93SCy Schubert 		dname = sldns_str2wire_dname(str, &dname_len);
5109cf5bc93SCy Schubert 		*s = '#';
5119cf5bc93SCy Schubert 	} else {
5129cf5bc93SCy Schubert 		dname = sldns_str2wire_dname(str, &dname_len);
5139cf5bc93SCy Schubert 	}
5149cf5bc93SCy Schubert 	return dname;
5159cf5bc93SCy Schubert }
5169cf5bc93SCy Schubert 
51757bddd21SDag-Erling Smørgrav /** store port number into sockaddr structure */
51857bddd21SDag-Erling Smørgrav void
51957bddd21SDag-Erling Smørgrav sockaddr_store_port(struct sockaddr_storage* addr, socklen_t addrlen, int port)
52057bddd21SDag-Erling Smørgrav {
52157bddd21SDag-Erling Smørgrav 	if(addr_is_ip6(addr, addrlen)) {
52257bddd21SDag-Erling Smørgrav 		struct sockaddr_in6* sa = (struct sockaddr_in6*)addr;
52357bddd21SDag-Erling Smørgrav 		sa->sin6_port = (in_port_t)htons((uint16_t)port);
52457bddd21SDag-Erling Smørgrav 	} else {
52557bddd21SDag-Erling Smørgrav 		struct sockaddr_in* sa = (struct sockaddr_in*)addr;
52657bddd21SDag-Erling Smørgrav 		sa->sin_port = (in_port_t)htons((uint16_t)port);
52757bddd21SDag-Erling Smørgrav 	}
52857bddd21SDag-Erling Smørgrav }
52957bddd21SDag-Erling Smørgrav 
530b7579f77SDag-Erling Smørgrav void
531b7579f77SDag-Erling Smørgrav log_nametypeclass(enum verbosity_value v, const char* str, uint8_t* name,
532b7579f77SDag-Erling Smørgrav 	uint16_t type, uint16_t dclass)
533b7579f77SDag-Erling Smørgrav {
534b7579f77SDag-Erling Smørgrav 	char buf[LDNS_MAX_DOMAINLEN+1];
535b7579f77SDag-Erling Smørgrav 	char t[12], c[12];
536b7579f77SDag-Erling Smørgrav 	const char *ts, *cs;
537b7579f77SDag-Erling Smørgrav 	if(verbosity < v)
538b7579f77SDag-Erling Smørgrav 		return;
539b7579f77SDag-Erling Smørgrav 	dname_str(name, buf);
540b7579f77SDag-Erling Smørgrav 	if(type == LDNS_RR_TYPE_TSIG) ts = "TSIG";
541b7579f77SDag-Erling Smørgrav 	else if(type == LDNS_RR_TYPE_IXFR) ts = "IXFR";
542b7579f77SDag-Erling Smørgrav 	else if(type == LDNS_RR_TYPE_AXFR) ts = "AXFR";
543b7579f77SDag-Erling Smørgrav 	else if(type == LDNS_RR_TYPE_MAILB) ts = "MAILB";
544b7579f77SDag-Erling Smørgrav 	else if(type == LDNS_RR_TYPE_MAILA) ts = "MAILA";
545b7579f77SDag-Erling Smørgrav 	else if(type == LDNS_RR_TYPE_ANY) ts = "ANY";
54617d15b25SDag-Erling Smørgrav 	else if(sldns_rr_descript(type) && sldns_rr_descript(type)->_name)
54717d15b25SDag-Erling Smørgrav 		ts = sldns_rr_descript(type)->_name;
548b7579f77SDag-Erling Smørgrav 	else {
549b7579f77SDag-Erling Smørgrav 		snprintf(t, sizeof(t), "TYPE%d", (int)type);
550b7579f77SDag-Erling Smørgrav 		ts = t;
551b7579f77SDag-Erling Smørgrav 	}
55217d15b25SDag-Erling Smørgrav 	if(sldns_lookup_by_id(sldns_rr_classes, (int)dclass) &&
55317d15b25SDag-Erling Smørgrav 		sldns_lookup_by_id(sldns_rr_classes, (int)dclass)->name)
55417d15b25SDag-Erling Smørgrav 		cs = sldns_lookup_by_id(sldns_rr_classes, (int)dclass)->name;
555b7579f77SDag-Erling Smørgrav 	else {
556b7579f77SDag-Erling Smørgrav 		snprintf(c, sizeof(c), "CLASS%d", (int)dclass);
557b7579f77SDag-Erling Smørgrav 		cs = c;
558b7579f77SDag-Erling Smørgrav 	}
559b7579f77SDag-Erling Smørgrav 	log_info("%s %s %s %s", str, buf, ts, cs);
560b7579f77SDag-Erling Smørgrav }
561b7579f77SDag-Erling Smørgrav 
562e86b9096SDag-Erling Smørgrav void
563e86b9096SDag-Erling Smørgrav log_query_in(const char* str, uint8_t* name, uint16_t type, uint16_t dclass)
564e86b9096SDag-Erling Smørgrav {
565e86b9096SDag-Erling Smørgrav 	char buf[LDNS_MAX_DOMAINLEN+1];
566e86b9096SDag-Erling Smørgrav 	char t[12], c[12];
567e86b9096SDag-Erling Smørgrav 	const char *ts, *cs;
568e86b9096SDag-Erling Smørgrav 	dname_str(name, buf);
569e86b9096SDag-Erling Smørgrav 	if(type == LDNS_RR_TYPE_TSIG) ts = "TSIG";
570e86b9096SDag-Erling Smørgrav 	else if(type == LDNS_RR_TYPE_IXFR) ts = "IXFR";
571e86b9096SDag-Erling Smørgrav 	else if(type == LDNS_RR_TYPE_AXFR) ts = "AXFR";
572e86b9096SDag-Erling Smørgrav 	else if(type == LDNS_RR_TYPE_MAILB) ts = "MAILB";
573e86b9096SDag-Erling Smørgrav 	else if(type == LDNS_RR_TYPE_MAILA) ts = "MAILA";
574e86b9096SDag-Erling Smørgrav 	else if(type == LDNS_RR_TYPE_ANY) ts = "ANY";
575e86b9096SDag-Erling Smørgrav 	else if(sldns_rr_descript(type) && sldns_rr_descript(type)->_name)
576e86b9096SDag-Erling Smørgrav 		ts = sldns_rr_descript(type)->_name;
577e86b9096SDag-Erling Smørgrav 	else {
578e86b9096SDag-Erling Smørgrav 		snprintf(t, sizeof(t), "TYPE%d", (int)type);
579e86b9096SDag-Erling Smørgrav 		ts = t;
580e86b9096SDag-Erling Smørgrav 	}
581e86b9096SDag-Erling Smørgrav 	if(sldns_lookup_by_id(sldns_rr_classes, (int)dclass) &&
582e86b9096SDag-Erling Smørgrav 		sldns_lookup_by_id(sldns_rr_classes, (int)dclass)->name)
583e86b9096SDag-Erling Smørgrav 		cs = sldns_lookup_by_id(sldns_rr_classes, (int)dclass)->name;
584e86b9096SDag-Erling Smørgrav 	else {
585e86b9096SDag-Erling Smørgrav 		snprintf(c, sizeof(c), "CLASS%d", (int)dclass);
586e86b9096SDag-Erling Smørgrav 		cs = c;
587e86b9096SDag-Erling Smørgrav 	}
588e86b9096SDag-Erling Smørgrav 	if(LOG_TAG_QUERYREPLY)
589e86b9096SDag-Erling Smørgrav 		log_query("%s %s %s %s", str, buf, ts, cs);
590e86b9096SDag-Erling Smørgrav 	else	log_info("%s %s %s %s", str, buf, ts, cs);
591e86b9096SDag-Erling Smørgrav }
592e86b9096SDag-Erling Smørgrav 
593b7579f77SDag-Erling Smørgrav void log_name_addr(enum verbosity_value v, const char* str, uint8_t* zone,
594b7579f77SDag-Erling Smørgrav 	struct sockaddr_storage* addr, socklen_t addrlen)
595b7579f77SDag-Erling Smørgrav {
596b7579f77SDag-Erling Smørgrav 	uint16_t port;
597b7579f77SDag-Erling Smørgrav 	const char* family = "unknown_family ";
598b7579f77SDag-Erling Smørgrav 	char namebuf[LDNS_MAX_DOMAINLEN+1];
599b7579f77SDag-Erling Smørgrav 	char dest[100];
600b7579f77SDag-Erling Smørgrav 	int af = (int)((struct sockaddr_in*)addr)->sin_family;
601b7579f77SDag-Erling Smørgrav 	void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
602b7579f77SDag-Erling Smørgrav 	if(verbosity < v)
603b7579f77SDag-Erling Smørgrav 		return;
604b7579f77SDag-Erling Smørgrav 	switch(af) {
605b7579f77SDag-Erling Smørgrav 		case AF_INET: family=""; break;
606b7579f77SDag-Erling Smørgrav 		case AF_INET6: family="";
607b7579f77SDag-Erling Smørgrav 			sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
608b7579f77SDag-Erling Smørgrav 			break;
60931099b50SDag-Erling Smørgrav 		case AF_LOCAL: family="local "; break;
610b7579f77SDag-Erling Smørgrav 		default: break;
611b7579f77SDag-Erling Smørgrav 	}
612b7579f77SDag-Erling Smørgrav 	if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
61317d15b25SDag-Erling Smørgrav 		(void)strlcpy(dest, "(inet_ntop error)", sizeof(dest));
614b7579f77SDag-Erling Smørgrav 	}
615b7579f77SDag-Erling Smørgrav 	dest[sizeof(dest)-1] = 0;
616b7579f77SDag-Erling Smørgrav 	port = ntohs(((struct sockaddr_in*)addr)->sin_port);
617b7579f77SDag-Erling Smørgrav 	dname_str(zone, namebuf);
618b7579f77SDag-Erling Smørgrav 	if(af != AF_INET && af != AF_INET6)
619b7579f77SDag-Erling Smørgrav 		verbose(v, "%s <%s> %s%s#%d (addrlen %d)",
620b7579f77SDag-Erling Smørgrav 			str, namebuf, family, dest, (int)port, (int)addrlen);
621b7579f77SDag-Erling Smørgrav 	else	verbose(v, "%s <%s> %s%s#%d",
622b7579f77SDag-Erling Smørgrav 			str, namebuf, family, dest, (int)port);
623b7579f77SDag-Erling Smørgrav }
624b7579f77SDag-Erling Smørgrav 
625ff825849SDag-Erling Smørgrav void log_err_addr(const char* str, const char* err,
626ff825849SDag-Erling Smørgrav 	struct sockaddr_storage* addr, socklen_t addrlen)
627ff825849SDag-Erling Smørgrav {
628ff825849SDag-Erling Smørgrav 	uint16_t port;
629ff825849SDag-Erling Smørgrav 	char dest[100];
630ff825849SDag-Erling Smørgrav 	int af = (int)((struct sockaddr_in*)addr)->sin_family;
631ff825849SDag-Erling Smørgrav 	void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
632ff825849SDag-Erling Smørgrav 	if(af == AF_INET6)
633ff825849SDag-Erling Smørgrav 		sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
634ff825849SDag-Erling Smørgrav 	if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
635ff825849SDag-Erling Smørgrav 		(void)strlcpy(dest, "(inet_ntop error)", sizeof(dest));
636ff825849SDag-Erling Smørgrav 	}
637ff825849SDag-Erling Smørgrav 	dest[sizeof(dest)-1] = 0;
638ff825849SDag-Erling Smørgrav 	port = ntohs(((struct sockaddr_in*)addr)->sin_port);
639ff825849SDag-Erling Smørgrav 	if(verbosity >= 4)
640ff825849SDag-Erling Smørgrav 		log_err("%s: %s for %s port %d (len %d)", str, err, dest,
641ff825849SDag-Erling Smørgrav 			(int)port, (int)addrlen);
6424c75e3aaSDag-Erling Smørgrav 	else	log_err("%s: %s for %s port %d", str, err, dest, (int)port);
643ff825849SDag-Erling Smørgrav }
644ff825849SDag-Erling Smørgrav 
645b7579f77SDag-Erling Smørgrav int
646b7579f77SDag-Erling Smørgrav sockaddr_cmp(struct sockaddr_storage* addr1, socklen_t len1,
647b7579f77SDag-Erling Smørgrav 	struct sockaddr_storage* addr2, socklen_t len2)
648b7579f77SDag-Erling Smørgrav {
649b7579f77SDag-Erling Smørgrav 	struct sockaddr_in* p1_in = (struct sockaddr_in*)addr1;
650b7579f77SDag-Erling Smørgrav 	struct sockaddr_in* p2_in = (struct sockaddr_in*)addr2;
651b7579f77SDag-Erling Smørgrav 	struct sockaddr_in6* p1_in6 = (struct sockaddr_in6*)addr1;
652b7579f77SDag-Erling Smørgrav 	struct sockaddr_in6* p2_in6 = (struct sockaddr_in6*)addr2;
653b7579f77SDag-Erling Smørgrav 	if(len1 < len2)
654b7579f77SDag-Erling Smørgrav 		return -1;
655b7579f77SDag-Erling Smørgrav 	if(len1 > len2)
656b7579f77SDag-Erling Smørgrav 		return 1;
657b7579f77SDag-Erling Smørgrav 	log_assert(len1 == len2);
658b7579f77SDag-Erling Smørgrav 	if( p1_in->sin_family < p2_in->sin_family)
659b7579f77SDag-Erling Smørgrav 		return -1;
660b7579f77SDag-Erling Smørgrav 	if( p1_in->sin_family > p2_in->sin_family)
661b7579f77SDag-Erling Smørgrav 		return 1;
662b7579f77SDag-Erling Smørgrav 	log_assert( p1_in->sin_family == p2_in->sin_family );
663b7579f77SDag-Erling Smørgrav 	/* compare ip4 */
664b7579f77SDag-Erling Smørgrav 	if( p1_in->sin_family == AF_INET ) {
665b7579f77SDag-Erling Smørgrav 		/* just order it, ntohs not required */
666b7579f77SDag-Erling Smørgrav 		if(p1_in->sin_port < p2_in->sin_port)
667b7579f77SDag-Erling Smørgrav 			return -1;
668b7579f77SDag-Erling Smørgrav 		if(p1_in->sin_port > p2_in->sin_port)
669b7579f77SDag-Erling Smørgrav 			return 1;
670b7579f77SDag-Erling Smørgrav 		log_assert(p1_in->sin_port == p2_in->sin_port);
671b7579f77SDag-Erling Smørgrav 		return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE);
672b7579f77SDag-Erling Smørgrav 	} else if (p1_in6->sin6_family == AF_INET6) {
673b7579f77SDag-Erling Smørgrav 		/* just order it, ntohs not required */
674b7579f77SDag-Erling Smørgrav 		if(p1_in6->sin6_port < p2_in6->sin6_port)
675b7579f77SDag-Erling Smørgrav 			return -1;
676b7579f77SDag-Erling Smørgrav 		if(p1_in6->sin6_port > p2_in6->sin6_port)
677b7579f77SDag-Erling Smørgrav 			return 1;
678b7579f77SDag-Erling Smørgrav 		log_assert(p1_in6->sin6_port == p2_in6->sin6_port);
679b7579f77SDag-Erling Smørgrav 		return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr,
680b7579f77SDag-Erling Smørgrav 			INET6_SIZE);
681b7579f77SDag-Erling Smørgrav 	} else {
682b7579f77SDag-Erling Smørgrav 		/* eek unknown type, perform this comparison for sanity. */
683b7579f77SDag-Erling Smørgrav 		return memcmp(addr1, addr2, len1);
684b7579f77SDag-Erling Smørgrav 	}
685b7579f77SDag-Erling Smørgrav }
686b7579f77SDag-Erling Smørgrav 
687b7579f77SDag-Erling Smørgrav int
688b7579f77SDag-Erling Smørgrav sockaddr_cmp_addr(struct sockaddr_storage* addr1, socklen_t len1,
689b7579f77SDag-Erling Smørgrav 	struct sockaddr_storage* addr2, socklen_t len2)
690b7579f77SDag-Erling Smørgrav {
691b7579f77SDag-Erling Smørgrav 	struct sockaddr_in* p1_in = (struct sockaddr_in*)addr1;
692b7579f77SDag-Erling Smørgrav 	struct sockaddr_in* p2_in = (struct sockaddr_in*)addr2;
693b7579f77SDag-Erling Smørgrav 	struct sockaddr_in6* p1_in6 = (struct sockaddr_in6*)addr1;
694b7579f77SDag-Erling Smørgrav 	struct sockaddr_in6* p2_in6 = (struct sockaddr_in6*)addr2;
695b7579f77SDag-Erling Smørgrav 	if(len1 < len2)
696b7579f77SDag-Erling Smørgrav 		return -1;
697b7579f77SDag-Erling Smørgrav 	if(len1 > len2)
698b7579f77SDag-Erling Smørgrav 		return 1;
699b7579f77SDag-Erling Smørgrav 	log_assert(len1 == len2);
700b7579f77SDag-Erling Smørgrav 	if( p1_in->sin_family < p2_in->sin_family)
701b7579f77SDag-Erling Smørgrav 		return -1;
702b7579f77SDag-Erling Smørgrav 	if( p1_in->sin_family > p2_in->sin_family)
703b7579f77SDag-Erling Smørgrav 		return 1;
704b7579f77SDag-Erling Smørgrav 	log_assert( p1_in->sin_family == p2_in->sin_family );
705b7579f77SDag-Erling Smørgrav 	/* compare ip4 */
706b7579f77SDag-Erling Smørgrav 	if( p1_in->sin_family == AF_INET ) {
707b7579f77SDag-Erling Smørgrav 		return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE);
708b7579f77SDag-Erling Smørgrav 	} else if (p1_in6->sin6_family == AF_INET6) {
709b7579f77SDag-Erling Smørgrav 		return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr,
710b7579f77SDag-Erling Smørgrav 			INET6_SIZE);
711b7579f77SDag-Erling Smørgrav 	} else {
712b7579f77SDag-Erling Smørgrav 		/* eek unknown type, perform this comparison for sanity. */
713b7579f77SDag-Erling Smørgrav 		return memcmp(addr1, addr2, len1);
714b7579f77SDag-Erling Smørgrav 	}
715b7579f77SDag-Erling Smørgrav }
716b7579f77SDag-Erling Smørgrav 
717b7579f77SDag-Erling Smørgrav int
718b7579f77SDag-Erling Smørgrav addr_is_ip6(struct sockaddr_storage* addr, socklen_t len)
719b7579f77SDag-Erling Smørgrav {
720b7579f77SDag-Erling Smørgrav 	if(len == (socklen_t)sizeof(struct sockaddr_in6) &&
721b7579f77SDag-Erling Smørgrav 		((struct sockaddr_in6*)addr)->sin6_family == AF_INET6)
722b7579f77SDag-Erling Smørgrav 		return 1;
723b7579f77SDag-Erling Smørgrav 	else    return 0;
724b7579f77SDag-Erling Smørgrav }
725b7579f77SDag-Erling Smørgrav 
726b7579f77SDag-Erling Smørgrav void
727b7579f77SDag-Erling Smørgrav addr_mask(struct sockaddr_storage* addr, socklen_t len, int net)
728b7579f77SDag-Erling Smørgrav {
729b7579f77SDag-Erling Smørgrav 	uint8_t mask[8] = {0x0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe};
730b7579f77SDag-Erling Smørgrav 	int i, max;
731b7579f77SDag-Erling Smørgrav 	uint8_t* s;
732b7579f77SDag-Erling Smørgrav 	if(addr_is_ip6(addr, len)) {
733b7579f77SDag-Erling Smørgrav 		s = (uint8_t*)&((struct sockaddr_in6*)addr)->sin6_addr;
734b7579f77SDag-Erling Smørgrav 		max = 128;
735b7579f77SDag-Erling Smørgrav 	} else {
736b7579f77SDag-Erling Smørgrav 		s = (uint8_t*)&((struct sockaddr_in*)addr)->sin_addr;
737b7579f77SDag-Erling Smørgrav 		max = 32;
738b7579f77SDag-Erling Smørgrav 	}
739b7579f77SDag-Erling Smørgrav 	if(net >= max)
740b7579f77SDag-Erling Smørgrav 		return;
741b7579f77SDag-Erling Smørgrav 	for(i=net/8+1; i<max/8; i++) {
742b7579f77SDag-Erling Smørgrav 		s[i] = 0;
743b7579f77SDag-Erling Smørgrav 	}
744b7579f77SDag-Erling Smørgrav 	s[net/8] &= mask[net&0x7];
745b7579f77SDag-Erling Smørgrav }
746b7579f77SDag-Erling Smørgrav 
747b7579f77SDag-Erling Smørgrav int
748b7579f77SDag-Erling Smørgrav addr_in_common(struct sockaddr_storage* addr1, int net1,
749b7579f77SDag-Erling Smørgrav 	struct sockaddr_storage* addr2, int net2, socklen_t addrlen)
750b7579f77SDag-Erling Smørgrav {
751b7579f77SDag-Erling Smørgrav 	int min = (net1<net2)?net1:net2;
752b7579f77SDag-Erling Smørgrav 	int i, to;
753b7579f77SDag-Erling Smørgrav 	int match = 0;
754b7579f77SDag-Erling Smørgrav 	uint8_t* s1, *s2;
755b7579f77SDag-Erling Smørgrav 	if(addr_is_ip6(addr1, addrlen)) {
756b7579f77SDag-Erling Smørgrav 		s1 = (uint8_t*)&((struct sockaddr_in6*)addr1)->sin6_addr;
757b7579f77SDag-Erling Smørgrav 		s2 = (uint8_t*)&((struct sockaddr_in6*)addr2)->sin6_addr;
758b7579f77SDag-Erling Smørgrav 		to = 16;
759b7579f77SDag-Erling Smørgrav 	} else {
760b7579f77SDag-Erling Smørgrav 		s1 = (uint8_t*)&((struct sockaddr_in*)addr1)->sin_addr;
761b7579f77SDag-Erling Smørgrav 		s2 = (uint8_t*)&((struct sockaddr_in*)addr2)->sin_addr;
762b7579f77SDag-Erling Smørgrav 		to = 4;
763b7579f77SDag-Erling Smørgrav 	}
764b7579f77SDag-Erling Smørgrav 	/* match = bits_in_common(s1, s2, to); */
765b7579f77SDag-Erling Smørgrav 	for(i=0; i<to; i++) {
766b7579f77SDag-Erling Smørgrav 		if(s1[i] == s2[i]) {
767b7579f77SDag-Erling Smørgrav 			match += 8;
768b7579f77SDag-Erling Smørgrav 		} else {
769b7579f77SDag-Erling Smørgrav 			uint8_t z = s1[i]^s2[i];
770b7579f77SDag-Erling Smørgrav 			log_assert(z);
771b7579f77SDag-Erling Smørgrav 			while(!(z&0x80)) {
772b7579f77SDag-Erling Smørgrav 				match++;
773b7579f77SDag-Erling Smørgrav 				z<<=1;
774b7579f77SDag-Erling Smørgrav 			}
775b7579f77SDag-Erling Smørgrav 			break;
776b7579f77SDag-Erling Smørgrav 		}
777b7579f77SDag-Erling Smørgrav 	}
778b7579f77SDag-Erling Smørgrav 	if(match > min) match = min;
779b7579f77SDag-Erling Smørgrav 	return match;
780b7579f77SDag-Erling Smørgrav }
781b7579f77SDag-Erling Smørgrav 
782b7579f77SDag-Erling Smørgrav void
783b7579f77SDag-Erling Smørgrav addr_to_str(struct sockaddr_storage* addr, socklen_t addrlen,
784b7579f77SDag-Erling Smørgrav 	char* buf, size_t len)
785b7579f77SDag-Erling Smørgrav {
786b7579f77SDag-Erling Smørgrav 	int af = (int)((struct sockaddr_in*)addr)->sin_family;
787b7579f77SDag-Erling Smørgrav 	void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
788b7579f77SDag-Erling Smørgrav 	if(addr_is_ip6(addr, addrlen))
789b7579f77SDag-Erling Smørgrav 		sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
790b7579f77SDag-Erling Smørgrav 	if(inet_ntop(af, sinaddr, buf, (socklen_t)len) == 0) {
791b7579f77SDag-Erling Smørgrav 		snprintf(buf, len, "(inet_ntop_error)");
792b7579f77SDag-Erling Smørgrav 	}
793b7579f77SDag-Erling Smørgrav }
794b7579f77SDag-Erling Smørgrav 
795b7579f77SDag-Erling Smørgrav int
796*8f76bb7dSCy Schubert prefixnet_is_nat64(int prefixnet)
797*8f76bb7dSCy Schubert {
798*8f76bb7dSCy Schubert 	return (prefixnet == 32 || prefixnet == 40 ||
799*8f76bb7dSCy Schubert 		prefixnet == 48 || prefixnet == 56 ||
800*8f76bb7dSCy Schubert 		prefixnet == 64 || prefixnet == 96);
801*8f76bb7dSCy Schubert }
802*8f76bb7dSCy Schubert 
803*8f76bb7dSCy Schubert void
804*8f76bb7dSCy Schubert addr_to_nat64(const struct sockaddr_storage* addr,
805*8f76bb7dSCy Schubert 	const struct sockaddr_storage* nat64_prefix,
806*8f76bb7dSCy Schubert 	socklen_t nat64_prefixlen, int nat64_prefixnet,
807*8f76bb7dSCy Schubert 	struct sockaddr_storage* nat64_addr, socklen_t* nat64_addrlen)
808*8f76bb7dSCy Schubert {
809*8f76bb7dSCy Schubert 	struct sockaddr_in *sin = (struct sockaddr_in *)addr;
810*8f76bb7dSCy Schubert 	struct sockaddr_in6 *sin6;
811*8f76bb7dSCy Schubert 	uint8_t *v4_byte;
812*8f76bb7dSCy Schubert 
813*8f76bb7dSCy Schubert 	/* This needs to be checked by the caller */
814*8f76bb7dSCy Schubert 	log_assert(addr->ss_family == AF_INET);
815*8f76bb7dSCy Schubert 	/* Current usage is only from config values; prefix lengths enforced
816*8f76bb7dSCy Schubert 	 * during config validation */
817*8f76bb7dSCy Schubert 	log_assert(prefixnet_is_nat64(nat64_prefixnet));
818*8f76bb7dSCy Schubert 
819*8f76bb7dSCy Schubert 	*nat64_addr = *nat64_prefix;
820*8f76bb7dSCy Schubert 	*nat64_addrlen = nat64_prefixlen;
821*8f76bb7dSCy Schubert 
822*8f76bb7dSCy Schubert 	sin6 = (struct sockaddr_in6 *)nat64_addr;
823*8f76bb7dSCy Schubert 	sin6->sin6_flowinfo = 0;
824*8f76bb7dSCy Schubert 	sin6->sin6_port = sin->sin_port;
825*8f76bb7dSCy Schubert 
826*8f76bb7dSCy Schubert 	nat64_prefixnet = nat64_prefixnet / 8;
827*8f76bb7dSCy Schubert 
828*8f76bb7dSCy Schubert 	v4_byte = (uint8_t *)&sin->sin_addr.s_addr;
829*8f76bb7dSCy Schubert 	for(int i = 0; i < 4; i++) {
830*8f76bb7dSCy Schubert 		if(nat64_prefixnet == 8) {
831*8f76bb7dSCy Schubert 			/* bits 64...71 are MBZ */
832*8f76bb7dSCy Schubert 			sin6->sin6_addr.s6_addr[nat64_prefixnet++] = 0;
833*8f76bb7dSCy Schubert 		}
834*8f76bb7dSCy Schubert 		sin6->sin6_addr.s6_addr[nat64_prefixnet++] = *v4_byte++;
835*8f76bb7dSCy Schubert 	}
836*8f76bb7dSCy Schubert }
837*8f76bb7dSCy Schubert 
838*8f76bb7dSCy Schubert int
839b7579f77SDag-Erling Smørgrav addr_is_ip4mapped(struct sockaddr_storage* addr, socklen_t addrlen)
840b7579f77SDag-Erling Smørgrav {
841b7579f77SDag-Erling Smørgrav 	/* prefix for ipv4 into ipv6 mapping is ::ffff:x.x.x.x */
842b7579f77SDag-Erling Smørgrav 	const uint8_t map_prefix[16] =
843b7579f77SDag-Erling Smørgrav 		{0,0,0,0,  0,0,0,0, 0,0,0xff,0xff, 0,0,0,0};
844b7579f77SDag-Erling Smørgrav 	uint8_t* s;
845b7579f77SDag-Erling Smørgrav 	if(!addr_is_ip6(addr, addrlen))
846b7579f77SDag-Erling Smørgrav 		return 0;
847b7579f77SDag-Erling Smørgrav 	/* s is 16 octet ipv6 address string */
848b7579f77SDag-Erling Smørgrav 	s = (uint8_t*)&((struct sockaddr_in6*)addr)->sin6_addr;
849b7579f77SDag-Erling Smørgrav 	return (memcmp(s, map_prefix, 12) == 0);
850b7579f77SDag-Erling Smørgrav }
851b7579f77SDag-Erling Smørgrav 
852b7579f77SDag-Erling Smørgrav int addr_is_broadcast(struct sockaddr_storage* addr, socklen_t addrlen)
853b7579f77SDag-Erling Smørgrav {
854b7579f77SDag-Erling Smørgrav 	int af = (int)((struct sockaddr_in*)addr)->sin_family;
855b7579f77SDag-Erling Smørgrav 	void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
856b7579f77SDag-Erling Smørgrav 	return af == AF_INET && addrlen>=(socklen_t)sizeof(struct sockaddr_in)
857b7579f77SDag-Erling Smørgrav 		&& memcmp(sinaddr, "\377\377\377\377", 4) == 0;
858b7579f77SDag-Erling Smørgrav }
859b7579f77SDag-Erling Smørgrav 
860b7579f77SDag-Erling Smørgrav int addr_is_any(struct sockaddr_storage* addr, socklen_t addrlen)
861b7579f77SDag-Erling Smørgrav {
862b7579f77SDag-Erling Smørgrav 	int af = (int)((struct sockaddr_in*)addr)->sin_family;
863b7579f77SDag-Erling Smørgrav 	void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
864b7579f77SDag-Erling Smørgrav 	void* sin6addr = &((struct sockaddr_in6*)addr)->sin6_addr;
865b7579f77SDag-Erling Smørgrav 	if(af == AF_INET && addrlen>=(socklen_t)sizeof(struct sockaddr_in)
866b7579f77SDag-Erling Smørgrav 		&& memcmp(sinaddr, "\000\000\000\000", 4) == 0)
867b7579f77SDag-Erling Smørgrav 		return 1;
868b7579f77SDag-Erling Smørgrav 	else if(af==AF_INET6 && addrlen>=(socklen_t)sizeof(struct sockaddr_in6)
869b7579f77SDag-Erling Smørgrav 		&& memcmp(sin6addr, "\000\000\000\000\000\000\000\000"
870b7579f77SDag-Erling Smørgrav 		"\000\000\000\000\000\000\000\000", 16) == 0)
871b7579f77SDag-Erling Smørgrav 		return 1;
872b7579f77SDag-Erling Smørgrav 	return 0;
873b7579f77SDag-Erling Smørgrav }
874b7579f77SDag-Erling Smørgrav 
875b7579f77SDag-Erling Smørgrav void sock_list_insert(struct sock_list** list, struct sockaddr_storage* addr,
876b7579f77SDag-Erling Smørgrav 	socklen_t len, struct regional* region)
877b7579f77SDag-Erling Smørgrav {
878b7579f77SDag-Erling Smørgrav 	struct sock_list* add = (struct sock_list*)regional_alloc(region,
879b7579f77SDag-Erling Smørgrav 		sizeof(*add) - sizeof(add->addr) + (size_t)len);
880b7579f77SDag-Erling Smørgrav 	if(!add) {
881b7579f77SDag-Erling Smørgrav 		log_err("out of memory in socketlist insert");
882b7579f77SDag-Erling Smørgrav 		return;
883b7579f77SDag-Erling Smørgrav 	}
884b7579f77SDag-Erling Smørgrav 	log_assert(list);
885b7579f77SDag-Erling Smørgrav 	add->next = *list;
886b7579f77SDag-Erling Smørgrav 	add->len = len;
887b7579f77SDag-Erling Smørgrav 	*list = add;
888b7579f77SDag-Erling Smørgrav 	if(len) memmove(&add->addr, addr, len);
889b7579f77SDag-Erling Smørgrav }
890b7579f77SDag-Erling Smørgrav 
891b7579f77SDag-Erling Smørgrav void sock_list_prepend(struct sock_list** list, struct sock_list* add)
892b7579f77SDag-Erling Smørgrav {
893b7579f77SDag-Erling Smørgrav 	struct sock_list* last = add;
894b7579f77SDag-Erling Smørgrav 	if(!last)
895b7579f77SDag-Erling Smørgrav 		return;
896b7579f77SDag-Erling Smørgrav 	while(last->next)
897b7579f77SDag-Erling Smørgrav 		last = last->next;
898b7579f77SDag-Erling Smørgrav 	last->next = *list;
899b7579f77SDag-Erling Smørgrav 	*list = add;
900b7579f77SDag-Erling Smørgrav }
901b7579f77SDag-Erling Smørgrav 
902b7579f77SDag-Erling Smørgrav int sock_list_find(struct sock_list* list, struct sockaddr_storage* addr,
903b7579f77SDag-Erling Smørgrav         socklen_t len)
904b7579f77SDag-Erling Smørgrav {
905b7579f77SDag-Erling Smørgrav 	while(list) {
906b7579f77SDag-Erling Smørgrav 		if(len == list->len) {
907b7579f77SDag-Erling Smørgrav 			if(len == 0 || sockaddr_cmp_addr(addr, len,
908b7579f77SDag-Erling Smørgrav 				&list->addr, list->len) == 0)
909b7579f77SDag-Erling Smørgrav 				return 1;
910b7579f77SDag-Erling Smørgrav 		}
911b7579f77SDag-Erling Smørgrav 		list = list->next;
912b7579f77SDag-Erling Smørgrav 	}
913b7579f77SDag-Erling Smørgrav 	return 0;
914b7579f77SDag-Erling Smørgrav }
915b7579f77SDag-Erling Smørgrav 
916b7579f77SDag-Erling Smørgrav void sock_list_merge(struct sock_list** list, struct regional* region,
917b7579f77SDag-Erling Smørgrav 	struct sock_list* add)
918b7579f77SDag-Erling Smørgrav {
919b7579f77SDag-Erling Smørgrav 	struct sock_list* p;
920b7579f77SDag-Erling Smørgrav 	for(p=add; p; p=p->next) {
921b7579f77SDag-Erling Smørgrav 		if(!sock_list_find(*list, &p->addr, p->len))
922b7579f77SDag-Erling Smørgrav 			sock_list_insert(list, &p->addr, p->len, region);
923b7579f77SDag-Erling Smørgrav 	}
924b7579f77SDag-Erling Smørgrav }
925b7579f77SDag-Erling Smørgrav 
926b7579f77SDag-Erling Smørgrav void
927b7579f77SDag-Erling Smørgrav log_crypto_err(const char* str)
928b7579f77SDag-Erling Smørgrav {
9298ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL
9300eefd307SCy Schubert 	log_crypto_err_code(str, ERR_get_error());
9310eefd307SCy Schubert #else
9320eefd307SCy Schubert 	(void)str;
9330eefd307SCy Schubert #endif /* HAVE_SSL */
9340eefd307SCy Schubert }
9350eefd307SCy Schubert 
9360eefd307SCy Schubert void log_crypto_err_code(const char* str, unsigned long err)
9370eefd307SCy Schubert {
9380eefd307SCy Schubert #ifdef HAVE_SSL
939b7579f77SDag-Erling Smørgrav 	/* error:[error code]:[library name]:[function name]:[reason string] */
940b7579f77SDag-Erling Smørgrav 	char buf[128];
941b7579f77SDag-Erling Smørgrav 	unsigned long e;
9420eefd307SCy Schubert 	ERR_error_string_n(err, buf, sizeof(buf));
943b7579f77SDag-Erling Smørgrav 	log_err("%s crypto %s", str, buf);
944b7579f77SDag-Erling Smørgrav 	while( (e=ERR_get_error()) ) {
945b7579f77SDag-Erling Smørgrav 		ERR_error_string_n(e, buf, sizeof(buf));
946b7579f77SDag-Erling Smørgrav 		log_err("and additionally crypto %s", buf);
947b7579f77SDag-Erling Smørgrav 	}
9488ed2b524SDag-Erling Smørgrav #else
9498ed2b524SDag-Erling Smørgrav 	(void)str;
9500eefd307SCy Schubert 	(void)err;
9518ed2b524SDag-Erling Smørgrav #endif /* HAVE_SSL */
952b7579f77SDag-Erling Smørgrav }
953b7579f77SDag-Erling Smørgrav 
95425039b37SCy Schubert #ifdef HAVE_SSL
95525039b37SCy Schubert /** log certificate details */
95625039b37SCy Schubert void
95725039b37SCy Schubert log_cert(unsigned level, const char* str, void* cert)
95825039b37SCy Schubert {
95925039b37SCy Schubert 	BIO* bio;
96025039b37SCy Schubert 	char nul = 0;
96125039b37SCy Schubert 	char* pp = NULL;
96225039b37SCy Schubert 	long len;
96325039b37SCy Schubert 	if(verbosity < level) return;
96425039b37SCy Schubert 	bio = BIO_new(BIO_s_mem());
96525039b37SCy Schubert 	if(!bio) return;
96625039b37SCy Schubert 	X509_print_ex(bio, (X509*)cert, 0, (unsigned long)-1
96725039b37SCy Schubert 		^(X509_FLAG_NO_SUBJECT
96825039b37SCy Schubert                         |X509_FLAG_NO_ISSUER|X509_FLAG_NO_VALIDITY
96925039b37SCy Schubert 			|X509_FLAG_NO_EXTENSIONS|X509_FLAG_NO_AUX
97025039b37SCy Schubert 			|X509_FLAG_NO_ATTRIBUTES));
97125039b37SCy Schubert 	BIO_write(bio, &nul, (int)sizeof(nul));
97225039b37SCy Schubert 	len = BIO_get_mem_data(bio, &pp);
97325039b37SCy Schubert 	if(len != 0 && pp) {
97424e36522SCy Schubert 		/* reduce size of cert printout */
97524e36522SCy Schubert 		char* s;
97624e36522SCy Schubert 		while((s=strstr(pp, "  "))!=NULL)
97724e36522SCy Schubert 			memmove(s, s+1, strlen(s+1)+1);
97824e36522SCy Schubert 		while((s=strstr(pp, "\t\t"))!=NULL)
97924e36522SCy Schubert 			memmove(s, s+1, strlen(s+1)+1);
98025039b37SCy Schubert 		verbose(level, "%s: \n%s", str, pp);
98125039b37SCy Schubert 	}
98225039b37SCy Schubert 	BIO_free(bio);
98325039b37SCy Schubert }
98425039b37SCy Schubert #endif /* HAVE_SSL */
98525039b37SCy Schubert 
9865469a995SCy Schubert #if defined(HAVE_SSL) && defined(HAVE_NGHTTP2) && defined(HAVE_SSL_CTX_SET_ALPN_SELECT_CB)
987c0caa2e2SCy Schubert static int alpn_select_cb(SSL* ATTR_UNUSED(ssl), const unsigned char** out,
988c0caa2e2SCy Schubert 	unsigned char* outlen, const unsigned char* in, unsigned int inlen,
989c0caa2e2SCy Schubert 	void* ATTR_UNUSED(arg))
990c0caa2e2SCy Schubert {
991c0caa2e2SCy Schubert 	int rv = nghttp2_select_next_protocol((unsigned char **)out, outlen, in,
992c0caa2e2SCy Schubert 		inlen);
993c0caa2e2SCy Schubert 	if(rv == -1) {
994c0caa2e2SCy Schubert 		return SSL_TLSEXT_ERR_NOACK;
995c0caa2e2SCy Schubert 	}
996c0caa2e2SCy Schubert 	/* either http/1.1 or h2 selected */
997c0caa2e2SCy Schubert 	return SSL_TLSEXT_ERR_OK;
998c0caa2e2SCy Schubert }
999c0caa2e2SCy Schubert #endif
1000c0caa2e2SCy Schubert 
1001971980c3SDag-Erling Smørgrav int
1002971980c3SDag-Erling Smørgrav listen_sslctx_setup(void* ctxt)
1003971980c3SDag-Erling Smørgrav {
1004971980c3SDag-Erling Smørgrav #ifdef HAVE_SSL
1005971980c3SDag-Erling Smørgrav 	SSL_CTX* ctx = (SSL_CTX*)ctxt;
1006971980c3SDag-Erling Smørgrav 	/* no SSLv2, SSLv3 because has defects */
1007091e9e46SCy Schubert #if SSL_OP_NO_SSLv2 != 0
1008971980c3SDag-Erling Smørgrav 	if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)
1009971980c3SDag-Erling Smørgrav 		!= SSL_OP_NO_SSLv2){
1010971980c3SDag-Erling Smørgrav 		log_crypto_err("could not set SSL_OP_NO_SSLv2");
1011971980c3SDag-Erling Smørgrav 		return 0;
1012971980c3SDag-Erling Smørgrav 	}
1013091e9e46SCy Schubert #endif
1014971980c3SDag-Erling Smørgrav 	if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3)
1015971980c3SDag-Erling Smørgrav 		!= SSL_OP_NO_SSLv3){
1016971980c3SDag-Erling Smørgrav 		log_crypto_err("could not set SSL_OP_NO_SSLv3");
1017971980c3SDag-Erling Smørgrav 		return 0;
1018971980c3SDag-Erling Smørgrav 	}
1019971980c3SDag-Erling Smørgrav #if defined(SSL_OP_NO_TLSv1) && defined(SSL_OP_NO_TLSv1_1)
1020971980c3SDag-Erling Smørgrav 	/* if we have tls 1.1 disable 1.0 */
1021971980c3SDag-Erling Smørgrav 	if((SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1) & SSL_OP_NO_TLSv1)
1022971980c3SDag-Erling Smørgrav 		!= SSL_OP_NO_TLSv1){
1023971980c3SDag-Erling Smørgrav 		log_crypto_err("could not set SSL_OP_NO_TLSv1");
1024971980c3SDag-Erling Smørgrav 		return 0;
1025971980c3SDag-Erling Smørgrav 	}
1026971980c3SDag-Erling Smørgrav #endif
1027971980c3SDag-Erling Smørgrav #if defined(SSL_OP_NO_TLSv1_1) && defined(SSL_OP_NO_TLSv1_2)
1028971980c3SDag-Erling Smørgrav 	/* if we have tls 1.2 disable 1.1 */
1029971980c3SDag-Erling Smørgrav 	if((SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_1) & SSL_OP_NO_TLSv1_1)
1030971980c3SDag-Erling Smørgrav 		!= SSL_OP_NO_TLSv1_1){
1031971980c3SDag-Erling Smørgrav 		log_crypto_err("could not set SSL_OP_NO_TLSv1_1");
1032971980c3SDag-Erling Smørgrav 		return 0;
1033971980c3SDag-Erling Smørgrav 	}
1034971980c3SDag-Erling Smørgrav #endif
10350eefd307SCy Schubert #if defined(SSL_OP_NO_RENEGOTIATION)
10360eefd307SCy Schubert 	/* disable client renegotiation */
10370eefd307SCy Schubert 	if((SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION) &
10380eefd307SCy Schubert 		SSL_OP_NO_RENEGOTIATION) != SSL_OP_NO_RENEGOTIATION) {
10390eefd307SCy Schubert 		log_crypto_err("could not set SSL_OP_NO_RENEGOTIATION");
10400eefd307SCy Schubert 		return 0;
10410eefd307SCy Schubert 	}
10420eefd307SCy Schubert #endif
1043971980c3SDag-Erling Smørgrav #if defined(SHA256_DIGEST_LENGTH) && defined(USE_ECDSA)
104424e36522SCy Schubert 	/* if we detect system-wide crypto policies, use those */
104524e36522SCy Schubert 	if (access( "/etc/crypto-policies/config", F_OK ) != 0 ) {
1046971980c3SDag-Erling Smørgrav 	/* if we have sha256, set the cipher list to have no known vulns */
104757bddd21SDag-Erling Smørgrav 		if(!SSL_CTX_set_cipher_list(ctx, "TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256"))
1048971980c3SDag-Erling Smørgrav 			log_crypto_err("could not set cipher list with SSL_CTX_set_cipher_list");
104924e36522SCy Schubert 	}
1050971980c3SDag-Erling Smørgrav #endif
1051*8f76bb7dSCy Schubert #if defined(SSL_OP_IGNORE_UNEXPECTED_EOF)
1052*8f76bb7dSCy Schubert 	/* ignore errors when peers do not send the mandatory close_notify
1053*8f76bb7dSCy Schubert 	 * alert on shutdown.
1054*8f76bb7dSCy Schubert 	 * Relevant for openssl >= 3 */
1055*8f76bb7dSCy Schubert 	if((SSL_CTX_set_options(ctx, SSL_OP_IGNORE_UNEXPECTED_EOF) &
1056*8f76bb7dSCy Schubert 		SSL_OP_IGNORE_UNEXPECTED_EOF) != SSL_OP_IGNORE_UNEXPECTED_EOF) {
1057*8f76bb7dSCy Schubert 		log_crypto_err("could not set SSL_OP_IGNORE_UNEXPECTED_EOF");
1058*8f76bb7dSCy Schubert 		return 0;
1059*8f76bb7dSCy Schubert 	}
1060*8f76bb7dSCy Schubert #endif
1061971980c3SDag-Erling Smørgrav 
1062971980c3SDag-Erling Smørgrav 	if((SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE) &
1063971980c3SDag-Erling Smørgrav 		SSL_OP_CIPHER_SERVER_PREFERENCE) !=
1064971980c3SDag-Erling Smørgrav 		SSL_OP_CIPHER_SERVER_PREFERENCE) {
1065971980c3SDag-Erling Smørgrav 		log_crypto_err("could not set SSL_OP_CIPHER_SERVER_PREFERENCE");
1066971980c3SDag-Erling Smørgrav 		return 0;
1067971980c3SDag-Erling Smørgrav 	}
1068971980c3SDag-Erling Smørgrav 
1069971980c3SDag-Erling Smørgrav #ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL
1070971980c3SDag-Erling Smørgrav 	SSL_CTX_set_security_level(ctx, 0);
1071971980c3SDag-Erling Smørgrav #endif
1072c0caa2e2SCy Schubert #if defined(HAVE_SSL_CTX_SET_ALPN_SELECT_CB) && defined(HAVE_NGHTTP2)
1073c0caa2e2SCy Schubert 	SSL_CTX_set_alpn_select_cb(ctx, alpn_select_cb, NULL);
1074c0caa2e2SCy Schubert #endif
1075971980c3SDag-Erling Smørgrav #else
1076971980c3SDag-Erling Smørgrav 	(void)ctxt;
1077971980c3SDag-Erling Smørgrav #endif /* HAVE_SSL */
1078971980c3SDag-Erling Smørgrav 	return 1;
1079971980c3SDag-Erling Smørgrav }
1080971980c3SDag-Erling Smørgrav 
1081971980c3SDag-Erling Smørgrav void
1082971980c3SDag-Erling Smørgrav listen_sslctx_setup_2(void* ctxt)
1083971980c3SDag-Erling Smørgrav {
1084971980c3SDag-Erling Smørgrav #ifdef HAVE_SSL
1085971980c3SDag-Erling Smørgrav 	SSL_CTX* ctx = (SSL_CTX*)ctxt;
1086971980c3SDag-Erling Smørgrav 	(void)ctx;
1087971980c3SDag-Erling Smørgrav #if HAVE_DECL_SSL_CTX_SET_ECDH_AUTO
1088971980c3SDag-Erling Smørgrav 	if(!SSL_CTX_set_ecdh_auto(ctx,1)) {
1089971980c3SDag-Erling Smørgrav 		log_crypto_err("Error in SSL_CTX_ecdh_auto, not enabling ECDHE");
1090971980c3SDag-Erling Smørgrav 	}
1091971980c3SDag-Erling Smørgrav #elif defined(USE_ECDSA)
1092971980c3SDag-Erling Smørgrav 	if(1) {
1093971980c3SDag-Erling Smørgrav 		EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1);
1094971980c3SDag-Erling Smørgrav 		if (!ecdh) {
1095971980c3SDag-Erling Smørgrav 			log_crypto_err("could not find p256, not enabling ECDHE");
1096971980c3SDag-Erling Smørgrav 		} else {
1097971980c3SDag-Erling Smørgrav 			if (1 != SSL_CTX_set_tmp_ecdh (ctx, ecdh)) {
1098971980c3SDag-Erling Smørgrav 				log_crypto_err("Error in SSL_CTX_set_tmp_ecdh, not enabling ECDHE");
1099971980c3SDag-Erling Smørgrav 			}
1100971980c3SDag-Erling Smørgrav 			EC_KEY_free (ecdh);
1101971980c3SDag-Erling Smørgrav 		}
1102971980c3SDag-Erling Smørgrav 	}
1103971980c3SDag-Erling Smørgrav #endif
1104971980c3SDag-Erling Smørgrav #else
1105971980c3SDag-Erling Smørgrav 	(void)ctxt;
1106971980c3SDag-Erling Smørgrav #endif /* HAVE_SSL */
1107971980c3SDag-Erling Smørgrav }
1108971980c3SDag-Erling Smørgrav 
1109b7579f77SDag-Erling Smørgrav void* listen_sslctx_create(char* key, char* pem, char* verifypem)
1110b7579f77SDag-Erling Smørgrav {
11118ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL
1112b7579f77SDag-Erling Smørgrav 	SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method());
1113b7579f77SDag-Erling Smørgrav 	if(!ctx) {
1114b7579f77SDag-Erling Smørgrav 		log_crypto_err("could not SSL_CTX_new");
1115b7579f77SDag-Erling Smørgrav 		return NULL;
1116b7579f77SDag-Erling Smørgrav 	}
1117e86b9096SDag-Erling Smørgrav 	if(!key || key[0] == 0) {
1118e86b9096SDag-Erling Smørgrav 		log_err("error: no tls-service-key file specified");
1119e86b9096SDag-Erling Smørgrav 		SSL_CTX_free(ctx);
1120e86b9096SDag-Erling Smørgrav 		return NULL;
1121e86b9096SDag-Erling Smørgrav 	}
1122e86b9096SDag-Erling Smørgrav 	if(!pem || pem[0] == 0) {
1123e86b9096SDag-Erling Smørgrav 		log_err("error: no tls-service-pem file specified");
1124e86b9096SDag-Erling Smørgrav 		SSL_CTX_free(ctx);
1125e86b9096SDag-Erling Smørgrav 		return NULL;
1126e86b9096SDag-Erling Smørgrav 	}
1127971980c3SDag-Erling Smørgrav 	if(!listen_sslctx_setup(ctx)) {
1128ff825849SDag-Erling Smørgrav 		SSL_CTX_free(ctx);
1129ff825849SDag-Erling Smørgrav 		return NULL;
1130ff825849SDag-Erling Smørgrav 	}
1131b75612f8SDag-Erling Smørgrav 	if(!SSL_CTX_use_certificate_chain_file(ctx, pem)) {
1132b7579f77SDag-Erling Smørgrav 		log_err("error for cert file: %s", pem);
1133b75612f8SDag-Erling Smørgrav 		log_crypto_err("error in SSL_CTX use_certificate_chain_file");
1134b7579f77SDag-Erling Smørgrav 		SSL_CTX_free(ctx);
1135b7579f77SDag-Erling Smørgrav 		return NULL;
1136b7579f77SDag-Erling Smørgrav 	}
1137b7579f77SDag-Erling Smørgrav 	if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) {
1138b7579f77SDag-Erling Smørgrav 		log_err("error for private key file: %s", key);
1139b7579f77SDag-Erling Smørgrav 		log_crypto_err("Error in SSL_CTX use_PrivateKey_file");
1140b7579f77SDag-Erling Smørgrav 		SSL_CTX_free(ctx);
1141b7579f77SDag-Erling Smørgrav 		return NULL;
1142b7579f77SDag-Erling Smørgrav 	}
1143b7579f77SDag-Erling Smørgrav 	if(!SSL_CTX_check_private_key(ctx)) {
1144b7579f77SDag-Erling Smørgrav 		log_err("error for key file: %s", key);
1145b7579f77SDag-Erling Smørgrav 		log_crypto_err("Error in SSL_CTX check_private_key");
1146b7579f77SDag-Erling Smørgrav 		SSL_CTX_free(ctx);
1147b7579f77SDag-Erling Smørgrav 		return NULL;
1148b7579f77SDag-Erling Smørgrav 	}
1149971980c3SDag-Erling Smørgrav 	listen_sslctx_setup_2(ctx);
1150b7579f77SDag-Erling Smørgrav 	if(verifypem && verifypem[0]) {
1151b7579f77SDag-Erling Smørgrav 		if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) {
1152b7579f77SDag-Erling Smørgrav 			log_crypto_err("Error in SSL_CTX verify locations");
1153b7579f77SDag-Erling Smørgrav 			SSL_CTX_free(ctx);
1154b7579f77SDag-Erling Smørgrav 			return NULL;
1155b7579f77SDag-Erling Smørgrav 		}
1156b7579f77SDag-Erling Smørgrav 		SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(
1157b7579f77SDag-Erling Smørgrav 			verifypem));
115825039b37SCy Schubert 		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
1159b7579f77SDag-Erling Smørgrav 	}
1160b7579f77SDag-Erling Smørgrav 	return ctx;
11618ed2b524SDag-Erling Smørgrav #else
11628ed2b524SDag-Erling Smørgrav 	(void)key; (void)pem; (void)verifypem;
11638ed2b524SDag-Erling Smørgrav 	return NULL;
11648ed2b524SDag-Erling Smørgrav #endif
1165b7579f77SDag-Erling Smørgrav }
1166b7579f77SDag-Erling Smørgrav 
11673bd4df0aSDag-Erling Smørgrav #ifdef USE_WINSOCK
11683bd4df0aSDag-Erling Smørgrav /* For windows, the CA trust store is not read by openssl.
11693bd4df0aSDag-Erling Smørgrav    Add code to open the trust store using wincrypt API and add
11703bd4df0aSDag-Erling Smørgrav    the root certs into openssl trust store */
11713bd4df0aSDag-Erling Smørgrav static int
11723bd4df0aSDag-Erling Smørgrav add_WIN_cacerts_to_openssl_store(SSL_CTX* tls_ctx)
11733bd4df0aSDag-Erling Smørgrav {
11743bd4df0aSDag-Erling Smørgrav 	HCERTSTORE      hSystemStore;
11753bd4df0aSDag-Erling Smørgrav 	PCCERT_CONTEXT  pTargetCert = NULL;
11763bd4df0aSDag-Erling Smørgrav 	X509_STORE*	store;
11773bd4df0aSDag-Erling Smørgrav 
11783bd4df0aSDag-Erling Smørgrav 	verbose(VERB_ALGO, "Adding Windows certificates from system root store to CA store");
11793bd4df0aSDag-Erling Smørgrav 
11803bd4df0aSDag-Erling Smørgrav 	/* load just once per context lifetime for this version
11813bd4df0aSDag-Erling Smørgrav 	   TODO: dynamically update CA trust changes as they are available */
11823bd4df0aSDag-Erling Smørgrav 	if (!tls_ctx)
11833bd4df0aSDag-Erling Smørgrav 		return 0;
11843bd4df0aSDag-Erling Smørgrav 
11853bd4df0aSDag-Erling Smørgrav 	/* Call wincrypt's CertOpenStore to open the CA root store. */
11863bd4df0aSDag-Erling Smørgrav 
11873bd4df0aSDag-Erling Smørgrav 	if ((hSystemStore = CertOpenStore(
11883bd4df0aSDag-Erling Smørgrav 		CERT_STORE_PROV_SYSTEM,
11893bd4df0aSDag-Erling Smørgrav 		0,
11903bd4df0aSDag-Erling Smørgrav 		0,
11913bd4df0aSDag-Erling Smørgrav 		/* NOTE: mingw does not have this const: replace with 1 << 16 from code
11923bd4df0aSDag-Erling Smørgrav 		   CERT_SYSTEM_STORE_CURRENT_USER, */
11933bd4df0aSDag-Erling Smørgrav 		1 << 16,
11943bd4df0aSDag-Erling Smørgrav 		L"root")) == 0)
11953bd4df0aSDag-Erling Smørgrav 	{
11963bd4df0aSDag-Erling Smørgrav 		return 0;
11973bd4df0aSDag-Erling Smørgrav 	}
11983bd4df0aSDag-Erling Smørgrav 
11993bd4df0aSDag-Erling Smørgrav 	store = SSL_CTX_get_cert_store(tls_ctx);
12003bd4df0aSDag-Erling Smørgrav 	if (!store)
12013bd4df0aSDag-Erling Smørgrav 		return 0;
12023bd4df0aSDag-Erling Smørgrav 
12033bd4df0aSDag-Erling Smørgrav 	/* failure if the CA store is empty or the call fails */
12043bd4df0aSDag-Erling Smørgrav 	if ((pTargetCert = CertEnumCertificatesInStore(
12053bd4df0aSDag-Erling Smørgrav 		hSystemStore, pTargetCert)) == 0) {
12063bd4df0aSDag-Erling Smørgrav 		verbose(VERB_ALGO, "CA certificate store for Windows is empty.");
12073bd4df0aSDag-Erling Smørgrav 		return 0;
12083bd4df0aSDag-Erling Smørgrav 	}
12093bd4df0aSDag-Erling Smørgrav 	/* iterate over the windows cert store and add to openssl store */
12103bd4df0aSDag-Erling Smørgrav 	do
12113bd4df0aSDag-Erling Smørgrav 	{
12123bd4df0aSDag-Erling Smørgrav 		X509 *cert1 = d2i_X509(NULL,
12133bd4df0aSDag-Erling Smørgrav 			(const unsigned char **)&pTargetCert->pbCertEncoded,
12143bd4df0aSDag-Erling Smørgrav 			pTargetCert->cbCertEncoded);
12153bd4df0aSDag-Erling Smørgrav 		if (!cert1) {
12160a92a9fcSCy Schubert 			unsigned long error = ERR_get_error();
12173bd4df0aSDag-Erling Smørgrav 			/* return error if a cert fails */
12183bd4df0aSDag-Erling Smørgrav 			verbose(VERB_ALGO, "%s %d:%s",
12193bd4df0aSDag-Erling Smørgrav 				"Unable to parse certificate in memory",
12200a92a9fcSCy Schubert 				(int)error, ERR_error_string(error, NULL));
12213bd4df0aSDag-Erling Smørgrav 			return 0;
12223bd4df0aSDag-Erling Smørgrav 		}
12233bd4df0aSDag-Erling Smørgrav 		else {
12243bd4df0aSDag-Erling Smørgrav 			/* return error if a cert add to store fails */
12253bd4df0aSDag-Erling Smørgrav 			if (X509_STORE_add_cert(store, cert1) == 0) {
12263bd4df0aSDag-Erling Smørgrav 				unsigned long error = ERR_peek_last_error();
12273bd4df0aSDag-Erling Smørgrav 
12283bd4df0aSDag-Erling Smørgrav 				/* Ignore error X509_R_CERT_ALREADY_IN_HASH_TABLE which means the
12293bd4df0aSDag-Erling Smørgrav 				* certificate is already in the store.  */
12303bd4df0aSDag-Erling Smørgrav 				if(ERR_GET_LIB(error) != ERR_LIB_X509 ||
12313bd4df0aSDag-Erling Smørgrav 					ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE) {
12320a92a9fcSCy Schubert 					error = ERR_get_error();
12333bd4df0aSDag-Erling Smørgrav 					verbose(VERB_ALGO, "%s %d:%s\n",
12340a92a9fcSCy Schubert 					    "Error adding certificate", (int)error,
12350a92a9fcSCy Schubert 					     ERR_error_string(error, NULL));
12363bd4df0aSDag-Erling Smørgrav 					X509_free(cert1);
12373bd4df0aSDag-Erling Smørgrav 					return 0;
12383bd4df0aSDag-Erling Smørgrav 				}
12393bd4df0aSDag-Erling Smørgrav 			}
12403bd4df0aSDag-Erling Smørgrav 			X509_free(cert1);
12413bd4df0aSDag-Erling Smørgrav 		}
12423bd4df0aSDag-Erling Smørgrav 	} while ((pTargetCert = CertEnumCertificatesInStore(
12433bd4df0aSDag-Erling Smørgrav 		hSystemStore, pTargetCert)) != 0);
12443bd4df0aSDag-Erling Smørgrav 
12453bd4df0aSDag-Erling Smørgrav 	/* Clean up memory and quit. */
12463bd4df0aSDag-Erling Smørgrav 	if (pTargetCert)
12473bd4df0aSDag-Erling Smørgrav 		CertFreeCertificateContext(pTargetCert);
12483bd4df0aSDag-Erling Smørgrav 	if (hSystemStore)
12493bd4df0aSDag-Erling Smørgrav 	{
12503bd4df0aSDag-Erling Smørgrav 		if (!CertCloseStore(
12513bd4df0aSDag-Erling Smørgrav 			hSystemStore, 0))
12523bd4df0aSDag-Erling Smørgrav 			return 0;
12533bd4df0aSDag-Erling Smørgrav 	}
12543bd4df0aSDag-Erling Smørgrav 	verbose(VERB_ALGO, "Completed adding Windows certificates to CA store successfully");
12553bd4df0aSDag-Erling Smørgrav 	return 1;
12563bd4df0aSDag-Erling Smørgrav }
12573bd4df0aSDag-Erling Smørgrav #endif /* USE_WINSOCK */
12583bd4df0aSDag-Erling Smørgrav 
12593bd4df0aSDag-Erling Smørgrav void* connect_sslctx_create(char* key, char* pem, char* verifypem, int wincert)
1260b7579f77SDag-Erling Smørgrav {
12618ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL
1262b7579f77SDag-Erling Smørgrav 	SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
1263b7579f77SDag-Erling Smørgrav 	if(!ctx) {
1264b7579f77SDag-Erling Smørgrav 		log_crypto_err("could not allocate SSL_CTX pointer");
1265b7579f77SDag-Erling Smørgrav 		return NULL;
1266b7579f77SDag-Erling Smørgrav 	}
1267091e9e46SCy Schubert #if SSL_OP_NO_SSLv2 != 0
126805ab2901SDag-Erling Smørgrav 	if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)
126905ab2901SDag-Erling Smørgrav 		!= SSL_OP_NO_SSLv2) {
1270b7579f77SDag-Erling Smørgrav 		log_crypto_err("could not set SSL_OP_NO_SSLv2");
1271b7579f77SDag-Erling Smørgrav 		SSL_CTX_free(ctx);
1272b7579f77SDag-Erling Smørgrav 		return NULL;
1273b7579f77SDag-Erling Smørgrav 	}
1274091e9e46SCy Schubert #endif
127505ab2901SDag-Erling Smørgrav 	if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3)
127605ab2901SDag-Erling Smørgrav 		!= SSL_OP_NO_SSLv3) {
1277ff825849SDag-Erling Smørgrav 		log_crypto_err("could not set SSL_OP_NO_SSLv3");
1278ff825849SDag-Erling Smørgrav 		SSL_CTX_free(ctx);
1279ff825849SDag-Erling Smørgrav 		return NULL;
1280ff825849SDag-Erling Smørgrav 	}
12810eefd307SCy Schubert #if defined(SSL_OP_NO_RENEGOTIATION)
12820eefd307SCy Schubert 	/* disable client renegotiation */
12830eefd307SCy Schubert 	if((SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION) &
12840eefd307SCy Schubert 		SSL_OP_NO_RENEGOTIATION) != SSL_OP_NO_RENEGOTIATION) {
12850eefd307SCy Schubert 		log_crypto_err("could not set SSL_OP_NO_RENEGOTIATION");
128624e36522SCy Schubert 		SSL_CTX_free(ctx);
12870eefd307SCy Schubert 		return 0;
12880eefd307SCy Schubert 	}
12890eefd307SCy Schubert #endif
1290*8f76bb7dSCy Schubert #if defined(SSL_OP_IGNORE_UNEXPECTED_EOF)
1291*8f76bb7dSCy Schubert 	/* ignore errors when peers do not send the mandatory close_notify
1292*8f76bb7dSCy Schubert 	 * alert on shutdown.
1293*8f76bb7dSCy Schubert 	 * Relevant for openssl >= 3 */
1294*8f76bb7dSCy Schubert 	if((SSL_CTX_set_options(ctx, SSL_OP_IGNORE_UNEXPECTED_EOF) &
1295*8f76bb7dSCy Schubert 		SSL_OP_IGNORE_UNEXPECTED_EOF) != SSL_OP_IGNORE_UNEXPECTED_EOF) {
1296*8f76bb7dSCy Schubert 		log_crypto_err("could not set SSL_OP_IGNORE_UNEXPECTED_EOF");
1297*8f76bb7dSCy Schubert 		SSL_CTX_free(ctx);
1298*8f76bb7dSCy Schubert 		return 0;
1299*8f76bb7dSCy Schubert 	}
1300*8f76bb7dSCy Schubert #endif
1301b7579f77SDag-Erling Smørgrav 	if(key && key[0]) {
1302b75612f8SDag-Erling Smørgrav 		if(!SSL_CTX_use_certificate_chain_file(ctx, pem)) {
1303b7579f77SDag-Erling Smørgrav 			log_err("error in client certificate %s", pem);
1304b7579f77SDag-Erling Smørgrav 			log_crypto_err("error in certificate file");
1305b7579f77SDag-Erling Smørgrav 			SSL_CTX_free(ctx);
1306b7579f77SDag-Erling Smørgrav 			return NULL;
1307b7579f77SDag-Erling Smørgrav 		}
1308b7579f77SDag-Erling Smørgrav 		if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) {
1309b7579f77SDag-Erling Smørgrav 			log_err("error in client private key %s", key);
1310b7579f77SDag-Erling Smørgrav 			log_crypto_err("error in key file");
1311b7579f77SDag-Erling Smørgrav 			SSL_CTX_free(ctx);
1312b7579f77SDag-Erling Smørgrav 			return NULL;
1313b7579f77SDag-Erling Smørgrav 		}
1314b7579f77SDag-Erling Smørgrav 		if(!SSL_CTX_check_private_key(ctx)) {
1315b7579f77SDag-Erling Smørgrav 			log_err("error in client key %s", key);
1316b7579f77SDag-Erling Smørgrav 			log_crypto_err("error in SSL_CTX_check_private_key");
1317b7579f77SDag-Erling Smørgrav 			SSL_CTX_free(ctx);
1318b7579f77SDag-Erling Smørgrav 			return NULL;
1319b7579f77SDag-Erling Smørgrav 		}
1320b7579f77SDag-Erling Smørgrav 	}
13213bd4df0aSDag-Erling Smørgrav 	if((verifypem && verifypem[0]) || wincert) {
1322b7579f77SDag-Erling Smørgrav 		if(verifypem && verifypem[0]) {
1323ff825849SDag-Erling Smørgrav 			if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) {
1324b7579f77SDag-Erling Smørgrav 				log_crypto_err("error in SSL_CTX verify");
1325b7579f77SDag-Erling Smørgrav 				SSL_CTX_free(ctx);
1326b7579f77SDag-Erling Smørgrav 				return NULL;
1327b7579f77SDag-Erling Smørgrav 			}
13283bd4df0aSDag-Erling Smørgrav 		}
13293bd4df0aSDag-Erling Smørgrav #ifdef USE_WINSOCK
13303bd4df0aSDag-Erling Smørgrav 		if(wincert) {
13313bd4df0aSDag-Erling Smørgrav 			if(!add_WIN_cacerts_to_openssl_store(ctx)) {
13323bd4df0aSDag-Erling Smørgrav 				log_crypto_err("error in add_WIN_cacerts_to_openssl_store");
13333bd4df0aSDag-Erling Smørgrav 				SSL_CTX_free(ctx);
13343bd4df0aSDag-Erling Smørgrav 				return NULL;
13353bd4df0aSDag-Erling Smørgrav 			}
13363bd4df0aSDag-Erling Smørgrav 		}
13373bd4df0aSDag-Erling Smørgrav #else
1338a39a5a69SCy Schubert 		if(wincert) {
1339a39a5a69SCy Schubert 			if(!SSL_CTX_set_default_verify_paths(ctx)) {
1340a39a5a69SCy Schubert 				log_crypto_err("error in default_verify_paths");
1341a39a5a69SCy Schubert 				SSL_CTX_free(ctx);
1342a39a5a69SCy Schubert 				return NULL;
1343a39a5a69SCy Schubert 			}
1344a39a5a69SCy Schubert 		}
13453bd4df0aSDag-Erling Smørgrav #endif
1346b7579f77SDag-Erling Smørgrav 		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
1347b7579f77SDag-Erling Smørgrav 	}
1348b7579f77SDag-Erling Smørgrav 	return ctx;
13498ed2b524SDag-Erling Smørgrav #else
13503bd4df0aSDag-Erling Smørgrav 	(void)key; (void)pem; (void)verifypem; (void)wincert;
13518ed2b524SDag-Erling Smørgrav 	return NULL;
13528ed2b524SDag-Erling Smørgrav #endif
1353b7579f77SDag-Erling Smørgrav }
1354b7579f77SDag-Erling Smørgrav 
1355b7579f77SDag-Erling Smørgrav void* incoming_ssl_fd(void* sslctx, int fd)
1356b7579f77SDag-Erling Smørgrav {
13578ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL
1358b7579f77SDag-Erling Smørgrav 	SSL* ssl = SSL_new((SSL_CTX*)sslctx);
1359b7579f77SDag-Erling Smørgrav 	if(!ssl) {
1360b7579f77SDag-Erling Smørgrav 		log_crypto_err("could not SSL_new");
1361b7579f77SDag-Erling Smørgrav 		return NULL;
1362b7579f77SDag-Erling Smørgrav 	}
1363b7579f77SDag-Erling Smørgrav 	SSL_set_accept_state(ssl);
13640eefd307SCy Schubert 	(void)SSL_set_mode(ssl, (long)SSL_MODE_AUTO_RETRY);
1365b7579f77SDag-Erling Smørgrav 	if(!SSL_set_fd(ssl, fd)) {
1366b7579f77SDag-Erling Smørgrav 		log_crypto_err("could not SSL_set_fd");
1367b7579f77SDag-Erling Smørgrav 		SSL_free(ssl);
1368b7579f77SDag-Erling Smørgrav 		return NULL;
1369b7579f77SDag-Erling Smørgrav 	}
1370b7579f77SDag-Erling Smørgrav 	return ssl;
13718ed2b524SDag-Erling Smørgrav #else
13728ed2b524SDag-Erling Smørgrav 	(void)sslctx; (void)fd;
13738ed2b524SDag-Erling Smørgrav 	return NULL;
13748ed2b524SDag-Erling Smørgrav #endif
1375b7579f77SDag-Erling Smørgrav }
1376b7579f77SDag-Erling Smørgrav 
1377b7579f77SDag-Erling Smørgrav void* outgoing_ssl_fd(void* sslctx, int fd)
1378b7579f77SDag-Erling Smørgrav {
13798ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL
1380b7579f77SDag-Erling Smørgrav 	SSL* ssl = SSL_new((SSL_CTX*)sslctx);
1381b7579f77SDag-Erling Smørgrav 	if(!ssl) {
1382b7579f77SDag-Erling Smørgrav 		log_crypto_err("could not SSL_new");
1383b7579f77SDag-Erling Smørgrav 		return NULL;
1384b7579f77SDag-Erling Smørgrav 	}
1385b7579f77SDag-Erling Smørgrav 	SSL_set_connect_state(ssl);
13860eefd307SCy Schubert 	(void)SSL_set_mode(ssl, (long)SSL_MODE_AUTO_RETRY);
1387b7579f77SDag-Erling Smørgrav 	if(!SSL_set_fd(ssl, fd)) {
1388b7579f77SDag-Erling Smørgrav 		log_crypto_err("could not SSL_set_fd");
1389b7579f77SDag-Erling Smørgrav 		SSL_free(ssl);
1390b7579f77SDag-Erling Smørgrav 		return NULL;
1391b7579f77SDag-Erling Smørgrav 	}
1392b7579f77SDag-Erling Smørgrav 	return ssl;
13938ed2b524SDag-Erling Smørgrav #else
13948ed2b524SDag-Erling Smørgrav 	(void)sslctx; (void)fd;
13958ed2b524SDag-Erling Smørgrav 	return NULL;
13968ed2b524SDag-Erling Smørgrav #endif
1397b7579f77SDag-Erling Smørgrav }
13988ed2b524SDag-Erling Smørgrav 
139925039b37SCy Schubert int check_auth_name_for_ssl(char* auth_name)
140025039b37SCy Schubert {
140125039b37SCy Schubert 	if(!auth_name) return 1;
140225039b37SCy Schubert #if defined(HAVE_SSL) && !defined(HAVE_SSL_SET1_HOST) && !defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
140325039b37SCy Schubert 	log_err("the query has an auth_name %s, but libssl has no call to "
140425039b37SCy Schubert 		"perform TLS authentication.  Remove that name from config "
140525039b37SCy Schubert 		"or upgrade the ssl crypto library.", auth_name);
140625039b37SCy Schubert 	return 0;
140725039b37SCy Schubert #else
140825039b37SCy Schubert 	return 1;
140925039b37SCy Schubert #endif
141025039b37SCy Schubert }
141125039b37SCy Schubert 
141225039b37SCy Schubert /** set the authname on an SSL structure, SSL* ssl */
141325039b37SCy Schubert int set_auth_name_on_ssl(void* ssl, char* auth_name, int use_sni)
141425039b37SCy Schubert {
141525039b37SCy Schubert 	if(!auth_name) return 1;
141625039b37SCy Schubert #ifdef HAVE_SSL
141725039b37SCy Schubert 	if(use_sni) {
141825039b37SCy Schubert 		(void)SSL_set_tlsext_host_name(ssl, auth_name);
141925039b37SCy Schubert 	}
142025039b37SCy Schubert #else
142125039b37SCy Schubert 	(void)ssl;
142225039b37SCy Schubert 	(void)use_sni;
142325039b37SCy Schubert #endif
142425039b37SCy Schubert #ifdef HAVE_SSL_SET1_HOST
142525039b37SCy Schubert 	SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);
142625039b37SCy Schubert 	/* setting the hostname makes openssl verify the
142725039b37SCy Schubert 	 * host name in the x509 certificate in the
142825039b37SCy Schubert 	 * SSL connection*/
142925039b37SCy Schubert 	if(!SSL_set1_host(ssl, auth_name)) {
143025039b37SCy Schubert 		log_err("SSL_set1_host failed");
143125039b37SCy Schubert 		return 0;
143225039b37SCy Schubert 	}
143325039b37SCy Schubert #elif defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
143425039b37SCy Schubert 	/* openssl 1.0.2 has this function that can be used for
143525039b37SCy Schubert 	 * set1_host like verification */
143625039b37SCy Schubert 	if(auth_name) {
143725039b37SCy Schubert 		X509_VERIFY_PARAM* param = SSL_get0_param(ssl);
143825039b37SCy Schubert #  ifdef X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS
143925039b37SCy Schubert 		X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
144025039b37SCy Schubert #  endif
144125039b37SCy Schubert 		if(!X509_VERIFY_PARAM_set1_host(param, auth_name, strlen(auth_name))) {
144225039b37SCy Schubert 			log_err("X509_VERIFY_PARAM_set1_host failed");
144325039b37SCy Schubert 			return 0;
144425039b37SCy Schubert 		}
144525039b37SCy Schubert 		SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);
144625039b37SCy Schubert 	}
144725039b37SCy Schubert #else
144825039b37SCy Schubert 	verbose(VERB_ALGO, "the query has an auth_name, but libssl has no call to perform TLS authentication");
144925039b37SCy Schubert #endif /* HAVE_SSL_SET1_HOST */
145025039b37SCy Schubert 	return 1;
145125039b37SCy Schubert }
145225039b37SCy Schubert 
1453b5663de9SDag-Erling Smørgrav #if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) && defined(CRYPTO_LOCK) && OPENSSL_VERSION_NUMBER < 0x10100000L
14548ed2b524SDag-Erling Smørgrav /** global lock list for openssl locks */
14553005e0a3SDag-Erling Smørgrav static lock_basic_type *ub_openssl_locks = NULL;
14568ed2b524SDag-Erling Smørgrav 
14578ed2b524SDag-Erling Smørgrav /** callback that gets thread id for openssl */
1458e86b9096SDag-Erling Smørgrav #ifdef HAVE_CRYPTO_THREADID_SET_CALLBACK
1459e86b9096SDag-Erling Smørgrav static void
1460e86b9096SDag-Erling Smørgrav ub_crypto_id_cb(CRYPTO_THREADID *id)
1461e86b9096SDag-Erling Smørgrav {
1462e86b9096SDag-Erling Smørgrav 	CRYPTO_THREADID_set_numeric(id, (unsigned long)log_thread_get());
1463e86b9096SDag-Erling Smørgrav }
1464e86b9096SDag-Erling Smørgrav #else
14658ed2b524SDag-Erling Smørgrav static unsigned long
14668ed2b524SDag-Erling Smørgrav ub_crypto_id_cb(void)
14678ed2b524SDag-Erling Smørgrav {
146809a3aaf3SDag-Erling Smørgrav 	return (unsigned long)log_thread_get();
14698ed2b524SDag-Erling Smørgrav }
1470e86b9096SDag-Erling Smørgrav #endif
14718ed2b524SDag-Erling Smørgrav 
14728ed2b524SDag-Erling Smørgrav static void
14738ed2b524SDag-Erling Smørgrav ub_crypto_lock_cb(int mode, int type, const char *ATTR_UNUSED(file),
14748ed2b524SDag-Erling Smørgrav 	int ATTR_UNUSED(line))
14758ed2b524SDag-Erling Smørgrav {
14768ed2b524SDag-Erling Smørgrav 	if((mode&CRYPTO_LOCK)) {
14778ed2b524SDag-Erling Smørgrav 		lock_basic_lock(&ub_openssl_locks[type]);
14788ed2b524SDag-Erling Smørgrav 	} else {
14798ed2b524SDag-Erling Smørgrav 		lock_basic_unlock(&ub_openssl_locks[type]);
14808ed2b524SDag-Erling Smørgrav 	}
14818ed2b524SDag-Erling Smørgrav }
14828ed2b524SDag-Erling Smørgrav #endif /* OPENSSL_THREADS */
14838ed2b524SDag-Erling Smørgrav 
14848ed2b524SDag-Erling Smørgrav int ub_openssl_lock_init(void)
14858ed2b524SDag-Erling Smørgrav {
1486b5663de9SDag-Erling Smørgrav #if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) && defined(CRYPTO_LOCK) && OPENSSL_VERSION_NUMBER < 0x10100000L
14878ed2b524SDag-Erling Smørgrav 	int i;
14883005e0a3SDag-Erling Smørgrav 	ub_openssl_locks = (lock_basic_type*)reallocarray(
14893005e0a3SDag-Erling Smørgrav 		NULL, (size_t)CRYPTO_num_locks(), sizeof(lock_basic_type));
14908ed2b524SDag-Erling Smørgrav 	if(!ub_openssl_locks)
14918ed2b524SDag-Erling Smørgrav 		return 0;
14928ed2b524SDag-Erling Smørgrav 	for(i=0; i<CRYPTO_num_locks(); i++) {
14938ed2b524SDag-Erling Smørgrav 		lock_basic_init(&ub_openssl_locks[i]);
14948ed2b524SDag-Erling Smørgrav 	}
1495e86b9096SDag-Erling Smørgrav #  ifdef HAVE_CRYPTO_THREADID_SET_CALLBACK
1496e86b9096SDag-Erling Smørgrav 	CRYPTO_THREADID_set_callback(&ub_crypto_id_cb);
1497e86b9096SDag-Erling Smørgrav #  else
14988ed2b524SDag-Erling Smørgrav 	CRYPTO_set_id_callback(&ub_crypto_id_cb);
1499e86b9096SDag-Erling Smørgrav #  endif
15008ed2b524SDag-Erling Smørgrav 	CRYPTO_set_locking_callback(&ub_crypto_lock_cb);
15018ed2b524SDag-Erling Smørgrav #endif /* OPENSSL_THREADS */
15028ed2b524SDag-Erling Smørgrav 	return 1;
15038ed2b524SDag-Erling Smørgrav }
15048ed2b524SDag-Erling Smørgrav 
15058ed2b524SDag-Erling Smørgrav void ub_openssl_lock_delete(void)
15068ed2b524SDag-Erling Smørgrav {
1507b5663de9SDag-Erling Smørgrav #if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) && defined(CRYPTO_LOCK) && OPENSSL_VERSION_NUMBER < 0x10100000L
15088ed2b524SDag-Erling Smørgrav 	int i;
15098ed2b524SDag-Erling Smørgrav 	if(!ub_openssl_locks)
15108ed2b524SDag-Erling Smørgrav 		return;
1511e86b9096SDag-Erling Smørgrav #  ifdef HAVE_CRYPTO_THREADID_SET_CALLBACK
1512e86b9096SDag-Erling Smørgrav 	CRYPTO_THREADID_set_callback(NULL);
1513e86b9096SDag-Erling Smørgrav #  else
15148ed2b524SDag-Erling Smørgrav 	CRYPTO_set_id_callback(NULL);
1515e86b9096SDag-Erling Smørgrav #  endif
15168ed2b524SDag-Erling Smørgrav 	CRYPTO_set_locking_callback(NULL);
15178ed2b524SDag-Erling Smørgrav 	for(i=0; i<CRYPTO_num_locks(); i++) {
15188ed2b524SDag-Erling Smørgrav 		lock_basic_destroy(&ub_openssl_locks[i]);
15198ed2b524SDag-Erling Smørgrav 	}
15208ed2b524SDag-Erling Smørgrav 	free(ub_openssl_locks);
15218ed2b524SDag-Erling Smørgrav #endif /* OPENSSL_THREADS */
15228ed2b524SDag-Erling Smørgrav }
15238ed2b524SDag-Erling Smørgrav 
1524e86b9096SDag-Erling Smørgrav int listen_sslctx_setup_ticket_keys(void* sslctx, struct config_strlist* tls_session_ticket_keys) {
1525e86b9096SDag-Erling Smørgrav #ifdef HAVE_SSL
1526e86b9096SDag-Erling Smørgrav 	size_t s = 1;
1527e86b9096SDag-Erling Smørgrav 	struct config_strlist* p;
1528e86b9096SDag-Erling Smørgrav 	struct tls_session_ticket_key *keys;
1529e86b9096SDag-Erling Smørgrav 	for(p = tls_session_ticket_keys; p; p = p->next) {
1530e86b9096SDag-Erling Smørgrav 		s++;
1531e86b9096SDag-Erling Smørgrav 	}
1532e86b9096SDag-Erling Smørgrav 	keys = calloc(s, sizeof(struct tls_session_ticket_key));
1533091e9e46SCy Schubert 	if(!keys)
1534091e9e46SCy Schubert 		return 0;
1535e86b9096SDag-Erling Smørgrav 	memset(keys, 0, s*sizeof(*keys));
1536e86b9096SDag-Erling Smørgrav 	ticket_keys = keys;
1537e86b9096SDag-Erling Smørgrav 
1538e86b9096SDag-Erling Smørgrav 	for(p = tls_session_ticket_keys; p; p = p->next) {
1539e86b9096SDag-Erling Smørgrav 		size_t n;
1540091e9e46SCy Schubert 		unsigned char *data;
1541091e9e46SCy Schubert 		FILE *f;
1542091e9e46SCy Schubert 
1543091e9e46SCy Schubert 		data = (unsigned char *)malloc(80);
1544091e9e46SCy Schubert 		if(!data)
1545091e9e46SCy Schubert 			return 0;
1546091e9e46SCy Schubert 
154725039b37SCy Schubert 		f = fopen(p->str, "rb");
1548e86b9096SDag-Erling Smørgrav 		if(!f) {
1549e86b9096SDag-Erling Smørgrav 			log_err("could not read tls-session-ticket-key %s: %s", p->str, strerror(errno));
1550e86b9096SDag-Erling Smørgrav 			free(data);
1551e86b9096SDag-Erling Smørgrav 			return 0;
1552e86b9096SDag-Erling Smørgrav 		}
1553e86b9096SDag-Erling Smørgrav 		n = fread(data, 1, 80, f);
1554e86b9096SDag-Erling Smørgrav 		fclose(f);
1555e86b9096SDag-Erling Smørgrav 
1556e86b9096SDag-Erling Smørgrav 		if(n != 80) {
1557e86b9096SDag-Erling Smørgrav 			log_err("tls-session-ticket-key %s is %d bytes, must be 80 bytes", p->str, (int)n);
1558e86b9096SDag-Erling Smørgrav 			free(data);
1559e86b9096SDag-Erling Smørgrav 			return 0;
1560e86b9096SDag-Erling Smørgrav 		}
1561e86b9096SDag-Erling Smørgrav 		verbose(VERB_OPS, "read tls-session-ticket-key: %s", p->str);
1562e86b9096SDag-Erling Smørgrav 
1563e86b9096SDag-Erling Smørgrav 		keys->key_name = data;
1564e86b9096SDag-Erling Smørgrav 		keys->aes_key = data + 16;
1565e86b9096SDag-Erling Smørgrav 		keys->hmac_key = data + 48;
1566e86b9096SDag-Erling Smørgrav 		keys++;
1567e86b9096SDag-Erling Smørgrav 	}
1568e86b9096SDag-Erling Smørgrav 	/* terminate array with NULL key name entry */
1569e86b9096SDag-Erling Smørgrav 	keys->key_name = NULL;
157025039b37SCy Schubert #  ifdef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
157125039b37SCy Schubert 	if(SSL_CTX_set_tlsext_ticket_key_evp_cb(sslctx, tls_session_ticket_key_cb) == 0) {
157225039b37SCy Schubert 		log_err("no support for TLS session ticket");
157325039b37SCy Schubert 		return 0;
157425039b37SCy Schubert 	}
157525039b37SCy Schubert #  else
1576e86b9096SDag-Erling Smørgrav 	if(SSL_CTX_set_tlsext_ticket_key_cb(sslctx, tls_session_ticket_key_cb) == 0) {
1577e86b9096SDag-Erling Smørgrav 		log_err("no support for TLS session ticket");
1578e86b9096SDag-Erling Smørgrav 		return 0;
1579e86b9096SDag-Erling Smørgrav 	}
158025039b37SCy Schubert #  endif
1581e86b9096SDag-Erling Smørgrav 	return 1;
1582e86b9096SDag-Erling Smørgrav #else
1583e86b9096SDag-Erling Smørgrav 	(void)sslctx;
1584e86b9096SDag-Erling Smørgrav 	(void)tls_session_ticket_keys;
1585e86b9096SDag-Erling Smørgrav 	return 0;
1586e86b9096SDag-Erling Smørgrav #endif
1587e86b9096SDag-Erling Smørgrav 
1588e86b9096SDag-Erling Smørgrav }
1589e86b9096SDag-Erling Smørgrav 
159025039b37SCy Schubert #ifdef HAVE_SSL
159125039b37SCy Schubert int tls_session_ticket_key_cb(SSL *ATTR_UNUSED(sslctx), unsigned char* key_name,
159225039b37SCy Schubert 	unsigned char* iv, EVP_CIPHER_CTX *evp_sctx,
159325039b37SCy Schubert #ifdef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
159425039b37SCy Schubert 	EVP_MAC_CTX *hmac_ctx,
159525039b37SCy Schubert #else
159625039b37SCy Schubert 	HMAC_CTX* hmac_ctx,
159725039b37SCy Schubert #endif
159825039b37SCy Schubert 	int enc)
1599e86b9096SDag-Erling Smørgrav {
1600e86b9096SDag-Erling Smørgrav #ifdef HAVE_SSL
160125039b37SCy Schubert #  ifdef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
160225039b37SCy Schubert 	OSSL_PARAM params[3];
160325039b37SCy Schubert #  else
1604e86b9096SDag-Erling Smørgrav 	const EVP_MD *digest;
160525039b37SCy Schubert #  endif
1606e86b9096SDag-Erling Smørgrav 	const EVP_CIPHER *cipher;
1607e86b9096SDag-Erling Smørgrav 	int evp_cipher_length;
160825039b37SCy Schubert #  ifndef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
1609e86b9096SDag-Erling Smørgrav 	digest = EVP_sha256();
161025039b37SCy Schubert #  endif
1611e86b9096SDag-Erling Smørgrav 	cipher = EVP_aes_256_cbc();
1612e86b9096SDag-Erling Smørgrav 	evp_cipher_length = EVP_CIPHER_iv_length(cipher);
1613e86b9096SDag-Erling Smørgrav 	if( enc == 1 ) {
1614e86b9096SDag-Erling Smørgrav 		/* encrypt */
1615e86b9096SDag-Erling Smørgrav 		verbose(VERB_CLIENT, "start session encrypt");
1616e86b9096SDag-Erling Smørgrav 		memcpy(key_name, ticket_keys->key_name, 16);
1617e86b9096SDag-Erling Smørgrav 		if (RAND_bytes(iv, evp_cipher_length) != 1) {
1618e86b9096SDag-Erling Smørgrav 			verbose(VERB_CLIENT, "RAND_bytes failed");
1619e86b9096SDag-Erling Smørgrav 			return -1;
1620e86b9096SDag-Erling Smørgrav 		}
1621e86b9096SDag-Erling Smørgrav 		if (EVP_EncryptInit_ex(evp_sctx, cipher, NULL, ticket_keys->aes_key, iv) != 1) {
1622e86b9096SDag-Erling Smørgrav 			verbose(VERB_CLIENT, "EVP_EncryptInit_ex failed");
1623e86b9096SDag-Erling Smørgrav 			return -1;
1624e86b9096SDag-Erling Smørgrav 		}
162525039b37SCy Schubert #ifdef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
162625039b37SCy Schubert 		params[0] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
162725039b37SCy Schubert 			ticket_keys->hmac_key, 32);
162825039b37SCy Schubert 		params[1] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
162925039b37SCy Schubert 			"sha256", 0);
163025039b37SCy Schubert 		params[2] = OSSL_PARAM_construct_end();
1631c0caa2e2SCy Schubert #ifdef HAVE_EVP_MAC_CTX_SET_PARAMS
1632c0caa2e2SCy Schubert 		EVP_MAC_CTX_set_params(hmac_ctx, params);
1633c0caa2e2SCy Schubert #else
163425039b37SCy Schubert 		EVP_MAC_set_ctx_params(hmac_ctx, params);
1635c0caa2e2SCy Schubert #endif
163625039b37SCy Schubert #elif !defined(HMAC_INIT_EX_RETURNS_VOID)
1637e86b9096SDag-Erling Smørgrav 		if (HMAC_Init_ex(hmac_ctx, ticket_keys->hmac_key, 32, digest, NULL) != 1) {
1638e86b9096SDag-Erling Smørgrav 			verbose(VERB_CLIENT, "HMAC_Init_ex failed");
1639e86b9096SDag-Erling Smørgrav 			return -1;
1640e86b9096SDag-Erling Smørgrav 		}
16410eefd307SCy Schubert #else
16420eefd307SCy Schubert 		HMAC_Init_ex(hmac_ctx, ticket_keys->hmac_key, 32, digest, NULL);
16430eefd307SCy Schubert #endif
1644e86b9096SDag-Erling Smørgrav 		return 1;
1645e86b9096SDag-Erling Smørgrav 	} else if (enc == 0) {
1646e86b9096SDag-Erling Smørgrav 		/* decrypt */
1647e86b9096SDag-Erling Smørgrav 		struct tls_session_ticket_key *key;
1648e86b9096SDag-Erling Smørgrav 		verbose(VERB_CLIENT, "start session decrypt");
1649e86b9096SDag-Erling Smørgrav 		for(key = ticket_keys; key->key_name != NULL; key++) {
1650e86b9096SDag-Erling Smørgrav 			if (!memcmp(key_name, key->key_name, 16)) {
1651e86b9096SDag-Erling Smørgrav 				verbose(VERB_CLIENT, "Found session_key");
1652e86b9096SDag-Erling Smørgrav 				break;
1653e86b9096SDag-Erling Smørgrav 			}
1654e86b9096SDag-Erling Smørgrav 		}
1655e86b9096SDag-Erling Smørgrav 		if(key->key_name == NULL) {
1656e86b9096SDag-Erling Smørgrav 			verbose(VERB_CLIENT, "Not found session_key");
1657e86b9096SDag-Erling Smørgrav 			return 0;
1658e86b9096SDag-Erling Smørgrav 		}
1659e86b9096SDag-Erling Smørgrav 
166025039b37SCy Schubert #ifdef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
166125039b37SCy Schubert 		params[0] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
166225039b37SCy Schubert 			key->hmac_key, 32);
166325039b37SCy Schubert 		params[1] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
166425039b37SCy Schubert 			"sha256", 0);
166525039b37SCy Schubert 		params[2] = OSSL_PARAM_construct_end();
1666c0caa2e2SCy Schubert #ifdef HAVE_EVP_MAC_CTX_SET_PARAMS
1667c0caa2e2SCy Schubert 		EVP_MAC_CTX_set_params(hmac_ctx, params);
1668c0caa2e2SCy Schubert #else
166925039b37SCy Schubert 		EVP_MAC_set_ctx_params(hmac_ctx, params);
1670c0caa2e2SCy Schubert #endif
167125039b37SCy Schubert #elif !defined(HMAC_INIT_EX_RETURNS_VOID)
1672e86b9096SDag-Erling Smørgrav 		if (HMAC_Init_ex(hmac_ctx, key->hmac_key, 32, digest, NULL) != 1) {
1673e86b9096SDag-Erling Smørgrav 			verbose(VERB_CLIENT, "HMAC_Init_ex failed");
1674e86b9096SDag-Erling Smørgrav 			return -1;
1675e86b9096SDag-Erling Smørgrav 		}
16760eefd307SCy Schubert #else
16770eefd307SCy Schubert 		HMAC_Init_ex(hmac_ctx, key->hmac_key, 32, digest, NULL);
16780eefd307SCy Schubert #endif
1679e86b9096SDag-Erling Smørgrav 		if (EVP_DecryptInit_ex(evp_sctx, cipher, NULL, key->aes_key, iv) != 1) {
1680e86b9096SDag-Erling Smørgrav 			log_err("EVP_DecryptInit_ex failed");
1681e86b9096SDag-Erling Smørgrav 			return -1;
1682e86b9096SDag-Erling Smørgrav 		}
1683e86b9096SDag-Erling Smørgrav 
1684e86b9096SDag-Erling Smørgrav 		return (key == ticket_keys) ? 1 : 2;
1685e86b9096SDag-Erling Smørgrav 	}
1686e86b9096SDag-Erling Smørgrav 	return -1;
1687e86b9096SDag-Erling Smørgrav #else
1688e86b9096SDag-Erling Smørgrav 	(void)key_name;
1689e86b9096SDag-Erling Smørgrav 	(void)iv;
1690e86b9096SDag-Erling Smørgrav 	(void)evp_sctx;
1691e86b9096SDag-Erling Smørgrav 	(void)hmac_ctx;
1692e86b9096SDag-Erling Smørgrav 	(void)enc;
1693e86b9096SDag-Erling Smørgrav 	return 0;
1694e86b9096SDag-Erling Smørgrav #endif
1695e86b9096SDag-Erling Smørgrav }
169625039b37SCy Schubert #endif /* HAVE_SSL */
1697e86b9096SDag-Erling Smørgrav 
1698e86b9096SDag-Erling Smørgrav void
1699e86b9096SDag-Erling Smørgrav listen_sslctx_delete_ticket_keys(void)
1700e86b9096SDag-Erling Smørgrav {
1701e86b9096SDag-Erling Smørgrav 	struct tls_session_ticket_key *key;
1702e86b9096SDag-Erling Smørgrav 	if(!ticket_keys) return;
1703e86b9096SDag-Erling Smørgrav 	for(key = ticket_keys; key->key_name != NULL; key++) {
1704e86b9096SDag-Erling Smørgrav 		/* wipe key data from memory*/
1705e86b9096SDag-Erling Smørgrav #ifdef HAVE_EXPLICIT_BZERO
1706e86b9096SDag-Erling Smørgrav 		explicit_bzero(key->key_name, 80);
1707e86b9096SDag-Erling Smørgrav #else
1708e86b9096SDag-Erling Smørgrav 		memset(key->key_name, 0xdd, 80);
1709e86b9096SDag-Erling Smørgrav #endif
1710e86b9096SDag-Erling Smørgrav 		free(key->key_name);
1711e86b9096SDag-Erling Smørgrav 	}
1712e86b9096SDag-Erling Smørgrav 	free(ticket_keys);
1713e86b9096SDag-Erling Smørgrav 	ticket_keys = NULL;
1714e86b9096SDag-Erling Smørgrav }
1715c0caa2e2SCy Schubert 
1716c0caa2e2SCy Schubert #  ifndef USE_WINSOCK
1717c0caa2e2SCy Schubert char*
1718c0caa2e2SCy Schubert sock_strerror(int errn)
1719c0caa2e2SCy Schubert {
1720c0caa2e2SCy Schubert 	return strerror(errn);
1721c0caa2e2SCy Schubert }
1722c0caa2e2SCy Schubert 
1723c0caa2e2SCy Schubert void
1724c0caa2e2SCy Schubert sock_close(int socket)
1725c0caa2e2SCy Schubert {
1726c0caa2e2SCy Schubert 	close(socket);
1727c0caa2e2SCy Schubert }
1728c0caa2e2SCy Schubert 
1729c0caa2e2SCy Schubert #  else
1730c0caa2e2SCy Schubert char*
1731c0caa2e2SCy Schubert sock_strerror(int ATTR_UNUSED(errn))
1732c0caa2e2SCy Schubert {
1733c0caa2e2SCy Schubert 	return wsa_strerror(WSAGetLastError());
1734c0caa2e2SCy Schubert }
1735c0caa2e2SCy Schubert 
1736c0caa2e2SCy Schubert void
1737c0caa2e2SCy Schubert sock_close(int socket)
1738c0caa2e2SCy Schubert {
1739c0caa2e2SCy Schubert 	closesocket(socket);
1740c0caa2e2SCy Schubert }
1741c0caa2e2SCy Schubert #  endif /* USE_WINSOCK */
1742