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 974120 : void zero_sockaddr(struct sockaddr_storage *pss)
42 : {
43 : /* Ensure we're at least a valid sockaddr-storage. */
44 974120 : *pss = (struct sockaddr_storage) { .ss_family = AF_INET };
45 974120 : }
46 :
47 1272075 : static char *normalize_ipv6_literal(const char *str, char *buf, size_t *_len)
48 : {
49 : #define IPv6_LITERAL_NET ".ipv6-literal.net"
50 1272075 : const size_t llen = sizeof(IPv6_LITERAL_NET) - 1;
51 1272075 : size_t len = *_len;
52 80975 : int cmp;
53 80975 : size_t i;
54 1272075 : size_t idx_chars = 0;
55 1272075 : size_t cnt_delimiter = 0;
56 1272075 : size_t cnt_chars = 0;
57 :
58 1272075 : if (len <= llen) {
59 974417 : return NULL;
60 : }
61 :
62 : /* ignore a trailing '.' */
63 220660 : if (str[len - 1] == '.') {
64 12 : len -= 1;
65 : }
66 :
67 220660 : len -= llen;
68 220660 : if (len >= INET6_ADDRSTRLEN) {
69 3165 : return NULL;
70 : }
71 217495 : if (len < 2) {
72 0 : return NULL;
73 : }
74 :
75 217495 : cmp = strncasecmp(&str[len], IPv6_LITERAL_NET, llen);
76 217495 : if (cmp != 0) {
77 213494 : 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 1042731 : bool interpret_string_addr_internal(struct addrinfo **ppres,
160 : const char *str, int flags)
161 : {
162 75158 : int ret;
163 75158 : struct addrinfo hints;
164 : #if defined(HAVE_IPV6)
165 1042731 : char addr[INET6_ADDRSTRLEN*2] = { 0, };
166 1042731 : unsigned int scope_id = 0;
167 1042731 : size_t len = strlen(str);
168 : #endif
169 :
170 1042731 : ZERO_STRUCT(hints);
171 :
172 : /* By default make sure it supports TCP. */
173 1042731 : 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 1042731 : hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
178 :
179 : #if defined(HAVE_IPV6)
180 1042731 : if (len < sizeof(addr)) {
181 1042731 : char *p = NULL;
182 :
183 1042731 : p = normalize_ipv6_literal(str, addr, &len);
184 1042731 : if (p != NULL) {
185 8 : hints.ai_family = AF_INET6;
186 8 : str = p;
187 : }
188 : }
189 :
190 1042731 : if (strchr_m(str, ':')) {
191 197447 : char *p = strchr_m(str, SCOPE_DELIMITER);
192 :
193 : /*
194 : * Cope with link-local.
195 : * This is IP:v6:addr%ifname.
196 : */
197 :
198 197447 : 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 1042731 : ret = getaddrinfo(str, NULL, &hints, ppres);
219 1042731 : if (ret == 0) {
220 : #if defined(HAVE_IPV6)
221 969594 : struct sockaddr_in6 *ps6 = NULL;
222 :
223 969594 : if (scope_id == 0) {
224 943319 : 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 73137 : hints.ai_flags = flags;
248 :
249 : /* Linux man page on getaddrinfo() says port will be
250 : uninitialized when service string is NULL */
251 :
252 73137 : ret = getaddrinfo(str, NULL,
253 : &hints,
254 : ppres);
255 :
256 73137 : if (ret) {
257 98 : DEBUG(3, ("interpret_string_addr_internal: "
258 : "getaddrinfo failed for name %s (flags %d) [%s]\n",
259 : str, flags, gai_strerror(ret)));
260 98 : return false;
261 : }
262 24156 : 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 966851 : static bool interpret_string_addr_pref(struct sockaddr_storage *pss,
272 : const char *str,
273 : int flags,
274 : bool prefer_ipv4)
275 : {
276 966851 : struct addrinfo *res = NULL;
277 26273 : int int_flags;
278 :
279 966851 : zero_sockaddr(pss);
280 :
281 966851 : if (flags & AI_NUMERICHOST) {
282 71362 : int_flags = flags;
283 : } else {
284 888573 : int_flags = flags|AI_ADDRCONFIG;
285 : }
286 :
287 966851 : if (!interpret_string_addr_internal(&res, str, int_flags)) {
288 43 : return false;
289 : }
290 966808 : if (!res) {
291 0 : return false;
292 : }
293 :
294 966808 : 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 966808 : memcpy(pss, res->ai_addr, res->ai_addrlen);
310 : }
311 :
312 966808 : freeaddrinfo(res);
313 966808 : 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 966851 : bool interpret_string_addr(struct sockaddr_storage *pss,
322 : const char *str,
323 : int flags)
324 : {
325 966851 : 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 116209 : uint32_t interpret_addr(const char *str)
352 : {
353 50218 : uint32_t ret;
354 :
355 : /* If it's in the form of an IP address then
356 : * get the lib to interpret it */
357 116209 : if (is_ipaddress_v4(str)) {
358 1333 : struct in_addr dest;
359 :
360 67192 : 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 67192 : 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 49017 : struct addrinfo *res = NULL;
372 49017 : struct addrinfo *res_list = NULL;
373 49017 : if (!interpret_string_addr_internal(&res_list,
374 : str,
375 : AI_ADDRCONFIG)) {
376 43 : DEBUG(3,("interpret_addr: Unknown host. %s\n",str));
377 108 : return 0;
378 : }
379 :
380 : /* Find the first IPv4 address. */
381 97922 : for (res = res_list; res; res = res->ai_next) {
382 97857 : if (res->ai_family != AF_INET) {
383 48948 : continue;
384 : }
385 48909 : if (res->ai_addr == NULL) {
386 0 : continue;
387 : }
388 26 : break;
389 : }
390 48974 : if(res == NULL) {
391 65 : DEBUG(3,("interpret_addr: host address is "
392 : "invalid for host %s\n",str));
393 65 : if (res_list) {
394 65 : freeaddrinfo(res_list);
395 : }
396 65 : return 0;
397 : }
398 48909 : memcpy((char *)&ret,
399 48909 : &((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr,
400 : sizeof(ret));
401 48909 : if (res_list) {
402 48909 : freeaddrinfo(res_list);
403 : }
404 : }
405 :
406 : /* This is so bogus - all callers need fixing... JRA. */
407 116101 : if (ret == (uint32_t)-1) {
408 0 : return 0;
409 : }
410 :
411 65885 : return ret;
412 : }
413 :
414 : /**
415 : A convenient addition to interpret_addr().
416 : **/
417 116107 : _PUBLIC_ struct in_addr interpret_addr2(const char *str)
418 : {
419 50218 : struct in_addr ret;
420 116107 : uint32_t a = interpret_addr(str);
421 116107 : ret.s_addr = a;
422 116107 : return ret;
423 : }
424 :
425 : /**
426 : Check if an IP is the 0.0.0.0.
427 : **/
428 :
429 52949 : _PUBLIC_ bool is_zero_ip_v4(struct in_addr ip)
430 : {
431 52949 : return ip.s_addr == 0;
432 : }
433 :
434 : /**
435 : Are two IPs on the same subnet?
436 : **/
437 :
438 21474 : _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 21474 : nmask = ntohl(mask.s_addr);
443 21474 : net1 = ntohl(ip1.s_addr);
444 21474 : net2 = ntohl(ip2.s_addr);
445 :
446 21474 : return((net1 & nmask) == (net2 & nmask));
447 : }
448 :
449 : /**
450 : * Return true if a string could be an IPv4 address.
451 : */
452 :
453 533884 : bool is_ipaddress_v4(const char *str)
454 : {
455 533884 : int ret = -1;
456 58986 : struct in_addr dest;
457 :
458 533884 : ret = inet_pton(AF_INET, str, &dest);
459 533884 : if (ret > 0) {
460 166683 : return true;
461 : }
462 311501 : return false;
463 : }
464 :
465 229344 : bool is_ipv6_literal(const char *str)
466 : {
467 : #if defined(HAVE_IPV6)
468 229344 : char buf[INET6_ADDRSTRLEN*2] = { 0, };
469 229344 : size_t len = strlen(str);
470 229344 : char *p = NULL;
471 :
472 229344 : if (len >= sizeof(buf)) {
473 0 : return false;
474 : }
475 :
476 229344 : p = normalize_ipv6_literal(str, buf, &len);
477 229344 : if (p == NULL) {
478 229328 : 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 465311 : bool is_ipaddress_v6(const char *str)
492 : {
493 : #if defined(HAVE_IPV6)
494 465311 : int ret = -1;
495 465311 : char *p = NULL;
496 465311 : char buf[INET6_ADDRSTRLEN] = { 0, };
497 9361 : size_t len;
498 465311 : const char *addr = str;
499 465311 : const char *idxs = NULL;
500 465311 : unsigned int idx = 0;
501 9361 : struct in6_addr ip6;
502 :
503 465311 : p = strchr_m(str, ':');
504 465311 : if (p == NULL) {
505 229344 : return is_ipv6_literal(str);
506 : }
507 :
508 235967 : p = strchr_m(str, SCOPE_DELIMITER);
509 235967 : if (p && (p > str)) {
510 8 : len = PTR_DIFF(p, str);
511 8 : idxs = p + 1;
512 : } else {
513 235959 : len = strlen(str);
514 : }
515 :
516 235967 : if (len >= sizeof(buf)) {
517 94 : return false;
518 : }
519 235873 : 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 235873 : 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 235873 : 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 235873 : if (idxs != NULL) {
556 0 : return false;
557 : }
558 :
559 235873 : ret = inet_pton(AF_INET6, addr, &ip6);
560 235873 : if (ret <= 0) {
561 176687 : return false;
562 : }
563 :
564 57413 : 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 206405 : bool is_ipaddress(const char *str)
575 : {
576 206405 : return is_ipaddress_v4(str) || is_ipaddress_v6(str);
577 : }
578 :
579 : /**
580 : * Is a sockaddr a broadcast address ?
581 : */
582 :
583 34115 : bool is_broadcast_addr(const struct sockaddr *pss)
584 : {
585 : #if defined(HAVE_IPV6)
586 34115 : if (pss->sa_family == AF_INET6) {
587 16436 : const struct in6_addr *sin6 =
588 : &((const struct sockaddr_in6 *)pss)->sin6_addr;
589 16436 : return IN6_IS_ADDR_MULTICAST(sin6);
590 : }
591 : #endif
592 17679 : if (pss->sa_family == AF_INET) {
593 0 : uint32_t addr =
594 17679 : ntohl(((const struct sockaddr_in *)pss)->sin_addr.s_addr);
595 17679 : return addr == INADDR_BROADCAST;
596 : }
597 0 : return false;
598 : }
599 :
600 : /**
601 : * Check if an IPv7 is 127.0.0.1
602 : */
603 7039 : bool is_loopback_ip_v4(struct in_addr ip)
604 : {
605 6 : struct in_addr a;
606 7039 : a.s_addr = htonl(INADDR_LOOPBACK);
607 7039 : return(ip.s_addr == a.s_addr);
608 : }
609 :
610 : /**
611 : * Check if a struct sockaddr is the loopback address.
612 : */
613 853 : bool is_loopback_addr(const struct sockaddr *pss)
614 : {
615 : #if defined(HAVE_IPV6)
616 853 : if (pss->sa_family == AF_INET6) {
617 340 : const struct in6_addr *pin6 =
618 : &((const struct sockaddr_in6 *)pss)->sin6_addr;
619 340 : return IN6_IS_ADDR_LOOPBACK(pin6);
620 : }
621 : #endif
622 513 : if (pss->sa_family == AF_INET) {
623 513 : const struct in_addr *pin = &((const struct sockaddr_in *)pss)->sin_addr;
624 513 : 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 93311 : bool is_zero_addr(const struct sockaddr_storage *pss)
633 : {
634 : #if defined(HAVE_IPV6)
635 93311 : if (pss->ss_family == AF_INET6) {
636 40362 : const struct in6_addr *pin6 =
637 : &((const struct sockaddr_in6 *)pss)->sin6_addr;
638 40364 : return IN6_IS_ADDR_UNSPECIFIED(pin6);
639 : }
640 : #endif
641 52949 : if (pss->ss_family == AF_INET) {
642 52949 : const struct in_addr *pin = &((const struct sockaddr_in *)pss)->sin_addr;
643 52949 : return is_zero_ip_v4(*pin);
644 : }
645 0 : if (pss->ss_family == AF_UNSPEC) {
646 0 : return true;
647 : }
648 0 : return false;
649 : }
650 :
651 : /**
652 : * Set an IP to 0.0.0.0.
653 : */
654 215 : void zero_ip_v4(struct in_addr *ip)
655 : {
656 215 : ZERO_STRUCTP(ip);
657 215 : }
658 :
659 226 : bool is_linklocal_addr(const struct sockaddr_storage *pss)
660 : {
661 : #ifdef HAVE_IPV6
662 226 : if (pss->ss_family == AF_INET6) {
663 48 : const struct in6_addr *pin6 =
664 : &((const struct sockaddr_in6 *)pss)->sin6_addr;
665 48 : return IN6_IS_ADDR_LINKLOCAL(pin6);
666 : }
667 : #endif
668 178 : if (pss->ss_family == AF_INET) {
669 178 : const struct in_addr *pin =
670 : &((const struct sockaddr_in *)pss)->sin_addr;
671 0 : struct in_addr ll_addr;
672 0 : struct in_addr mask_addr;
673 :
674 : /* 169.254.0.0/16, is link local, see RFC 3927 */
675 178 : ll_addr.s_addr = 0xa9fe0000;
676 178 : mask_addr.s_addr = 0xffff0000;
677 178 : return same_net_v4(*pin, ll_addr, mask_addr);
678 : }
679 0 : return false;
680 : }
681 :
682 : /**
683 : * Convert an IPv4 struct in_addr to a struct sockaddr_storage.
684 : */
685 9245 : void in_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
686 : struct in_addr ip)
687 : {
688 9245 : struct sockaddr_in *sa = (struct sockaddr_in *)ss;
689 9245 : ZERO_STRUCTP(ss);
690 9245 : sa->sin_family = AF_INET;
691 9245 : sa->sin_addr = ip;
692 9245 : }
693 :
694 : #if defined(HAVE_IPV6)
695 : /**
696 : * Convert an IPv6 struct in_addr to a struct sockaddr_storage.
697 : */
698 0 : void in6_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
699 : struct in6_addr ip)
700 : {
701 0 : struct sockaddr_in6 *sa = (struct sockaddr_in6 *)ss;
702 0 : memset(ss, '\0', sizeof(*ss));
703 0 : sa->sin6_family = AF_INET6;
704 0 : sa->sin6_addr = ip;
705 0 : }
706 : #endif
707 :
708 : /**
709 : * Are two IPs on the same subnet?
710 : */
711 22003 : bool same_net(const struct sockaddr *ip1,
712 : const struct sockaddr *ip2,
713 : const struct sockaddr *mask)
714 : {
715 22003 : if (ip1->sa_family != ip2->sa_family) {
716 : /* Never on the same net. */
717 7401 : return false;
718 : }
719 :
720 : #if defined(HAVE_IPV6)
721 13474 : if (ip1->sa_family == AF_INET6) {
722 2095 : struct sockaddr_in6 ip1_6 = *(const struct sockaddr_in6 *)ip1;
723 2095 : struct sockaddr_in6 ip2_6 = *(const struct sockaddr_in6 *)ip2;
724 2095 : struct sockaddr_in6 mask_6 = *(const struct sockaddr_in6 *)mask;
725 2095 : char *p1 = (char *)&ip1_6.sin6_addr;
726 2095 : char *p2 = (char *)&ip2_6.sin6_addr;
727 2095 : char *m = (char *)&mask_6.sin6_addr;
728 172 : size_t i;
729 :
730 35615 : for (i = 0; i < sizeof(struct in6_addr); i++) {
731 33520 : *p1++ &= *m;
732 33520 : *p2++ &= *m;
733 33520 : m++;
734 : }
735 2095 : return (memcmp(&ip1_6.sin6_addr,
736 : &ip2_6.sin6_addr,
737 2095 : sizeof(struct in6_addr)) == 0);
738 : }
739 : #endif
740 11379 : if (ip1->sa_family == AF_INET) {
741 11379 : return same_net_v4(((const struct sockaddr_in *)ip1)->sin_addr,
742 : ((const struct sockaddr_in *)ip2)->sin_addr,
743 : ((const struct sockaddr_in *)mask)->sin_addr);
744 : }
745 0 : return false;
746 : }
747 :
748 : /**
749 : * Are two sockaddr 's the same family and address ? Ignore port etc.
750 : */
751 :
752 4139992 : bool sockaddr_equal(const struct sockaddr *ip1,
753 : const struct sockaddr *ip2)
754 : {
755 4139992 : if (ip1->sa_family != ip2->sa_family) {
756 : /* Never the same. */
757 717719 : return false;
758 : }
759 :
760 : #if defined(HAVE_IPV6)
761 3405721 : if (ip1->sa_family == AF_INET6) {
762 336643 : return (memcmp(&((const struct sockaddr_in6 *)ip1)->sin6_addr,
763 336643 : &((const struct sockaddr_in6 *)ip2)->sin6_addr,
764 336643 : sizeof(struct in6_addr)) == 0);
765 : }
766 : #endif
767 3069078 : if (ip1->sa_family == AF_INET) {
768 3069078 : return (memcmp(&((const struct sockaddr_in *)ip1)->sin_addr,
769 3069078 : &((const struct sockaddr_in *)ip2)->sin_addr,
770 3069078 : sizeof(struct in_addr)) == 0);
771 : }
772 0 : return false;
773 : }
774 :
775 : /**
776 : * Is an IP address the INADDR_ANY or in6addr_any value ?
777 : */
778 883561 : bool is_address_any(const struct sockaddr *psa)
779 : {
780 : #if defined(HAVE_IPV6)
781 883561 : if (psa->sa_family == AF_INET6) {
782 167949 : const struct sockaddr_in6 *si6 = (const struct sockaddr_in6 *)psa;
783 167949 : if (memcmp(&in6addr_any,
784 167949 : &si6->sin6_addr,
785 : sizeof(in6addr_any)) == 0) {
786 0 : return true;
787 : }
788 167949 : return false;
789 : }
790 : #endif
791 715612 : if (psa->sa_family == AF_INET) {
792 715612 : const struct sockaddr_in *si = (const struct sockaddr_in *)psa;
793 715612 : if (si->sin_addr.s_addr == INADDR_ANY) {
794 0 : return true;
795 : }
796 715612 : return false;
797 : }
798 0 : return false;
799 : }
800 :
801 2933 : void set_sockaddr_port(struct sockaddr *psa, uint16_t port)
802 : {
803 : #if defined(HAVE_IPV6)
804 2933 : if (psa->sa_family == AF_INET6) {
805 0 : ((struct sockaddr_in6 *)psa)->sin6_port = htons(port);
806 : }
807 : #endif
808 2933 : if (psa->sa_family == AF_INET) {
809 2933 : ((struct sockaddr_in *)psa)->sin_port = htons(port);
810 : }
811 2933 : }
812 :
813 :
814 : /****************************************************************************
815 : Get a port number in host byte order from a sockaddr_storage.
816 : ****************************************************************************/
817 :
818 857 : uint16_t get_sockaddr_port(const struct sockaddr_storage *pss)
819 : {
820 857 : uint16_t port = 0;
821 :
822 857 : if (pss->ss_family != AF_INET) {
823 : #if defined(HAVE_IPV6)
824 : /* IPv6 */
825 0 : const struct sockaddr_in6 *sa6 =
826 : (const struct sockaddr_in6 *)pss;
827 0 : port = ntohs(sa6->sin6_port);
828 : #endif
829 : } else {
830 857 : const struct sockaddr_in *sa =
831 : (const struct sockaddr_in *)pss;
832 857 : port = ntohs(sa->sin_port);
833 : }
834 857 : return port;
835 : }
836 :
837 : /****************************************************************************
838 : Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
839 : ****************************************************************************/
840 :
841 2307846 : char *print_sockaddr_len(char *dest,
842 : size_t destlen,
843 : const struct sockaddr *psa,
844 : socklen_t psalen)
845 : {
846 2307846 : if (destlen > 0) {
847 2307846 : dest[0] = '\0';
848 : }
849 2307846 : (void)sys_getnameinfo(psa,
850 : psalen,
851 : dest, destlen,
852 : NULL, 0,
853 : NI_NUMERICHOST);
854 2307846 : return dest;
855 : }
856 :
857 : /****************************************************************************
858 : Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
859 : ****************************************************************************/
860 :
861 2307846 : char *print_sockaddr(char *dest,
862 : size_t destlen,
863 : const struct sockaddr_storage *psa)
864 : {
865 2307846 : return print_sockaddr_len(dest, destlen, (const struct sockaddr *)psa,
866 : sizeof(struct sockaddr_storage));
867 : }
868 :
869 : /****************************************************************************
870 : Print out a canonical IPv4 or IPv6 address from a struct sockaddr_storage.
871 : ****************************************************************************/
872 :
873 446 : char *print_canonical_sockaddr(TALLOC_CTX *ctx,
874 : const struct sockaddr_storage *pss)
875 : {
876 0 : char addr[INET6_ADDRSTRLEN];
877 446 : char *dest = NULL;
878 0 : int ret;
879 :
880 : /* Linux getnameinfo() man pages says port is uninitialized if
881 : service name is NULL. */
882 :
883 446 : ret = sys_getnameinfo((const struct sockaddr *)pss,
884 : sizeof(struct sockaddr_storage),
885 : addr, sizeof(addr),
886 : NULL, 0,
887 : NI_NUMERICHOST);
888 446 : if (ret != 0) {
889 0 : return NULL;
890 : }
891 :
892 446 : if (pss->ss_family != AF_INET) {
893 : #if defined(HAVE_IPV6)
894 188 : dest = talloc_asprintf(ctx, "[%s]", addr);
895 : #else
896 : return NULL;
897 : #endif
898 : } else {
899 258 : dest = talloc_asprintf(ctx, "%s", addr);
900 : }
901 :
902 446 : return dest;
903 : }
904 :
905 : enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
906 :
907 : typedef struct smb_socket_option {
908 : const char *name;
909 : int level;
910 : int option;
911 : int value;
912 : int opttype;
913 : } smb_socket_option;
914 :
915 : static const smb_socket_option socket_options[] = {
916 : {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
917 : {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
918 : {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
919 : #ifdef TCP_NODELAY
920 : {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
921 : #endif
922 : #ifdef TCP_KEEPCNT
923 : {"TCP_KEEPCNT", IPPROTO_TCP, TCP_KEEPCNT, 0, OPT_INT},
924 : #endif
925 : #ifdef TCP_KEEPIDLE
926 : {"TCP_KEEPIDLE", IPPROTO_TCP, TCP_KEEPIDLE, 0, OPT_INT},
927 : #endif
928 : #ifdef TCP_KEEPINTVL
929 : {"TCP_KEEPINTVL", IPPROTO_TCP, TCP_KEEPINTVL, 0, OPT_INT},
930 : #endif
931 : #ifdef IPTOS_LOWDELAY
932 : {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
933 : #endif
934 : #ifdef IPTOS_THROUGHPUT
935 : {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
936 : #endif
937 : #ifdef SO_REUSEPORT
938 : {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
939 : #endif
940 : #ifdef SO_SNDBUF
941 : {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
942 : #endif
943 : #ifdef SO_RCVBUF
944 : {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
945 : #endif
946 : #ifdef SO_SNDLOWAT
947 : {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
948 : #endif
949 : #ifdef SO_RCVLOWAT
950 : {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
951 : #endif
952 : #ifdef SO_SNDTIMEO
953 : {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
954 : #endif
955 : #ifdef SO_RCVTIMEO
956 : {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
957 : #endif
958 : #ifdef TCP_FASTACK
959 : {"TCP_FASTACK", IPPROTO_TCP, TCP_FASTACK, 0, OPT_INT},
960 : #endif
961 : #ifdef TCP_QUICKACK
962 : {"TCP_QUICKACK", IPPROTO_TCP, TCP_QUICKACK, 0, OPT_BOOL},
963 : #endif
964 : #ifdef TCP_NODELAYACK
965 : {"TCP_NODELAYACK", IPPROTO_TCP, TCP_NODELAYACK, 0, OPT_BOOL},
966 : #endif
967 : #ifdef TCP_KEEPALIVE_THRESHOLD
968 : {"TCP_KEEPALIVE_THRESHOLD", IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, 0, OPT_INT},
969 : #endif
970 : #ifdef TCP_KEEPALIVE_ABORT_THRESHOLD
971 : {"TCP_KEEPALIVE_ABORT_THRESHOLD", IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, 0, OPT_INT},
972 : #endif
973 : #ifdef TCP_DEFER_ACCEPT
974 : {"TCP_DEFER_ACCEPT", IPPROTO_TCP, TCP_DEFER_ACCEPT, 0, OPT_INT},
975 : #endif
976 : #ifdef TCP_USER_TIMEOUT
977 : {"TCP_USER_TIMEOUT", IPPROTO_TCP, TCP_USER_TIMEOUT, 0, OPT_INT},
978 : #endif
979 : {NULL,0,0,0,0}};
980 :
981 : /****************************************************************************
982 : Print socket options.
983 : ****************************************************************************/
984 :
985 116907 : static void print_socket_options(TALLOC_CTX *ctx, int s)
986 : {
987 116907 : const smb_socket_option *p = &socket_options[0];
988 116907 : char *str = NULL;
989 :
990 116907 : if (DEBUGLEVEL < 5) {
991 116899 : return;
992 : }
993 :
994 8 : str = talloc_strdup(ctx, "");
995 8 : if (str == NULL) {
996 0 : DBG_WARNING("talloc failed\n");
997 0 : goto done;
998 : }
999 :
1000 160 : for (; p->name != NULL; p++) {
1001 0 : int ret, val;
1002 152 : socklen_t vlen = sizeof(val);
1003 :
1004 152 : ret = getsockopt(s, p->level, p->option, (void *)&val, &vlen);
1005 152 : if (ret == -1) {
1006 64 : DBG_INFO("Could not test socket option %s: %s.\n",
1007 : p->name, strerror(errno));
1008 64 : continue;
1009 : }
1010 :
1011 88 : talloc_asprintf_addbuf(
1012 : &str,
1013 : "%s%s=%d",
1014 88 : str[0] != '\0' ? ", " : "",
1015 88 : p->name,
1016 : val);
1017 : }
1018 :
1019 8 : DEBUG(5, ("socket options: %s\n", str));
1020 8 : done:
1021 8 : TALLOC_FREE(str);
1022 : }
1023 :
1024 : /****************************************************************************
1025 : Set user socket options.
1026 : ****************************************************************************/
1027 :
1028 116907 : void set_socket_options(int fd, const char *options)
1029 : {
1030 116907 : TALLOC_CTX *ctx = talloc_new(NULL);
1031 2810 : char *tok;
1032 :
1033 233814 : while (next_token_talloc(ctx, &options, &tok," \t,")) {
1034 116907 : int ret=0,i;
1035 116907 : int value = 1;
1036 2810 : char *p;
1037 116907 : bool got_value = false;
1038 :
1039 116907 : if ((p = strchr_m(tok,'='))) {
1040 1764 : *p = 0;
1041 1764 : value = atoi(p+1);
1042 1764 : got_value = true;
1043 : }
1044 :
1045 347784 : for (i=0;socket_options[i].name;i++)
1046 347784 : if (strequal(socket_options[i].name,tok))
1047 114097 : break;
1048 :
1049 116907 : if (!socket_options[i].name) {
1050 0 : DEBUG(0,("Unknown socket option %s\n",tok));
1051 0 : continue;
1052 : }
1053 :
1054 116907 : switch (socket_options[i].opttype) {
1055 116907 : case OPT_BOOL:
1056 : case OPT_INT:
1057 116907 : ret = setsockopt(fd,socket_options[i].level,
1058 116907 : socket_options[i].option,
1059 : (char *)&value,sizeof(int));
1060 116907 : break;
1061 :
1062 0 : case OPT_ON:
1063 0 : if (got_value)
1064 0 : DEBUG(0,("syntax error - %s "
1065 : "does not take a value\n",tok));
1066 :
1067 : {
1068 0 : int on = socket_options[i].value;
1069 0 : ret = setsockopt(fd,socket_options[i].level,
1070 0 : socket_options[i].option,
1071 : (char *)&on,sizeof(int));
1072 : }
1073 0 : break;
1074 : }
1075 :
1076 116907 : if (ret != 0) {
1077 : /* be aware that some systems like Solaris return
1078 : * EINVAL to a setsockopt() call when the client
1079 : * sent a RST previously - no need to worry */
1080 0 : DEBUG(2,("Failed to set socket option %s (Error %s)\n",
1081 : tok, strerror(errno) ));
1082 : }
1083 : }
1084 :
1085 116907 : print_socket_options(ctx, fd);
1086 116907 : TALLOC_FREE(ctx);
1087 116907 : }
1088 :
1089 : /*
1090 : * Utility function that copes only with AF_INET and AF_INET6
1091 : * as that's all we're going to get out of DNS / NetBIOS / WINS
1092 : * name resolution functions.
1093 : */
1094 :
1095 22558 : bool sockaddr_storage_to_samba_sockaddr(
1096 : struct samba_sockaddr *sa, const struct sockaddr_storage *ss)
1097 : {
1098 22558 : sa->u.ss = *ss;
1099 :
1100 22558 : switch (ss->ss_family) {
1101 12767 : case AF_INET:
1102 12767 : sa->sa_socklen = sizeof(struct sockaddr_in);
1103 12767 : break;
1104 : #ifdef HAVE_IPV6
1105 9791 : case AF_INET6:
1106 9791 : sa->sa_socklen = sizeof(struct sockaddr_in6);
1107 9791 : break;
1108 : #endif
1109 0 : default:
1110 0 : return false;
1111 : }
1112 22558 : return true;
1113 : }
1114 :
1115 911 : bool samba_sockaddr_set_port(struct samba_sockaddr *sa, uint16_t port)
1116 : {
1117 911 : if (sa->u.sa.sa_family == AF_INET) {
1118 751 : sa->u.in.sin_port = htons(port);
1119 751 : return true;
1120 : }
1121 : #ifdef HAVE_IPV6
1122 160 : if (sa->u.sa.sa_family == AF_INET6) {
1123 160 : sa->u.in6.sin6_port = htons(port);
1124 160 : return true;
1125 : }
1126 : #endif
1127 0 : return false;
1128 : }
1129 :
1130 1596 : bool samba_sockaddr_get_port(const struct samba_sockaddr *sa, uint16_t *port)
1131 : {
1132 1596 : if (sa->u.sa.sa_family == AF_INET) {
1133 1596 : *port = ntohs(sa->u.in.sin_port);
1134 1596 : return true;
1135 : }
1136 : #ifdef HAVE_IPV6
1137 0 : if (sa->u.sa.sa_family == AF_INET6) {
1138 0 : *port = ntohs(sa->u.in6.sin6_port);
1139 0 : return true;
1140 : }
1141 : #endif
1142 0 : return false;
1143 : }
1144 :
1145 196816 : int samba_socket_poll_error(int fd)
1146 : {
1147 196816 : struct pollfd pfd = {
1148 : .fd = fd,
1149 : #ifdef POLLRDHUP
1150 : .events = POLLRDHUP, /* POLLERR and POLLHUP are not needed */
1151 : #endif
1152 : };
1153 4221 : int ret;
1154 :
1155 196816 : errno = 0;
1156 196816 : ret = sys_poll_intr(&pfd, 1, 0);
1157 196816 : if (ret == 0) {
1158 6177 : return 0;
1159 : }
1160 190205 : if (ret != 1) {
1161 0 : return POLLNVAL;
1162 : }
1163 :
1164 190205 : if (pfd.revents & POLLERR) {
1165 814 : return POLLERR;
1166 : }
1167 189243 : if (pfd.revents & POLLHUP) {
1168 185604 : return POLLHUP;
1169 : }
1170 : #ifdef POLLRDHUP
1171 4 : if (pfd.revents & POLLRDHUP) {
1172 4 : return POLLRDHUP;
1173 : }
1174 : #endif
1175 :
1176 : /* should never be reached! */
1177 0 : return POLLNVAL;
1178 : }
1179 :
1180 962 : int samba_socket_sock_error(int fd)
1181 : {
1182 962 : int ret, error = 0;
1183 962 : socklen_t len = sizeof(error);
1184 :
1185 : /*
1186 : * if no data is available check if the socket is in error state. For
1187 : * dgram sockets it's the way to return ICMP error messages of
1188 : * connected sockets to the caller.
1189 : */
1190 962 : ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
1191 962 : if (ret == -1) {
1192 0 : return ret;
1193 : }
1194 962 : if (error != 0) {
1195 962 : errno = error;
1196 962 : return -1;
1197 : }
1198 0 : return 0;
1199 : }
1200 :
1201 196816 : int samba_socket_poll_or_sock_error(int fd)
1202 : {
1203 4221 : int ret;
1204 196816 : int poll_error = 0;
1205 :
1206 196816 : poll_error = samba_socket_poll_error(fd);
1207 196816 : if (poll_error == 0) {
1208 6177 : return 0;
1209 : }
1210 :
1211 : #ifdef POLLRDHUP
1212 190205 : if (poll_error == POLLRDHUP) {
1213 4 : errno = ECONNRESET;
1214 4 : return -1;
1215 : }
1216 : #endif
1217 :
1218 190201 : if (poll_error == POLLHUP) {
1219 189239 : errno = EPIPE;
1220 189239 : return -1;
1221 : }
1222 :
1223 : /*
1224 : * POLLERR and POLLNVAL fallback to
1225 : * getsockopt(fd, SOL_SOCKET, SO_ERROR)
1226 : * and force EPIPE as fallback.
1227 : */
1228 :
1229 962 : errno = 0;
1230 962 : ret = samba_socket_sock_error(fd);
1231 962 : if (ret == 0) {
1232 0 : errno = EPIPE;
1233 : }
1234 :
1235 962 : if (errno == 0) {
1236 0 : errno = EPIPE;
1237 : }
1238 :
1239 814 : return -1;
1240 : }
|