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