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