xref: /openbsd-src/usr.sbin/unbound/util/net_help.c (revision 98bc733b08604094f4138174a0ee0bb9faaca4bd)
1933707f3Ssthen /*
2933707f3Ssthen  * util/net_help.c - implementation of the network helper code
3933707f3Ssthen  *
4933707f3Ssthen  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5933707f3Ssthen  *
6933707f3Ssthen  * This software is open source.
7933707f3Ssthen  *
8933707f3Ssthen  * Redistribution and use in source and binary forms, with or without
9933707f3Ssthen  * modification, are permitted provided that the following conditions
10933707f3Ssthen  * are met:
11933707f3Ssthen  *
12933707f3Ssthen  * Redistributions of source code must retain the above copyright notice,
13933707f3Ssthen  * this list of conditions and the following disclaimer.
14933707f3Ssthen  *
15933707f3Ssthen  * Redistributions in binary form must reproduce the above copyright notice,
16933707f3Ssthen  * this list of conditions and the following disclaimer in the documentation
17933707f3Ssthen  * and/or other materials provided with the distribution.
18933707f3Ssthen  *
19933707f3Ssthen  * Neither the name of the NLNET LABS nor the names of its contributors may
20933707f3Ssthen  * be used to endorse or promote products derived from this software without
21933707f3Ssthen  * specific prior written permission.
22933707f3Ssthen  *
23933707f3Ssthen  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
245d76a658Ssthen  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
255d76a658Ssthen  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
265d76a658Ssthen  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
275d76a658Ssthen  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
285d76a658Ssthen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
295d76a658Ssthen  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
305d76a658Ssthen  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
315d76a658Ssthen  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
325d76a658Ssthen  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
335d76a658Ssthen  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen  */
35933707f3Ssthen /**
36933707f3Ssthen  * \file
37933707f3Ssthen  * Implementation of net_help.h.
38933707f3Ssthen  */
39933707f3Ssthen 
40933707f3Ssthen #include "config.h"
416eb11800Sflorian #ifdef HAVE_SYS_TYPES_H
426eb11800Sflorian #  include <sys/types.h>
436eb11800Sflorian #endif
446eb11800Sflorian #ifdef HAVE_NET_IF_H
456eb11800Sflorian #include <net/if.h>
466eb11800Sflorian #endif
47e21c60efSsthen #ifdef HAVE_NETIOAPI_H
48e21c60efSsthen #include <netioapi.h>
49e21c60efSsthen #endif
50*98bc733bSsthen #include <ctype.h>
51933707f3Ssthen #include "util/net_help.h"
52933707f3Ssthen #include "util/log.h"
53933707f3Ssthen #include "util/data/dname.h"
54933707f3Ssthen #include "util/module.h"
55933707f3Ssthen #include "util/regional.h"
56f6b99bafSsthen #include "util/config_file.h"
57a58bff56Ssthen #include "sldns/parseutil.h"
58a58bff56Ssthen #include "sldns/wire2str.h"
59e21c60efSsthen #include "sldns/str2wire.h"
60933707f3Ssthen #include <fcntl.h>
613dcb24b8Ssthen #ifdef HAVE_OPENSSL_SSL_H
62933707f3Ssthen #include <openssl/ssl.h>
63f6b99bafSsthen #include <openssl/evp.h>
64f6b99bafSsthen #include <openssl/rand.h>
653dcb24b8Ssthen #endif
663dcb24b8Ssthen #ifdef HAVE_OPENSSL_ERR_H
67933707f3Ssthen #include <openssl/err.h>
683dcb24b8Ssthen #endif
69a3167c07Ssthen #ifdef HAVE_OPENSSL_CORE_NAMES_H
70a3167c07Ssthen #include <openssl/core_names.h>
71a3167c07Ssthen #endif
7220237c55Ssthen #ifdef USE_WINSOCK
7320237c55Ssthen #include <wincrypt.h>
7420237c55Ssthen #endif
752c144df0Ssthen #ifdef HAVE_NGHTTP2_NGHTTP2_H
762c144df0Ssthen #include <nghttp2/nghttp2.h>
772c144df0Ssthen #endif
78933707f3Ssthen 
79933707f3Ssthen /** max length of an IP address (the address portion) that we allow */
80933707f3Ssthen #define MAX_ADDR_STRLEN 128 /* characters */
812bdc0ed1Ssthen /** max length of a hostname (with port and tls name) that we allow */
822bdc0ed1Ssthen #define MAX_HOST_STRLEN (LDNS_MAX_DOMAINLEN * 3) /* characters */
83933707f3Ssthen /** default value for EDNS ADVERTISED size */
84933707f3Ssthen uint16_t EDNS_ADVERTISED_SIZE = 4096;
85933707f3Ssthen 
86d8d14d0cSsthen /** minimal responses when positive answer: default is no */
87d8d14d0cSsthen int MINIMAL_RESPONSES = 0;
88d8d14d0cSsthen 
89a3167c07Ssthen /** rrset order roundrobin: default is yes */
90a3167c07Ssthen int RRSET_ROUNDROBIN = 1;
91d8d14d0cSsthen 
92f6b99bafSsthen /** log tag queries with name instead of 'info' for filtering */
93f6b99bafSsthen int LOG_TAG_QUERYREPLY = 0;
94f6b99bafSsthen 
95f6b99bafSsthen static struct tls_session_ticket_key {
96f6b99bafSsthen 	unsigned char *key_name;
97f6b99bafSsthen 	unsigned char *aes_key;
98f6b99bafSsthen 	unsigned char *hmac_key;
99f6b99bafSsthen } *ticket_keys;
100f6b99bafSsthen 
1012c144df0Ssthen #ifdef HAVE_SSL
102a3167c07Ssthen /**
103a3167c07Ssthen  * callback TLS session ticket encrypt and decrypt
104a3167c07Ssthen  * For use with SSL_CTX_set_tlsext_ticket_key_cb or
105a3167c07Ssthen  * SSL_CTX_set_tlsext_ticket_key_evp_cb
106a3167c07Ssthen  * @param s: the SSL_CTX to use (from connect_sslctx_create())
107a3167c07Ssthen  * @param key_name: secret name, 16 bytes
108a3167c07Ssthen  * @param iv: up to EVP_MAX_IV_LENGTH.
109a3167c07Ssthen  * @param evp_ctx: the evp cipher context, function sets this.
110a3167c07Ssthen  * @param hmac_ctx: the hmac context, function sets this.
111a3167c07Ssthen  * 	with ..key_cb it is of type HMAC_CTX*
112a3167c07Ssthen  * 	with ..key_evp_cb it is of type EVP_MAC_CTX*
113a3167c07Ssthen  * @param enc: 1 is encrypt, 0 is decrypt
114a3167c07Ssthen  * @return 0 on no ticket, 1 for okay, and 2 for okay but renew the ticket
115a3167c07Ssthen  * 	(the ticket is decrypt only). and <0 for failures.
116a3167c07Ssthen  */
117a3167c07Ssthen int tls_session_ticket_key_cb(SSL *s, unsigned char* key_name,
118a3167c07Ssthen 	unsigned char* iv, EVP_CIPHER_CTX *evp_ctx,
119a3167c07Ssthen #ifdef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
120a3167c07Ssthen 	EVP_MAC_CTX *hmac_ctx,
121a3167c07Ssthen #else
122a3167c07Ssthen 	HMAC_CTX* hmac_ctx,
123a3167c07Ssthen #endif
124a3167c07Ssthen 	int enc);
125a3167c07Ssthen #endif /* HAVE_SSL */
126a3167c07Ssthen 
127933707f3Ssthen /* returns true is string addr is an ip6 specced address */
128933707f3Ssthen int
129933707f3Ssthen str_is_ip6(const char* str)
130933707f3Ssthen {
131933707f3Ssthen 	if(strchr(str, ':'))
132933707f3Ssthen 		return 1;
133933707f3Ssthen 	else    return 0;
134933707f3Ssthen }
135933707f3Ssthen 
136933707f3Ssthen int
137933707f3Ssthen fd_set_nonblock(int s)
138933707f3Ssthen {
139933707f3Ssthen #ifdef HAVE_FCNTL
140933707f3Ssthen 	int flag;
141933707f3Ssthen 	if((flag = fcntl(s, F_GETFL)) == -1) {
142933707f3Ssthen 		log_err("can't fcntl F_GETFL: %s", strerror(errno));
143933707f3Ssthen 		flag = 0;
144933707f3Ssthen 	}
145933707f3Ssthen 	flag |= O_NONBLOCK;
146933707f3Ssthen 	if(fcntl(s, F_SETFL, flag) == -1) {
147933707f3Ssthen 		log_err("can't fcntl F_SETFL: %s", strerror(errno));
148933707f3Ssthen 		return 0;
149933707f3Ssthen 	}
150933707f3Ssthen #elif defined(HAVE_IOCTLSOCKET)
151933707f3Ssthen 	unsigned long on = 1;
152933707f3Ssthen 	if(ioctlsocket(s, FIONBIO, &on) != 0) {
153933707f3Ssthen 		log_err("can't ioctlsocket FIONBIO on: %s",
154933707f3Ssthen 			wsa_strerror(WSAGetLastError()));
155933707f3Ssthen 	}
156933707f3Ssthen #endif
157933707f3Ssthen 	return 1;
158933707f3Ssthen }
159933707f3Ssthen 
160933707f3Ssthen int
161933707f3Ssthen fd_set_block(int s)
162933707f3Ssthen {
163933707f3Ssthen #ifdef HAVE_FCNTL
164933707f3Ssthen 	int flag;
165933707f3Ssthen 	if((flag = fcntl(s, F_GETFL)) == -1) {
166933707f3Ssthen 		log_err("cannot fcntl F_GETFL: %s", strerror(errno));
167933707f3Ssthen 		flag = 0;
168933707f3Ssthen 	}
169933707f3Ssthen 	flag &= ~O_NONBLOCK;
170933707f3Ssthen 	if(fcntl(s, F_SETFL, flag) == -1) {
171933707f3Ssthen 		log_err("cannot fcntl F_SETFL: %s", strerror(errno));
172933707f3Ssthen 		return 0;
173933707f3Ssthen 	}
174933707f3Ssthen #elif defined(HAVE_IOCTLSOCKET)
175933707f3Ssthen 	unsigned long off = 0;
176933707f3Ssthen 	if(ioctlsocket(s, FIONBIO, &off) != 0) {
1777191de28Ssthen 		if(WSAGetLastError() != WSAEINVAL || verbosity >= 4)
178933707f3Ssthen 			log_err("can't ioctlsocket FIONBIO off: %s",
179933707f3Ssthen 				wsa_strerror(WSAGetLastError()));
180933707f3Ssthen 	}
181933707f3Ssthen #endif
182933707f3Ssthen 	return 1;
183933707f3Ssthen }
184933707f3Ssthen 
185933707f3Ssthen int
186933707f3Ssthen is_pow2(size_t num)
187933707f3Ssthen {
188933707f3Ssthen 	if(num == 0) return 1;
189933707f3Ssthen 	return (num & (num-1)) == 0;
190933707f3Ssthen }
191933707f3Ssthen 
192933707f3Ssthen void*
193933707f3Ssthen memdup(void* data, size_t len)
194933707f3Ssthen {
195933707f3Ssthen 	void* d;
196933707f3Ssthen 	if(!data) return NULL;
197933707f3Ssthen 	if(len == 0) return NULL;
198933707f3Ssthen 	d = malloc(len);
199933707f3Ssthen 	if(!d) return NULL;
200933707f3Ssthen 	memcpy(d, data, len);
201933707f3Ssthen 	return d;
202933707f3Ssthen }
203933707f3Ssthen 
204933707f3Ssthen void
205933707f3Ssthen log_addr(enum verbosity_value v, const char* str,
206933707f3Ssthen 	struct sockaddr_storage* addr, socklen_t addrlen)
207933707f3Ssthen {
208933707f3Ssthen 	uint16_t port;
209933707f3Ssthen 	const char* family = "unknown";
210933707f3Ssthen 	char dest[100];
211933707f3Ssthen 	int af = (int)((struct sockaddr_in*)addr)->sin_family;
212933707f3Ssthen 	void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
213933707f3Ssthen 	if(verbosity < v)
214933707f3Ssthen 		return;
215933707f3Ssthen 	switch(af) {
216933707f3Ssthen 		case AF_INET: family="ip4"; break;
217933707f3Ssthen 		case AF_INET6: family="ip6";
218933707f3Ssthen 			sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
219933707f3Ssthen 			break;
22031f127bbSsthen 		case AF_LOCAL:
22131f127bbSsthen 			dest[0]=0;
22231f127bbSsthen 			(void)inet_ntop(af, sinaddr, dest,
22331f127bbSsthen 				(socklen_t)sizeof(dest));
22431f127bbSsthen 			verbose(v, "%s local %s", str, dest);
22531f127bbSsthen 			return; /* do not continue and try to get port */
226933707f3Ssthen 		default: break;
227933707f3Ssthen 	}
228933707f3Ssthen 	if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
2295d76a658Ssthen 		(void)strlcpy(dest, "(inet_ntop error)", sizeof(dest));
230933707f3Ssthen 	}
231933707f3Ssthen 	dest[sizeof(dest)-1] = 0;
232933707f3Ssthen 	port = ntohs(((struct sockaddr_in*)addr)->sin_port);
233933707f3Ssthen 	if(verbosity >= 4)
234933707f3Ssthen 		verbose(v, "%s %s %s port %d (len %d)", str, family, dest,
235933707f3Ssthen 			(int)port, (int)addrlen);
236933707f3Ssthen 	else	verbose(v, "%s %s port %d", str, dest, (int)port);
237933707f3Ssthen }
238933707f3Ssthen 
239933707f3Ssthen int
240933707f3Ssthen extstrtoaddr(const char* str, struct sockaddr_storage* addr,
24145872187Ssthen 	socklen_t* addrlen, int port)
242933707f3Ssthen {
243933707f3Ssthen 	char* s;
244933707f3Ssthen 	if((s=strchr(str, '@'))) {
245933707f3Ssthen 		char buf[MAX_ADDR_STRLEN];
246933707f3Ssthen 		if(s-str >= MAX_ADDR_STRLEN) {
247933707f3Ssthen 			return 0;
248933707f3Ssthen 		}
2495d76a658Ssthen 		(void)strlcpy(buf, str, sizeof(buf));
250933707f3Ssthen 		buf[s-str] = 0;
251933707f3Ssthen 		port = atoi(s+1);
252933707f3Ssthen 		if(port == 0 && strcmp(s+1,"0")!=0) {
253933707f3Ssthen 			return 0;
254933707f3Ssthen 		}
255933707f3Ssthen 		return ipstrtoaddr(buf, port, addr, addrlen);
256933707f3Ssthen 	}
257933707f3Ssthen 	return ipstrtoaddr(str, port, addr, addrlen);
258933707f3Ssthen }
259933707f3Ssthen 
260933707f3Ssthen int
261933707f3Ssthen ipstrtoaddr(const char* ip, int port, struct sockaddr_storage* addr,
262933707f3Ssthen 	socklen_t* addrlen)
263933707f3Ssthen {
264933707f3Ssthen 	uint16_t p;
265933707f3Ssthen 	if(!ip) return 0;
266933707f3Ssthen 	p = (uint16_t) port;
267933707f3Ssthen 	if(str_is_ip6(ip)) {
268933707f3Ssthen 		char buf[MAX_ADDR_STRLEN];
269933707f3Ssthen 		char* s;
270933707f3Ssthen 		struct sockaddr_in6* sa = (struct sockaddr_in6*)addr;
271933707f3Ssthen 		*addrlen = (socklen_t)sizeof(struct sockaddr_in6);
272933707f3Ssthen 		memset(sa, 0, *addrlen);
273933707f3Ssthen 		sa->sin6_family = AF_INET6;
274933707f3Ssthen 		sa->sin6_port = (in_port_t)htons(p);
275933707f3Ssthen 		if((s=strchr(ip, '%'))) { /* ip6%interface, rfc 4007 */
276933707f3Ssthen 			if(s-ip >= MAX_ADDR_STRLEN)
277933707f3Ssthen 				return 0;
2785d76a658Ssthen 			(void)strlcpy(buf, ip, sizeof(buf));
279933707f3Ssthen 			buf[s-ip]=0;
2806eb11800Sflorian #ifdef HAVE_IF_NAMETOINDEX
2816eb11800Sflorian 			if (!(sa->sin6_scope_id = if_nametoindex(s+1)))
2826eb11800Sflorian #endif /* HAVE_IF_NAMETOINDEX */
283933707f3Ssthen 				sa->sin6_scope_id = (uint32_t)atoi(s+1);
284933707f3Ssthen 			ip = buf;
285933707f3Ssthen 		}
286933707f3Ssthen 		if(inet_pton((int)sa->sin6_family, ip, &sa->sin6_addr) <= 0) {
287933707f3Ssthen 			return 0;
288933707f3Ssthen 		}
289933707f3Ssthen 	} else { /* ip4 */
290933707f3Ssthen 		struct sockaddr_in* sa = (struct sockaddr_in*)addr;
291933707f3Ssthen 		*addrlen = (socklen_t)sizeof(struct sockaddr_in);
292933707f3Ssthen 		memset(sa, 0, *addrlen);
293933707f3Ssthen 		sa->sin_family = AF_INET;
294933707f3Ssthen 		sa->sin_port = (in_port_t)htons(p);
295933707f3Ssthen 		if(inet_pton((int)sa->sin_family, ip, &sa->sin_addr) <= 0) {
296933707f3Ssthen 			return 0;
297933707f3Ssthen 		}
298933707f3Ssthen 	}
299933707f3Ssthen 	return 1;
300933707f3Ssthen }
301933707f3Ssthen 
302933707f3Ssthen int netblockstrtoaddr(const char* str, int port, struct sockaddr_storage* addr,
303933707f3Ssthen         socklen_t* addrlen, int* net)
304933707f3Ssthen {
30520237c55Ssthen 	char buf[64];
30620237c55Ssthen 	char* s;
307933707f3Ssthen 	*net = (str_is_ip6(str)?128:32);
308933707f3Ssthen 	if((s=strchr(str, '/'))) {
309933707f3Ssthen 		if(atoi(s+1) > *net) {
310933707f3Ssthen 			log_err("netblock too large: %s", str);
311933707f3Ssthen 			return 0;
312933707f3Ssthen 		}
313933707f3Ssthen 		*net = atoi(s+1);
314933707f3Ssthen 		if(*net == 0 && strcmp(s+1, "0") != 0) {
315933707f3Ssthen 			log_err("cannot parse netblock: '%s'", str);
316933707f3Ssthen 			return 0;
317933707f3Ssthen 		}
31820237c55Ssthen 		strlcpy(buf, str, sizeof(buf));
31920237c55Ssthen 		s = strchr(buf, '/');
32020237c55Ssthen 		if(s) *s = 0;
32120237c55Ssthen 		s = buf;
322933707f3Ssthen 	}
323933707f3Ssthen 	if(!ipstrtoaddr(s?s:str, port, addr, addrlen)) {
324933707f3Ssthen 		log_err("cannot parse ip address: '%s'", str);
325933707f3Ssthen 		return 0;
326933707f3Ssthen 	}
327933707f3Ssthen 	if(s) {
328933707f3Ssthen 		addr_mask(addr, *addrlen, *net);
329933707f3Ssthen 	}
330933707f3Ssthen 	return 1;
331933707f3Ssthen }
332933707f3Ssthen 
333eaf2578eSsthen /* RPZ format address dname to network byte order address */
334eaf2578eSsthen static int ipdnametoaddr(uint8_t* dname, size_t dnamelen,
335eaf2578eSsthen 	struct sockaddr_storage* addr, socklen_t* addrlen, int* af)
336eaf2578eSsthen {
337eaf2578eSsthen 	uint8_t* ia;
3389982a05dSsthen 	int dnamelabs = dname_count_labels(dname);
339eaf2578eSsthen 	uint8_t lablen;
340eaf2578eSsthen 	char* e = NULL;
341eaf2578eSsthen 	int z = 0;
342eaf2578eSsthen 	size_t len = 0;
343eaf2578eSsthen 	int i;
344eaf2578eSsthen 	*af = AF_INET;
345eaf2578eSsthen 
346eaf2578eSsthen 	/* need 1 byte for label length */
347eaf2578eSsthen 	if(dnamelen < 1)
348eaf2578eSsthen 		return 0;
349eaf2578eSsthen 
350eaf2578eSsthen 	if(dnamelabs > 6 ||
351eaf2578eSsthen 		dname_has_label(dname, dnamelen, (uint8_t*)"\002zz")) {
352eaf2578eSsthen 		*af = AF_INET6;
353eaf2578eSsthen 	}
354eaf2578eSsthen 	len = *dname;
355eaf2578eSsthen 	lablen = *dname++;
356eaf2578eSsthen 	i = (*af == AF_INET) ? 3 : 15;
357eaf2578eSsthen 	if(*af == AF_INET6) {
358eaf2578eSsthen 		struct sockaddr_in6* sa = (struct sockaddr_in6*)addr;
359eaf2578eSsthen 		*addrlen = (socklen_t)sizeof(struct sockaddr_in6);
360eaf2578eSsthen 		memset(sa, 0, *addrlen);
361eaf2578eSsthen 		sa->sin6_family = AF_INET6;
362eaf2578eSsthen 		ia = (uint8_t*)&sa->sin6_addr;
363eaf2578eSsthen 	} else { /* ip4 */
364eaf2578eSsthen 		struct sockaddr_in* sa = (struct sockaddr_in*)addr;
365eaf2578eSsthen 		*addrlen = (socklen_t)sizeof(struct sockaddr_in);
366eaf2578eSsthen 		memset(sa, 0, *addrlen);
367eaf2578eSsthen 		sa->sin_family = AF_INET;
368eaf2578eSsthen 		ia = (uint8_t*)&sa->sin_addr;
369eaf2578eSsthen 	}
370eaf2578eSsthen 	while(lablen && i >= 0 && len <= dnamelen) {
371eaf2578eSsthen 		char buff[LDNS_MAX_LABELLEN+1];
372eaf2578eSsthen 		uint16_t chunk; /* big enough to not overflow on IPv6 hextet */
373eaf2578eSsthen 		if((*af == AF_INET && (lablen > 3 || dnamelabs > 6)) ||
374eaf2578eSsthen 			(*af == AF_INET6 && (lablen > 4 || dnamelabs > 10))) {
375eaf2578eSsthen 			return 0;
376eaf2578eSsthen 		}
377eaf2578eSsthen 		if(memcmp(dname, "zz", 2) == 0 && *af == AF_INET6) {
378eaf2578eSsthen 			/* Add one or more 0 labels. Address is initialised at
379eaf2578eSsthen 			 * 0, so just skip the zero part. */
380eaf2578eSsthen 			int zl = 11 - dnamelabs;
381eaf2578eSsthen 			if(z || zl < 0)
382eaf2578eSsthen 				return 0;
383eaf2578eSsthen 			z = 1;
384eaf2578eSsthen 			i -= (zl*2);
385eaf2578eSsthen 		} else {
386eaf2578eSsthen 			memcpy(buff, dname, lablen);
387eaf2578eSsthen 			buff[lablen] = '\0';
388eaf2578eSsthen 			chunk = strtol(buff, &e, (*af == AF_INET) ? 10 : 16);
389eaf2578eSsthen 			if(!e || *e != '\0' || (*af == AF_INET && chunk > 255))
390eaf2578eSsthen 				return 0;
391eaf2578eSsthen 			if(*af == AF_INET) {
392eaf2578eSsthen 				log_assert(i < 4 && i >= 0);
393eaf2578eSsthen 				ia[i] = (uint8_t)chunk;
394eaf2578eSsthen 				i--;
395eaf2578eSsthen 			} else {
396eaf2578eSsthen 				log_assert(i < 16 && i >= 1);
397eaf2578eSsthen 				/* ia in network byte order */
398eaf2578eSsthen 				ia[i-1] = (uint8_t)(chunk >> 8);
399eaf2578eSsthen 				ia[i] = (uint8_t)(chunk & 0x00FF);
400eaf2578eSsthen 				i -= 2;
401eaf2578eSsthen 			}
402eaf2578eSsthen 		}
403eaf2578eSsthen 		dname += lablen;
404eaf2578eSsthen 		lablen = *dname++;
405eaf2578eSsthen 		len += lablen;
406eaf2578eSsthen 	}
407eaf2578eSsthen 	if(i != -1)
408eaf2578eSsthen 		/* input too short */
409eaf2578eSsthen 		return 0;
410eaf2578eSsthen 	return 1;
411eaf2578eSsthen }
412eaf2578eSsthen 
413eaf2578eSsthen int netblockdnametoaddr(uint8_t* dname, size_t dnamelen,
414eaf2578eSsthen 	struct sockaddr_storage* addr, socklen_t* addrlen, int* net, int* af)
415eaf2578eSsthen {
416eaf2578eSsthen 	char buff[3 /* 3 digit netblock */ + 1];
417eaf2578eSsthen 	size_t nlablen;
418eaf2578eSsthen 	if(dnamelen < 1 || *dname > 3)
419eaf2578eSsthen 		/* netblock invalid */
420eaf2578eSsthen 		return 0;
421eaf2578eSsthen 	nlablen = *dname;
422eaf2578eSsthen 
423eaf2578eSsthen 	if(dnamelen < 1 + nlablen)
424eaf2578eSsthen 		return 0;
425eaf2578eSsthen 
426eaf2578eSsthen 	memcpy(buff, dname+1, nlablen);
427eaf2578eSsthen 	buff[nlablen] = '\0';
428eaf2578eSsthen 	*net = atoi(buff);
429eaf2578eSsthen 	if(*net == 0 && strcmp(buff, "0") != 0)
430eaf2578eSsthen 		return 0;
431eaf2578eSsthen 	dname += nlablen;
432eaf2578eSsthen 	dname++;
433eaf2578eSsthen 	if(!ipdnametoaddr(dname, dnamelen-1-nlablen, addr, addrlen, af))
434eaf2578eSsthen 		return 0;
435eaf2578eSsthen 	if((*af == AF_INET6 && *net > 128) || (*af == AF_INET && *net > 32))
436eaf2578eSsthen 		return 0;
437eaf2578eSsthen 	return 1;
438eaf2578eSsthen }
439eaf2578eSsthen 
44020237c55Ssthen int authextstrtoaddr(char* str, struct sockaddr_storage* addr,
44120237c55Ssthen 	socklen_t* addrlen, char** auth_name)
44220237c55Ssthen {
44320237c55Ssthen 	char* s;
44420237c55Ssthen 	int port = UNBOUND_DNS_PORT;
44520237c55Ssthen 	if((s=strchr(str, '@'))) {
44620237c55Ssthen 		char buf[MAX_ADDR_STRLEN];
44720237c55Ssthen 		size_t len = (size_t)(s-str);
44820237c55Ssthen 		char* hash = strchr(s+1, '#');
44920237c55Ssthen 		if(hash) {
45020237c55Ssthen 			*auth_name = hash+1;
45120237c55Ssthen 		} else {
45220237c55Ssthen 			*auth_name = NULL;
45320237c55Ssthen 		}
45420237c55Ssthen 		if(len >= MAX_ADDR_STRLEN) {
45520237c55Ssthen 			return 0;
45620237c55Ssthen 		}
45720237c55Ssthen 		(void)strlcpy(buf, str, sizeof(buf));
45820237c55Ssthen 		buf[len] = 0;
45920237c55Ssthen 		port = atoi(s+1);
46020237c55Ssthen 		if(port == 0) {
46120237c55Ssthen 			if(!hash && strcmp(s+1,"0")!=0)
46220237c55Ssthen 				return 0;
46320237c55Ssthen 			if(hash && strncmp(s+1,"0#",2)!=0)
46420237c55Ssthen 				return 0;
46520237c55Ssthen 		}
46620237c55Ssthen 		return ipstrtoaddr(buf, port, addr, addrlen);
46720237c55Ssthen 	}
46820237c55Ssthen 	if((s=strchr(str, '#'))) {
46920237c55Ssthen 		char buf[MAX_ADDR_STRLEN];
47020237c55Ssthen 		size_t len = (size_t)(s-str);
47120237c55Ssthen 		if(len >= MAX_ADDR_STRLEN) {
47220237c55Ssthen 			return 0;
47320237c55Ssthen 		}
47420237c55Ssthen 		(void)strlcpy(buf, str, sizeof(buf));
47520237c55Ssthen 		buf[len] = 0;
47620237c55Ssthen 		port = UNBOUND_DNS_OVER_TLS_PORT;
47720237c55Ssthen 		*auth_name = s+1;
47820237c55Ssthen 		return ipstrtoaddr(buf, port, addr, addrlen);
47920237c55Ssthen 	}
48020237c55Ssthen 	*auth_name = NULL;
48120237c55Ssthen 	return ipstrtoaddr(str, port, addr, addrlen);
48220237c55Ssthen }
48320237c55Ssthen 
484e21c60efSsthen uint8_t* authextstrtodname(char* str, int* port, char** auth_name)
485e21c60efSsthen {
486e21c60efSsthen 	char* s;
487e21c60efSsthen 	uint8_t* dname;
488e21c60efSsthen 	size_t dname_len;
489e21c60efSsthen 	*port = UNBOUND_DNS_PORT;
490e21c60efSsthen 	*auth_name = NULL;
491e21c60efSsthen 	if((s=strchr(str, '@'))) {
4922bdc0ed1Ssthen 		char buf[MAX_HOST_STRLEN];
4932bdc0ed1Ssthen 		size_t len = (size_t)(s-str);
494e21c60efSsthen 		char* hash = strchr(s+1, '#');
495e21c60efSsthen 		if(hash) {
496e21c60efSsthen 			*auth_name = hash+1;
497e21c60efSsthen 		} else {
498e21c60efSsthen 			*auth_name = NULL;
499e21c60efSsthen 		}
5002bdc0ed1Ssthen 		if(len >= MAX_HOST_STRLEN) {
5012bdc0ed1Ssthen 			return NULL;
5022bdc0ed1Ssthen 		}
5032bdc0ed1Ssthen 		(void)strlcpy(buf, str, sizeof(buf));
5042bdc0ed1Ssthen 		buf[len] = 0;
505e21c60efSsthen 		*port = atoi(s+1);
506e21c60efSsthen 		if(*port == 0) {
507e21c60efSsthen 			if(!hash && strcmp(s+1,"0")!=0)
5082bdc0ed1Ssthen 				return NULL;
509e21c60efSsthen 			if(hash && strncmp(s+1,"0#",2)!=0)
5102bdc0ed1Ssthen 				return NULL;
511e21c60efSsthen 		}
5122bdc0ed1Ssthen 		dname = sldns_str2wire_dname(buf, &dname_len);
513e21c60efSsthen 	} else if((s=strchr(str, '#'))) {
5142bdc0ed1Ssthen 		char buf[MAX_HOST_STRLEN];
5152bdc0ed1Ssthen 		size_t len = (size_t)(s-str);
5162bdc0ed1Ssthen 		if(len >= MAX_HOST_STRLEN) {
5172bdc0ed1Ssthen 			return NULL;
5182bdc0ed1Ssthen 		}
5192bdc0ed1Ssthen 		(void)strlcpy(buf, str, sizeof(buf));
5202bdc0ed1Ssthen 		buf[len] = 0;
521e21c60efSsthen 		*port = UNBOUND_DNS_OVER_TLS_PORT;
522e21c60efSsthen 		*auth_name = s+1;
5232bdc0ed1Ssthen 		dname = sldns_str2wire_dname(buf, &dname_len);
524e21c60efSsthen 	} else {
525e21c60efSsthen 		dname = sldns_str2wire_dname(str, &dname_len);
526e21c60efSsthen 	}
527e21c60efSsthen 	return dname;
528e21c60efSsthen }
529e21c60efSsthen 
530938a3a5eSflorian /** store port number into sockaddr structure */
531938a3a5eSflorian void
532938a3a5eSflorian sockaddr_store_port(struct sockaddr_storage* addr, socklen_t addrlen, int port)
533938a3a5eSflorian {
534938a3a5eSflorian 	if(addr_is_ip6(addr, addrlen)) {
535938a3a5eSflorian 		struct sockaddr_in6* sa = (struct sockaddr_in6*)addr;
536938a3a5eSflorian 		sa->sin6_port = (in_port_t)htons((uint16_t)port);
537938a3a5eSflorian 	} else {
538938a3a5eSflorian 		struct sockaddr_in* sa = (struct sockaddr_in*)addr;
539938a3a5eSflorian 		sa->sin_port = (in_port_t)htons((uint16_t)port);
540938a3a5eSflorian 	}
541938a3a5eSflorian }
542938a3a5eSflorian 
543933707f3Ssthen void
544933707f3Ssthen log_nametypeclass(enum verbosity_value v, const char* str, uint8_t* name,
545933707f3Ssthen 	uint16_t type, uint16_t dclass)
546933707f3Ssthen {
547933707f3Ssthen 	char buf[LDNS_MAX_DOMAINLEN+1];
548933707f3Ssthen 	char t[12], c[12];
549933707f3Ssthen 	const char *ts, *cs;
550933707f3Ssthen 	if(verbosity < v)
551933707f3Ssthen 		return;
552933707f3Ssthen 	dname_str(name, buf);
553933707f3Ssthen 	if(type == LDNS_RR_TYPE_TSIG) ts = "TSIG";
554933707f3Ssthen 	else if(type == LDNS_RR_TYPE_IXFR) ts = "IXFR";
555933707f3Ssthen 	else if(type == LDNS_RR_TYPE_AXFR) ts = "AXFR";
556933707f3Ssthen 	else if(type == LDNS_RR_TYPE_MAILB) ts = "MAILB";
557933707f3Ssthen 	else if(type == LDNS_RR_TYPE_MAILA) ts = "MAILA";
558933707f3Ssthen 	else if(type == LDNS_RR_TYPE_ANY) ts = "ANY";
5595d76a658Ssthen 	else if(sldns_rr_descript(type) && sldns_rr_descript(type)->_name)
5605d76a658Ssthen 		ts = sldns_rr_descript(type)->_name;
561933707f3Ssthen 	else {
562933707f3Ssthen 		snprintf(t, sizeof(t), "TYPE%d", (int)type);
563933707f3Ssthen 		ts = t;
564933707f3Ssthen 	}
5655d76a658Ssthen 	if(sldns_lookup_by_id(sldns_rr_classes, (int)dclass) &&
5665d76a658Ssthen 		sldns_lookup_by_id(sldns_rr_classes, (int)dclass)->name)
5675d76a658Ssthen 		cs = sldns_lookup_by_id(sldns_rr_classes, (int)dclass)->name;
568933707f3Ssthen 	else {
569933707f3Ssthen 		snprintf(c, sizeof(c), "CLASS%d", (int)dclass);
570933707f3Ssthen 		cs = c;
571933707f3Ssthen 	}
572933707f3Ssthen 	log_info("%s %s %s %s", str, buf, ts, cs);
573933707f3Ssthen }
574933707f3Ssthen 
575f6b99bafSsthen void
576f6b99bafSsthen log_query_in(const char* str, uint8_t* name, uint16_t type, uint16_t dclass)
577f6b99bafSsthen {
578f6b99bafSsthen 	char buf[LDNS_MAX_DOMAINLEN+1];
579f6b99bafSsthen 	char t[12], c[12];
580f6b99bafSsthen 	const char *ts, *cs;
581f6b99bafSsthen 	dname_str(name, buf);
582f6b99bafSsthen 	if(type == LDNS_RR_TYPE_TSIG) ts = "TSIG";
583f6b99bafSsthen 	else if(type == LDNS_RR_TYPE_IXFR) ts = "IXFR";
584f6b99bafSsthen 	else if(type == LDNS_RR_TYPE_AXFR) ts = "AXFR";
585f6b99bafSsthen 	else if(type == LDNS_RR_TYPE_MAILB) ts = "MAILB";
586f6b99bafSsthen 	else if(type == LDNS_RR_TYPE_MAILA) ts = "MAILA";
587f6b99bafSsthen 	else if(type == LDNS_RR_TYPE_ANY) ts = "ANY";
588f6b99bafSsthen 	else if(sldns_rr_descript(type) && sldns_rr_descript(type)->_name)
589f6b99bafSsthen 		ts = sldns_rr_descript(type)->_name;
590f6b99bafSsthen 	else {
591f6b99bafSsthen 		snprintf(t, sizeof(t), "TYPE%d", (int)type);
592f6b99bafSsthen 		ts = t;
593f6b99bafSsthen 	}
594f6b99bafSsthen 	if(sldns_lookup_by_id(sldns_rr_classes, (int)dclass) &&
595f6b99bafSsthen 		sldns_lookup_by_id(sldns_rr_classes, (int)dclass)->name)
596f6b99bafSsthen 		cs = sldns_lookup_by_id(sldns_rr_classes, (int)dclass)->name;
597f6b99bafSsthen 	else {
598f6b99bafSsthen 		snprintf(c, sizeof(c), "CLASS%d", (int)dclass);
599f6b99bafSsthen 		cs = c;
600f6b99bafSsthen 	}
601f6b99bafSsthen 	if(LOG_TAG_QUERYREPLY)
602f6b99bafSsthen 		log_query("%s %s %s %s", str, buf, ts, cs);
603f6b99bafSsthen 	else	log_info("%s %s %s %s", str, buf, ts, cs);
604f6b99bafSsthen }
605f6b99bafSsthen 
606933707f3Ssthen void log_name_addr(enum verbosity_value v, const char* str, uint8_t* zone,
607933707f3Ssthen 	struct sockaddr_storage* addr, socklen_t addrlen)
608933707f3Ssthen {
609933707f3Ssthen 	uint16_t port;
610933707f3Ssthen 	const char* family = "unknown_family ";
611933707f3Ssthen 	char namebuf[LDNS_MAX_DOMAINLEN+1];
612933707f3Ssthen 	char dest[100];
613933707f3Ssthen 	int af = (int)((struct sockaddr_in*)addr)->sin_family;
614933707f3Ssthen 	void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
615933707f3Ssthen 	if(verbosity < v)
616933707f3Ssthen 		return;
617933707f3Ssthen 	switch(af) {
618933707f3Ssthen 		case AF_INET: family=""; break;
619933707f3Ssthen 		case AF_INET6: family="";
620933707f3Ssthen 			sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
621933707f3Ssthen 			break;
62231f127bbSsthen 		case AF_LOCAL: family="local "; break;
623933707f3Ssthen 		default: break;
624933707f3Ssthen 	}
625933707f3Ssthen 	if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
6265d76a658Ssthen 		(void)strlcpy(dest, "(inet_ntop error)", sizeof(dest));
627933707f3Ssthen 	}
628933707f3Ssthen 	dest[sizeof(dest)-1] = 0;
629933707f3Ssthen 	port = ntohs(((struct sockaddr_in*)addr)->sin_port);
630933707f3Ssthen 	dname_str(zone, namebuf);
631933707f3Ssthen 	if(af != AF_INET && af != AF_INET6)
632933707f3Ssthen 		verbose(v, "%s <%s> %s%s#%d (addrlen %d)",
633933707f3Ssthen 			str, namebuf, family, dest, (int)port, (int)addrlen);
634933707f3Ssthen 	else	verbose(v, "%s <%s> %s%s#%d",
635933707f3Ssthen 			str, namebuf, family, dest, (int)port);
636933707f3Ssthen }
637933707f3Ssthen 
63898f3ca02Sbrad void log_err_addr(const char* str, const char* err,
63998f3ca02Sbrad 	struct sockaddr_storage* addr, socklen_t addrlen)
64098f3ca02Sbrad {
64198f3ca02Sbrad 	uint16_t port;
64298f3ca02Sbrad 	char dest[100];
64398f3ca02Sbrad 	int af = (int)((struct sockaddr_in*)addr)->sin_family;
64498f3ca02Sbrad 	void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
64598f3ca02Sbrad 	if(af == AF_INET6)
64698f3ca02Sbrad 		sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
64798f3ca02Sbrad 	if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
64898f3ca02Sbrad 		(void)strlcpy(dest, "(inet_ntop error)", sizeof(dest));
64998f3ca02Sbrad 	}
65098f3ca02Sbrad 	dest[sizeof(dest)-1] = 0;
65198f3ca02Sbrad 	port = ntohs(((struct sockaddr_in*)addr)->sin_port);
65298f3ca02Sbrad 	if(verbosity >= 4)
65398f3ca02Sbrad 		log_err("%s: %s for %s port %d (len %d)", str, err, dest,
65498f3ca02Sbrad 			(int)port, (int)addrlen);
6552308e98cSsthen 	else	log_err("%s: %s for %s port %d", str, err, dest, (int)port);
65698f3ca02Sbrad }
65798f3ca02Sbrad 
658933707f3Ssthen int
659933707f3Ssthen sockaddr_cmp(struct sockaddr_storage* addr1, socklen_t len1,
660933707f3Ssthen 	struct sockaddr_storage* addr2, socklen_t len2)
661933707f3Ssthen {
662933707f3Ssthen 	struct sockaddr_in* p1_in = (struct sockaddr_in*)addr1;
663933707f3Ssthen 	struct sockaddr_in* p2_in = (struct sockaddr_in*)addr2;
664933707f3Ssthen 	struct sockaddr_in6* p1_in6 = (struct sockaddr_in6*)addr1;
665933707f3Ssthen 	struct sockaddr_in6* p2_in6 = (struct sockaddr_in6*)addr2;
666933707f3Ssthen 	if(len1 < len2)
667933707f3Ssthen 		return -1;
668933707f3Ssthen 	if(len1 > len2)
669933707f3Ssthen 		return 1;
670933707f3Ssthen 	log_assert(len1 == len2);
671933707f3Ssthen 	if( p1_in->sin_family < p2_in->sin_family)
672933707f3Ssthen 		return -1;
673933707f3Ssthen 	if( p1_in->sin_family > p2_in->sin_family)
674933707f3Ssthen 		return 1;
675933707f3Ssthen 	log_assert( p1_in->sin_family == p2_in->sin_family );
676933707f3Ssthen 	/* compare ip4 */
677933707f3Ssthen 	if( p1_in->sin_family == AF_INET ) {
678933707f3Ssthen 		/* just order it, ntohs not required */
679933707f3Ssthen 		if(p1_in->sin_port < p2_in->sin_port)
680933707f3Ssthen 			return -1;
681933707f3Ssthen 		if(p1_in->sin_port > p2_in->sin_port)
682933707f3Ssthen 			return 1;
683933707f3Ssthen 		log_assert(p1_in->sin_port == p2_in->sin_port);
684933707f3Ssthen 		return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE);
685933707f3Ssthen 	} else if (p1_in6->sin6_family == AF_INET6) {
686933707f3Ssthen 		/* just order it, ntohs not required */
687933707f3Ssthen 		if(p1_in6->sin6_port < p2_in6->sin6_port)
688933707f3Ssthen 			return -1;
689933707f3Ssthen 		if(p1_in6->sin6_port > p2_in6->sin6_port)
690933707f3Ssthen 			return 1;
691933707f3Ssthen 		log_assert(p1_in6->sin6_port == p2_in6->sin6_port);
692933707f3Ssthen 		return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr,
693933707f3Ssthen 			INET6_SIZE);
694933707f3Ssthen 	} else {
695933707f3Ssthen 		/* eek unknown type, perform this comparison for sanity. */
696933707f3Ssthen 		return memcmp(addr1, addr2, len1);
697933707f3Ssthen 	}
698933707f3Ssthen }
699933707f3Ssthen 
700933707f3Ssthen int
701933707f3Ssthen sockaddr_cmp_addr(struct sockaddr_storage* addr1, socklen_t len1,
702933707f3Ssthen 	struct sockaddr_storage* addr2, socklen_t len2)
703933707f3Ssthen {
704933707f3Ssthen 	struct sockaddr_in* p1_in = (struct sockaddr_in*)addr1;
705933707f3Ssthen 	struct sockaddr_in* p2_in = (struct sockaddr_in*)addr2;
706933707f3Ssthen 	struct sockaddr_in6* p1_in6 = (struct sockaddr_in6*)addr1;
707933707f3Ssthen 	struct sockaddr_in6* p2_in6 = (struct sockaddr_in6*)addr2;
708933707f3Ssthen 	if(len1 < len2)
709933707f3Ssthen 		return -1;
710933707f3Ssthen 	if(len1 > len2)
711933707f3Ssthen 		return 1;
712933707f3Ssthen 	log_assert(len1 == len2);
713933707f3Ssthen 	if( p1_in->sin_family < p2_in->sin_family)
714933707f3Ssthen 		return -1;
715933707f3Ssthen 	if( p1_in->sin_family > p2_in->sin_family)
716933707f3Ssthen 		return 1;
717933707f3Ssthen 	log_assert( p1_in->sin_family == p2_in->sin_family );
718933707f3Ssthen 	/* compare ip4 */
719933707f3Ssthen 	if( p1_in->sin_family == AF_INET ) {
720933707f3Ssthen 		return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE);
721933707f3Ssthen 	} else if (p1_in6->sin6_family == AF_INET6) {
722933707f3Ssthen 		return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr,
723933707f3Ssthen 			INET6_SIZE);
724933707f3Ssthen 	} else {
725933707f3Ssthen 		/* eek unknown type, perform this comparison for sanity. */
726933707f3Ssthen 		return memcmp(addr1, addr2, len1);
727933707f3Ssthen 	}
728933707f3Ssthen }
729933707f3Ssthen 
730933707f3Ssthen int
731933707f3Ssthen addr_is_ip6(struct sockaddr_storage* addr, socklen_t len)
732933707f3Ssthen {
733933707f3Ssthen 	if(len == (socklen_t)sizeof(struct sockaddr_in6) &&
734933707f3Ssthen 		((struct sockaddr_in6*)addr)->sin6_family == AF_INET6)
735933707f3Ssthen 		return 1;
736933707f3Ssthen 	else    return 0;
737933707f3Ssthen }
738933707f3Ssthen 
739933707f3Ssthen void
740933707f3Ssthen addr_mask(struct sockaddr_storage* addr, socklen_t len, int net)
741933707f3Ssthen {
742933707f3Ssthen 	uint8_t mask[8] = {0x0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe};
743933707f3Ssthen 	int i, max;
744933707f3Ssthen 	uint8_t* s;
745933707f3Ssthen 	if(addr_is_ip6(addr, len)) {
746933707f3Ssthen 		s = (uint8_t*)&((struct sockaddr_in6*)addr)->sin6_addr;
747933707f3Ssthen 		max = 128;
748933707f3Ssthen 	} else {
749933707f3Ssthen 		s = (uint8_t*)&((struct sockaddr_in*)addr)->sin_addr;
750933707f3Ssthen 		max = 32;
751933707f3Ssthen 	}
752933707f3Ssthen 	if(net >= max)
753933707f3Ssthen 		return;
754933707f3Ssthen 	for(i=net/8+1; i<max/8; i++) {
755933707f3Ssthen 		s[i] = 0;
756933707f3Ssthen 	}
757933707f3Ssthen 	s[net/8] &= mask[net&0x7];
758933707f3Ssthen }
759933707f3Ssthen 
760933707f3Ssthen int
761933707f3Ssthen addr_in_common(struct sockaddr_storage* addr1, int net1,
762933707f3Ssthen 	struct sockaddr_storage* addr2, int net2, socklen_t addrlen)
763933707f3Ssthen {
764933707f3Ssthen 	int min = (net1<net2)?net1:net2;
765933707f3Ssthen 	int i, to;
766933707f3Ssthen 	int match = 0;
767933707f3Ssthen 	uint8_t* s1, *s2;
768933707f3Ssthen 	if(addr_is_ip6(addr1, addrlen)) {
769933707f3Ssthen 		s1 = (uint8_t*)&((struct sockaddr_in6*)addr1)->sin6_addr;
770933707f3Ssthen 		s2 = (uint8_t*)&((struct sockaddr_in6*)addr2)->sin6_addr;
771933707f3Ssthen 		to = 16;
772933707f3Ssthen 	} else {
773933707f3Ssthen 		s1 = (uint8_t*)&((struct sockaddr_in*)addr1)->sin_addr;
774933707f3Ssthen 		s2 = (uint8_t*)&((struct sockaddr_in*)addr2)->sin_addr;
775933707f3Ssthen 		to = 4;
776933707f3Ssthen 	}
777933707f3Ssthen 	/* match = bits_in_common(s1, s2, to); */
778933707f3Ssthen 	for(i=0; i<to; i++) {
779933707f3Ssthen 		if(s1[i] == s2[i]) {
780933707f3Ssthen 			match += 8;
781933707f3Ssthen 		} else {
782933707f3Ssthen 			uint8_t z = s1[i]^s2[i];
783933707f3Ssthen 			log_assert(z);
784933707f3Ssthen 			while(!(z&0x80)) {
785933707f3Ssthen 				match++;
786933707f3Ssthen 				z<<=1;
787933707f3Ssthen 			}
788933707f3Ssthen 			break;
789933707f3Ssthen 		}
790933707f3Ssthen 	}
791933707f3Ssthen 	if(match > min) match = min;
792933707f3Ssthen 	return match;
793933707f3Ssthen }
794933707f3Ssthen 
795933707f3Ssthen void
796933707f3Ssthen addr_to_str(struct sockaddr_storage* addr, socklen_t addrlen,
797933707f3Ssthen 	char* buf, size_t len)
798933707f3Ssthen {
799933707f3Ssthen 	int af = (int)((struct sockaddr_in*)addr)->sin_family;
800933707f3Ssthen 	void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
801933707f3Ssthen 	if(addr_is_ip6(addr, addrlen))
802933707f3Ssthen 		sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
803933707f3Ssthen 	if(inet_ntop(af, sinaddr, buf, (socklen_t)len) == 0) {
804933707f3Ssthen 		snprintf(buf, len, "(inet_ntop_error)");
805933707f3Ssthen 	}
806933707f3Ssthen }
807933707f3Ssthen 
808933707f3Ssthen int
8098b7325afSsthen prefixnet_is_nat64(int prefixnet)
8108b7325afSsthen {
8118b7325afSsthen 	return (prefixnet == 32 || prefixnet == 40 ||
8128b7325afSsthen 		prefixnet == 48 || prefixnet == 56 ||
8138b7325afSsthen 		prefixnet == 64 || prefixnet == 96);
8148b7325afSsthen }
8158b7325afSsthen 
8168b7325afSsthen void
8178b7325afSsthen addr_to_nat64(const struct sockaddr_storage* addr,
8188b7325afSsthen 	const struct sockaddr_storage* nat64_prefix,
8198b7325afSsthen 	socklen_t nat64_prefixlen, int nat64_prefixnet,
8208b7325afSsthen 	struct sockaddr_storage* nat64_addr, socklen_t* nat64_addrlen)
8218b7325afSsthen {
8228b7325afSsthen 	struct sockaddr_in *sin = (struct sockaddr_in *)addr;
8238b7325afSsthen 	struct sockaddr_in6 *sin6;
8248b7325afSsthen 	uint8_t *v4_byte;
8253a958a18Sderaadt 	int i;
8268b7325afSsthen 
8278b7325afSsthen 	/* This needs to be checked by the caller */
8288b7325afSsthen 	log_assert(addr->ss_family == AF_INET);
8298b7325afSsthen 	/* Current usage is only from config values; prefix lengths enforced
8308b7325afSsthen 	 * during config validation */
8318b7325afSsthen 	log_assert(prefixnet_is_nat64(nat64_prefixnet));
8328b7325afSsthen 
8338b7325afSsthen 	*nat64_addr = *nat64_prefix;
8348b7325afSsthen 	*nat64_addrlen = nat64_prefixlen;
8358b7325afSsthen 
8368b7325afSsthen 	sin6 = (struct sockaddr_in6 *)nat64_addr;
8378b7325afSsthen 	sin6->sin6_flowinfo = 0;
8388b7325afSsthen 	sin6->sin6_port = sin->sin_port;
8398b7325afSsthen 
8408b7325afSsthen 	nat64_prefixnet = nat64_prefixnet / 8;
8418b7325afSsthen 
8428b7325afSsthen 	v4_byte = (uint8_t *)&sin->sin_addr.s_addr;
8433a958a18Sderaadt 	for(i = 0; i < 4; i++) {
8448b7325afSsthen 		if(nat64_prefixnet == 8) {
8458b7325afSsthen 			/* bits 64...71 are MBZ */
8468b7325afSsthen 			sin6->sin6_addr.s6_addr[nat64_prefixnet++] = 0;
8478b7325afSsthen 		}
8488b7325afSsthen 		sin6->sin6_addr.s6_addr[nat64_prefixnet++] = *v4_byte++;
8498b7325afSsthen 	}
8508b7325afSsthen }
8518b7325afSsthen 
8528b7325afSsthen int
853933707f3Ssthen addr_is_ip4mapped(struct sockaddr_storage* addr, socklen_t addrlen)
854933707f3Ssthen {
855933707f3Ssthen 	/* prefix for ipv4 into ipv6 mapping is ::ffff:x.x.x.x */
856933707f3Ssthen 	const uint8_t map_prefix[16] =
857933707f3Ssthen 		{0,0,0,0,  0,0,0,0, 0,0,0xff,0xff, 0,0,0,0};
858933707f3Ssthen 	uint8_t* s;
859933707f3Ssthen 	if(!addr_is_ip6(addr, addrlen))
860933707f3Ssthen 		return 0;
861933707f3Ssthen 	/* s is 16 octet ipv6 address string */
862933707f3Ssthen 	s = (uint8_t*)&((struct sockaddr_in6*)addr)->sin6_addr;
863933707f3Ssthen 	return (memcmp(s, map_prefix, 12) == 0);
864933707f3Ssthen }
865933707f3Ssthen 
866*98bc733bSsthen int addr_is_ip6linklocal(struct sockaddr_storage* addr, socklen_t addrlen)
867*98bc733bSsthen {
868*98bc733bSsthen 	const uint8_t prefix[2] = {0xfe, 0x80};
869*98bc733bSsthen 	int af = (int)((struct sockaddr_in6*)addr)->sin6_family;
870*98bc733bSsthen 	void* sin6addr = &((struct sockaddr_in6*)addr)->sin6_addr;
871*98bc733bSsthen 	uint8_t start[2];
872*98bc733bSsthen 	if(af != AF_INET6 || addrlen<(socklen_t)sizeof(struct sockaddr_in6))
873*98bc733bSsthen 		return 0;
874*98bc733bSsthen 	/* Put the first 10 bits of sin6addr in start, match fe80::/10. */
875*98bc733bSsthen 	memmove(start, sin6addr, 2);
876*98bc733bSsthen 	start[1] &= 0xc0;
877*98bc733bSsthen 	return memcmp(start, prefix, 2) == 0;
878*98bc733bSsthen }
879*98bc733bSsthen 
880933707f3Ssthen int addr_is_broadcast(struct sockaddr_storage* addr, socklen_t addrlen)
881933707f3Ssthen {
882933707f3Ssthen 	int af = (int)((struct sockaddr_in*)addr)->sin_family;
883933707f3Ssthen 	void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
884933707f3Ssthen 	return af == AF_INET && addrlen>=(socklen_t)sizeof(struct sockaddr_in)
885933707f3Ssthen 		&& memcmp(sinaddr, "\377\377\377\377", 4) == 0;
886933707f3Ssthen }
887933707f3Ssthen 
888933707f3Ssthen int addr_is_any(struct sockaddr_storage* addr, socklen_t addrlen)
889933707f3Ssthen {
890933707f3Ssthen 	int af = (int)((struct sockaddr_in*)addr)->sin_family;
891933707f3Ssthen 	void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
892933707f3Ssthen 	void* sin6addr = &((struct sockaddr_in6*)addr)->sin6_addr;
893933707f3Ssthen 	if(af == AF_INET && addrlen>=(socklen_t)sizeof(struct sockaddr_in)
894933707f3Ssthen 		&& memcmp(sinaddr, "\000\000\000\000", 4) == 0)
895933707f3Ssthen 		return 1;
896933707f3Ssthen 	else if(af==AF_INET6 && addrlen>=(socklen_t)sizeof(struct sockaddr_in6)
897933707f3Ssthen 		&& memcmp(sin6addr, "\000\000\000\000\000\000\000\000"
898933707f3Ssthen 		"\000\000\000\000\000\000\000\000", 16) == 0)
899933707f3Ssthen 		return 1;
900933707f3Ssthen 	return 0;
901933707f3Ssthen }
902933707f3Ssthen 
903933707f3Ssthen void sock_list_insert(struct sock_list** list, struct sockaddr_storage* addr,
904933707f3Ssthen 	socklen_t len, struct regional* region)
905933707f3Ssthen {
906933707f3Ssthen 	struct sock_list* add = (struct sock_list*)regional_alloc(region,
907933707f3Ssthen 		sizeof(*add) - sizeof(add->addr) + (size_t)len);
908933707f3Ssthen 	if(!add) {
909933707f3Ssthen 		log_err("out of memory in socketlist insert");
910933707f3Ssthen 		return;
911933707f3Ssthen 	}
912933707f3Ssthen 	log_assert(list);
913933707f3Ssthen 	add->next = *list;
914933707f3Ssthen 	add->len = len;
915933707f3Ssthen 	*list = add;
916933707f3Ssthen 	if(len) memmove(&add->addr, addr, len);
917933707f3Ssthen }
918933707f3Ssthen 
919933707f3Ssthen void sock_list_prepend(struct sock_list** list, struct sock_list* add)
920933707f3Ssthen {
921933707f3Ssthen 	struct sock_list* last = add;
922933707f3Ssthen 	if(!last)
923933707f3Ssthen 		return;
924933707f3Ssthen 	while(last->next)
925933707f3Ssthen 		last = last->next;
926933707f3Ssthen 	last->next = *list;
927933707f3Ssthen 	*list = add;
928933707f3Ssthen }
929933707f3Ssthen 
930933707f3Ssthen int sock_list_find(struct sock_list* list, struct sockaddr_storage* addr,
931933707f3Ssthen         socklen_t len)
932933707f3Ssthen {
933933707f3Ssthen 	while(list) {
934933707f3Ssthen 		if(len == list->len) {
935933707f3Ssthen 			if(len == 0 || sockaddr_cmp_addr(addr, len,
936933707f3Ssthen 				&list->addr, list->len) == 0)
937933707f3Ssthen 				return 1;
938933707f3Ssthen 		}
939933707f3Ssthen 		list = list->next;
940933707f3Ssthen 	}
941933707f3Ssthen 	return 0;
942933707f3Ssthen }
943933707f3Ssthen 
944933707f3Ssthen void sock_list_merge(struct sock_list** list, struct regional* region,
945933707f3Ssthen 	struct sock_list* add)
946933707f3Ssthen {
947933707f3Ssthen 	struct sock_list* p;
948933707f3Ssthen 	for(p=add; p; p=p->next) {
949933707f3Ssthen 		if(!sock_list_find(*list, &p->addr, p->len))
950933707f3Ssthen 			sock_list_insert(list, &p->addr, p->len, region);
951933707f3Ssthen 	}
952933707f3Ssthen }
953933707f3Ssthen 
954933707f3Ssthen void
955933707f3Ssthen log_crypto_err(const char* str)
956933707f3Ssthen {
9573dcb24b8Ssthen #ifdef HAVE_SSL
958ebf5bb73Ssthen 	log_crypto_err_code(str, ERR_get_error());
959ebf5bb73Ssthen #else
960ebf5bb73Ssthen 	(void)str;
961ebf5bb73Ssthen #endif /* HAVE_SSL */
962ebf5bb73Ssthen }
963ebf5bb73Ssthen 
964ebf5bb73Ssthen void log_crypto_err_code(const char* str, unsigned long err)
965ebf5bb73Ssthen {
966ebf5bb73Ssthen #ifdef HAVE_SSL
967933707f3Ssthen 	/* error:[error code]:[library name]:[function name]:[reason string] */
968933707f3Ssthen 	char buf[128];
969933707f3Ssthen 	unsigned long e;
970ebf5bb73Ssthen 	ERR_error_string_n(err, buf, sizeof(buf));
971933707f3Ssthen 	log_err("%s crypto %s", str, buf);
972933707f3Ssthen 	while( (e=ERR_get_error()) ) {
973933707f3Ssthen 		ERR_error_string_n(e, buf, sizeof(buf));
974933707f3Ssthen 		log_err("and additionally crypto %s", buf);
975933707f3Ssthen 	}
9763dcb24b8Ssthen #else
9773dcb24b8Ssthen 	(void)str;
978ebf5bb73Ssthen 	(void)err;
9793dcb24b8Ssthen #endif /* HAVE_SSL */
980933707f3Ssthen }
981933707f3Ssthen 
982a3167c07Ssthen #ifdef HAVE_SSL
983d896b962Ssthen /** Print crypt erro with SSL_get_error want code and err_get_error code */
984d896b962Ssthen static void log_crypto_err_io_code_arg(const char* str, int r,
985d896b962Ssthen 	unsigned long err, int err_present)
986d896b962Ssthen {
987d896b962Ssthen 	int print_errno = 0, print_crypto_err = 0;
988d896b962Ssthen 	const char* inf = NULL;
989d896b962Ssthen 
990d896b962Ssthen 	switch(r) {
991d896b962Ssthen 	case SSL_ERROR_NONE:
992d896b962Ssthen 		inf = "no error";
993d896b962Ssthen 		break;
994d896b962Ssthen 	case SSL_ERROR_ZERO_RETURN:
995d896b962Ssthen 		inf = "channel closed";
996d896b962Ssthen 		break;
997d896b962Ssthen 	case SSL_ERROR_WANT_READ:
998d896b962Ssthen 		inf = "want read";
999d896b962Ssthen 		break;
1000d896b962Ssthen 	case SSL_ERROR_WANT_WRITE:
1001d896b962Ssthen 		inf = "want write";
1002d896b962Ssthen 		break;
1003d896b962Ssthen 	case SSL_ERROR_WANT_CONNECT:
1004d896b962Ssthen 		inf = "want connect";
1005d896b962Ssthen 		break;
1006d896b962Ssthen 	case SSL_ERROR_WANT_ACCEPT:
1007d896b962Ssthen 		inf = "want accept";
1008d896b962Ssthen 		break;
1009d896b962Ssthen 	case SSL_ERROR_WANT_X509_LOOKUP:
1010d896b962Ssthen 		inf = "want X509 lookup";
1011d896b962Ssthen 		break;
1012d896b962Ssthen #ifdef SSL_ERROR_WANT_ASYNC
1013d896b962Ssthen 	case SSL_ERROR_WANT_ASYNC:
1014d896b962Ssthen 		inf = "want async";
1015d896b962Ssthen 		break;
1016d896b962Ssthen #endif
1017d896b962Ssthen #ifdef SSL_ERROR_WANT_ASYNC_JOB
1018d896b962Ssthen 	case SSL_ERROR_WANT_ASYNC_JOB:
1019d896b962Ssthen 		inf = "want async job";
1020d896b962Ssthen 		break;
1021d896b962Ssthen #endif
1022d896b962Ssthen #ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB
1023d896b962Ssthen 	case SSL_ERROR_WANT_CLIENT_HELLO_CB:
1024d896b962Ssthen 		inf = "want client hello cb";
1025d896b962Ssthen 		break;
1026d896b962Ssthen #endif
1027d896b962Ssthen 	case SSL_ERROR_SYSCALL:
1028d896b962Ssthen 		print_errno = 1;
1029d896b962Ssthen 		inf = "syscall";
1030d896b962Ssthen 		break;
1031d896b962Ssthen 	case SSL_ERROR_SSL:
1032d896b962Ssthen 		print_crypto_err = 1;
1033d896b962Ssthen 		inf = "SSL, usually protocol, error";
1034d896b962Ssthen 		break;
1035d896b962Ssthen 	default:
1036d896b962Ssthen 		inf = "unknown SSL_get_error result code";
1037d896b962Ssthen 		print_errno = 1;
1038d896b962Ssthen 		print_crypto_err = 1;
1039d896b962Ssthen 	}
1040d896b962Ssthen 	if(print_crypto_err) {
1041d896b962Ssthen 		if(print_errno) {
1042d896b962Ssthen 			char buf[1024];
1043d896b962Ssthen 			snprintf(buf, sizeof(buf), "%s with errno %s",
1044d896b962Ssthen 				str, strerror(errno));
1045d896b962Ssthen 			if(err_present)
1046d896b962Ssthen 				log_crypto_err_code(buf, err);
1047d896b962Ssthen 			else	log_crypto_err(buf);
1048d896b962Ssthen 		} else {
1049d896b962Ssthen 			if(err_present)
1050d896b962Ssthen 				log_crypto_err_code(str, err);
1051d896b962Ssthen 			else	log_crypto_err(str);
1052d896b962Ssthen 		}
1053d896b962Ssthen 	} else {
1054d896b962Ssthen 		if(print_errno) {
1055d896b962Ssthen 			if(errno == 0)
10562bdc0ed1Ssthen 				log_err("%s: syscall error with errno %s",
10572bdc0ed1Ssthen 					str, strerror(errno));
10582bdc0ed1Ssthen 			else log_err("%s: %s", str, strerror(errno));
1059d896b962Ssthen 		} else {
10602bdc0ed1Ssthen 			log_err("%s: %s", str, inf);
1061d896b962Ssthen 		}
1062d896b962Ssthen 	}
1063d896b962Ssthen }
1064d896b962Ssthen #endif /* HAVE_SSL */
1065d896b962Ssthen 
1066d896b962Ssthen void log_crypto_err_io(const char* str, int r)
1067d896b962Ssthen {
1068d896b962Ssthen #ifdef HAVE_SSL
1069d896b962Ssthen 	log_crypto_err_io_code_arg(str, r, 0, 0);
1070d896b962Ssthen #else
1071d896b962Ssthen 	(void)str;
1072d896b962Ssthen 	(void)r;
1073d896b962Ssthen #endif /* HAVE_SSL */
1074d896b962Ssthen }
1075d896b962Ssthen 
1076d896b962Ssthen void log_crypto_err_io_code(const char* str, int r, unsigned long err)
1077d896b962Ssthen {
1078d896b962Ssthen #ifdef HAVE_SSL
1079d896b962Ssthen 	log_crypto_err_io_code_arg(str, r, err, 1);
1080d896b962Ssthen #else
1081d896b962Ssthen 	(void)str;
1082d896b962Ssthen 	(void)r;
1083d896b962Ssthen 	(void)err;
1084d896b962Ssthen #endif /* HAVE_SSL */
1085d896b962Ssthen }
1086d896b962Ssthen 
1087d896b962Ssthen #ifdef HAVE_SSL
1088a3167c07Ssthen /** log certificate details */
1089a3167c07Ssthen void
1090a3167c07Ssthen log_cert(unsigned level, const char* str, void* cert)
1091a3167c07Ssthen {
1092a3167c07Ssthen 	BIO* bio;
1093a3167c07Ssthen 	char nul = 0;
1094a3167c07Ssthen 	char* pp = NULL;
1095a3167c07Ssthen 	long len;
1096a3167c07Ssthen 	if(verbosity < level) return;
1097a3167c07Ssthen 	bio = BIO_new(BIO_s_mem());
1098a3167c07Ssthen 	if(!bio) return;
1099a3167c07Ssthen 	X509_print_ex(bio, (X509*)cert, 0, (unsigned long)-1
1100a3167c07Ssthen 		^(X509_FLAG_NO_SUBJECT
1101a3167c07Ssthen                         |X509_FLAG_NO_ISSUER|X509_FLAG_NO_VALIDITY
1102a3167c07Ssthen 			|X509_FLAG_NO_EXTENSIONS|X509_FLAG_NO_AUX
1103a3167c07Ssthen 			|X509_FLAG_NO_ATTRIBUTES));
1104a3167c07Ssthen 	BIO_write(bio, &nul, (int)sizeof(nul));
1105a3167c07Ssthen 	len = BIO_get_mem_data(bio, &pp);
1106a3167c07Ssthen 	if(len != 0 && pp) {
1107e21c60efSsthen 		/* reduce size of cert printout */
1108e21c60efSsthen 		char* s;
1109e21c60efSsthen 		while((s=strstr(pp, "  "))!=NULL)
1110e21c60efSsthen 			memmove(s, s+1, strlen(s+1)+1);
1111e21c60efSsthen 		while((s=strstr(pp, "\t\t"))!=NULL)
1112e21c60efSsthen 			memmove(s, s+1, strlen(s+1)+1);
1113a3167c07Ssthen 		verbose(level, "%s: \n%s", str, pp);
1114a3167c07Ssthen 	}
1115a3167c07Ssthen 	BIO_free(bio);
1116a3167c07Ssthen }
1117a3167c07Ssthen #endif /* HAVE_SSL */
1118a3167c07Ssthen 
1119191f22c6Ssthen #if defined(HAVE_SSL) && defined(HAVE_NGHTTP2) && defined(HAVE_SSL_CTX_SET_ALPN_SELECT_CB)
11202c144df0Ssthen static int alpn_select_cb(SSL* ATTR_UNUSED(ssl), const unsigned char** out,
11212c144df0Ssthen 	unsigned char* outlen, const unsigned char* in, unsigned int inlen,
11222c144df0Ssthen 	void* ATTR_UNUSED(arg))
11232c144df0Ssthen {
11242c144df0Ssthen 	int rv = nghttp2_select_next_protocol((unsigned char **)out, outlen, in,
11252c144df0Ssthen 		inlen);
11262c144df0Ssthen 	if(rv == -1) {
11272c144df0Ssthen 		return SSL_TLSEXT_ERR_NOACK;
11282c144df0Ssthen 	}
11292c144df0Ssthen 	/* either http/1.1 or h2 selected */
11302c144df0Ssthen 	return SSL_TLSEXT_ERR_OK;
11312c144df0Ssthen }
11322c144df0Ssthen #endif
11332c144df0Ssthen 
11347191de28Ssthen int
11357191de28Ssthen listen_sslctx_setup(void* ctxt)
11367191de28Ssthen {
11377191de28Ssthen #ifdef HAVE_SSL
11387191de28Ssthen 	SSL_CTX* ctx = (SSL_CTX*)ctxt;
11397191de28Ssthen 	/* no SSLv2, SSLv3 because has defects */
1140eaf2578eSsthen #if SSL_OP_NO_SSLv2 != 0
11417191de28Ssthen 	if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)
11427191de28Ssthen 		!= SSL_OP_NO_SSLv2){
11437191de28Ssthen 		log_crypto_err("could not set SSL_OP_NO_SSLv2");
11447191de28Ssthen 		return 0;
11457191de28Ssthen 	}
1146eaf2578eSsthen #endif
11477191de28Ssthen 	if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3)
11487191de28Ssthen 		!= SSL_OP_NO_SSLv3){
11497191de28Ssthen 		log_crypto_err("could not set SSL_OP_NO_SSLv3");
11507191de28Ssthen 		return 0;
11517191de28Ssthen 	}
11527191de28Ssthen #if defined(SSL_OP_NO_TLSv1) && defined(SSL_OP_NO_TLSv1_1)
11537191de28Ssthen 	/* if we have tls 1.1 disable 1.0 */
11547191de28Ssthen 	if((SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1) & SSL_OP_NO_TLSv1)
11557191de28Ssthen 		!= SSL_OP_NO_TLSv1){
11567191de28Ssthen 		log_crypto_err("could not set SSL_OP_NO_TLSv1");
11577191de28Ssthen 		return 0;
11587191de28Ssthen 	}
11597191de28Ssthen #endif
11607191de28Ssthen #if defined(SSL_OP_NO_TLSv1_1) && defined(SSL_OP_NO_TLSv1_2)
11617191de28Ssthen 	/* if we have tls 1.2 disable 1.1 */
11627191de28Ssthen 	if((SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_1) & SSL_OP_NO_TLSv1_1)
11637191de28Ssthen 		!= SSL_OP_NO_TLSv1_1){
11647191de28Ssthen 		log_crypto_err("could not set SSL_OP_NO_TLSv1_1");
11657191de28Ssthen 		return 0;
11667191de28Ssthen 	}
11677191de28Ssthen #endif
11688240c1b9Ssthen #if defined(SSL_OP_NO_RENEGOTIATION)
11698240c1b9Ssthen 	/* disable client renegotiation */
11708240c1b9Ssthen 	if((SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION) &
11718240c1b9Ssthen 		SSL_OP_NO_RENEGOTIATION) != SSL_OP_NO_RENEGOTIATION) {
11728240c1b9Ssthen 		log_crypto_err("could not set SSL_OP_NO_RENEGOTIATION");
11738240c1b9Ssthen 		return 0;
11748240c1b9Ssthen 	}
11758240c1b9Ssthen #endif
11767191de28Ssthen #if defined(SHA256_DIGEST_LENGTH) && defined(USE_ECDSA)
1177e21c60efSsthen 	/* if we detect system-wide crypto policies, use those */
1178e21c60efSsthen 	if (access( "/etc/crypto-policies/config", F_OK ) != 0 ) {
11797191de28Ssthen 	/* if we have sha256, set the cipher list to have no known vulns */
1180bdfc4d55Sflorian 		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"))
11817191de28Ssthen 			log_crypto_err("could not set cipher list with SSL_CTX_set_cipher_list");
1182e21c60efSsthen 	}
11837191de28Ssthen #endif
11848b7325afSsthen #if defined(SSL_OP_IGNORE_UNEXPECTED_EOF)
11858b7325afSsthen 	/* ignore errors when peers do not send the mandatory close_notify
11868b7325afSsthen 	 * alert on shutdown.
11878b7325afSsthen 	 * Relevant for openssl >= 3 */
11888b7325afSsthen 	if((SSL_CTX_set_options(ctx, SSL_OP_IGNORE_UNEXPECTED_EOF) &
11898b7325afSsthen 		SSL_OP_IGNORE_UNEXPECTED_EOF) != SSL_OP_IGNORE_UNEXPECTED_EOF) {
11908b7325afSsthen 		log_crypto_err("could not set SSL_OP_IGNORE_UNEXPECTED_EOF");
11918b7325afSsthen 		return 0;
11928b7325afSsthen 	}
11938b7325afSsthen #endif
11947191de28Ssthen 
11957191de28Ssthen 	if((SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE) &
11967191de28Ssthen 		SSL_OP_CIPHER_SERVER_PREFERENCE) !=
11977191de28Ssthen 		SSL_OP_CIPHER_SERVER_PREFERENCE) {
11987191de28Ssthen 		log_crypto_err("could not set SSL_OP_CIPHER_SERVER_PREFERENCE");
11997191de28Ssthen 		return 0;
12007191de28Ssthen 	}
12017191de28Ssthen 
12027191de28Ssthen #ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL
12037191de28Ssthen 	SSL_CTX_set_security_level(ctx, 0);
12047191de28Ssthen #endif
12052c144df0Ssthen #if defined(HAVE_SSL_CTX_SET_ALPN_SELECT_CB) && defined(HAVE_NGHTTP2)
12062c144df0Ssthen 	SSL_CTX_set_alpn_select_cb(ctx, alpn_select_cb, NULL);
12072c144df0Ssthen #endif
12087191de28Ssthen #else
12097191de28Ssthen 	(void)ctxt;
12107191de28Ssthen #endif /* HAVE_SSL */
12117191de28Ssthen 	return 1;
12127191de28Ssthen }
12137191de28Ssthen 
12147191de28Ssthen void
12157191de28Ssthen listen_sslctx_setup_2(void* ctxt)
12167191de28Ssthen {
12177191de28Ssthen #ifdef HAVE_SSL
12187191de28Ssthen 	SSL_CTX* ctx = (SSL_CTX*)ctxt;
12197191de28Ssthen 	(void)ctx;
12207191de28Ssthen #if HAVE_DECL_SSL_CTX_SET_ECDH_AUTO
12217191de28Ssthen 	if(!SSL_CTX_set_ecdh_auto(ctx,1)) {
12227191de28Ssthen 		log_crypto_err("Error in SSL_CTX_ecdh_auto, not enabling ECDHE");
12237191de28Ssthen 	}
1224*98bc733bSsthen #elif defined(USE_ECDSA) && defined(HAVE_SSL_CTX_SET_TMP_ECDH)
12257191de28Ssthen 	if(1) {
12267191de28Ssthen 		EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1);
12277191de28Ssthen 		if (!ecdh) {
12287191de28Ssthen 			log_crypto_err("could not find p256, not enabling ECDHE");
12297191de28Ssthen 		} else {
12307191de28Ssthen 			if (1 != SSL_CTX_set_tmp_ecdh (ctx, ecdh)) {
12317191de28Ssthen 				log_crypto_err("Error in SSL_CTX_set_tmp_ecdh, not enabling ECDHE");
12327191de28Ssthen 			}
12337191de28Ssthen 			EC_KEY_free (ecdh);
12347191de28Ssthen 		}
12357191de28Ssthen 	}
12367191de28Ssthen #endif
12377191de28Ssthen #else
12387191de28Ssthen 	(void)ctxt;
12397191de28Ssthen #endif /* HAVE_SSL */
12407191de28Ssthen }
12417191de28Ssthen 
1242933707f3Ssthen void* listen_sslctx_create(char* key, char* pem, char* verifypem)
1243933707f3Ssthen {
12443dcb24b8Ssthen #ifdef HAVE_SSL
1245933707f3Ssthen 	SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method());
1246933707f3Ssthen 	if(!ctx) {
1247933707f3Ssthen 		log_crypto_err("could not SSL_CTX_new");
1248933707f3Ssthen 		return NULL;
1249933707f3Ssthen 	}
1250550cf4a9Ssthen 	if(!key || key[0] == 0) {
1251550cf4a9Ssthen 		log_err("error: no tls-service-key file specified");
1252550cf4a9Ssthen 		SSL_CTX_free(ctx);
1253550cf4a9Ssthen 		return NULL;
1254550cf4a9Ssthen 	}
1255550cf4a9Ssthen 	if(!pem || pem[0] == 0) {
1256550cf4a9Ssthen 		log_err("error: no tls-service-pem file specified");
1257550cf4a9Ssthen 		SSL_CTX_free(ctx);
1258550cf4a9Ssthen 		return NULL;
1259550cf4a9Ssthen 	}
12607191de28Ssthen 	if(!listen_sslctx_setup(ctx)) {
126198f3ca02Sbrad 		SSL_CTX_free(ctx);
126298f3ca02Sbrad 		return NULL;
126398f3ca02Sbrad 	}
1264a961b961Ssthen 	if(!SSL_CTX_use_certificate_chain_file(ctx, pem)) {
1265933707f3Ssthen 		log_err("error for cert file: %s", pem);
1266a961b961Ssthen 		log_crypto_err("error in SSL_CTX use_certificate_chain_file");
1267933707f3Ssthen 		SSL_CTX_free(ctx);
1268933707f3Ssthen 		return NULL;
1269933707f3Ssthen 	}
1270933707f3Ssthen 	if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) {
1271933707f3Ssthen 		log_err("error for private key file: %s", key);
1272933707f3Ssthen 		log_crypto_err("Error in SSL_CTX use_PrivateKey_file");
1273933707f3Ssthen 		SSL_CTX_free(ctx);
1274933707f3Ssthen 		return NULL;
1275933707f3Ssthen 	}
1276933707f3Ssthen 	if(!SSL_CTX_check_private_key(ctx)) {
1277933707f3Ssthen 		log_err("error for key file: %s", key);
1278933707f3Ssthen 		log_crypto_err("Error in SSL_CTX check_private_key");
1279933707f3Ssthen 		SSL_CTX_free(ctx);
1280933707f3Ssthen 		return NULL;
1281933707f3Ssthen 	}
12827191de28Ssthen 	listen_sslctx_setup_2(ctx);
1283933707f3Ssthen 	if(verifypem && verifypem[0]) {
1284933707f3Ssthen 		if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) {
1285933707f3Ssthen 			log_crypto_err("Error in SSL_CTX verify locations");
1286933707f3Ssthen 			SSL_CTX_free(ctx);
1287933707f3Ssthen 			return NULL;
1288933707f3Ssthen 		}
1289933707f3Ssthen 		SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(
1290933707f3Ssthen 			verifypem));
1291a3167c07Ssthen 		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
1292933707f3Ssthen 	}
1293933707f3Ssthen 	return ctx;
12943dcb24b8Ssthen #else
12953dcb24b8Ssthen 	(void)key; (void)pem; (void)verifypem;
12963dcb24b8Ssthen 	return NULL;
12973dcb24b8Ssthen #endif
1298933707f3Ssthen }
1299933707f3Ssthen 
130020237c55Ssthen #ifdef USE_WINSOCK
130120237c55Ssthen /* For windows, the CA trust store is not read by openssl.
130220237c55Ssthen    Add code to open the trust store using wincrypt API and add
130320237c55Ssthen    the root certs into openssl trust store */
130420237c55Ssthen static int
130520237c55Ssthen add_WIN_cacerts_to_openssl_store(SSL_CTX* tls_ctx)
130620237c55Ssthen {
130720237c55Ssthen 	HCERTSTORE      hSystemStore;
130820237c55Ssthen 	PCCERT_CONTEXT  pTargetCert = NULL;
130920237c55Ssthen 	X509_STORE*	store;
131020237c55Ssthen 
131120237c55Ssthen 	verbose(VERB_ALGO, "Adding Windows certificates from system root store to CA store");
131220237c55Ssthen 
131320237c55Ssthen 	/* load just once per context lifetime for this version
131420237c55Ssthen 	   TODO: dynamically update CA trust changes as they are available */
131520237c55Ssthen 	if (!tls_ctx)
131620237c55Ssthen 		return 0;
131720237c55Ssthen 
131820237c55Ssthen 	/* Call wincrypt's CertOpenStore to open the CA root store. */
131920237c55Ssthen 
132020237c55Ssthen 	if ((hSystemStore = CertOpenStore(
132120237c55Ssthen 		CERT_STORE_PROV_SYSTEM,
132220237c55Ssthen 		0,
132320237c55Ssthen 		0,
132420237c55Ssthen 		/* NOTE: mingw does not have this const: replace with 1 << 16 from code
132520237c55Ssthen 		   CERT_SYSTEM_STORE_CURRENT_USER, */
132620237c55Ssthen 		1 << 16,
132720237c55Ssthen 		L"root")) == 0)
132820237c55Ssthen 	{
132920237c55Ssthen 		return 0;
133020237c55Ssthen 	}
133120237c55Ssthen 
133220237c55Ssthen 	store = SSL_CTX_get_cert_store(tls_ctx);
133320237c55Ssthen 	if (!store)
133420237c55Ssthen 		return 0;
133520237c55Ssthen 
133620237c55Ssthen 	/* failure if the CA store is empty or the call fails */
133720237c55Ssthen 	if ((pTargetCert = CertEnumCertificatesInStore(
133820237c55Ssthen 		hSystemStore, pTargetCert)) == 0) {
133920237c55Ssthen 		verbose(VERB_ALGO, "CA certificate store for Windows is empty.");
134020237c55Ssthen 		return 0;
134120237c55Ssthen 	}
134220237c55Ssthen 	/* iterate over the windows cert store and add to openssl store */
134320237c55Ssthen 	do
134420237c55Ssthen 	{
134520237c55Ssthen 		X509 *cert1 = d2i_X509(NULL,
134620237c55Ssthen 			(const unsigned char **)&pTargetCert->pbCertEncoded,
134720237c55Ssthen 			pTargetCert->cbCertEncoded);
134820237c55Ssthen 		if (!cert1) {
1349d1e2768aSsthen 			unsigned long error = ERR_get_error();
135020237c55Ssthen 			/* return error if a cert fails */
135120237c55Ssthen 			verbose(VERB_ALGO, "%s %d:%s",
135220237c55Ssthen 				"Unable to parse certificate in memory",
1353d1e2768aSsthen 				(int)error, ERR_error_string(error, NULL));
135420237c55Ssthen 			return 0;
135520237c55Ssthen 		}
135620237c55Ssthen 		else {
135720237c55Ssthen 			/* return error if a cert add to store fails */
135820237c55Ssthen 			if (X509_STORE_add_cert(store, cert1) == 0) {
135920237c55Ssthen 				unsigned long error = ERR_peek_last_error();
136020237c55Ssthen 
136120237c55Ssthen 				/* Ignore error X509_R_CERT_ALREADY_IN_HASH_TABLE which means the
136220237c55Ssthen 				* certificate is already in the store.  */
136320237c55Ssthen 				if(ERR_GET_LIB(error) != ERR_LIB_X509 ||
136420237c55Ssthen 					ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE) {
1365d1e2768aSsthen 					error = ERR_get_error();
136620237c55Ssthen 					verbose(VERB_ALGO, "%s %d:%s\n",
1367d1e2768aSsthen 					    "Error adding certificate", (int)error,
1368d1e2768aSsthen 					     ERR_error_string(error, NULL));
136920237c55Ssthen 					X509_free(cert1);
137020237c55Ssthen 					return 0;
137120237c55Ssthen 				}
137220237c55Ssthen 			}
137320237c55Ssthen 			X509_free(cert1);
137420237c55Ssthen 		}
137520237c55Ssthen 	} while ((pTargetCert = CertEnumCertificatesInStore(
137620237c55Ssthen 		hSystemStore, pTargetCert)) != 0);
137720237c55Ssthen 
137820237c55Ssthen 	/* Clean up memory and quit. */
137920237c55Ssthen 	if (pTargetCert)
138020237c55Ssthen 		CertFreeCertificateContext(pTargetCert);
138120237c55Ssthen 	if (hSystemStore)
138220237c55Ssthen 	{
138320237c55Ssthen 		if (!CertCloseStore(
138420237c55Ssthen 			hSystemStore, 0))
138520237c55Ssthen 			return 0;
138620237c55Ssthen 	}
138720237c55Ssthen 	verbose(VERB_ALGO, "Completed adding Windows certificates to CA store successfully");
138820237c55Ssthen 	return 1;
138920237c55Ssthen }
139020237c55Ssthen #endif /* USE_WINSOCK */
139120237c55Ssthen 
139220237c55Ssthen void* connect_sslctx_create(char* key, char* pem, char* verifypem, int wincert)
1393933707f3Ssthen {
13943dcb24b8Ssthen #ifdef HAVE_SSL
1395933707f3Ssthen 	SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
1396933707f3Ssthen 	if(!ctx) {
1397933707f3Ssthen 		log_crypto_err("could not allocate SSL_CTX pointer");
1398933707f3Ssthen 		return NULL;
1399933707f3Ssthen 	}
1400eaf2578eSsthen #if SSL_OP_NO_SSLv2 != 0
14013c667526Sdoug 	if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)
14023c667526Sdoug 		!= SSL_OP_NO_SSLv2) {
1403933707f3Ssthen 		log_crypto_err("could not set SSL_OP_NO_SSLv2");
1404933707f3Ssthen 		SSL_CTX_free(ctx);
1405933707f3Ssthen 		return NULL;
1406933707f3Ssthen 	}
1407eaf2578eSsthen #endif
14083c667526Sdoug 	if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3)
14093c667526Sdoug 		!= SSL_OP_NO_SSLv3) {
141098f3ca02Sbrad 		log_crypto_err("could not set SSL_OP_NO_SSLv3");
141198f3ca02Sbrad 		SSL_CTX_free(ctx);
141298f3ca02Sbrad 		return NULL;
141398f3ca02Sbrad 	}
14148240c1b9Ssthen #if defined(SSL_OP_NO_RENEGOTIATION)
14158240c1b9Ssthen 	/* disable client renegotiation */
14168240c1b9Ssthen 	if((SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION) &
14178240c1b9Ssthen 		SSL_OP_NO_RENEGOTIATION) != SSL_OP_NO_RENEGOTIATION) {
14188240c1b9Ssthen 		log_crypto_err("could not set SSL_OP_NO_RENEGOTIATION");
1419e21c60efSsthen 		SSL_CTX_free(ctx);
14208240c1b9Ssthen 		return 0;
14218240c1b9Ssthen 	}
14228240c1b9Ssthen #endif
14238b7325afSsthen #if defined(SSL_OP_IGNORE_UNEXPECTED_EOF)
14248b7325afSsthen 	/* ignore errors when peers do not send the mandatory close_notify
14258b7325afSsthen 	 * alert on shutdown.
14268b7325afSsthen 	 * Relevant for openssl >= 3 */
14278b7325afSsthen 	if((SSL_CTX_set_options(ctx, SSL_OP_IGNORE_UNEXPECTED_EOF) &
14288b7325afSsthen 		SSL_OP_IGNORE_UNEXPECTED_EOF) != SSL_OP_IGNORE_UNEXPECTED_EOF) {
14298b7325afSsthen 		log_crypto_err("could not set SSL_OP_IGNORE_UNEXPECTED_EOF");
14308b7325afSsthen 		SSL_CTX_free(ctx);
14318b7325afSsthen 		return 0;
14328b7325afSsthen 	}
14338b7325afSsthen #endif
1434933707f3Ssthen 	if(key && key[0]) {
1435a961b961Ssthen 		if(!SSL_CTX_use_certificate_chain_file(ctx, pem)) {
1436933707f3Ssthen 			log_err("error in client certificate %s", pem);
1437933707f3Ssthen 			log_crypto_err("error in certificate file");
1438933707f3Ssthen 			SSL_CTX_free(ctx);
1439933707f3Ssthen 			return NULL;
1440933707f3Ssthen 		}
1441933707f3Ssthen 		if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) {
1442933707f3Ssthen 			log_err("error in client private key %s", key);
1443933707f3Ssthen 			log_crypto_err("error in key file");
1444933707f3Ssthen 			SSL_CTX_free(ctx);
1445933707f3Ssthen 			return NULL;
1446933707f3Ssthen 		}
1447933707f3Ssthen 		if(!SSL_CTX_check_private_key(ctx)) {
1448933707f3Ssthen 			log_err("error in client key %s", key);
1449933707f3Ssthen 			log_crypto_err("error in SSL_CTX_check_private_key");
1450933707f3Ssthen 			SSL_CTX_free(ctx);
1451933707f3Ssthen 			return NULL;
1452933707f3Ssthen 		}
1453933707f3Ssthen 	}
145420237c55Ssthen 	if((verifypem && verifypem[0]) || wincert) {
1455933707f3Ssthen 		if(verifypem && verifypem[0]) {
145657dceb2aSbrad 			if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) {
1457933707f3Ssthen 				log_crypto_err("error in SSL_CTX verify");
1458933707f3Ssthen 				SSL_CTX_free(ctx);
1459933707f3Ssthen 				return NULL;
1460933707f3Ssthen 			}
146120237c55Ssthen 		}
146220237c55Ssthen #ifdef USE_WINSOCK
146320237c55Ssthen 		if(wincert) {
146420237c55Ssthen 			if(!add_WIN_cacerts_to_openssl_store(ctx)) {
146520237c55Ssthen 				log_crypto_err("error in add_WIN_cacerts_to_openssl_store");
146620237c55Ssthen 				SSL_CTX_free(ctx);
146720237c55Ssthen 				return NULL;
146820237c55Ssthen 			}
146920237c55Ssthen 		}
147020237c55Ssthen #else
14710bdb4f62Ssthen 		if(wincert) {
14720bdb4f62Ssthen 			if(!SSL_CTX_set_default_verify_paths(ctx)) {
14730bdb4f62Ssthen 				log_crypto_err("error in default_verify_paths");
14740bdb4f62Ssthen 				SSL_CTX_free(ctx);
14750bdb4f62Ssthen 				return NULL;
14760bdb4f62Ssthen 			}
14770bdb4f62Ssthen 		}
147820237c55Ssthen #endif
1479933707f3Ssthen 		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
1480933707f3Ssthen 	}
1481933707f3Ssthen 	return ctx;
14823dcb24b8Ssthen #else
148320237c55Ssthen 	(void)key; (void)pem; (void)verifypem; (void)wincert;
14843dcb24b8Ssthen 	return NULL;
14853dcb24b8Ssthen #endif
1486933707f3Ssthen }
1487933707f3Ssthen 
1488933707f3Ssthen void* incoming_ssl_fd(void* sslctx, int fd)
1489933707f3Ssthen {
14903dcb24b8Ssthen #ifdef HAVE_SSL
1491933707f3Ssthen 	SSL* ssl = SSL_new((SSL_CTX*)sslctx);
1492933707f3Ssthen 	if(!ssl) {
1493933707f3Ssthen 		log_crypto_err("could not SSL_new");
1494933707f3Ssthen 		return NULL;
1495933707f3Ssthen 	}
1496933707f3Ssthen 	SSL_set_accept_state(ssl);
1497ebf5bb73Ssthen 	(void)SSL_set_mode(ssl, (long)SSL_MODE_AUTO_RETRY);
1498933707f3Ssthen 	if(!SSL_set_fd(ssl, fd)) {
1499933707f3Ssthen 		log_crypto_err("could not SSL_set_fd");
1500933707f3Ssthen 		SSL_free(ssl);
1501933707f3Ssthen 		return NULL;
1502933707f3Ssthen 	}
1503933707f3Ssthen 	return ssl;
15043dcb24b8Ssthen #else
15053dcb24b8Ssthen 	(void)sslctx; (void)fd;
15063dcb24b8Ssthen 	return NULL;
15073dcb24b8Ssthen #endif
1508933707f3Ssthen }
1509933707f3Ssthen 
1510933707f3Ssthen void* outgoing_ssl_fd(void* sslctx, int fd)
1511933707f3Ssthen {
15123dcb24b8Ssthen #ifdef HAVE_SSL
1513933707f3Ssthen 	SSL* ssl = SSL_new((SSL_CTX*)sslctx);
1514933707f3Ssthen 	if(!ssl) {
1515933707f3Ssthen 		log_crypto_err("could not SSL_new");
1516933707f3Ssthen 		return NULL;
1517933707f3Ssthen 	}
1518933707f3Ssthen 	SSL_set_connect_state(ssl);
1519ebf5bb73Ssthen 	(void)SSL_set_mode(ssl, (long)SSL_MODE_AUTO_RETRY);
1520933707f3Ssthen 	if(!SSL_set_fd(ssl, fd)) {
1521933707f3Ssthen 		log_crypto_err("could not SSL_set_fd");
1522933707f3Ssthen 		SSL_free(ssl);
1523933707f3Ssthen 		return NULL;
1524933707f3Ssthen 	}
1525933707f3Ssthen 	return ssl;
15263dcb24b8Ssthen #else
15273dcb24b8Ssthen 	(void)sslctx; (void)fd;
15283dcb24b8Ssthen 	return NULL;
15293dcb24b8Ssthen #endif
1530933707f3Ssthen }
1531229e174cSsthen 
1532a3167c07Ssthen int check_auth_name_for_ssl(char* auth_name)
1533a3167c07Ssthen {
1534a3167c07Ssthen 	if(!auth_name) return 1;
1535a3167c07Ssthen #if defined(HAVE_SSL) && !defined(HAVE_SSL_SET1_HOST) && !defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
1536a3167c07Ssthen 	log_err("the query has an auth_name %s, but libssl has no call to "
1537a3167c07Ssthen 		"perform TLS authentication.  Remove that name from config "
1538a3167c07Ssthen 		"or upgrade the ssl crypto library.", auth_name);
1539a3167c07Ssthen 	return 0;
1540a3167c07Ssthen #else
1541a3167c07Ssthen 	return 1;
1542a3167c07Ssthen #endif
1543a3167c07Ssthen }
1544a3167c07Ssthen 
1545a3167c07Ssthen /** set the authname on an SSL structure, SSL* ssl */
1546a3167c07Ssthen int set_auth_name_on_ssl(void* ssl, char* auth_name, int use_sni)
1547a3167c07Ssthen {
1548a3167c07Ssthen 	if(!auth_name) return 1;
1549a3167c07Ssthen #ifdef HAVE_SSL
1550a3167c07Ssthen 	if(use_sni) {
1551a3167c07Ssthen 		(void)SSL_set_tlsext_host_name(ssl, auth_name);
1552a3167c07Ssthen 	}
1553a3167c07Ssthen #else
1554a3167c07Ssthen 	(void)ssl;
1555a3167c07Ssthen 	(void)use_sni;
1556a3167c07Ssthen #endif
1557a3167c07Ssthen #ifdef HAVE_SSL_SET1_HOST
1558a3167c07Ssthen 	SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);
1559a3167c07Ssthen 	/* setting the hostname makes openssl verify the
1560a3167c07Ssthen 	 * host name in the x509 certificate in the
1561a3167c07Ssthen 	 * SSL connection*/
1562a3167c07Ssthen 	if(!SSL_set1_host(ssl, auth_name)) {
1563a3167c07Ssthen 		log_err("SSL_set1_host failed");
1564a3167c07Ssthen 		return 0;
1565a3167c07Ssthen 	}
1566a3167c07Ssthen #elif defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
1567a3167c07Ssthen 	/* openssl 1.0.2 has this function that can be used for
1568a3167c07Ssthen 	 * set1_host like verification */
1569a3167c07Ssthen 	if(auth_name) {
1570a3167c07Ssthen 		X509_VERIFY_PARAM* param = SSL_get0_param(ssl);
1571a3167c07Ssthen #  ifdef X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS
1572a3167c07Ssthen 		X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
1573a3167c07Ssthen #  endif
1574a3167c07Ssthen 		if(!X509_VERIFY_PARAM_set1_host(param, auth_name, strlen(auth_name))) {
1575a3167c07Ssthen 			log_err("X509_VERIFY_PARAM_set1_host failed");
1576a3167c07Ssthen 			return 0;
1577a3167c07Ssthen 		}
1578a3167c07Ssthen 		SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);
1579a3167c07Ssthen 	}
1580a3167c07Ssthen #else
1581a3167c07Ssthen 	verbose(VERB_ALGO, "the query has an auth_name, but libssl has no call to perform TLS authentication");
1582a3167c07Ssthen #endif /* HAVE_SSL_SET1_HOST */
1583a3167c07Ssthen 	return 1;
1584a3167c07Ssthen }
1585a3167c07Ssthen 
158677079be7Ssthen #if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) && defined(CRYPTO_LOCK) && OPENSSL_VERSION_NUMBER < 0x10100000L
1587229e174cSsthen /** global lock list for openssl locks */
158877079be7Ssthen static lock_basic_type *ub_openssl_locks = NULL;
1589229e174cSsthen 
1590229e174cSsthen /** callback that gets thread id for openssl */
1591c3b38330Ssthen #ifdef HAVE_CRYPTO_THREADID_SET_CALLBACK
1592c3b38330Ssthen static void
1593c3b38330Ssthen ub_crypto_id_cb(CRYPTO_THREADID *id)
1594c3b38330Ssthen {
1595c3b38330Ssthen 	CRYPTO_THREADID_set_numeric(id, (unsigned long)log_thread_get());
1596c3b38330Ssthen }
1597c3b38330Ssthen #else
1598229e174cSsthen static unsigned long
1599229e174cSsthen ub_crypto_id_cb(void)
1600229e174cSsthen {
1601a58bff56Ssthen 	return (unsigned long)log_thread_get();
1602229e174cSsthen }
1603c3b38330Ssthen #endif
1604229e174cSsthen 
1605229e174cSsthen static void
1606229e174cSsthen ub_crypto_lock_cb(int mode, int type, const char *ATTR_UNUSED(file),
1607229e174cSsthen 	int ATTR_UNUSED(line))
1608229e174cSsthen {
1609229e174cSsthen 	if((mode&CRYPTO_LOCK)) {
1610229e174cSsthen 		lock_basic_lock(&ub_openssl_locks[type]);
1611229e174cSsthen 	} else {
1612229e174cSsthen 		lock_basic_unlock(&ub_openssl_locks[type]);
1613229e174cSsthen 	}
1614229e174cSsthen }
1615229e174cSsthen #endif /* OPENSSL_THREADS */
1616229e174cSsthen 
1617229e174cSsthen int ub_openssl_lock_init(void)
1618229e174cSsthen {
161977079be7Ssthen #if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) && defined(CRYPTO_LOCK) && OPENSSL_VERSION_NUMBER < 0x10100000L
1620229e174cSsthen 	int i;
162177079be7Ssthen 	ub_openssl_locks = (lock_basic_type*)reallocarray(
162277079be7Ssthen 		NULL, (size_t)CRYPTO_num_locks(), sizeof(lock_basic_type));
1623229e174cSsthen 	if(!ub_openssl_locks)
1624229e174cSsthen 		return 0;
1625229e174cSsthen 	for(i=0; i<CRYPTO_num_locks(); i++) {
1626229e174cSsthen 		lock_basic_init(&ub_openssl_locks[i]);
1627229e174cSsthen 	}
1628c3b38330Ssthen #  ifdef HAVE_CRYPTO_THREADID_SET_CALLBACK
1629c3b38330Ssthen 	CRYPTO_THREADID_set_callback(&ub_crypto_id_cb);
1630c3b38330Ssthen #  else
1631229e174cSsthen 	CRYPTO_set_id_callback(&ub_crypto_id_cb);
1632c3b38330Ssthen #  endif
1633229e174cSsthen 	CRYPTO_set_locking_callback(&ub_crypto_lock_cb);
1634229e174cSsthen #endif /* OPENSSL_THREADS */
1635229e174cSsthen 	return 1;
1636229e174cSsthen }
1637229e174cSsthen 
1638229e174cSsthen void ub_openssl_lock_delete(void)
1639229e174cSsthen {
164077079be7Ssthen #if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) && defined(CRYPTO_LOCK) && OPENSSL_VERSION_NUMBER < 0x10100000L
1641229e174cSsthen 	int i;
1642229e174cSsthen 	if(!ub_openssl_locks)
1643229e174cSsthen 		return;
1644c3b38330Ssthen #  ifdef HAVE_CRYPTO_THREADID_SET_CALLBACK
1645c3b38330Ssthen 	CRYPTO_THREADID_set_callback(NULL);
1646c3b38330Ssthen #  else
1647229e174cSsthen 	CRYPTO_set_id_callback(NULL);
1648c3b38330Ssthen #  endif
1649229e174cSsthen 	CRYPTO_set_locking_callback(NULL);
1650229e174cSsthen 	for(i=0; i<CRYPTO_num_locks(); i++) {
1651229e174cSsthen 		lock_basic_destroy(&ub_openssl_locks[i]);
1652229e174cSsthen 	}
1653229e174cSsthen 	free(ub_openssl_locks);
1654229e174cSsthen #endif /* OPENSSL_THREADS */
1655229e174cSsthen }
1656229e174cSsthen 
1657f6b99bafSsthen int listen_sslctx_setup_ticket_keys(void* sslctx, struct config_strlist* tls_session_ticket_keys) {
1658f6b99bafSsthen #ifdef HAVE_SSL
1659f6b99bafSsthen 	size_t s = 1;
1660f6b99bafSsthen 	struct config_strlist* p;
1661f6b99bafSsthen 	struct tls_session_ticket_key *keys;
1662f6b99bafSsthen 	for(p = tls_session_ticket_keys; p; p = p->next) {
1663f6b99bafSsthen 		s++;
1664f6b99bafSsthen 	}
1665f6b99bafSsthen 	keys = calloc(s, sizeof(struct tls_session_ticket_key));
1666eaf2578eSsthen 	if(!keys)
1667eaf2578eSsthen 		return 0;
1668f6b99bafSsthen 	memset(keys, 0, s*sizeof(*keys));
1669f6b99bafSsthen 	ticket_keys = keys;
1670f6b99bafSsthen 
1671f6b99bafSsthen 	for(p = tls_session_ticket_keys; p; p = p->next) {
1672f6b99bafSsthen 		size_t n;
1673eaf2578eSsthen 		unsigned char *data;
1674eaf2578eSsthen 		FILE *f;
1675eaf2578eSsthen 
1676eaf2578eSsthen 		data = (unsigned char *)malloc(80);
1677eaf2578eSsthen 		if(!data)
1678eaf2578eSsthen 			return 0;
1679eaf2578eSsthen 
1680a3167c07Ssthen 		f = fopen(p->str, "rb");
1681f6b99bafSsthen 		if(!f) {
1682f6b99bafSsthen 			log_err("could not read tls-session-ticket-key %s: %s", p->str, strerror(errno));
1683f6b99bafSsthen 			free(data);
1684f6b99bafSsthen 			return 0;
1685f6b99bafSsthen 		}
1686f6b99bafSsthen 		n = fread(data, 1, 80, f);
1687f6b99bafSsthen 		fclose(f);
1688f6b99bafSsthen 
1689f6b99bafSsthen 		if(n != 80) {
1690f6b99bafSsthen 			log_err("tls-session-ticket-key %s is %d bytes, must be 80 bytes", p->str, (int)n);
1691f6b99bafSsthen 			free(data);
1692f6b99bafSsthen 			return 0;
1693f6b99bafSsthen 		}
1694f6b99bafSsthen 		verbose(VERB_OPS, "read tls-session-ticket-key: %s", p->str);
1695f6b99bafSsthen 
1696f6b99bafSsthen 		keys->key_name = data;
1697f6b99bafSsthen 		keys->aes_key = data + 16;
1698f6b99bafSsthen 		keys->hmac_key = data + 48;
1699f6b99bafSsthen 		keys++;
1700f6b99bafSsthen 	}
1701f6b99bafSsthen 	/* terminate array with NULL key name entry */
1702f6b99bafSsthen 	keys->key_name = NULL;
1703a3167c07Ssthen #  ifdef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
1704a3167c07Ssthen 	if(SSL_CTX_set_tlsext_ticket_key_evp_cb(sslctx, tls_session_ticket_key_cb) == 0) {
1705a3167c07Ssthen 		log_err("no support for TLS session ticket");
1706a3167c07Ssthen 		return 0;
1707a3167c07Ssthen 	}
1708a3167c07Ssthen #  else
1709f6b99bafSsthen 	if(SSL_CTX_set_tlsext_ticket_key_cb(sslctx, tls_session_ticket_key_cb) == 0) {
1710f6b99bafSsthen 		log_err("no support for TLS session ticket");
1711f6b99bafSsthen 		return 0;
1712f6b99bafSsthen 	}
1713a3167c07Ssthen #  endif
1714f6b99bafSsthen 	return 1;
1715f6b99bafSsthen #else
1716f6b99bafSsthen 	(void)sslctx;
1717f6b99bafSsthen 	(void)tls_session_ticket_keys;
1718f6b99bafSsthen 	return 0;
1719f6b99bafSsthen #endif
1720f6b99bafSsthen 
1721f6b99bafSsthen }
1722f6b99bafSsthen 
1723a3167c07Ssthen #ifdef HAVE_SSL
1724a3167c07Ssthen int tls_session_ticket_key_cb(SSL *ATTR_UNUSED(sslctx), unsigned char* key_name,
1725a3167c07Ssthen 	unsigned char* iv, EVP_CIPHER_CTX *evp_sctx,
1726a3167c07Ssthen #ifdef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
1727a3167c07Ssthen 	EVP_MAC_CTX *hmac_ctx,
1728a3167c07Ssthen #else
1729a3167c07Ssthen 	HMAC_CTX* hmac_ctx,
1730a3167c07Ssthen #endif
1731a3167c07Ssthen 	int enc)
1732f6b99bafSsthen {
1733f6b99bafSsthen #ifdef HAVE_SSL
1734a3167c07Ssthen #  ifdef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
1735a3167c07Ssthen 	OSSL_PARAM params[3];
1736a3167c07Ssthen #  else
1737f6b99bafSsthen 	const EVP_MD *digest;
1738a3167c07Ssthen #  endif
1739f6b99bafSsthen 	const EVP_CIPHER *cipher;
1740f6b99bafSsthen 	int evp_cipher_length;
1741a3167c07Ssthen #  ifndef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
1742f6b99bafSsthen 	digest = EVP_sha256();
1743a3167c07Ssthen #  endif
1744f6b99bafSsthen 	cipher = EVP_aes_256_cbc();
1745f6b99bafSsthen 	evp_cipher_length = EVP_CIPHER_iv_length(cipher);
1746f6b99bafSsthen 	if( enc == 1 ) {
1747f6b99bafSsthen 		/* encrypt */
1748f6b99bafSsthen 		verbose(VERB_CLIENT, "start session encrypt");
1749f6b99bafSsthen 		memcpy(key_name, ticket_keys->key_name, 16);
1750f6b99bafSsthen 		if (RAND_bytes(iv, evp_cipher_length) != 1) {
1751f6b99bafSsthen 			verbose(VERB_CLIENT, "RAND_bytes failed");
1752f6b99bafSsthen 			return -1;
1753f6b99bafSsthen 		}
1754f6b99bafSsthen 		if (EVP_EncryptInit_ex(evp_sctx, cipher, NULL, ticket_keys->aes_key, iv) != 1) {
1755f6b99bafSsthen 			verbose(VERB_CLIENT, "EVP_EncryptInit_ex failed");
1756f6b99bafSsthen 			return -1;
1757f6b99bafSsthen 		}
1758a3167c07Ssthen #ifdef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
1759a3167c07Ssthen 		params[0] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
1760a3167c07Ssthen 			ticket_keys->hmac_key, 32);
1761a3167c07Ssthen 		params[1] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
1762a3167c07Ssthen 			"sha256", 0);
1763a3167c07Ssthen 		params[2] = OSSL_PARAM_construct_end();
17642c144df0Ssthen #ifdef HAVE_EVP_MAC_CTX_SET_PARAMS
17652c144df0Ssthen 		EVP_MAC_CTX_set_params(hmac_ctx, params);
17662c144df0Ssthen #else
1767a3167c07Ssthen 		EVP_MAC_set_ctx_params(hmac_ctx, params);
17682c144df0Ssthen #endif
1769a3167c07Ssthen #elif !defined(HMAC_INIT_EX_RETURNS_VOID)
1770f6b99bafSsthen 		if (HMAC_Init_ex(hmac_ctx, ticket_keys->hmac_key, 32, digest, NULL) != 1) {
1771f6b99bafSsthen 			verbose(VERB_CLIENT, "HMAC_Init_ex failed");
1772f6b99bafSsthen 			return -1;
1773f6b99bafSsthen 		}
1774ebf5bb73Ssthen #else
1775ebf5bb73Ssthen 		HMAC_Init_ex(hmac_ctx, ticket_keys->hmac_key, 32, digest, NULL);
1776ebf5bb73Ssthen #endif
1777f6b99bafSsthen 		return 1;
1778f6b99bafSsthen 	} else if (enc == 0) {
1779f6b99bafSsthen 		/* decrypt */
1780f6b99bafSsthen 		struct tls_session_ticket_key *key;
1781f6b99bafSsthen 		verbose(VERB_CLIENT, "start session decrypt");
1782f6b99bafSsthen 		for(key = ticket_keys; key->key_name != NULL; key++) {
1783f6b99bafSsthen 			if (!memcmp(key_name, key->key_name, 16)) {
1784f6b99bafSsthen 				verbose(VERB_CLIENT, "Found session_key");
1785f6b99bafSsthen 				break;
1786f6b99bafSsthen 			}
1787f6b99bafSsthen 		}
1788f6b99bafSsthen 		if(key->key_name == NULL) {
1789f6b99bafSsthen 			verbose(VERB_CLIENT, "Not found session_key");
1790f6b99bafSsthen 			return 0;
1791f6b99bafSsthen 		}
1792f6b99bafSsthen 
1793a3167c07Ssthen #ifdef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
1794a3167c07Ssthen 		params[0] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
1795a3167c07Ssthen 			key->hmac_key, 32);
1796a3167c07Ssthen 		params[1] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
1797a3167c07Ssthen 			"sha256", 0);
1798a3167c07Ssthen 		params[2] = OSSL_PARAM_construct_end();
17992c144df0Ssthen #ifdef HAVE_EVP_MAC_CTX_SET_PARAMS
18002c144df0Ssthen 		EVP_MAC_CTX_set_params(hmac_ctx, params);
18012c144df0Ssthen #else
1802a3167c07Ssthen 		EVP_MAC_set_ctx_params(hmac_ctx, params);
18032c144df0Ssthen #endif
1804a3167c07Ssthen #elif !defined(HMAC_INIT_EX_RETURNS_VOID)
1805f6b99bafSsthen 		if (HMAC_Init_ex(hmac_ctx, key->hmac_key, 32, digest, NULL) != 1) {
1806f6b99bafSsthen 			verbose(VERB_CLIENT, "HMAC_Init_ex failed");
1807f6b99bafSsthen 			return -1;
1808f6b99bafSsthen 		}
1809ebf5bb73Ssthen #else
1810ebf5bb73Ssthen 		HMAC_Init_ex(hmac_ctx, key->hmac_key, 32, digest, NULL);
1811ebf5bb73Ssthen #endif
1812f6b99bafSsthen 		if (EVP_DecryptInit_ex(evp_sctx, cipher, NULL, key->aes_key, iv) != 1) {
1813f6b99bafSsthen 			log_err("EVP_DecryptInit_ex failed");
1814f6b99bafSsthen 			return -1;
1815f6b99bafSsthen 		}
1816f6b99bafSsthen 
1817f6b99bafSsthen 		return (key == ticket_keys) ? 1 : 2;
1818f6b99bafSsthen 	}
1819f6b99bafSsthen 	return -1;
1820f6b99bafSsthen #else
1821f6b99bafSsthen 	(void)key_name;
1822f6b99bafSsthen 	(void)iv;
1823f6b99bafSsthen 	(void)evp_sctx;
1824f6b99bafSsthen 	(void)hmac_ctx;
1825f6b99bafSsthen 	(void)enc;
1826f6b99bafSsthen 	return 0;
1827f6b99bafSsthen #endif
1828f6b99bafSsthen }
1829a3167c07Ssthen #endif /* HAVE_SSL */
1830f6b99bafSsthen 
1831f6b99bafSsthen void
1832f6b99bafSsthen listen_sslctx_delete_ticket_keys(void)
1833f6b99bafSsthen {
1834f6b99bafSsthen 	struct tls_session_ticket_key *key;
1835f6b99bafSsthen 	if(!ticket_keys) return;
1836f6b99bafSsthen 	for(key = ticket_keys; key->key_name != NULL; key++) {
1837550cf4a9Ssthen 		/* wipe key data from memory*/
1838550cf4a9Ssthen #ifdef HAVE_EXPLICIT_BZERO
1839550cf4a9Ssthen 		explicit_bzero(key->key_name, 80);
1840550cf4a9Ssthen #else
1841550cf4a9Ssthen 		memset(key->key_name, 0xdd, 80);
1842550cf4a9Ssthen #endif
1843f6b99bafSsthen 		free(key->key_name);
1844f6b99bafSsthen 	}
1845f6b99bafSsthen 	free(ticket_keys);
1846f6b99bafSsthen 	ticket_keys = NULL;
1847f6b99bafSsthen }
18482c144df0Ssthen 
18492c144df0Ssthen #  ifndef USE_WINSOCK
18502c144df0Ssthen char*
18512c144df0Ssthen sock_strerror(int errn)
18522c144df0Ssthen {
18532c144df0Ssthen 	return strerror(errn);
18542c144df0Ssthen }
18552c144df0Ssthen 
18562c144df0Ssthen void
18572c144df0Ssthen sock_close(int socket)
18582c144df0Ssthen {
18592c144df0Ssthen 	close(socket);
18602c144df0Ssthen }
18612c144df0Ssthen 
18622c144df0Ssthen #  else
18632c144df0Ssthen char*
18642c144df0Ssthen sock_strerror(int ATTR_UNUSED(errn))
18652c144df0Ssthen {
18662c144df0Ssthen 	return wsa_strerror(WSAGetLastError());
18672c144df0Ssthen }
18682c144df0Ssthen 
18692c144df0Ssthen void
18702c144df0Ssthen sock_close(int socket)
18712c144df0Ssthen {
18722c144df0Ssthen 	closesocket(socket);
18732c144df0Ssthen }
18742c144df0Ssthen #  endif /* USE_WINSOCK */
1875*98bc733bSsthen 
1876*98bc733bSsthen ssize_t
1877*98bc733bSsthen hex_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize)
1878*98bc733bSsthen {
1879*98bc733bSsthen 	static char hexdigits[] = {
1880*98bc733bSsthen 		'0', '1', '2', '3', '4', '5', '6', '7',
1881*98bc733bSsthen 		'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
1882*98bc733bSsthen 	};
1883*98bc733bSsthen 	size_t i;
1884*98bc733bSsthen 
1885*98bc733bSsthen 	if (targsize < srclength * 2 + 1) {
1886*98bc733bSsthen 		return -1;
1887*98bc733bSsthen 	}
1888*98bc733bSsthen 
1889*98bc733bSsthen 	for (i = 0; i < srclength; ++i) {
1890*98bc733bSsthen 		*target++ = hexdigits[src[i] >> 4U];
1891*98bc733bSsthen 		*target++ = hexdigits[src[i] & 0xfU];
1892*98bc733bSsthen 	}
1893*98bc733bSsthen 	*target = '\0';
1894*98bc733bSsthen 	return 2 * srclength;
1895*98bc733bSsthen }
1896*98bc733bSsthen 
1897*98bc733bSsthen ssize_t
1898*98bc733bSsthen hex_pton(const char* src, uint8_t* target, size_t targsize)
1899*98bc733bSsthen {
1900*98bc733bSsthen 	uint8_t *t = target;
1901*98bc733bSsthen 	if(strlen(src) % 2 != 0 || strlen(src)/2 > targsize) {
1902*98bc733bSsthen 		return -1;
1903*98bc733bSsthen 	}
1904*98bc733bSsthen 	while(*src) {
1905*98bc733bSsthen 		if(!isxdigit((unsigned char)src[0]) ||
1906*98bc733bSsthen 			!isxdigit((unsigned char)src[1]))
1907*98bc733bSsthen 			return -1;
1908*98bc733bSsthen 		*t++ = sldns_hexdigit_to_int(src[0]) * 16 +
1909*98bc733bSsthen 			sldns_hexdigit_to_int(src[1]) ;
1910*98bc733bSsthen 		src += 2;
1911*98bc733bSsthen 	}
1912*98bc733bSsthen 	return t-target;
1913*98bc733bSsthen }
1914