]>
Commit | Line | Data |
---|---|---|
89c4ed63 A |
1 | /* |
2 | * util/net_help.c - implementation of the network helper code | |
3 | * | |
4 | * Copyright (c) 2007, NLnet Labs. All rights reserved. | |
5 | * | |
6 | * This software is open source. | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * | |
12 | * Redistributions of source code must retain the above copyright notice, | |
13 | * this list of conditions and the following disclaimer. | |
14 | * | |
15 | * Redistributions in binary form must reproduce the above copyright notice, | |
16 | * this list of conditions and the following disclaimer in the documentation | |
17 | * and/or other materials provided with the distribution. | |
18 | * | |
19 | * Neither the name of the NLNET LABS nor the names of its contributors may | |
20 | * be used to endorse or promote products derived from this software without | |
21 | * specific prior written permission. | |
22 | * | |
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
26 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
27 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | |
29 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
30 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
31 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
32 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
33 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
34 | */ | |
35 | /** | |
36 | * \file | |
37 | * Implementation of net_help.h. | |
38 | */ | |
39 | ||
40 | #include "config.h" | |
41 | #include "util/net_help.h" | |
42 | #include "util/log.h" | |
43 | #include "util/data/dname.h" | |
44 | #include "util/module.h" | |
45 | #include "util/regional.h" | |
46 | #include "ldns/parseutil.h" | |
47 | #include "ldns/wire2str.h" | |
48 | #include <fcntl.h> | |
49 | #ifdef HAVE_OPENSSL_SSL_H | |
50 | #include <openssl/ssl.h> | |
51 | #endif | |
52 | #ifdef HAVE_OPENSSL_ERR_H | |
53 | #include <openssl/err.h> | |
54 | #endif | |
55 | ||
56 | /** max length of an IP address (the address portion) that we allow */ | |
57 | #define MAX_ADDR_STRLEN 128 /* characters */ | |
58 | /** default value for EDNS ADVERTISED size */ | |
59 | uint16_t EDNS_ADVERTISED_SIZE = 4096; | |
60 | ||
61 | /** minimal responses when positive answer: default is no */ | |
62 | int MINIMAL_RESPONSES = 0; | |
63 | ||
64 | /** rrset order roundrobin: default is no */ | |
65 | int RRSET_ROUNDROBIN = 0; | |
66 | ||
67 | /* returns true is string addr is an ip6 specced address */ | |
68 | int | |
69 | str_is_ip6(const char* str) | |
70 | { | |
71 | if(strchr(str, ':')) | |
72 | return 1; | |
73 | else return 0; | |
74 | } | |
75 | ||
76 | int | |
77 | fd_set_nonblock(int s) | |
78 | { | |
79 | #ifdef HAVE_FCNTL | |
80 | int flag; | |
81 | if((flag = fcntl(s, F_GETFL)) == -1) { | |
82 | log_err("can't fcntl F_GETFL: %s", strerror(errno)); | |
83 | flag = 0; | |
84 | } | |
85 | flag |= O_NONBLOCK; | |
86 | if(fcntl(s, F_SETFL, flag) == -1) { | |
87 | log_err("can't fcntl F_SETFL: %s", strerror(errno)); | |
88 | return 0; | |
89 | } | |
90 | #elif defined(HAVE_IOCTLSOCKET) | |
91 | unsigned long on = 1; | |
92 | if(ioctlsocket(s, FIONBIO, &on) != 0) { | |
93 | log_err("can't ioctlsocket FIONBIO on: %s", | |
94 | wsa_strerror(WSAGetLastError())); | |
95 | } | |
96 | #endif | |
97 | return 1; | |
98 | } | |
99 | ||
100 | int | |
101 | fd_set_block(int s) | |
102 | { | |
103 | #ifdef HAVE_FCNTL | |
104 | int flag; | |
105 | if((flag = fcntl(s, F_GETFL)) == -1) { | |
106 | log_err("cannot fcntl F_GETFL: %s", strerror(errno)); | |
107 | flag = 0; | |
108 | } | |
109 | flag &= ~O_NONBLOCK; | |
110 | if(fcntl(s, F_SETFL, flag) == -1) { | |
111 | log_err("cannot fcntl F_SETFL: %s", strerror(errno)); | |
112 | return 0; | |
113 | } | |
114 | #elif defined(HAVE_IOCTLSOCKET) | |
115 | unsigned long off = 0; | |
116 | if(ioctlsocket(s, FIONBIO, &off) != 0) { | |
117 | log_err("can't ioctlsocket FIONBIO off: %s", | |
118 | wsa_strerror(WSAGetLastError())); | |
119 | } | |
120 | #endif | |
121 | return 1; | |
122 | } | |
123 | ||
124 | int | |
125 | is_pow2(size_t num) | |
126 | { | |
127 | if(num == 0) return 1; | |
128 | return (num & (num-1)) == 0; | |
129 | } | |
130 | ||
131 | void* | |
132 | memdup(void* data, size_t len) | |
133 | { | |
134 | void* d; | |
135 | if(!data) return NULL; | |
136 | if(len == 0) return NULL; | |
137 | d = malloc(len); | |
138 | if(!d) return NULL; | |
139 | memcpy(d, data, len); | |
140 | return d; | |
141 | } | |
142 | ||
143 | void | |
144 | log_addr(enum verbosity_value v, const char* str, | |
145 | struct sockaddr_storage* addr, socklen_t addrlen) | |
146 | { | |
147 | uint16_t port; | |
148 | const char* family = "unknown"; | |
149 | char dest[100]; | |
150 | int af = (int)((struct sockaddr_in*)addr)->sin_family; | |
151 | void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr; | |
152 | if(verbosity < v) | |
153 | return; | |
154 | switch(af) { | |
155 | case AF_INET: family="ip4"; break; | |
156 | case AF_INET6: family="ip6"; | |
157 | sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr; | |
158 | break; | |
159 | case AF_UNIX: family="unix"; break; | |
160 | default: break; | |
161 | } | |
162 | if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) { | |
163 | (void)strlcpy(dest, "(inet_ntop error)", sizeof(dest)); | |
164 | } | |
165 | dest[sizeof(dest)-1] = 0; | |
166 | port = ntohs(((struct sockaddr_in*)addr)->sin_port); | |
167 | if(verbosity >= 4) | |
168 | verbose(v, "%s %s %s port %d (len %d)", str, family, dest, | |
169 | (int)port, (int)addrlen); | |
170 | else verbose(v, "%s %s port %d", str, dest, (int)port); | |
171 | } | |
172 | ||
173 | int | |
174 | extstrtoaddr(const char* str, struct sockaddr_storage* addr, | |
175 | socklen_t* addrlen) | |
176 | { | |
177 | char* s; | |
178 | int port = UNBOUND_DNS_PORT; | |
179 | if((s=strchr(str, '@'))) { | |
180 | char buf[MAX_ADDR_STRLEN]; | |
181 | if(s-str >= MAX_ADDR_STRLEN) { | |
182 | return 0; | |
183 | } | |
184 | (void)strlcpy(buf, str, sizeof(buf)); | |
185 | buf[s-str] = 0; | |
186 | port = atoi(s+1); | |
187 | if(port == 0 && strcmp(s+1,"0")!=0) { | |
188 | return 0; | |
189 | } | |
190 | return ipstrtoaddr(buf, port, addr, addrlen); | |
191 | } | |
192 | return ipstrtoaddr(str, port, addr, addrlen); | |
193 | } | |
194 | ||
195 | ||
196 | int | |
197 | ipstrtoaddr(const char* ip, int port, struct sockaddr_storage* addr, | |
198 | socklen_t* addrlen) | |
199 | { | |
200 | uint16_t p; | |
201 | if(!ip) return 0; | |
202 | p = (uint16_t) port; | |
203 | if(str_is_ip6(ip)) { | |
204 | char buf[MAX_ADDR_STRLEN]; | |
205 | char* s; | |
206 | struct sockaddr_in6* sa = (struct sockaddr_in6*)addr; | |
207 | *addrlen = (socklen_t)sizeof(struct sockaddr_in6); | |
208 | memset(sa, 0, *addrlen); | |
209 | sa->sin6_family = AF_INET6; | |
210 | sa->sin6_port = (in_port_t)htons(p); | |
211 | if((s=strchr(ip, '%'))) { /* ip6%interface, rfc 4007 */ | |
212 | if(s-ip >= MAX_ADDR_STRLEN) | |
213 | return 0; | |
214 | (void)strlcpy(buf, ip, sizeof(buf)); | |
215 | buf[s-ip]=0; | |
216 | sa->sin6_scope_id = (uint32_t)atoi(s+1); | |
217 | ip = buf; | |
218 | } | |
219 | if(inet_pton((int)sa->sin6_family, ip, &sa->sin6_addr) <= 0) { | |
220 | return 0; | |
221 | } | |
222 | } else { /* ip4 */ | |
223 | struct sockaddr_in* sa = (struct sockaddr_in*)addr; | |
224 | *addrlen = (socklen_t)sizeof(struct sockaddr_in); | |
225 | memset(sa, 0, *addrlen); | |
226 | sa->sin_family = AF_INET; | |
227 | sa->sin_port = (in_port_t)htons(p); | |
228 | if(inet_pton((int)sa->sin_family, ip, &sa->sin_addr) <= 0) { | |
229 | return 0; | |
230 | } | |
231 | } | |
232 | return 1; | |
233 | } | |
234 | ||
235 | int netblockstrtoaddr(const char* str, int port, struct sockaddr_storage* addr, | |
236 | socklen_t* addrlen, int* net) | |
237 | { | |
238 | char* s = NULL; | |
239 | *net = (str_is_ip6(str)?128:32); | |
240 | if((s=strchr(str, '/'))) { | |
241 | if(atoi(s+1) > *net) { | |
242 | log_err("netblock too large: %s", str); | |
243 | return 0; | |
244 | } | |
245 | *net = atoi(s+1); | |
246 | if(*net == 0 && strcmp(s+1, "0") != 0) { | |
247 | log_err("cannot parse netblock: '%s'", str); | |
248 | return 0; | |
249 | } | |
250 | if(!(s = strdup(str))) { | |
251 | log_err("out of memory"); | |
252 | return 0; | |
253 | } | |
254 | *strchr(s, '/') = '\0'; | |
255 | } | |
256 | if(!ipstrtoaddr(s?s:str, port, addr, addrlen)) { | |
257 | free(s); | |
258 | log_err("cannot parse ip address: '%s'", str); | |
259 | return 0; | |
260 | } | |
261 | if(s) { | |
262 | free(s); | |
263 | addr_mask(addr, *addrlen, *net); | |
264 | } | |
265 | return 1; | |
266 | } | |
267 | ||
268 | void | |
269 | log_nametypeclass(enum verbosity_value v, const char* str, uint8_t* name, | |
270 | uint16_t type, uint16_t dclass) | |
271 | { | |
272 | char buf[LDNS_MAX_DOMAINLEN+1]; | |
273 | char t[12], c[12]; | |
274 | const char *ts, *cs; | |
275 | if(verbosity < v) | |
276 | return; | |
277 | dname_str(name, buf); | |
278 | if(type == LDNS_RR_TYPE_TSIG) ts = "TSIG"; | |
279 | else if(type == LDNS_RR_TYPE_IXFR) ts = "IXFR"; | |
280 | else if(type == LDNS_RR_TYPE_AXFR) ts = "AXFR"; | |
281 | else if(type == LDNS_RR_TYPE_MAILB) ts = "MAILB"; | |
282 | else if(type == LDNS_RR_TYPE_MAILA) ts = "MAILA"; | |
283 | else if(type == LDNS_RR_TYPE_ANY) ts = "ANY"; | |
284 | else if(sldns_rr_descript(type) && sldns_rr_descript(type)->_name) | |
285 | ts = sldns_rr_descript(type)->_name; | |
286 | else { | |
287 | snprintf(t, sizeof(t), "TYPE%d", (int)type); | |
288 | ts = t; | |
289 | } | |
290 | if(sldns_lookup_by_id(sldns_rr_classes, (int)dclass) && | |
291 | sldns_lookup_by_id(sldns_rr_classes, (int)dclass)->name) | |
292 | cs = sldns_lookup_by_id(sldns_rr_classes, (int)dclass)->name; | |
293 | else { | |
294 | snprintf(c, sizeof(c), "CLASS%d", (int)dclass); | |
295 | cs = c; | |
296 | } | |
297 | log_info("%s %s %s %s", str, buf, ts, cs); | |
298 | } | |
299 | ||
300 | void log_name_addr(enum verbosity_value v, const char* str, uint8_t* zone, | |
301 | struct sockaddr_storage* addr, socklen_t addrlen) | |
302 | { | |
303 | uint16_t port; | |
304 | const char* family = "unknown_family "; | |
305 | char namebuf[LDNS_MAX_DOMAINLEN+1]; | |
306 | char dest[100]; | |
307 | int af = (int)((struct sockaddr_in*)addr)->sin_family; | |
308 | void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr; | |
309 | if(verbosity < v) | |
310 | return; | |
311 | switch(af) { | |
312 | case AF_INET: family=""; break; | |
313 | case AF_INET6: family=""; | |
314 | sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr; | |
315 | break; | |
316 | case AF_UNIX: family="unix_family "; break; | |
317 | default: break; | |
318 | } | |
319 | if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) { | |
320 | (void)strlcpy(dest, "(inet_ntop error)", sizeof(dest)); | |
321 | } | |
322 | dest[sizeof(dest)-1] = 0; | |
323 | port = ntohs(((struct sockaddr_in*)addr)->sin_port); | |
324 | dname_str(zone, namebuf); | |
325 | if(af != AF_INET && af != AF_INET6) | |
326 | verbose(v, "%s <%s> %s%s#%d (addrlen %d)", | |
327 | str, namebuf, family, dest, (int)port, (int)addrlen); | |
328 | else verbose(v, "%s <%s> %s%s#%d", | |
329 | str, namebuf, family, dest, (int)port); | |
330 | } | |
331 | ||
332 | void log_err_addr(const char* str, const char* err, | |
333 | struct sockaddr_storage* addr, socklen_t addrlen) | |
334 | { | |
335 | uint16_t port; | |
336 | char dest[100]; | |
337 | int af = (int)((struct sockaddr_in*)addr)->sin_family; | |
338 | void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr; | |
339 | if(af == AF_INET6) | |
340 | sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr; | |
341 | if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) { | |
342 | (void)strlcpy(dest, "(inet_ntop error)", sizeof(dest)); | |
343 | } | |
344 | dest[sizeof(dest)-1] = 0; | |
345 | port = ntohs(((struct sockaddr_in*)addr)->sin_port); | |
346 | if(verbosity >= 4) | |
347 | log_err("%s: %s for %s port %d (len %d)", str, err, dest, | |
348 | (int)port, (int)addrlen); | |
349 | else log_err("%s: %s for %s", str, err, dest); | |
350 | } | |
351 | ||
352 | int | |
353 | sockaddr_cmp(struct sockaddr_storage* addr1, socklen_t len1, | |
354 | struct sockaddr_storage* addr2, socklen_t len2) | |
355 | { | |
356 | struct sockaddr_in* p1_in = (struct sockaddr_in*)addr1; | |
357 | struct sockaddr_in* p2_in = (struct sockaddr_in*)addr2; | |
358 | struct sockaddr_in6* p1_in6 = (struct sockaddr_in6*)addr1; | |
359 | struct sockaddr_in6* p2_in6 = (struct sockaddr_in6*)addr2; | |
360 | if(len1 < len2) | |
361 | return -1; | |
362 | if(len1 > len2) | |
363 | return 1; | |
364 | log_assert(len1 == len2); | |
365 | if( p1_in->sin_family < p2_in->sin_family) | |
366 | return -1; | |
367 | if( p1_in->sin_family > p2_in->sin_family) | |
368 | return 1; | |
369 | log_assert( p1_in->sin_family == p2_in->sin_family ); | |
370 | /* compare ip4 */ | |
371 | if( p1_in->sin_family == AF_INET ) { | |
372 | /* just order it, ntohs not required */ | |
373 | if(p1_in->sin_port < p2_in->sin_port) | |
374 | return -1; | |
375 | if(p1_in->sin_port > p2_in->sin_port) | |
376 | return 1; | |
377 | log_assert(p1_in->sin_port == p2_in->sin_port); | |
378 | return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE); | |
379 | } else if (p1_in6->sin6_family == AF_INET6) { | |
380 | /* just order it, ntohs not required */ | |
381 | if(p1_in6->sin6_port < p2_in6->sin6_port) | |
382 | return -1; | |
383 | if(p1_in6->sin6_port > p2_in6->sin6_port) | |
384 | return 1; | |
385 | log_assert(p1_in6->sin6_port == p2_in6->sin6_port); | |
386 | return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr, | |
387 | INET6_SIZE); | |
388 | } else { | |
389 | /* eek unknown type, perform this comparison for sanity. */ | |
390 | return memcmp(addr1, addr2, len1); | |
391 | } | |
392 | } | |
393 | ||
394 | int | |
395 | sockaddr_cmp_addr(struct sockaddr_storage* addr1, socklen_t len1, | |
396 | struct sockaddr_storage* addr2, socklen_t len2) | |
397 | { | |
398 | struct sockaddr_in* p1_in = (struct sockaddr_in*)addr1; | |
399 | struct sockaddr_in* p2_in = (struct sockaddr_in*)addr2; | |
400 | struct sockaddr_in6* p1_in6 = (struct sockaddr_in6*)addr1; | |
401 | struct sockaddr_in6* p2_in6 = (struct sockaddr_in6*)addr2; | |
402 | if(len1 < len2) | |
403 | return -1; | |
404 | if(len1 > len2) | |
405 | return 1; | |
406 | log_assert(len1 == len2); | |
407 | if( p1_in->sin_family < p2_in->sin_family) | |
408 | return -1; | |
409 | if( p1_in->sin_family > p2_in->sin_family) | |
410 | return 1; | |
411 | log_assert( p1_in->sin_family == p2_in->sin_family ); | |
412 | /* compare ip4 */ | |
413 | if( p1_in->sin_family == AF_INET ) { | |
414 | return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE); | |
415 | } else if (p1_in6->sin6_family == AF_INET6) { | |
416 | return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr, | |
417 | INET6_SIZE); | |
418 | } else { | |
419 | /* eek unknown type, perform this comparison for sanity. */ | |
420 | return memcmp(addr1, addr2, len1); | |
421 | } | |
422 | } | |
423 | ||
424 | int | |
425 | addr_is_ip6(struct sockaddr_storage* addr, socklen_t len) | |
426 | { | |
427 | if(len == (socklen_t)sizeof(struct sockaddr_in6) && | |
428 | ((struct sockaddr_in6*)addr)->sin6_family == AF_INET6) | |
429 | return 1; | |
430 | else return 0; | |
431 | } | |
432 | ||
433 | void | |
434 | addr_mask(struct sockaddr_storage* addr, socklen_t len, int net) | |
435 | { | |
436 | uint8_t mask[8] = {0x0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe}; | |
437 | int i, max; | |
438 | uint8_t* s; | |
439 | if(addr_is_ip6(addr, len)) { | |
440 | s = (uint8_t*)&((struct sockaddr_in6*)addr)->sin6_addr; | |
441 | max = 128; | |
442 | } else { | |
443 | s = (uint8_t*)&((struct sockaddr_in*)addr)->sin_addr; | |
444 | max = 32; | |
445 | } | |
446 | if(net >= max) | |
447 | return; | |
448 | for(i=net/8+1; i<max/8; i++) { | |
449 | s[i] = 0; | |
450 | } | |
451 | s[net/8] &= mask[net&0x7]; | |
452 | } | |
453 | ||
454 | int | |
455 | addr_in_common(struct sockaddr_storage* addr1, int net1, | |
456 | struct sockaddr_storage* addr2, int net2, socklen_t addrlen) | |
457 | { | |
458 | int min = (net1<net2)?net1:net2; | |
459 | int i, to; | |
460 | int match = 0; | |
461 | uint8_t* s1, *s2; | |
462 | if(addr_is_ip6(addr1, addrlen)) { | |
463 | s1 = (uint8_t*)&((struct sockaddr_in6*)addr1)->sin6_addr; | |
464 | s2 = (uint8_t*)&((struct sockaddr_in6*)addr2)->sin6_addr; | |
465 | to = 16; | |
466 | } else { | |
467 | s1 = (uint8_t*)&((struct sockaddr_in*)addr1)->sin_addr; | |
468 | s2 = (uint8_t*)&((struct sockaddr_in*)addr2)->sin_addr; | |
469 | to = 4; | |
470 | } | |
471 | /* match = bits_in_common(s1, s2, to); */ | |
472 | for(i=0; i<to; i++) { | |
473 | if(s1[i] == s2[i]) { | |
474 | match += 8; | |
475 | } else { | |
476 | uint8_t z = s1[i]^s2[i]; | |
477 | log_assert(z); | |
478 | while(!(z&0x80)) { | |
479 | match++; | |
480 | z<<=1; | |
481 | } | |
482 | break; | |
483 | } | |
484 | } | |
485 | if(match > min) match = min; | |
486 | return match; | |
487 | } | |
488 | ||
489 | void | |
490 | addr_to_str(struct sockaddr_storage* addr, socklen_t addrlen, | |
491 | char* buf, size_t len) | |
492 | { | |
493 | int af = (int)((struct sockaddr_in*)addr)->sin_family; | |
494 | void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr; | |
495 | if(addr_is_ip6(addr, addrlen)) | |
496 | sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr; | |
497 | if(inet_ntop(af, sinaddr, buf, (socklen_t)len) == 0) { | |
498 | snprintf(buf, len, "(inet_ntop_error)"); | |
499 | } | |
500 | } | |
501 | ||
502 | int | |
503 | addr_is_ip4mapped(struct sockaddr_storage* addr, socklen_t addrlen) | |
504 | { | |
505 | /* prefix for ipv4 into ipv6 mapping is ::ffff:x.x.x.x */ | |
506 | const uint8_t map_prefix[16] = | |
507 | {0,0,0,0, 0,0,0,0, 0,0,0xff,0xff, 0,0,0,0}; | |
508 | uint8_t* s; | |
509 | if(!addr_is_ip6(addr, addrlen)) | |
510 | return 0; | |
511 | /* s is 16 octet ipv6 address string */ | |
512 | s = (uint8_t*)&((struct sockaddr_in6*)addr)->sin6_addr; | |
513 | return (memcmp(s, map_prefix, 12) == 0); | |
514 | } | |
515 | ||
516 | int addr_is_broadcast(struct sockaddr_storage* addr, socklen_t addrlen) | |
517 | { | |
518 | int af = (int)((struct sockaddr_in*)addr)->sin_family; | |
519 | void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr; | |
520 | return af == AF_INET && addrlen>=(socklen_t)sizeof(struct sockaddr_in) | |
521 | && memcmp(sinaddr, "\377\377\377\377", 4) == 0; | |
522 | } | |
523 | ||
524 | int addr_is_any(struct sockaddr_storage* addr, socklen_t addrlen) | |
525 | { | |
526 | int af = (int)((struct sockaddr_in*)addr)->sin_family; | |
527 | void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr; | |
528 | void* sin6addr = &((struct sockaddr_in6*)addr)->sin6_addr; | |
529 | if(af == AF_INET && addrlen>=(socklen_t)sizeof(struct sockaddr_in) | |
530 | && memcmp(sinaddr, "\000\000\000\000", 4) == 0) | |
531 | return 1; | |
532 | else if(af==AF_INET6 && addrlen>=(socklen_t)sizeof(struct sockaddr_in6) | |
533 | && memcmp(sin6addr, "\000\000\000\000\000\000\000\000" | |
534 | "\000\000\000\000\000\000\000\000", 16) == 0) | |
535 | return 1; | |
536 | return 0; | |
537 | } | |
538 | ||
539 | void sock_list_insert(struct sock_list** list, struct sockaddr_storage* addr, | |
540 | socklen_t len, struct regional* region) | |
541 | { | |
542 | struct sock_list* add = (struct sock_list*)regional_alloc(region, | |
543 | sizeof(*add) - sizeof(add->addr) + (size_t)len); | |
544 | if(!add) { | |
545 | log_err("out of memory in socketlist insert"); | |
546 | return; | |
547 | } | |
548 | log_assert(list); | |
549 | add->next = *list; | |
550 | add->len = len; | |
551 | *list = add; | |
552 | if(len) memmove(&add->addr, addr, len); | |
553 | } | |
554 | ||
555 | void sock_list_prepend(struct sock_list** list, struct sock_list* add) | |
556 | { | |
557 | struct sock_list* last = add; | |
558 | if(!last) | |
559 | return; | |
560 | while(last->next) | |
561 | last = last->next; | |
562 | last->next = *list; | |
563 | *list = add; | |
564 | } | |
565 | ||
566 | int sock_list_find(struct sock_list* list, struct sockaddr_storage* addr, | |
567 | socklen_t len) | |
568 | { | |
569 | while(list) { | |
570 | if(len == list->len) { | |
571 | if(len == 0 || sockaddr_cmp_addr(addr, len, | |
572 | &list->addr, list->len) == 0) | |
573 | return 1; | |
574 | } | |
575 | list = list->next; | |
576 | } | |
577 | return 0; | |
578 | } | |
579 | ||
580 | void sock_list_merge(struct sock_list** list, struct regional* region, | |
581 | struct sock_list* add) | |
582 | { | |
583 | struct sock_list* p; | |
584 | for(p=add; p; p=p->next) { | |
585 | if(!sock_list_find(*list, &p->addr, p->len)) | |
586 | sock_list_insert(list, &p->addr, p->len, region); | |
587 | } | |
588 | } | |
589 | ||
590 | void | |
591 | log_crypto_err(const char* str) | |
592 | { | |
593 | #ifdef HAVE_SSL | |
594 | /* error:[error code]:[library name]:[function name]:[reason string] */ | |
595 | char buf[128]; | |
596 | unsigned long e; | |
597 | ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); | |
598 | log_err("%s crypto %s", str, buf); | |
599 | while( (e=ERR_get_error()) ) { | |
600 | ERR_error_string_n(e, buf, sizeof(buf)); | |
601 | log_err("and additionally crypto %s", buf); | |
602 | } | |
603 | #else | |
604 | (void)str; | |
605 | #endif /* HAVE_SSL */ | |
606 | } | |
607 | ||
608 | void* listen_sslctx_create(char* key, char* pem, char* verifypem) | |
609 | { | |
610 | #ifdef HAVE_SSL | |
611 | SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method()); | |
612 | if(!ctx) { | |
613 | log_crypto_err("could not SSL_CTX_new"); | |
614 | return NULL; | |
615 | } | |
89c4ed63 A |
616 | if(!SSL_CTX_use_certificate_file(ctx, pem, SSL_FILETYPE_PEM)) { |
617 | log_err("error for cert file: %s", pem); | |
618 | log_crypto_err("error in SSL_CTX use_certificate_file"); | |
619 | SSL_CTX_free(ctx); | |
620 | return NULL; | |
621 | } | |
622 | if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) { | |
623 | log_err("error for private key file: %s", key); | |
624 | log_crypto_err("Error in SSL_CTX use_PrivateKey_file"); | |
625 | SSL_CTX_free(ctx); | |
626 | return NULL; | |
627 | } | |
628 | if(!SSL_CTX_check_private_key(ctx)) { | |
629 | log_err("error for key file: %s", key); | |
630 | log_crypto_err("Error in SSL_CTX check_private_key"); | |
631 | SSL_CTX_free(ctx); | |
632 | return NULL; | |
633 | } | |
634 | ||
635 | if(verifypem && verifypem[0]) { | |
636 | if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) { | |
637 | log_crypto_err("Error in SSL_CTX verify locations"); | |
638 | SSL_CTX_free(ctx); | |
639 | return NULL; | |
640 | } | |
641 | SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file( | |
642 | verifypem)); | |
643 | SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); | |
644 | } | |
645 | return ctx; | |
646 | #else | |
647 | (void)key; (void)pem; (void)verifypem; | |
648 | return NULL; | |
649 | #endif | |
650 | } | |
651 | ||
652 | void* connect_sslctx_create(char* key, char* pem, char* verifypem) | |
653 | { | |
654 | #ifdef HAVE_SSL | |
655 | SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method()); | |
656 | if(!ctx) { | |
657 | log_crypto_err("could not allocate SSL_CTX pointer"); | |
658 | return NULL; | |
659 | } | |
89c4ed63 A |
660 | if(key && key[0]) { |
661 | if(!SSL_CTX_use_certificate_file(ctx, pem, SSL_FILETYPE_PEM)) { | |
662 | log_err("error in client certificate %s", pem); | |
663 | log_crypto_err("error in certificate file"); | |
664 | SSL_CTX_free(ctx); | |
665 | return NULL; | |
666 | } | |
667 | if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) { | |
668 | log_err("error in client private key %s", key); | |
669 | log_crypto_err("error in key file"); | |
670 | SSL_CTX_free(ctx); | |
671 | return NULL; | |
672 | } | |
673 | if(!SSL_CTX_check_private_key(ctx)) { | |
674 | log_err("error in client key %s", key); | |
675 | log_crypto_err("error in SSL_CTX_check_private_key"); | |
676 | SSL_CTX_free(ctx); | |
677 | return NULL; | |
678 | } | |
679 | } | |
680 | if(verifypem && verifypem[0]) { | |
681 | if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) { | |
682 | log_crypto_err("error in SSL_CTX verify"); | |
683 | SSL_CTX_free(ctx); | |
684 | return NULL; | |
685 | } | |
686 | SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); | |
687 | } | |
688 | return ctx; | |
689 | #else | |
690 | (void)key; (void)pem; (void)verifypem; | |
691 | return NULL; | |
692 | #endif | |
693 | } | |
694 | ||
695 | void* incoming_ssl_fd(void* sslctx, int fd) | |
696 | { | |
697 | #ifdef HAVE_SSL | |
698 | SSL* ssl = SSL_new((SSL_CTX*)sslctx); | |
699 | if(!ssl) { | |
700 | log_crypto_err("could not SSL_new"); | |
701 | return NULL; | |
702 | } | |
703 | SSL_set_accept_state(ssl); | |
704 | (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); | |
705 | if(!SSL_set_fd(ssl, fd)) { | |
706 | log_crypto_err("could not SSL_set_fd"); | |
707 | SSL_free(ssl); | |
708 | return NULL; | |
709 | } | |
710 | return ssl; | |
711 | #else | |
712 | (void)sslctx; (void)fd; | |
713 | return NULL; | |
714 | #endif | |
715 | } | |
716 | ||
717 | void* outgoing_ssl_fd(void* sslctx, int fd) | |
718 | { | |
719 | #ifdef HAVE_SSL | |
720 | SSL* ssl = SSL_new((SSL_CTX*)sslctx); | |
721 | if(!ssl) { | |
722 | log_crypto_err("could not SSL_new"); | |
723 | return NULL; | |
724 | } | |
725 | SSL_set_connect_state(ssl); | |
726 | (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); | |
727 | if(!SSL_set_fd(ssl, fd)) { | |
728 | log_crypto_err("could not SSL_set_fd"); | |
729 | SSL_free(ssl); | |
730 | return NULL; | |
731 | } | |
732 | return ssl; | |
733 | #else | |
734 | (void)sslctx; (void)fd; | |
735 | return NULL; | |
736 | #endif | |
737 | } | |
738 | ||
739 | #if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) | |
740 | /** global lock list for openssl locks */ | |
741 | static lock_basic_t *ub_openssl_locks = NULL; | |
742 | ||
743 | /** callback that gets thread id for openssl */ | |
744 | static unsigned long | |
745 | ub_crypto_id_cb(void) | |
746 | { | |
747 | return (unsigned long)ub_thread_self(); | |
748 | } | |
749 | ||
750 | static void | |
751 | ub_crypto_lock_cb(int mode, int type, const char *ATTR_UNUSED(file), | |
752 | int ATTR_UNUSED(line)) | |
753 | { | |
754 | if((mode&CRYPTO_LOCK)) { | |
755 | lock_basic_lock(&ub_openssl_locks[type]); | |
756 | } else { | |
757 | lock_basic_unlock(&ub_openssl_locks[type]); | |
758 | } | |
759 | } | |
760 | #endif /* OPENSSL_THREADS */ | |
761 | ||
762 | int ub_openssl_lock_init(void) | |
763 | { | |
764 | #if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) | |
765 | int i; | |
766 | ub_openssl_locks = (lock_basic_t*)malloc( | |
767 | sizeof(lock_basic_t)*CRYPTO_num_locks()); | |
768 | if(!ub_openssl_locks) | |
769 | return 0; | |
770 | for(i=0; i<CRYPTO_num_locks(); i++) { | |
771 | lock_basic_init(&ub_openssl_locks[i]); | |
772 | } | |
773 | CRYPTO_set_id_callback(&ub_crypto_id_cb); | |
774 | CRYPTO_set_locking_callback(&ub_crypto_lock_cb); | |
775 | #endif /* OPENSSL_THREADS */ | |
776 | return 1; | |
777 | } | |
778 | ||
779 | void ub_openssl_lock_delete(void) | |
780 | { | |
781 | #if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) | |
782 | int i; | |
783 | if(!ub_openssl_locks) | |
784 | return; | |
785 | CRYPTO_set_id_callback(NULL); | |
786 | CRYPTO_set_locking_callback(NULL); | |
787 | for(i=0; i<CRYPTO_num_locks(); i++) { | |
788 | lock_basic_destroy(&ub_openssl_locks[i]); | |
789 | } | |
790 | free(ub_openssl_locks); | |
791 | #endif /* OPENSSL_THREADS */ | |
792 | } | |
793 |