Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Samba utility functions
4 : Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
5 : Copyright (C) Andrew Tridgell 1992-1998
6 : Copyright (C) Jeremy Allison 1992-2007
7 : Copyright (C) Simo Sorce 2001
8 : Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003.
9 : Copyright (C) James J Myers 2003
10 : Copyright (C) Tim Potter 2000-2001
11 :
12 : This program is free software; you can redistribute it and/or modify
13 : it under the terms of the GNU General Public License as published by
14 : the Free Software Foundation; either version 3 of the License, or
15 : (at your option) any later version.
16 :
17 : This program is distributed in the hope that it will be useful,
18 : but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : GNU General Public License for more details.
21 :
22 : You should have received a copy of the GNU General Public License
23 : along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : */
25 :
26 : #include "includes.h"
27 : #include "system/network.h"
28 : #include "system/locale.h"
29 : #include "system/filesys.h"
30 : #include "system/select.h"
31 : #include "lib/util/select.h"
32 : #include "lib/util/util_net.h"
33 :
34 : #undef strcasecmp
35 : #undef strncasecmp
36 :
37 : /*******************************************************************
38 : Set an address to INADDR_ANY.
39 : ******************************************************************/
40 :
41 967343 : void zero_sockaddr(struct sockaddr_storage *pss)
42 : {
43 : /* Ensure we're at least a valid sockaddr-storage. */
44 967343 : *pss = (struct sockaddr_storage) { .ss_family = AF_INET };
45 967343 : }
46 :
47 1258496 : static char *normalize_ipv6_literal(const char *str, char *buf, size_t *_len)
48 : {
49 : #define IPv6_LITERAL_NET ".ipv6-literal.net"
50 1258496 : const size_t llen = sizeof(IPv6_LITERAL_NET) - 1;
51 1258496 : size_t len = *_len;
52 75176 : int cmp;
53 75176 : size_t i;
54 1258496 : size_t idx_chars = 0;
55 1258496 : size_t cnt_delimiter = 0;
56 1258496 : size_t cnt_chars = 0;
57 :
58 1258496 : if (len <= llen) {
59 963545 : return NULL;
60 : }
61 :
62 : /* ignore a trailing '.' */
63 223752 : if (str[len - 1] == '.') {
64 12 : len -= 1;
65 : }
66 :
67 223752 : len -= llen;
68 223752 : if (len >= INET6_ADDRSTRLEN) {
69 4421 : return NULL;
70 : }
71 219331 : if (len < 2) {
72 0 : return NULL;
73 : }
74 :
75 219331 : cmp = strncasecmp(&str[len], IPv6_LITERAL_NET, llen);
76 219331 : if (cmp != 0) {
77 215330 : return NULL;
78 : }
79 :
80 960 : for (i = 0; i < len; i++) {
81 936 : if (idx_chars != 0) {
82 0 : break;
83 : }
84 :
85 936 : switch (str[i]) {
86 168 : case '-':
87 168 : buf[i] = ':';
88 168 : cnt_chars = 0;
89 168 : cnt_delimiter += 1;
90 168 : break;
91 0 : case 's':
92 0 : buf[i] = SCOPE_DELIMITER;
93 0 : idx_chars += 1;
94 0 : break;
95 768 : case '0':
96 : case '1':
97 : case '2':
98 : case '3':
99 : case '4':
100 : case '5':
101 : case '6':
102 : case '7':
103 : case '8':
104 : case '9':
105 : case 'a':
106 : case 'A':
107 : case 'b':
108 : case 'B':
109 : case 'c':
110 : case 'C':
111 : case 'd':
112 : case 'D':
113 : case 'e':
114 : case 'E':
115 : case 'f':
116 : case 'F':
117 768 : buf[i] = str[i];
118 768 : cnt_chars += 1;
119 768 : break;
120 0 : default:
121 0 : return NULL;
122 : }
123 936 : if (cnt_chars > 4) {
124 0 : return NULL;
125 : }
126 936 : if (cnt_delimiter > 7) {
127 0 : return NULL;
128 : }
129 : }
130 :
131 24 : if (cnt_delimiter < 2) {
132 0 : return NULL;
133 : }
134 :
135 24 : for (; idx_chars != 0 && i < len; i++) {
136 0 : switch (str[i]) {
137 0 : case SCOPE_DELIMITER:
138 : case ':':
139 0 : return NULL;
140 0 : default:
141 0 : buf[i] = str[i];
142 0 : idx_chars += 1;
143 0 : break;
144 : }
145 : }
146 :
147 24 : if (idx_chars == 1) {
148 0 : return NULL;
149 : }
150 :
151 24 : buf[i] = '\0';
152 24 : *_len = len;
153 24 : return buf;
154 : }
155 :
156 : /**
157 : * Wrap getaddrinfo...
158 : */
159 1029821 : bool interpret_string_addr_internal(struct addrinfo **ppres,
160 : const char *str, int flags)
161 : {
162 69419 : int ret;
163 69419 : struct addrinfo hints;
164 : #if defined(HAVE_IPV6)
165 1029821 : char addr[INET6_ADDRSTRLEN*2] = { 0, };
166 1029821 : unsigned int scope_id = 0;
167 1029821 : size_t len = strlen(str);
168 : #endif
169 :
170 1029821 : ZERO_STRUCT(hints);
171 :
172 : /* By default make sure it supports TCP. */
173 1029821 : hints.ai_socktype = SOCK_STREAM;
174 :
175 : /* always try as a numeric host first. This prevents unnecessary name
176 : * lookups, and also ensures we accept IPv6 addresses */
177 1029821 : hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
178 :
179 : #if defined(HAVE_IPV6)
180 1029821 : if (len < sizeof(addr)) {
181 1029821 : char *p = NULL;
182 :
183 1029821 : p = normalize_ipv6_literal(str, addr, &len);
184 1029821 : if (p != NULL) {
185 8 : hints.ai_family = AF_INET6;
186 8 : str = p;
187 : }
188 : }
189 :
190 1029821 : if (strchr_m(str, ':')) {
191 198602 : char *p = strchr_m(str, SCOPE_DELIMITER);
192 :
193 : /*
194 : * Cope with link-local.
195 : * This is IP:v6:addr%ifname.
196 : */
197 :
198 198602 : if (p && (p > str) && ((scope_id = if_nametoindex(p+1)) != 0)) {
199 : /* Length of string we want to copy.
200 : This is IP:v6:addr (removing the %ifname).
201 : */
202 0 : len = PTR_DIFF(p,str);
203 :
204 0 : if (len+1 > sizeof(addr)) {
205 : /* string+nul too long for array. */
206 0 : return false;
207 : }
208 0 : if (str != addr) {
209 0 : memcpy(addr, str, len);
210 : }
211 0 : addr[len] = '\0';
212 :
213 0 : str = addr;
214 : }
215 : }
216 : #endif
217 :
218 1029821 : ret = getaddrinfo(str, NULL, &hints, ppres);
219 1029821 : if (ret == 0) {
220 : #if defined(HAVE_IPV6)
221 962838 : struct sockaddr_in6 *ps6 = NULL;
222 :
223 962838 : if (scope_id == 0) {
224 936563 : return true;
225 : }
226 0 : if (ppres == NULL) {
227 0 : return true;
228 : }
229 0 : if ((*ppres) == NULL) {
230 0 : return true;
231 : }
232 0 : if ((*ppres)->ai_addr->sa_family != AF_INET6) {
233 0 : return true;
234 : }
235 :
236 0 : ps6 = (struct sockaddr_in6 *)(*ppres)->ai_addr;
237 :
238 0 : if (IN6_IS_ADDR_LINKLOCAL(&ps6->sin6_addr) &&
239 0 : ps6->sin6_scope_id == 0) {
240 0 : ps6->sin6_scope_id = scope_id;
241 : }
242 : #endif
243 :
244 0 : return true;
245 : }
246 :
247 66983 : hints.ai_flags = flags;
248 :
249 : /* Linux man page on getaddrinfo() says port will be
250 : uninitialized when service string is NULL */
251 :
252 66983 : ret = getaddrinfo(str, NULL,
253 : &hints,
254 : ppres);
255 :
256 66983 : if (ret) {
257 90 : DEBUG(3, ("interpret_string_addr_internal: "
258 : "getaddrinfo failed for name %s (flags %d) [%s]\n",
259 : str, flags, gai_strerror(ret)));
260 90 : return false;
261 : }
262 23749 : return true;
263 : }
264 :
265 : /*******************************************************************
266 : Map a text hostname or IP address (IPv4 or IPv6) into a
267 : struct sockaddr_storage. Takes a flag which allows it to
268 : prefer an IPv4 address (needed for DC's).
269 : ******************************************************************/
270 :
271 960090 : static bool interpret_string_addr_pref(struct sockaddr_storage *pss,
272 : const char *str,
273 : int flags,
274 : bool prefer_ipv4)
275 : {
276 960090 : struct addrinfo *res = NULL;
277 26273 : int int_flags;
278 :
279 960090 : zero_sockaddr(pss);
280 :
281 960090 : if (flags & AI_NUMERICHOST) {
282 70905 : int_flags = flags;
283 : } else {
284 882269 : int_flags = flags|AI_ADDRCONFIG;
285 : }
286 :
287 960090 : if (!interpret_string_addr_internal(&res, str, int_flags)) {
288 39 : return false;
289 : }
290 960051 : if (!res) {
291 0 : return false;
292 : }
293 :
294 960051 : if (prefer_ipv4) {
295 : struct addrinfo *p;
296 :
297 0 : for (p = res; p; p = p->ai_next) {
298 0 : if (p->ai_family == AF_INET) {
299 0 : memcpy(pss, p->ai_addr, p->ai_addrlen);
300 0 : break;
301 : }
302 : }
303 0 : if (p == NULL) {
304 : /* Copy the first sockaddr. */
305 0 : memcpy(pss, res->ai_addr, res->ai_addrlen);
306 : }
307 : } else {
308 : /* Copy the first sockaddr. */
309 960051 : memcpy(pss, res->ai_addr, res->ai_addrlen);
310 : }
311 :
312 960051 : freeaddrinfo(res);
313 960051 : return true;
314 : }
315 :
316 : /*******************************************************************
317 : Map a text hostname or IP address (IPv4 or IPv6) into a
318 : struct sockaddr_storage. Address agnostic version.
319 : ******************************************************************/
320 :
321 960090 : bool interpret_string_addr(struct sockaddr_storage *pss,
322 : const char *str,
323 : int flags)
324 : {
325 960090 : return interpret_string_addr_pref(pss,
326 : str,
327 : flags,
328 : false);
329 : }
330 :
331 : /*******************************************************************
332 : Map a text hostname or IP address (IPv4 or IPv6) into a
333 : struct sockaddr_storage. Version that prefers IPv4.
334 : ******************************************************************/
335 :
336 0 : bool interpret_string_addr_prefer_ipv4(struct sockaddr_storage *pss,
337 : const char *str,
338 : int flags)
339 : {
340 0 : return interpret_string_addr_pref(pss,
341 : str,
342 : flags,
343 : true);
344 : }
345 :
346 : /**
347 : * Interpret an internet address or name into an IP address in 4 byte form.
348 : * RETURNS IN NETWORK BYTE ORDER (big endian).
349 : */
350 :
351 109819 : uint32_t interpret_addr(const char *str)
352 : {
353 44479 : uint32_t ret;
354 :
355 : /* If it's in the form of an IP address then
356 : * get the lib to interpret it */
357 109819 : if (is_ipaddress_v4(str)) {
358 1333 : struct in_addr dest;
359 :
360 66544 : if (inet_pton(AF_INET, str, &dest) <= 0) {
361 : /* Error - this shouldn't happen ! */
362 0 : DEBUG(0,("interpret_addr: inet_pton failed "
363 : "host %s\n",
364 : str));
365 0 : return 0;
366 : }
367 66544 : ret = dest.s_addr; /* NETWORK BYTE ORDER ! */
368 : } else {
369 : /* Otherwise assume it's a network name of some sort and use
370 : getaddrinfo. */
371 43275 : struct addrinfo *res = NULL;
372 43275 : struct addrinfo *res_list = NULL;
373 43275 : if (!interpret_string_addr_internal(&res_list,
374 : str,
375 : AI_ADDRCONFIG)) {
376 39 : DEBUG(3,("interpret_addr: Unknown host. %s\n",str));
377 105 : return 0;
378 : }
379 :
380 : /* Find the first IPv4 address. */
381 86446 : for (res = res_list; res; res = res->ai_next) {
382 86380 : if (res->ai_family != AF_INET) {
383 43210 : continue;
384 : }
385 43170 : if (res->ai_addr == NULL) {
386 0 : continue;
387 : }
388 26 : break;
389 : }
390 43236 : if(res == NULL) {
391 66 : DEBUG(3,("interpret_addr: host address is "
392 : "invalid for host %s\n",str));
393 66 : if (res_list) {
394 66 : freeaddrinfo(res_list);
395 : }
396 66 : return 0;
397 : }
398 43170 : memcpy((char *)&ret,
399 43170 : &((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr,
400 : sizeof(ret));
401 43170 : if (res_list) {
402 43170 : freeaddrinfo(res_list);
403 : }
404 : }
405 :
406 : /* This is so bogus - all callers need fixing... JRA. */
407 109714 : if (ret == (uint32_t)-1) {
408 0 : return 0;
409 : }
410 :
411 65237 : return ret;
412 : }
413 :
414 : /**
415 : A convenient addition to interpret_addr().
416 : **/
417 109736 : _PUBLIC_ struct in_addr interpret_addr2(const char *str)
418 : {
419 44479 : struct in_addr ret;
420 109736 : uint32_t a = interpret_addr(str);
421 109736 : ret.s_addr = a;
422 109736 : return ret;
423 : }
424 :
425 : /**
426 : Check if an IP is the 0.0.0.0.
427 : **/
428 :
429 52604 : _PUBLIC_ bool is_zero_ip_v4(struct in_addr ip)
430 : {
431 52604 : return ip.s_addr == 0;
432 : }
433 :
434 : /**
435 : Are two IPs on the same subnet?
436 : **/
437 :
438 19574 : _PUBLIC_ bool same_net_v4(struct in_addr ip1, struct in_addr ip2, struct in_addr mask)
439 : {
440 1072 : uint32_t net1,net2,nmask;
441 :
442 19574 : nmask = ntohl(mask.s_addr);
443 19574 : net1 = ntohl(ip1.s_addr);
444 19574 : net2 = ntohl(ip2.s_addr);
445 :
446 19574 : return((net1 & nmask) == (net2 & nmask));
447 : }
448 :
449 : /**
450 : * Return true if a string could be an IPv4 address.
451 : */
452 :
453 526840 : bool is_ipaddress_v4(const char *str)
454 : {
455 526840 : int ret = -1;
456 53247 : struct in_addr dest;
457 :
458 526840 : ret = inet_pton(AF_INET, str, &dest);
459 526840 : if (ret > 0) {
460 166254 : return true;
461 : }
462 310625 : return false;
463 : }
464 :
465 228675 : bool is_ipv6_literal(const char *str)
466 : {
467 : #if defined(HAVE_IPV6)
468 228675 : char buf[INET6_ADDRSTRLEN*2] = { 0, };
469 228675 : size_t len = strlen(str);
470 228675 : char *p = NULL;
471 :
472 228675 : if (len >= sizeof(buf)) {
473 0 : return false;
474 : }
475 :
476 228675 : p = normalize_ipv6_literal(str, buf, &len);
477 228675 : if (p == NULL) {
478 228659 : return false;
479 : }
480 :
481 16 : return true;
482 : #else
483 : return false;
484 : #endif
485 : }
486 :
487 : /**
488 : * Return true if a string could be a IPv6 address.
489 : */
490 :
491 473897 : bool is_ipaddress_v6(const char *str)
492 : {
493 : #if defined(HAVE_IPV6)
494 473897 : int ret = -1;
495 473897 : char *p = NULL;
496 473897 : char buf[INET6_ADDRSTRLEN] = { 0, };
497 9241 : size_t len;
498 473897 : const char *addr = str;
499 473897 : const char *idxs = NULL;
500 473897 : unsigned int idx = 0;
501 9241 : struct in6_addr ip6;
502 :
503 473897 : p = strchr_m(str, ':');
504 473897 : if (p == NULL) {
505 228675 : return is_ipv6_literal(str);
506 : }
507 :
508 245222 : p = strchr_m(str, SCOPE_DELIMITER);
509 245222 : if (p && (p > str)) {
510 8 : len = PTR_DIFF(p, str);
511 8 : idxs = p + 1;
512 : } else {
513 245214 : len = strlen(str);
514 : }
515 :
516 245222 : if (len >= sizeof(buf)) {
517 94 : return false;
518 : }
519 245128 : if (idxs != NULL) {
520 8 : strncpy(buf, str, len);
521 8 : addr = buf;
522 : }
523 :
524 : /*
525 : * Cope with link-local.
526 : * This is IP:v6:addr%ifidx.
527 : */
528 245128 : if (idxs != NULL) {
529 8 : char c;
530 :
531 8 : ret = sscanf(idxs, "%5u%c", &idx, &c);
532 8 : if (ret != 1) {
533 0 : idx = 0;
534 : }
535 :
536 8 : if (idx > 0 && idx < UINT16_MAX) {
537 : /* a valid index */
538 8 : idxs = NULL;
539 : }
540 : }
541 :
542 : /*
543 : * Cope with link-local.
544 : * This is IP:v6:addr%ifname.
545 : */
546 245128 : if (idxs != NULL) {
547 0 : idx = if_nametoindex(idxs);
548 :
549 0 : if (idx > 0) {
550 : /* a valid index */
551 0 : idxs = NULL;
552 : }
553 : }
554 :
555 245128 : if (idxs != NULL) {
556 0 : return false;
557 : }
558 :
559 245128 : ret = inet_pton(AF_INET6, addr, &ip6);
560 245128 : if (ret <= 0) {
561 186482 : return false;
562 : }
563 :
564 56933 : return true;
565 : #else
566 : return false;
567 : #endif
568 : }
569 :
570 : /**
571 : * Return true if a string could be an IPv4 or IPv6 address.
572 : */
573 :
574 207083 : bool is_ipaddress(const char *str)
575 : {
576 207083 : return is_ipaddress_v4(str) || is_ipaddress_v6(str);
577 : }
578 :
579 : /**
580 : * Is a sockaddr a broadcast address ?
581 : */
582 :
583 34141 : bool is_broadcast_addr(const struct sockaddr *pss)
584 : {
585 : #if defined(HAVE_IPV6)
586 34141 : if (pss->sa_family == AF_INET6) {
587 16444 : const struct in6_addr *sin6 =
588 : &((const struct sockaddr_in6 *)pss)->sin6_addr;
589 16444 : return IN6_IS_ADDR_MULTICAST(sin6);
590 : }
591 : #endif
592 17697 : if (pss->sa_family == AF_INET) {
593 0 : uint32_t addr =
594 17697 : ntohl(((const struct sockaddr_in *)pss)->sin_addr.s_addr);
595 17697 : return addr == INADDR_BROADCAST;
596 : }
597 0 : return false;
598 : }
599 :
600 : /**
601 : * Check if an IPv7 is 127.0.0.1
602 : */
603 6939 : bool is_loopback_ip_v4(struct in_addr ip)
604 : {
605 6 : struct in_addr a;
606 6939 : a.s_addr = htonl(INADDR_LOOPBACK);
607 6939 : return(ip.s_addr == a.s_addr);
608 : }
609 :
610 : /**
611 : * Check if a struct sockaddr is the loopback address.
612 : */
613 833 : bool is_loopback_addr(const struct sockaddr *pss)
614 : {
615 : #if defined(HAVE_IPV6)
616 833 : if (pss->sa_family == AF_INET6) {
617 332 : const struct in6_addr *pin6 =
618 : &((const struct sockaddr_in6 *)pss)->sin6_addr;
619 332 : return IN6_IS_ADDR_LOOPBACK(pin6);
620 : }
621 : #endif
622 501 : if (pss->sa_family == AF_INET) {
623 501 : const struct in_addr *pin = &((const struct sockaddr_in *)pss)->sin_addr;
624 501 : return is_loopback_ip_v4(*pin);
625 : }
626 0 : return false;
627 : }
628 :
629 : /**
630 : * Check if a struct sockaddr has an unspecified address.
631 : */
632 93005 : bool is_zero_addr(const struct sockaddr_storage *pss)
633 : {
634 : #if defined(HAVE_IPV6)
635 93005 : if (pss->ss_family == AF_INET6) {
636 40415 : const struct in6_addr *pin6 =
637 : &((const struct sockaddr_in6 *)pss)->sin6_addr;
638 40417 : return IN6_IS_ADDR_UNSPECIFIED(pin6);
639 : }
640 : #endif
641 52590 : if (pss->ss_family == AF_INET) {
642 52590 : const struct in_addr *pin = &((const struct sockaddr_in *)pss)->sin_addr;
643 52590 : return is_zero_ip_v4(*pin);
644 : }
645 0 : return false;
646 : }
647 :
648 : /**
649 : * Set an IP to 0.0.0.0.
650 : */
651 210 : void zero_ip_v4(struct in_addr *ip)
652 : {
653 210 : ZERO_STRUCTP(ip);
654 210 : }
655 :
656 226 : bool is_linklocal_addr(const struct sockaddr_storage *pss)
657 : {
658 : #ifdef HAVE_IPV6
659 226 : if (pss->ss_family == AF_INET6) {
660 48 : const struct in6_addr *pin6 =
661 : &((const struct sockaddr_in6 *)pss)->sin6_addr;
662 48 : return IN6_IS_ADDR_LINKLOCAL(pin6);
663 : }
664 : #endif
665 178 : if (pss->ss_family == AF_INET) {
666 178 : const struct in_addr *pin =
667 : &((const struct sockaddr_in *)pss)->sin_addr;
668 0 : struct in_addr ll_addr;
669 0 : struct in_addr mask_addr;
670 :
671 : /* 169.254.0.0/16, is link local, see RFC 3927 */
672 178 : ll_addr.s_addr = 0xa9fe0000;
673 178 : mask_addr.s_addr = 0xffff0000;
674 178 : return same_net_v4(*pin, ll_addr, mask_addr);
675 : }
676 0 : return false;
677 : }
678 :
679 : /**
680 : * Convert an IPv4 struct in_addr to a struct sockaddr_storage.
681 : */
682 8878 : void in_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
683 : struct in_addr ip)
684 : {
685 8878 : struct sockaddr_in *sa = (struct sockaddr_in *)ss;
686 8878 : ZERO_STRUCTP(ss);
687 8878 : sa->sin_family = AF_INET;
688 8878 : sa->sin_addr = ip;
689 8878 : }
690 :
691 : #if defined(HAVE_IPV6)
692 : /**
693 : * Convert an IPv6 struct in_addr to a struct sockaddr_storage.
694 : */
695 0 : void in6_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
696 : struct in6_addr ip)
697 : {
698 0 : struct sockaddr_in6 *sa = (struct sockaddr_in6 *)ss;
699 0 : memset(ss, '\0', sizeof(*ss));
700 0 : sa->sin6_family = AF_INET6;
701 0 : sa->sin6_addr = ip;
702 0 : }
703 : #endif
704 :
705 : /**
706 : * Are two IPs on the same subnet?
707 : */
708 21677 : bool same_net(const struct sockaddr *ip1,
709 : const struct sockaddr *ip2,
710 : const struct sockaddr *mask)
711 : {
712 21677 : if (ip1->sa_family != ip2->sa_family) {
713 : /* Never on the same net. */
714 7368 : return false;
715 : }
716 :
717 : #if defined(HAVE_IPV6)
718 13181 : if (ip1->sa_family == AF_INET6) {
719 2081 : struct sockaddr_in6 ip1_6 = *(const struct sockaddr_in6 *)ip1;
720 2081 : struct sockaddr_in6 ip2_6 = *(const struct sockaddr_in6 *)ip2;
721 2081 : struct sockaddr_in6 mask_6 = *(const struct sockaddr_in6 *)mask;
722 2081 : char *p1 = (char *)&ip1_6.sin6_addr;
723 2081 : char *p2 = (char *)&ip2_6.sin6_addr;
724 2081 : char *m = (char *)&mask_6.sin6_addr;
725 172 : size_t i;
726 :
727 35377 : for (i = 0; i < sizeof(struct in6_addr); i++) {
728 33296 : *p1++ &= *m;
729 33296 : *p2++ &= *m;
730 33296 : m++;
731 : }
732 2081 : return (memcmp(&ip1_6.sin6_addr,
733 : &ip2_6.sin6_addr,
734 2081 : sizeof(struct in6_addr)) == 0);
735 : }
736 : #endif
737 11100 : if (ip1->sa_family == AF_INET) {
738 11100 : return same_net_v4(((const struct sockaddr_in *)ip1)->sin_addr,
739 : ((const struct sockaddr_in *)ip2)->sin_addr,
740 : ((const struct sockaddr_in *)mask)->sin_addr);
741 : }
742 0 : return false;
743 : }
744 :
745 : /**
746 : * Are two sockaddr 's the same family and address ? Ignore port etc.
747 : */
748 :
749 4095343 : bool sockaddr_equal(const struct sockaddr *ip1,
750 : const struct sockaddr *ip2)
751 : {
752 4095343 : if (ip1->sa_family != ip2->sa_family) {
753 : /* Never the same. */
754 710231 : return false;
755 : }
756 :
757 : #if defined(HAVE_IPV6)
758 3368560 : if (ip1->sa_family == AF_INET6) {
759 338956 : return (memcmp(&((const struct sockaddr_in6 *)ip1)->sin6_addr,
760 338956 : &((const struct sockaddr_in6 *)ip2)->sin6_addr,
761 338956 : sizeof(struct in6_addr)) == 0);
762 : }
763 : #endif
764 3029604 : if (ip1->sa_family == AF_INET) {
765 3029604 : return (memcmp(&((const struct sockaddr_in *)ip1)->sin_addr,
766 3029604 : &((const struct sockaddr_in *)ip2)->sin_addr,
767 3029604 : sizeof(struct in_addr)) == 0);
768 : }
769 0 : return false;
770 : }
771 :
772 : /**
773 : * Is an IP address the INADDR_ANY or in6addr_any value ?
774 : */
775 877336 : bool is_address_any(const struct sockaddr *psa)
776 : {
777 : #if defined(HAVE_IPV6)
778 877336 : if (psa->sa_family == AF_INET6) {
779 169090 : const struct sockaddr_in6 *si6 = (const struct sockaddr_in6 *)psa;
780 169090 : if (memcmp(&in6addr_any,
781 169090 : &si6->sin6_addr,
782 : sizeof(in6addr_any)) == 0) {
783 0 : return true;
784 : }
785 169090 : return false;
786 : }
787 : #endif
788 708246 : if (psa->sa_family == AF_INET) {
789 708246 : const struct sockaddr_in *si = (const struct sockaddr_in *)psa;
790 708246 : if (si->sin_addr.s_addr == INADDR_ANY) {
791 0 : return true;
792 : }
793 708246 : return false;
794 : }
795 0 : return false;
796 : }
797 :
798 2853 : void set_sockaddr_port(struct sockaddr *psa, uint16_t port)
799 : {
800 : #if defined(HAVE_IPV6)
801 2853 : if (psa->sa_family == AF_INET6) {
802 2 : ((struct sockaddr_in6 *)psa)->sin6_port = htons(port);
803 : }
804 : #endif
805 2853 : if (psa->sa_family == AF_INET) {
806 2851 : ((struct sockaddr_in *)psa)->sin_port = htons(port);
807 : }
808 2853 : }
809 :
810 :
811 : /****************************************************************************
812 : Get a port number in host byte order from a sockaddr_storage.
813 : ****************************************************************************/
814 :
815 857 : uint16_t get_sockaddr_port(const struct sockaddr_storage *pss)
816 : {
817 857 : uint16_t port = 0;
818 :
819 857 : if (pss->ss_family != AF_INET) {
820 : #if defined(HAVE_IPV6)
821 : /* IPv6 */
822 0 : const struct sockaddr_in6 *sa6 =
823 : (const struct sockaddr_in6 *)pss;
824 0 : port = ntohs(sa6->sin6_port);
825 : #endif
826 : } else {
827 857 : const struct sockaddr_in *sa =
828 : (const struct sockaddr_in *)pss;
829 857 : port = ntohs(sa->sin_port);
830 : }
831 857 : return port;
832 : }
833 :
834 : /****************************************************************************
835 : Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
836 : ****************************************************************************/
837 :
838 2297558 : char *print_sockaddr_len(char *dest,
839 : size_t destlen,
840 : const struct sockaddr *psa,
841 : socklen_t psalen)
842 : {
843 2297558 : if (destlen > 0) {
844 2297558 : dest[0] = '\0';
845 : }
846 2297558 : (void)sys_getnameinfo(psa,
847 : psalen,
848 : dest, destlen,
849 : NULL, 0,
850 : NI_NUMERICHOST);
851 2297558 : return dest;
852 : }
853 :
854 : /****************************************************************************
855 : Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
856 : ****************************************************************************/
857 :
858 2297558 : char *print_sockaddr(char *dest,
859 : size_t destlen,
860 : const struct sockaddr_storage *psa)
861 : {
862 2297558 : return print_sockaddr_len(dest, destlen, (const struct sockaddr *)psa,
863 : sizeof(struct sockaddr_storage));
864 : }
865 :
866 : /****************************************************************************
867 : Print out a canonical IPv4 or IPv6 address from a struct sockaddr_storage.
868 : ****************************************************************************/
869 :
870 448 : char *print_canonical_sockaddr(TALLOC_CTX *ctx,
871 : const struct sockaddr_storage *pss)
872 : {
873 0 : char addr[INET6_ADDRSTRLEN];
874 448 : char *dest = NULL;
875 0 : int ret;
876 :
877 : /* Linux getnameinfo() man pages says port is uninitialized if
878 : service name is NULL. */
879 :
880 448 : ret = sys_getnameinfo((const struct sockaddr *)pss,
881 : sizeof(struct sockaddr_storage),
882 : addr, sizeof(addr),
883 : NULL, 0,
884 : NI_NUMERICHOST);
885 448 : if (ret != 0) {
886 0 : return NULL;
887 : }
888 :
889 448 : if (pss->ss_family != AF_INET) {
890 : #if defined(HAVE_IPV6)
891 188 : dest = talloc_asprintf(ctx, "[%s]", addr);
892 : #else
893 : return NULL;
894 : #endif
895 : } else {
896 260 : dest = talloc_asprintf(ctx, "%s", addr);
897 : }
898 :
899 448 : return dest;
900 : }
901 :
902 : enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
903 :
904 : typedef struct smb_socket_option {
905 : const char *name;
906 : int level;
907 : int option;
908 : int value;
909 : int opttype;
910 : } smb_socket_option;
911 :
912 : static const smb_socket_option socket_options[] = {
913 : {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
914 : {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
915 : {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
916 : #ifdef TCP_NODELAY
917 : {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
918 : #endif
919 : #ifdef TCP_KEEPCNT
920 : {"TCP_KEEPCNT", IPPROTO_TCP, TCP_KEEPCNT, 0, OPT_INT},
921 : #endif
922 : #ifdef TCP_KEEPIDLE
923 : {"TCP_KEEPIDLE", IPPROTO_TCP, TCP_KEEPIDLE, 0, OPT_INT},
924 : #endif
925 : #ifdef TCP_KEEPINTVL
926 : {"TCP_KEEPINTVL", IPPROTO_TCP, TCP_KEEPINTVL, 0, OPT_INT},
927 : #endif
928 : #ifdef IPTOS_LOWDELAY
929 : {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
930 : #endif
931 : #ifdef IPTOS_THROUGHPUT
932 : {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
933 : #endif
934 : #ifdef SO_REUSEPORT
935 : {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
936 : #endif
937 : #ifdef SO_SNDBUF
938 : {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
939 : #endif
940 : #ifdef SO_RCVBUF
941 : {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
942 : #endif
943 : #ifdef SO_SNDLOWAT
944 : {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
945 : #endif
946 : #ifdef SO_RCVLOWAT
947 : {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
948 : #endif
949 : #ifdef SO_SNDTIMEO
950 : {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
951 : #endif
952 : #ifdef SO_RCVTIMEO
953 : {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
954 : #endif
955 : #ifdef TCP_FASTACK
956 : {"TCP_FASTACK", IPPROTO_TCP, TCP_FASTACK, 0, OPT_INT},
957 : #endif
958 : #ifdef TCP_QUICKACK
959 : {"TCP_QUICKACK", IPPROTO_TCP, TCP_QUICKACK, 0, OPT_BOOL},
960 : #endif
961 : #ifdef TCP_NODELAYACK
962 : {"TCP_NODELAYACK", IPPROTO_TCP, TCP_NODELAYACK, 0, OPT_BOOL},
963 : #endif
964 : #ifdef TCP_KEEPALIVE_THRESHOLD
965 : {"TCP_KEEPALIVE_THRESHOLD", IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, 0, OPT_INT},
966 : #endif
967 : #ifdef TCP_KEEPALIVE_ABORT_THRESHOLD
968 : {"TCP_KEEPALIVE_ABORT_THRESHOLD", IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, 0, OPT_INT},
969 : #endif
970 : #ifdef TCP_DEFER_ACCEPT
971 : {"TCP_DEFER_ACCEPT", IPPROTO_TCP, TCP_DEFER_ACCEPT, 0, OPT_INT},
972 : #endif
973 : #ifdef TCP_USER_TIMEOUT
974 : {"TCP_USER_TIMEOUT", IPPROTO_TCP, TCP_USER_TIMEOUT, 0, OPT_INT},
975 : #endif
976 : {NULL,0,0,0,0}};
977 :
978 : /****************************************************************************
979 : Print socket options.
980 : ****************************************************************************/
981 :
982 115283 : static void print_socket_options(TALLOC_CTX *ctx, int s)
983 : {
984 115283 : const smb_socket_option *p = &socket_options[0];
985 115283 : char *str = NULL;
986 :
987 115283 : if (DEBUGLEVEL < 5) {
988 115275 : return;
989 : }
990 :
991 8 : str = talloc_strdup(ctx, "");
992 8 : if (str == NULL) {
993 0 : DBG_WARNING("talloc failed\n");
994 0 : goto done;
995 : }
996 :
997 160 : for (; p->name != NULL; p++) {
998 0 : int ret, val;
999 152 : socklen_t vlen = sizeof(val);
1000 :
1001 152 : ret = getsockopt(s, p->level, p->option, (void *)&val, &vlen);
1002 152 : if (ret == -1) {
1003 64 : DBG_INFO("Could not test socket option %s: %s.\n",
1004 : p->name, strerror(errno));
1005 64 : continue;
1006 : }
1007 :
1008 88 : talloc_asprintf_addbuf(
1009 : &str,
1010 : "%s%s=%d",
1011 88 : str[0] != '\0' ? ", " : "",
1012 88 : p->name,
1013 : val);
1014 : }
1015 :
1016 8 : DEBUG(5, ("socket options: %s\n", str));
1017 8 : done:
1018 8 : TALLOC_FREE(str);
1019 : }
1020 :
1021 : /****************************************************************************
1022 : Set user socket options.
1023 : ****************************************************************************/
1024 :
1025 115283 : void set_socket_options(int fd, const char *options)
1026 : {
1027 115283 : TALLOC_CTX *ctx = talloc_new(NULL);
1028 2810 : char *tok;
1029 :
1030 230566 : while (next_token_talloc(ctx, &options, &tok," \t,")) {
1031 115283 : int ret=0,i;
1032 115283 : int value = 1;
1033 2810 : char *p;
1034 115283 : bool got_value = false;
1035 :
1036 115283 : if ((p = strchr_m(tok,'='))) {
1037 1764 : *p = 0;
1038 1764 : value = atoi(p+1);
1039 1764 : got_value = true;
1040 : }
1041 :
1042 343100 : for (i=0;socket_options[i].name;i++)
1043 343100 : if (strequal(socket_options[i].name,tok))
1044 112473 : break;
1045 :
1046 115283 : if (!socket_options[i].name) {
1047 0 : DEBUG(0,("Unknown socket option %s\n",tok));
1048 0 : continue;
1049 : }
1050 :
1051 115283 : switch (socket_options[i].opttype) {
1052 115283 : case OPT_BOOL:
1053 : case OPT_INT:
1054 115283 : ret = setsockopt(fd,socket_options[i].level,
1055 115283 : socket_options[i].option,
1056 : (char *)&value,sizeof(int));
1057 115283 : break;
1058 :
1059 0 : case OPT_ON:
1060 0 : if (got_value)
1061 0 : DEBUG(0,("syntax error - %s "
1062 : "does not take a value\n",tok));
1063 :
1064 : {
1065 0 : int on = socket_options[i].value;
1066 0 : ret = setsockopt(fd,socket_options[i].level,
1067 0 : socket_options[i].option,
1068 : (char *)&on,sizeof(int));
1069 : }
1070 0 : break;
1071 : }
1072 :
1073 115283 : if (ret != 0) {
1074 : /* be aware that some systems like Solaris return
1075 : * EINVAL to a setsockopt() call when the client
1076 : * sent a RST previously - no need to worry */
1077 0 : DEBUG(2,("Failed to set socket option %s (Error %s)\n",
1078 : tok, strerror(errno) ));
1079 : }
1080 : }
1081 :
1082 115283 : print_socket_options(ctx, fd);
1083 115283 : TALLOC_FREE(ctx);
1084 115283 : }
1085 :
1086 : /*
1087 : * Utility function that copes only with AF_INET and AF_INET6
1088 : * as that's all we're going to get out of DNS / NetBIOS / WINS
1089 : * name resolution functions.
1090 : */
1091 :
1092 22399 : bool sockaddr_storage_to_samba_sockaddr(
1093 : struct samba_sockaddr *sa, const struct sockaddr_storage *ss)
1094 : {
1095 22399 : sa->u.ss = *ss;
1096 :
1097 22399 : switch (ss->ss_family) {
1098 12608 : case AF_INET:
1099 12608 : sa->sa_socklen = sizeof(struct sockaddr_in);
1100 12608 : break;
1101 : #ifdef HAVE_IPV6
1102 9791 : case AF_INET6:
1103 9791 : sa->sa_socklen = sizeof(struct sockaddr_in6);
1104 9791 : break;
1105 : #endif
1106 0 : default:
1107 0 : return false;
1108 : }
1109 22399 : return true;
1110 : }
1111 :
1112 779 : bool samba_sockaddr_set_port(struct samba_sockaddr *sa, uint16_t port)
1113 : {
1114 779 : if (sa->u.sa.sa_family == AF_INET) {
1115 659 : sa->u.in.sin_port = htons(port);
1116 659 : return true;
1117 : }
1118 : #ifdef HAVE_IPV6
1119 120 : if (sa->u.sa.sa_family == AF_INET6) {
1120 120 : sa->u.in6.sin6_port = htons(port);
1121 120 : return true;
1122 : }
1123 : #endif
1124 0 : return false;
1125 : }
1126 :
1127 1596 : bool samba_sockaddr_get_port(const struct samba_sockaddr *sa, uint16_t *port)
1128 : {
1129 1596 : if (sa->u.sa.sa_family == AF_INET) {
1130 1596 : *port = ntohs(sa->u.in.sin_port);
1131 1596 : return true;
1132 : }
1133 : #ifdef HAVE_IPV6
1134 0 : if (sa->u.sa.sa_family == AF_INET6) {
1135 0 : *port = ntohs(sa->u.in6.sin6_port);
1136 0 : return true;
1137 : }
1138 : #endif
1139 0 : return false;
1140 : }
1141 :
1142 190791 : int samba_socket_poll_error(int fd)
1143 : {
1144 190791 : struct pollfd pfd = {
1145 : .fd = fd,
1146 : #ifdef POLLRDHUP
1147 : .events = POLLRDHUP, /* POLLERR and POLLHUP are not needed */
1148 : #endif
1149 : };
1150 4291 : int ret;
1151 :
1152 190791 : errno = 0;
1153 190791 : ret = sys_poll_intr(&pfd, 1, 0);
1154 190791 : if (ret == 0) {
1155 4633 : return 0;
1156 : }
1157 185675 : if (ret != 1) {
1158 0 : return POLLNVAL;
1159 : }
1160 :
1161 185675 : if (pfd.revents & POLLERR) {
1162 911 : return POLLERR;
1163 : }
1164 184604 : if (pfd.revents & POLLHUP) {
1165 180956 : return POLLHUP;
1166 : }
1167 : #ifdef POLLRDHUP
1168 4 : if (pfd.revents & POLLRDHUP) {
1169 4 : return POLLRDHUP;
1170 : }
1171 : #endif
1172 :
1173 : /* should never be reached! */
1174 0 : return POLLNVAL;
1175 : }
1176 :
1177 1071 : int samba_socket_sock_error(int fd)
1178 : {
1179 1071 : int ret, error = 0;
1180 1071 : socklen_t len = sizeof(error);
1181 :
1182 : /*
1183 : * if no data is available check if the socket is in error state. For
1184 : * dgram sockets it's the way to return ICMP error messages of
1185 : * connected sockets to the caller.
1186 : */
1187 1071 : ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
1188 1071 : if (ret == -1) {
1189 0 : return ret;
1190 : }
1191 1071 : if (error != 0) {
1192 1071 : errno = error;
1193 1071 : return -1;
1194 : }
1195 0 : return 0;
1196 : }
1197 :
1198 190791 : int samba_socket_poll_or_sock_error(int fd)
1199 : {
1200 4291 : int ret;
1201 190791 : int poll_error = 0;
1202 :
1203 190791 : poll_error = samba_socket_poll_error(fd);
1204 190791 : if (poll_error == 0) {
1205 4633 : return 0;
1206 : }
1207 :
1208 : #ifdef POLLRDHUP
1209 185675 : if (poll_error == POLLRDHUP) {
1210 4 : errno = ECONNRESET;
1211 4 : return -1;
1212 : }
1213 : #endif
1214 :
1215 185671 : if (poll_error == POLLHUP) {
1216 184600 : errno = EPIPE;
1217 184600 : return -1;
1218 : }
1219 :
1220 : /*
1221 : * POLLERR and POLLNVAL fallback to
1222 : * getsockopt(fd, SOL_SOCKET, SO_ERROR)
1223 : * and force EPIPE as fallback.
1224 : */
1225 :
1226 1071 : errno = 0;
1227 1071 : ret = samba_socket_sock_error(fd);
1228 1071 : if (ret == 0) {
1229 0 : errno = EPIPE;
1230 : }
1231 :
1232 1071 : if (errno == 0) {
1233 0 : errno = EPIPE;
1234 : }
1235 :
1236 911 : return -1;
1237 : }
|