1238106Sdes/*
2238106Sdes * util/net_help.c - implementation of the network helper code
3238106Sdes *
4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved.
5238106Sdes *
6238106Sdes * This software is open source.
7238106Sdes *
8238106Sdes * Redistribution and use in source and binary forms, with or without
9238106Sdes * modification, are permitted provided that the following conditions
10238106Sdes * are met:
11238106Sdes *
12238106Sdes * Redistributions of source code must retain the above copyright notice,
13238106Sdes * this list of conditions and the following disclaimer.
14238106Sdes *
15238106Sdes * Redistributions in binary form must reproduce the above copyright notice,
16238106Sdes * this list of conditions and the following disclaimer in the documentation
17238106Sdes * and/or other materials provided with the distribution.
18238106Sdes *
19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may
20238106Sdes * be used to endorse or promote products derived from this software without
21238106Sdes * specific prior written permission.
22238106Sdes *
23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34238106Sdes */
35238106Sdes/**
36238106Sdes * \file
37238106Sdes * Implementation of net_help.h.
38238106Sdes */
39238106Sdes
40238106Sdes#include "config.h"
41238106Sdes#include "util/net_help.h"
42238106Sdes#include "util/log.h"
43238106Sdes#include "util/data/dname.h"
44238106Sdes#include "util/module.h"
45238106Sdes#include "util/regional.h"
46269257Sdes#include "ldns/parseutil.h"
47269257Sdes#include "ldns/wire2str.h"
48238106Sdes#include <fcntl.h>
49249141Sdes#ifdef HAVE_OPENSSL_SSL_H
50238106Sdes#include <openssl/ssl.h>
51249141Sdes#endif
52249141Sdes#ifdef HAVE_OPENSSL_ERR_H
53238106Sdes#include <openssl/err.h>
54249141Sdes#endif
55238106Sdes
56238106Sdes/** max length of an IP address (the address portion) that we allow */
57238106Sdes#define MAX_ADDR_STRLEN 128 /* characters */
58238106Sdes/** default value for EDNS ADVERTISED size */
59238106Sdesuint16_t EDNS_ADVERTISED_SIZE = 4096;
60238106Sdes
61238106Sdes/** minimal responses when positive answer: default is no */
62238106Sdesint MINIMAL_RESPONSES = 0;
63238106Sdes
64238106Sdes/** rrset order roundrobin: default is no */
65238106Sdesint RRSET_ROUNDROBIN = 0;
66238106Sdes
67238106Sdes/* returns true is string addr is an ip6 specced address */
68238106Sdesint
69238106Sdesstr_is_ip6(const char* str)
70238106Sdes{
71238106Sdes	if(strchr(str, ':'))
72238106Sdes		return 1;
73238106Sdes	else    return 0;
74238106Sdes}
75238106Sdes
76238106Sdesint
77238106Sdesfd_set_nonblock(int s)
78238106Sdes{
79238106Sdes#ifdef HAVE_FCNTL
80238106Sdes	int flag;
81238106Sdes	if((flag = fcntl(s, F_GETFL)) == -1) {
82238106Sdes		log_err("can't fcntl F_GETFL: %s", strerror(errno));
83238106Sdes		flag = 0;
84238106Sdes	}
85238106Sdes	flag |= O_NONBLOCK;
86238106Sdes	if(fcntl(s, F_SETFL, flag) == -1) {
87238106Sdes		log_err("can't fcntl F_SETFL: %s", strerror(errno));
88238106Sdes		return 0;
89238106Sdes	}
90238106Sdes#elif defined(HAVE_IOCTLSOCKET)
91238106Sdes	unsigned long on = 1;
92238106Sdes	if(ioctlsocket(s, FIONBIO, &on) != 0) {
93238106Sdes		log_err("can't ioctlsocket FIONBIO on: %s",
94238106Sdes			wsa_strerror(WSAGetLastError()));
95238106Sdes	}
96238106Sdes#endif
97238106Sdes	return 1;
98238106Sdes}
99238106Sdes
100238106Sdesint
101238106Sdesfd_set_block(int s)
102238106Sdes{
103238106Sdes#ifdef HAVE_FCNTL
104238106Sdes	int flag;
105238106Sdes	if((flag = fcntl(s, F_GETFL)) == -1) {
106238106Sdes		log_err("cannot fcntl F_GETFL: %s", strerror(errno));
107238106Sdes		flag = 0;
108238106Sdes	}
109238106Sdes	flag &= ~O_NONBLOCK;
110238106Sdes	if(fcntl(s, F_SETFL, flag) == -1) {
111238106Sdes		log_err("cannot fcntl F_SETFL: %s", strerror(errno));
112238106Sdes		return 0;
113238106Sdes	}
114238106Sdes#elif defined(HAVE_IOCTLSOCKET)
115238106Sdes	unsigned long off = 0;
116238106Sdes	if(ioctlsocket(s, FIONBIO, &off) != 0) {
117238106Sdes		log_err("can't ioctlsocket FIONBIO off: %s",
118238106Sdes			wsa_strerror(WSAGetLastError()));
119238106Sdes	}
120238106Sdes#endif
121238106Sdes	return 1;
122238106Sdes}
123238106Sdes
124238106Sdesint
125238106Sdesis_pow2(size_t num)
126238106Sdes{
127238106Sdes	if(num == 0) return 1;
128238106Sdes	return (num & (num-1)) == 0;
129238106Sdes}
130238106Sdes
131238106Sdesvoid*
132238106Sdesmemdup(void* data, size_t len)
133238106Sdes{
134238106Sdes	void* d;
135238106Sdes	if(!data) return NULL;
136238106Sdes	if(len == 0) return NULL;
137238106Sdes	d = malloc(len);
138238106Sdes	if(!d) return NULL;
139238106Sdes	memcpy(d, data, len);
140238106Sdes	return d;
141238106Sdes}
142238106Sdes
143238106Sdesvoid
144238106Sdeslog_addr(enum verbosity_value v, const char* str,
145238106Sdes	struct sockaddr_storage* addr, socklen_t addrlen)
146238106Sdes{
147238106Sdes	uint16_t port;
148238106Sdes	const char* family = "unknown";
149238106Sdes	char dest[100];
150238106Sdes	int af = (int)((struct sockaddr_in*)addr)->sin_family;
151238106Sdes	void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
152238106Sdes	if(verbosity < v)
153238106Sdes		return;
154238106Sdes	switch(af) {
155238106Sdes		case AF_INET: family="ip4"; break;
156238106Sdes		case AF_INET6: family="ip6";
157238106Sdes			sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
158238106Sdes			break;
159238106Sdes		case AF_UNIX: family="unix"; break;
160238106Sdes		default: break;
161238106Sdes	}
162238106Sdes	if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
163269257Sdes		(void)strlcpy(dest, "(inet_ntop error)", sizeof(dest));
164238106Sdes	}
165238106Sdes	dest[sizeof(dest)-1] = 0;
166238106Sdes	port = ntohs(((struct sockaddr_in*)addr)->sin_port);
167238106Sdes	if(verbosity >= 4)
168238106Sdes		verbose(v, "%s %s %s port %d (len %d)", str, family, dest,
169238106Sdes			(int)port, (int)addrlen);
170238106Sdes	else	verbose(v, "%s %s port %d", str, dest, (int)port);
171238106Sdes}
172238106Sdes
173238106Sdesint
174238106Sdesextstrtoaddr(const char* str, struct sockaddr_storage* addr,
175238106Sdes	socklen_t* addrlen)
176238106Sdes{
177238106Sdes	char* s;
178238106Sdes	int port = UNBOUND_DNS_PORT;
179238106Sdes	if((s=strchr(str, '@'))) {
180238106Sdes		char buf[MAX_ADDR_STRLEN];
181238106Sdes		if(s-str >= MAX_ADDR_STRLEN) {
182238106Sdes			return 0;
183238106Sdes		}
184269257Sdes		(void)strlcpy(buf, str, sizeof(buf));
185238106Sdes		buf[s-str] = 0;
186238106Sdes		port = atoi(s+1);
187238106Sdes		if(port == 0 && strcmp(s+1,"0")!=0) {
188238106Sdes			return 0;
189238106Sdes		}
190238106Sdes		return ipstrtoaddr(buf, port, addr, addrlen);
191238106Sdes	}
192238106Sdes	return ipstrtoaddr(str, port, addr, addrlen);
193238106Sdes}
194238106Sdes
195238106Sdes
196238106Sdesint
197238106Sdesipstrtoaddr(const char* ip, int port, struct sockaddr_storage* addr,
198238106Sdes	socklen_t* addrlen)
199238106Sdes{
200238106Sdes	uint16_t p;
201238106Sdes	if(!ip) return 0;
202238106Sdes	p = (uint16_t) port;
203238106Sdes	if(str_is_ip6(ip)) {
204238106Sdes		char buf[MAX_ADDR_STRLEN];
205238106Sdes		char* s;
206238106Sdes		struct sockaddr_in6* sa = (struct sockaddr_in6*)addr;
207238106Sdes		*addrlen = (socklen_t)sizeof(struct sockaddr_in6);
208238106Sdes		memset(sa, 0, *addrlen);
209238106Sdes		sa->sin6_family = AF_INET6;
210238106Sdes		sa->sin6_port = (in_port_t)htons(p);
211238106Sdes		if((s=strchr(ip, '%'))) { /* ip6%interface, rfc 4007 */
212238106Sdes			if(s-ip >= MAX_ADDR_STRLEN)
213238106Sdes				return 0;
214269257Sdes			(void)strlcpy(buf, ip, sizeof(buf));
215238106Sdes			buf[s-ip]=0;
216238106Sdes			sa->sin6_scope_id = (uint32_t)atoi(s+1);
217238106Sdes			ip = buf;
218238106Sdes		}
219238106Sdes		if(inet_pton((int)sa->sin6_family, ip, &sa->sin6_addr) <= 0) {
220238106Sdes			return 0;
221238106Sdes		}
222238106Sdes	} else { /* ip4 */
223238106Sdes		struct sockaddr_in* sa = (struct sockaddr_in*)addr;
224238106Sdes		*addrlen = (socklen_t)sizeof(struct sockaddr_in);
225238106Sdes		memset(sa, 0, *addrlen);
226238106Sdes		sa->sin_family = AF_INET;
227238106Sdes		sa->sin_port = (in_port_t)htons(p);
228238106Sdes		if(inet_pton((int)sa->sin_family, ip, &sa->sin_addr) <= 0) {
229238106Sdes			return 0;
230238106Sdes		}
231238106Sdes	}
232238106Sdes	return 1;
233238106Sdes}
234238106Sdes
235238106Sdesint netblockstrtoaddr(const char* str, int port, struct sockaddr_storage* addr,
236238106Sdes        socklen_t* addrlen, int* net)
237238106Sdes{
238238106Sdes	char* s = NULL;
239238106Sdes	*net = (str_is_ip6(str)?128:32);
240238106Sdes	if((s=strchr(str, '/'))) {
241238106Sdes		if(atoi(s+1) > *net) {
242238106Sdes			log_err("netblock too large: %s", str);
243238106Sdes			return 0;
244238106Sdes		}
245238106Sdes		*net = atoi(s+1);
246238106Sdes		if(*net == 0 && strcmp(s+1, "0") != 0) {
247238106Sdes			log_err("cannot parse netblock: '%s'", str);
248238106Sdes			return 0;
249238106Sdes		}
250238106Sdes		if(!(s = strdup(str))) {
251238106Sdes			log_err("out of memory");
252238106Sdes			return 0;
253238106Sdes		}
254238106Sdes		*strchr(s, '/') = '\0';
255238106Sdes	}
256238106Sdes	if(!ipstrtoaddr(s?s:str, port, addr, addrlen)) {
257238106Sdes		free(s);
258238106Sdes		log_err("cannot parse ip address: '%s'", str);
259238106Sdes		return 0;
260238106Sdes	}
261238106Sdes	if(s) {
262238106Sdes		free(s);
263238106Sdes		addr_mask(addr, *addrlen, *net);
264238106Sdes	}
265238106Sdes	return 1;
266238106Sdes}
267238106Sdes
268238106Sdesvoid
269238106Sdeslog_nametypeclass(enum verbosity_value v, const char* str, uint8_t* name,
270238106Sdes	uint16_t type, uint16_t dclass)
271238106Sdes{
272238106Sdes	char buf[LDNS_MAX_DOMAINLEN+1];
273238106Sdes	char t[12], c[12];
274238106Sdes	const char *ts, *cs;
275238106Sdes	if(verbosity < v)
276238106Sdes		return;
277238106Sdes	dname_str(name, buf);
278238106Sdes	if(type == LDNS_RR_TYPE_TSIG) ts = "TSIG";
279238106Sdes	else if(type == LDNS_RR_TYPE_IXFR) ts = "IXFR";
280238106Sdes	else if(type == LDNS_RR_TYPE_AXFR) ts = "AXFR";
281238106Sdes	else if(type == LDNS_RR_TYPE_MAILB) ts = "MAILB";
282238106Sdes	else if(type == LDNS_RR_TYPE_MAILA) ts = "MAILA";
283238106Sdes	else if(type == LDNS_RR_TYPE_ANY) ts = "ANY";
284269257Sdes	else if(sldns_rr_descript(type) && sldns_rr_descript(type)->_name)
285269257Sdes		ts = sldns_rr_descript(type)->_name;
286238106Sdes	else {
287238106Sdes		snprintf(t, sizeof(t), "TYPE%d", (int)type);
288238106Sdes		ts = t;
289238106Sdes	}
290269257Sdes	if(sldns_lookup_by_id(sldns_rr_classes, (int)dclass) &&
291269257Sdes		sldns_lookup_by_id(sldns_rr_classes, (int)dclass)->name)
292269257Sdes		cs = sldns_lookup_by_id(sldns_rr_classes, (int)dclass)->name;
293238106Sdes	else {
294238106Sdes		snprintf(c, sizeof(c), "CLASS%d", (int)dclass);
295238106Sdes		cs = c;
296238106Sdes	}
297238106Sdes	log_info("%s %s %s %s", str, buf, ts, cs);
298238106Sdes}
299238106Sdes
300238106Sdesvoid log_name_addr(enum verbosity_value v, const char* str, uint8_t* zone,
301238106Sdes	struct sockaddr_storage* addr, socklen_t addrlen)
302238106Sdes{
303238106Sdes	uint16_t port;
304238106Sdes	const char* family = "unknown_family ";
305238106Sdes	char namebuf[LDNS_MAX_DOMAINLEN+1];
306238106Sdes	char dest[100];
307238106Sdes	int af = (int)((struct sockaddr_in*)addr)->sin_family;
308238106Sdes	void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
309238106Sdes	if(verbosity < v)
310238106Sdes		return;
311238106Sdes	switch(af) {
312238106Sdes		case AF_INET: family=""; break;
313238106Sdes		case AF_INET6: family="";
314238106Sdes			sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
315238106Sdes			break;
316238106Sdes		case AF_UNIX: family="unix_family "; break;
317238106Sdes		default: break;
318238106Sdes	}
319238106Sdes	if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
320269257Sdes		(void)strlcpy(dest, "(inet_ntop error)", sizeof(dest));
321238106Sdes	}
322238106Sdes	dest[sizeof(dest)-1] = 0;
323238106Sdes	port = ntohs(((struct sockaddr_in*)addr)->sin_port);
324238106Sdes	dname_str(zone, namebuf);
325238106Sdes	if(af != AF_INET && af != AF_INET6)
326238106Sdes		verbose(v, "%s <%s> %s%s#%d (addrlen %d)",
327238106Sdes			str, namebuf, family, dest, (int)port, (int)addrlen);
328238106Sdes	else	verbose(v, "%s <%s> %s%s#%d",
329238106Sdes			str, namebuf, family, dest, (int)port);
330238106Sdes}
331238106Sdes
332238106Sdesint
333238106Sdessockaddr_cmp(struct sockaddr_storage* addr1, socklen_t len1,
334238106Sdes	struct sockaddr_storage* addr2, socklen_t len2)
335238106Sdes{
336238106Sdes	struct sockaddr_in* p1_in = (struct sockaddr_in*)addr1;
337238106Sdes	struct sockaddr_in* p2_in = (struct sockaddr_in*)addr2;
338238106Sdes	struct sockaddr_in6* p1_in6 = (struct sockaddr_in6*)addr1;
339238106Sdes	struct sockaddr_in6* p2_in6 = (struct sockaddr_in6*)addr2;
340238106Sdes	if(len1 < len2)
341238106Sdes		return -1;
342238106Sdes	if(len1 > len2)
343238106Sdes		return 1;
344238106Sdes	log_assert(len1 == len2);
345238106Sdes	if( p1_in->sin_family < p2_in->sin_family)
346238106Sdes		return -1;
347238106Sdes	if( p1_in->sin_family > p2_in->sin_family)
348238106Sdes		return 1;
349238106Sdes	log_assert( p1_in->sin_family == p2_in->sin_family );
350238106Sdes	/* compare ip4 */
351238106Sdes	if( p1_in->sin_family == AF_INET ) {
352238106Sdes		/* just order it, ntohs not required */
353238106Sdes		if(p1_in->sin_port < p2_in->sin_port)
354238106Sdes			return -1;
355238106Sdes		if(p1_in->sin_port > p2_in->sin_port)
356238106Sdes			return 1;
357238106Sdes		log_assert(p1_in->sin_port == p2_in->sin_port);
358238106Sdes		return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE);
359238106Sdes	} else if (p1_in6->sin6_family == AF_INET6) {
360238106Sdes		/* just order it, ntohs not required */
361238106Sdes		if(p1_in6->sin6_port < p2_in6->sin6_port)
362238106Sdes			return -1;
363238106Sdes		if(p1_in6->sin6_port > p2_in6->sin6_port)
364238106Sdes			return 1;
365238106Sdes		log_assert(p1_in6->sin6_port == p2_in6->sin6_port);
366238106Sdes		return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr,
367238106Sdes			INET6_SIZE);
368238106Sdes	} else {
369238106Sdes		/* eek unknown type, perform this comparison for sanity. */
370238106Sdes		return memcmp(addr1, addr2, len1);
371238106Sdes	}
372238106Sdes}
373238106Sdes
374238106Sdesint
375238106Sdessockaddr_cmp_addr(struct sockaddr_storage* addr1, socklen_t len1,
376238106Sdes	struct sockaddr_storage* addr2, socklen_t len2)
377238106Sdes{
378238106Sdes	struct sockaddr_in* p1_in = (struct sockaddr_in*)addr1;
379238106Sdes	struct sockaddr_in* p2_in = (struct sockaddr_in*)addr2;
380238106Sdes	struct sockaddr_in6* p1_in6 = (struct sockaddr_in6*)addr1;
381238106Sdes	struct sockaddr_in6* p2_in6 = (struct sockaddr_in6*)addr2;
382238106Sdes	if(len1 < len2)
383238106Sdes		return -1;
384238106Sdes	if(len1 > len2)
385238106Sdes		return 1;
386238106Sdes	log_assert(len1 == len2);
387238106Sdes	if( p1_in->sin_family < p2_in->sin_family)
388238106Sdes		return -1;
389238106Sdes	if( p1_in->sin_family > p2_in->sin_family)
390238106Sdes		return 1;
391238106Sdes	log_assert( p1_in->sin_family == p2_in->sin_family );
392238106Sdes	/* compare ip4 */
393238106Sdes	if( p1_in->sin_family == AF_INET ) {
394238106Sdes		return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE);
395238106Sdes	} else if (p1_in6->sin6_family == AF_INET6) {
396238106Sdes		return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr,
397238106Sdes			INET6_SIZE);
398238106Sdes	} else {
399238106Sdes		/* eek unknown type, perform this comparison for sanity. */
400238106Sdes		return memcmp(addr1, addr2, len1);
401238106Sdes	}
402238106Sdes}
403238106Sdes
404238106Sdesint
405238106Sdesaddr_is_ip6(struct sockaddr_storage* addr, socklen_t len)
406238106Sdes{
407238106Sdes	if(len == (socklen_t)sizeof(struct sockaddr_in6) &&
408238106Sdes		((struct sockaddr_in6*)addr)->sin6_family == AF_INET6)
409238106Sdes		return 1;
410238106Sdes	else    return 0;
411238106Sdes}
412238106Sdes
413238106Sdesvoid
414238106Sdesaddr_mask(struct sockaddr_storage* addr, socklen_t len, int net)
415238106Sdes{
416238106Sdes	uint8_t mask[8] = {0x0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe};
417238106Sdes	int i, max;
418238106Sdes	uint8_t* s;
419238106Sdes	if(addr_is_ip6(addr, len)) {
420238106Sdes		s = (uint8_t*)&((struct sockaddr_in6*)addr)->sin6_addr;
421238106Sdes		max = 128;
422238106Sdes	} else {
423238106Sdes		s = (uint8_t*)&((struct sockaddr_in*)addr)->sin_addr;
424238106Sdes		max = 32;
425238106Sdes	}
426238106Sdes	if(net >= max)
427238106Sdes		return;
428238106Sdes	for(i=net/8+1; i<max/8; i++) {
429238106Sdes		s[i] = 0;
430238106Sdes	}
431238106Sdes	s[net/8] &= mask[net&0x7];
432238106Sdes}
433238106Sdes
434238106Sdesint
435238106Sdesaddr_in_common(struct sockaddr_storage* addr1, int net1,
436238106Sdes	struct sockaddr_storage* addr2, int net2, socklen_t addrlen)
437238106Sdes{
438238106Sdes	int min = (net1<net2)?net1:net2;
439238106Sdes	int i, to;
440238106Sdes	int match = 0;
441238106Sdes	uint8_t* s1, *s2;
442238106Sdes	if(addr_is_ip6(addr1, addrlen)) {
443238106Sdes		s1 = (uint8_t*)&((struct sockaddr_in6*)addr1)->sin6_addr;
444238106Sdes		s2 = (uint8_t*)&((struct sockaddr_in6*)addr2)->sin6_addr;
445238106Sdes		to = 16;
446238106Sdes	} else {
447238106Sdes		s1 = (uint8_t*)&((struct sockaddr_in*)addr1)->sin_addr;
448238106Sdes		s2 = (uint8_t*)&((struct sockaddr_in*)addr2)->sin_addr;
449238106Sdes		to = 4;
450238106Sdes	}
451238106Sdes	/* match = bits_in_common(s1, s2, to); */
452238106Sdes	for(i=0; i<to; i++) {
453238106Sdes		if(s1[i] == s2[i]) {
454238106Sdes			match += 8;
455238106Sdes		} else {
456238106Sdes			uint8_t z = s1[i]^s2[i];
457238106Sdes			log_assert(z);
458238106Sdes			while(!(z&0x80)) {
459238106Sdes				match++;
460238106Sdes				z<<=1;
461238106Sdes			}
462238106Sdes			break;
463238106Sdes		}
464238106Sdes	}
465238106Sdes	if(match > min) match = min;
466238106Sdes	return match;
467238106Sdes}
468238106Sdes
469238106Sdesvoid
470238106Sdesaddr_to_str(struct sockaddr_storage* addr, socklen_t addrlen,
471238106Sdes	char* buf, size_t len)
472238106Sdes{
473238106Sdes	int af = (int)((struct sockaddr_in*)addr)->sin_family;
474238106Sdes	void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
475238106Sdes	if(addr_is_ip6(addr, addrlen))
476238106Sdes		sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
477238106Sdes	if(inet_ntop(af, sinaddr, buf, (socklen_t)len) == 0) {
478238106Sdes		snprintf(buf, len, "(inet_ntop_error)");
479238106Sdes	}
480238106Sdes}
481238106Sdes
482238106Sdesint
483238106Sdesaddr_is_ip4mapped(struct sockaddr_storage* addr, socklen_t addrlen)
484238106Sdes{
485238106Sdes	/* prefix for ipv4 into ipv6 mapping is ::ffff:x.x.x.x */
486238106Sdes	const uint8_t map_prefix[16] =
487238106Sdes		{0,0,0,0,  0,0,0,0, 0,0,0xff,0xff, 0,0,0,0};
488238106Sdes	uint8_t* s;
489238106Sdes	if(!addr_is_ip6(addr, addrlen))
490238106Sdes		return 0;
491238106Sdes	/* s is 16 octet ipv6 address string */
492238106Sdes	s = (uint8_t*)&((struct sockaddr_in6*)addr)->sin6_addr;
493238106Sdes	return (memcmp(s, map_prefix, 12) == 0);
494238106Sdes}
495238106Sdes
496238106Sdesint addr_is_broadcast(struct sockaddr_storage* addr, socklen_t addrlen)
497238106Sdes{
498238106Sdes	int af = (int)((struct sockaddr_in*)addr)->sin_family;
499238106Sdes	void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
500238106Sdes	return af == AF_INET && addrlen>=(socklen_t)sizeof(struct sockaddr_in)
501238106Sdes		&& memcmp(sinaddr, "\377\377\377\377", 4) == 0;
502238106Sdes}
503238106Sdes
504238106Sdesint addr_is_any(struct sockaddr_storage* addr, socklen_t addrlen)
505238106Sdes{
506238106Sdes	int af = (int)((struct sockaddr_in*)addr)->sin_family;
507238106Sdes	void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
508238106Sdes	void* sin6addr = &((struct sockaddr_in6*)addr)->sin6_addr;
509238106Sdes	if(af == AF_INET && addrlen>=(socklen_t)sizeof(struct sockaddr_in)
510238106Sdes		&& memcmp(sinaddr, "\000\000\000\000", 4) == 0)
511238106Sdes		return 1;
512238106Sdes	else if(af==AF_INET6 && addrlen>=(socklen_t)sizeof(struct sockaddr_in6)
513238106Sdes		&& memcmp(sin6addr, "\000\000\000\000\000\000\000\000"
514238106Sdes		"\000\000\000\000\000\000\000\000", 16) == 0)
515238106Sdes		return 1;
516238106Sdes	return 0;
517238106Sdes}
518238106Sdes
519238106Sdesvoid sock_list_insert(struct sock_list** list, struct sockaddr_storage* addr,
520238106Sdes	socklen_t len, struct regional* region)
521238106Sdes{
522238106Sdes	struct sock_list* add = (struct sock_list*)regional_alloc(region,
523238106Sdes		sizeof(*add) - sizeof(add->addr) + (size_t)len);
524238106Sdes	if(!add) {
525238106Sdes		log_err("out of memory in socketlist insert");
526238106Sdes		return;
527238106Sdes	}
528238106Sdes	log_assert(list);
529238106Sdes	add->next = *list;
530238106Sdes	add->len = len;
531238106Sdes	*list = add;
532238106Sdes	if(len) memmove(&add->addr, addr, len);
533238106Sdes}
534238106Sdes
535238106Sdesvoid sock_list_prepend(struct sock_list** list, struct sock_list* add)
536238106Sdes{
537238106Sdes	struct sock_list* last = add;
538238106Sdes	if(!last)
539238106Sdes		return;
540238106Sdes	while(last->next)
541238106Sdes		last = last->next;
542238106Sdes	last->next = *list;
543238106Sdes	*list = add;
544238106Sdes}
545238106Sdes
546238106Sdesint sock_list_find(struct sock_list* list, struct sockaddr_storage* addr,
547238106Sdes        socklen_t len)
548238106Sdes{
549238106Sdes	while(list) {
550238106Sdes		if(len == list->len) {
551238106Sdes			if(len == 0 || sockaddr_cmp_addr(addr, len,
552238106Sdes				&list->addr, list->len) == 0)
553238106Sdes				return 1;
554238106Sdes		}
555238106Sdes		list = list->next;
556238106Sdes	}
557238106Sdes	return 0;
558238106Sdes}
559238106Sdes
560238106Sdesvoid sock_list_merge(struct sock_list** list, struct regional* region,
561238106Sdes	struct sock_list* add)
562238106Sdes{
563238106Sdes	struct sock_list* p;
564238106Sdes	for(p=add; p; p=p->next) {
565238106Sdes		if(!sock_list_find(*list, &p->addr, p->len))
566238106Sdes			sock_list_insert(list, &p->addr, p->len, region);
567238106Sdes	}
568238106Sdes}
569238106Sdes
570238106Sdesvoid
571238106Sdeslog_crypto_err(const char* str)
572238106Sdes{
573249141Sdes#ifdef HAVE_SSL
574238106Sdes	/* error:[error code]:[library name]:[function name]:[reason string] */
575238106Sdes	char buf[128];
576238106Sdes	unsigned long e;
577238106Sdes	ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
578238106Sdes	log_err("%s crypto %s", str, buf);
579238106Sdes	while( (e=ERR_get_error()) ) {
580238106Sdes		ERR_error_string_n(e, buf, sizeof(buf));
581238106Sdes		log_err("and additionally crypto %s", buf);
582238106Sdes	}
583249141Sdes#else
584249141Sdes	(void)str;
585249141Sdes#endif /* HAVE_SSL */
586238106Sdes}
587238106Sdes
588238106Sdesvoid* listen_sslctx_create(char* key, char* pem, char* verifypem)
589238106Sdes{
590249141Sdes#ifdef HAVE_SSL
591238106Sdes	SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method());
592238106Sdes	if(!ctx) {
593238106Sdes		log_crypto_err("could not SSL_CTX_new");
594238106Sdes		return NULL;
595238106Sdes	}
596238106Sdes	/* no SSLv2 because has defects */
597238106Sdes	if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)){
598238106Sdes		log_crypto_err("could not set SSL_OP_NO_SSLv2");
599238106Sdes		SSL_CTX_free(ctx);
600238106Sdes		return NULL;
601238106Sdes	}
602238106Sdes	if(!SSL_CTX_use_certificate_file(ctx, pem, SSL_FILETYPE_PEM)) {
603238106Sdes		log_err("error for cert file: %s", pem);
604238106Sdes		log_crypto_err("error in SSL_CTX use_certificate_file");
605238106Sdes		SSL_CTX_free(ctx);
606238106Sdes		return NULL;
607238106Sdes	}
608238106Sdes	if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) {
609238106Sdes		log_err("error for private key file: %s", key);
610238106Sdes		log_crypto_err("Error in SSL_CTX use_PrivateKey_file");
611238106Sdes		SSL_CTX_free(ctx);
612238106Sdes		return NULL;
613238106Sdes	}
614238106Sdes	if(!SSL_CTX_check_private_key(ctx)) {
615238106Sdes		log_err("error for key file: %s", key);
616238106Sdes		log_crypto_err("Error in SSL_CTX check_private_key");
617238106Sdes		SSL_CTX_free(ctx);
618238106Sdes		return NULL;
619238106Sdes	}
620238106Sdes
621238106Sdes	if(verifypem && verifypem[0]) {
622238106Sdes		if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) {
623238106Sdes			log_crypto_err("Error in SSL_CTX verify locations");
624238106Sdes			SSL_CTX_free(ctx);
625238106Sdes			return NULL;
626238106Sdes		}
627238106Sdes		SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(
628238106Sdes			verifypem));
629238106Sdes		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
630238106Sdes	}
631238106Sdes	return ctx;
632249141Sdes#else
633249141Sdes	(void)key; (void)pem; (void)verifypem;
634249141Sdes	return NULL;
635249141Sdes#endif
636238106Sdes}
637238106Sdes
638238106Sdesvoid* connect_sslctx_create(char* key, char* pem, char* verifypem)
639238106Sdes{
640249141Sdes#ifdef HAVE_SSL
641238106Sdes	SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
642238106Sdes	if(!ctx) {
643238106Sdes		log_crypto_err("could not allocate SSL_CTX pointer");
644238106Sdes		return NULL;
645238106Sdes	}
646238106Sdes	if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)) {
647238106Sdes		log_crypto_err("could not set SSL_OP_NO_SSLv2");
648238106Sdes		SSL_CTX_free(ctx);
649238106Sdes		return NULL;
650238106Sdes	}
651238106Sdes	if(key && key[0]) {
652238106Sdes		if(!SSL_CTX_use_certificate_file(ctx, pem, SSL_FILETYPE_PEM)) {
653238106Sdes			log_err("error in client certificate %s", pem);
654238106Sdes			log_crypto_err("error in certificate file");
655238106Sdes			SSL_CTX_free(ctx);
656238106Sdes			return NULL;
657238106Sdes		}
658238106Sdes		if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) {
659238106Sdes			log_err("error in client private key %s", key);
660238106Sdes			log_crypto_err("error in key file");
661238106Sdes			SSL_CTX_free(ctx);
662238106Sdes			return NULL;
663238106Sdes		}
664238106Sdes		if(!SSL_CTX_check_private_key(ctx)) {
665238106Sdes			log_err("error in client key %s", key);
666238106Sdes			log_crypto_err("error in SSL_CTX_check_private_key");
667238106Sdes			SSL_CTX_free(ctx);
668238106Sdes			return NULL;
669238106Sdes		}
670238106Sdes	}
671238106Sdes	if(verifypem && verifypem[0]) {
672238106Sdes		if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL) != 1) {
673238106Sdes			log_crypto_err("error in SSL_CTX verify");
674238106Sdes			SSL_CTX_free(ctx);
675238106Sdes			return NULL;
676238106Sdes		}
677238106Sdes		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
678238106Sdes	}
679238106Sdes	return ctx;
680249141Sdes#else
681249141Sdes	(void)key; (void)pem; (void)verifypem;
682249141Sdes	return NULL;
683249141Sdes#endif
684238106Sdes}
685238106Sdes
686238106Sdesvoid* incoming_ssl_fd(void* sslctx, int fd)
687238106Sdes{
688249141Sdes#ifdef HAVE_SSL
689238106Sdes	SSL* ssl = SSL_new((SSL_CTX*)sslctx);
690238106Sdes	if(!ssl) {
691238106Sdes		log_crypto_err("could not SSL_new");
692238106Sdes		return NULL;
693238106Sdes	}
694238106Sdes	SSL_set_accept_state(ssl);
695238106Sdes	(void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
696238106Sdes	if(!SSL_set_fd(ssl, fd)) {
697238106Sdes		log_crypto_err("could not SSL_set_fd");
698238106Sdes		SSL_free(ssl);
699238106Sdes		return NULL;
700238106Sdes	}
701238106Sdes	return ssl;
702249141Sdes#else
703249141Sdes	(void)sslctx; (void)fd;
704249141Sdes	return NULL;
705249141Sdes#endif
706238106Sdes}
707238106Sdes
708238106Sdesvoid* outgoing_ssl_fd(void* sslctx, int fd)
709238106Sdes{
710249141Sdes#ifdef HAVE_SSL
711238106Sdes	SSL* ssl = SSL_new((SSL_CTX*)sslctx);
712238106Sdes	if(!ssl) {
713238106Sdes		log_crypto_err("could not SSL_new");
714238106Sdes		return NULL;
715238106Sdes	}
716238106Sdes	SSL_set_connect_state(ssl);
717238106Sdes	(void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
718238106Sdes	if(!SSL_set_fd(ssl, fd)) {
719238106Sdes		log_crypto_err("could not SSL_set_fd");
720238106Sdes		SSL_free(ssl);
721238106Sdes		return NULL;
722238106Sdes	}
723238106Sdes	return ssl;
724249141Sdes#else
725249141Sdes	(void)sslctx; (void)fd;
726249141Sdes	return NULL;
727249141Sdes#endif
728238106Sdes}
729249141Sdes
730249141Sdes#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
731249141Sdes/** global lock list for openssl locks */
732249141Sdesstatic lock_basic_t *ub_openssl_locks = NULL;
733249141Sdes
734249141Sdes/** callback that gets thread id for openssl */
735249141Sdesstatic unsigned long
736249141Sdesub_crypto_id_cb(void)
737249141Sdes{
738249141Sdes	return (unsigned long)ub_thread_self();
739249141Sdes}
740249141Sdes
741249141Sdesstatic void
742249141Sdesub_crypto_lock_cb(int mode, int type, const char *ATTR_UNUSED(file),
743249141Sdes	int ATTR_UNUSED(line))
744249141Sdes{
745249141Sdes	if((mode&CRYPTO_LOCK)) {
746249141Sdes		lock_basic_lock(&ub_openssl_locks[type]);
747249141Sdes	} else {
748249141Sdes		lock_basic_unlock(&ub_openssl_locks[type]);
749249141Sdes	}
750249141Sdes}
751249141Sdes#endif /* OPENSSL_THREADS */
752249141Sdes
753249141Sdesint ub_openssl_lock_init(void)
754249141Sdes{
755249141Sdes#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
756249141Sdes	int i;
757249141Sdes	ub_openssl_locks = (lock_basic_t*)malloc(
758249141Sdes		sizeof(lock_basic_t)*CRYPTO_num_locks());
759249141Sdes	if(!ub_openssl_locks)
760249141Sdes		return 0;
761249141Sdes	for(i=0; i<CRYPTO_num_locks(); i++) {
762249141Sdes		lock_basic_init(&ub_openssl_locks[i]);
763249141Sdes	}
764249141Sdes	CRYPTO_set_id_callback(&ub_crypto_id_cb);
765249141Sdes	CRYPTO_set_locking_callback(&ub_crypto_lock_cb);
766249141Sdes#endif /* OPENSSL_THREADS */
767249141Sdes	return 1;
768249141Sdes}
769249141Sdes
770249141Sdesvoid ub_openssl_lock_delete(void)
771249141Sdes{
772249141Sdes#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
773249141Sdes	int i;
774249141Sdes	if(!ub_openssl_locks)
775249141Sdes		return;
776249141Sdes	CRYPTO_set_id_callback(NULL);
777249141Sdes	CRYPTO_set_locking_callback(NULL);
778249141Sdes	for(i=0; i<CRYPTO_num_locks(); i++) {
779249141Sdes		lock_basic_destroy(&ub_openssl_locks[i]);
780249141Sdes	}
781249141Sdes	free(ub_openssl_locks);
782249141Sdes#endif /* OPENSSL_THREADS */
783249141Sdes}
784249141Sdes
785