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