lib: Fix a false/NULL hickup
[metze/samba/wip.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         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 NULL;
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         char buf[INET6_ADDRSTRLEN] = { 0, };
494         size_t len;
495         const char *addr = str;
496         const char *idxs = NULL;
497         unsigned int idx = 0;
498         struct in6_addr ip6;
499
500         p = strchr_m(str, ':');
501         if (p == NULL) {
502                 return is_ipv6_literal(str);
503         }
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 #endif
563         return false;
564 }
565
566 /**
567  * Return true if a string could be an IPv4 or IPv6 address.
568  */
569
570 bool is_ipaddress(const char *str)
571 {
572         return is_ipaddress_v4(str) || is_ipaddress_v6(str);
573 }
574
575 /**
576  * Is a sockaddr a broadcast address ?
577  */
578
579 bool is_broadcast_addr(const struct sockaddr *pss)
580 {
581 #if defined(HAVE_IPV6)
582         if (pss->sa_family == AF_INET6) {
583                 const struct in6_addr *sin6 =
584                         &((const struct sockaddr_in6 *)pss)->sin6_addr;
585                 return IN6_IS_ADDR_MULTICAST(sin6);
586         }
587 #endif
588         if (pss->sa_family == AF_INET) {
589                 uint32_t addr =
590                 ntohl(((const struct sockaddr_in *)pss)->sin_addr.s_addr);
591                 return addr == INADDR_BROADCAST;
592         }
593         return false;
594 }
595
596 /**
597  * Check if an IPv7 is 127.0.0.1
598  */
599 bool is_loopback_ip_v4(struct in_addr ip)
600 {
601         struct in_addr a;
602         a.s_addr = htonl(INADDR_LOOPBACK);
603         return(ip.s_addr == a.s_addr);
604 }
605
606 /**
607  * Check if a struct sockaddr is the loopback address.
608  */
609 bool is_loopback_addr(const struct sockaddr *pss)
610 {
611 #if defined(HAVE_IPV6)
612         if (pss->sa_family == AF_INET6) {
613                 const struct in6_addr *pin6 =
614                         &((const struct sockaddr_in6 *)pss)->sin6_addr;
615                 return IN6_IS_ADDR_LOOPBACK(pin6);
616         }
617 #endif
618         if (pss->sa_family == AF_INET) {
619                 const struct in_addr *pin = &((const struct sockaddr_in *)pss)->sin_addr;
620                 return is_loopback_ip_v4(*pin);
621         }
622         return false;
623 }
624
625 /**
626  * Check if a struct sockaddr has an unspecified address.
627  */
628 bool is_zero_addr(const struct sockaddr_storage *pss)
629 {
630 #if defined(HAVE_IPV6)
631         if (pss->ss_family == AF_INET6) {
632                 const struct in6_addr *pin6 =
633                         &((const struct sockaddr_in6 *)pss)->sin6_addr;
634                 return IN6_IS_ADDR_UNSPECIFIED(pin6);
635         }
636 #endif
637         if (pss->ss_family == AF_INET) {
638                 const struct in_addr *pin = &((const struct sockaddr_in *)pss)->sin_addr;
639                 return is_zero_ip_v4(*pin);
640         }
641         return false;
642 }
643
644 /**
645  * Set an IP to 0.0.0.0.
646  */
647 void zero_ip_v4(struct in_addr *ip)
648 {
649         ZERO_STRUCTP(ip);
650 }
651
652 bool is_linklocal_addr(const struct sockaddr_storage *pss)
653 {
654 #ifdef HAVE_IPV6
655         if (pss->ss_family == AF_INET6) {
656                 const struct in6_addr *pin6 =
657                         &((const struct sockaddr_in6 *)pss)->sin6_addr;
658                 return IN6_IS_ADDR_LINKLOCAL(pin6);
659         }
660 #endif
661         if (pss->ss_family == AF_INET) {
662                 const struct in_addr *pin =
663                         &((const struct sockaddr_in *)pss)->sin_addr;
664                 struct in_addr ll_addr;
665                 struct in_addr mask_addr;
666
667                 /* 169.254.0.0/16, is link local, see RFC 3927 */
668                 ll_addr.s_addr = 0xa9fe0000;
669                 mask_addr.s_addr = 0xffff0000;
670                 return same_net_v4(*pin, ll_addr, mask_addr);
671         }
672         return false;
673 }
674
675 /**
676  * Convert an IPv4 struct in_addr to a struct sockaddr_storage.
677  */
678 void in_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
679                 struct in_addr ip)
680 {
681         struct sockaddr_in *sa = (struct sockaddr_in *)ss;
682         ZERO_STRUCTP(ss);
683         sa->sin_family = AF_INET;
684         sa->sin_addr = ip;
685 }
686
687 #if defined(HAVE_IPV6)
688 /**
689  * Convert an IPv6 struct in_addr to a struct sockaddr_storage.
690  */
691 void in6_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
692                 struct in6_addr ip)
693 {
694         struct sockaddr_in6 *sa = (struct sockaddr_in6 *)ss;
695         memset(ss, '\0', sizeof(*ss));
696         sa->sin6_family = AF_INET6;
697         sa->sin6_addr = ip;
698 }
699 #endif
700
701 /**
702  * Are two IPs on the same subnet?
703  */
704 bool same_net(const struct sockaddr *ip1,
705                 const struct sockaddr *ip2,
706                 const struct sockaddr *mask)
707 {
708         if (ip1->sa_family != ip2->sa_family) {
709                 /* Never on the same net. */
710                 return false;
711         }
712
713 #if defined(HAVE_IPV6)
714         if (ip1->sa_family == AF_INET6) {
715                 struct sockaddr_in6 ip1_6 = *(const struct sockaddr_in6 *)ip1;
716                 struct sockaddr_in6 ip2_6 = *(const struct sockaddr_in6 *)ip2;
717                 struct sockaddr_in6 mask_6 = *(const struct sockaddr_in6 *)mask;
718                 char *p1 = (char *)&ip1_6.sin6_addr;
719                 char *p2 = (char *)&ip2_6.sin6_addr;
720                 char *m = (char *)&mask_6.sin6_addr;
721                 int i;
722
723                 for (i = 0; i < sizeof(struct in6_addr); i++) {
724                         *p1++ &= *m;
725                         *p2++ &= *m;
726                         m++;
727                 }
728                 return (memcmp(&ip1_6.sin6_addr,
729                                 &ip2_6.sin6_addr,
730                                 sizeof(struct in6_addr)) == 0);
731         }
732 #endif
733         if (ip1->sa_family == AF_INET) {
734                 return same_net_v4(((const struct sockaddr_in *)ip1)->sin_addr,
735                                 ((const struct sockaddr_in *)ip2)->sin_addr,
736                                 ((const struct sockaddr_in *)mask)->sin_addr);
737         }
738         return false;
739 }
740
741 /**
742  * Are two sockaddr 's the same family and address ? Ignore port etc.
743  */
744
745 bool sockaddr_equal(const struct sockaddr *ip1,
746                 const struct sockaddr *ip2)
747 {
748         if (ip1->sa_family != ip2->sa_family) {
749                 /* Never the same. */
750                 return false;
751         }
752
753 #if defined(HAVE_IPV6)
754         if (ip1->sa_family == AF_INET6) {
755                 return (memcmp(&((const struct sockaddr_in6 *)ip1)->sin6_addr,
756                                 &((const struct sockaddr_in6 *)ip2)->sin6_addr,
757                                 sizeof(struct in6_addr)) == 0);
758         }
759 #endif
760         if (ip1->sa_family == AF_INET) {
761                 return (memcmp(&((const struct sockaddr_in *)ip1)->sin_addr,
762                                 &((const struct sockaddr_in *)ip2)->sin_addr,
763                                 sizeof(struct in_addr)) == 0);
764         }
765         return false;
766 }
767
768 /**
769  * Is an IP address the INADDR_ANY or in6addr_any value ?
770  */
771 bool is_address_any(const struct sockaddr *psa)
772 {
773 #if defined(HAVE_IPV6)
774         if (psa->sa_family == AF_INET6) {
775                 const struct sockaddr_in6 *si6 = (const struct sockaddr_in6 *)psa;
776                 if (memcmp(&in6addr_any,
777                                 &si6->sin6_addr,
778                                 sizeof(in6addr_any)) == 0) {
779                         return true;
780                 }
781                 return false;
782         }
783 #endif
784         if (psa->sa_family == AF_INET) {
785                 const struct sockaddr_in *si = (const struct sockaddr_in *)psa;
786                 if (si->sin_addr.s_addr == INADDR_ANY) {
787                         return true;
788                 }
789                 return false;
790         }
791         return false;
792 }
793
794 void set_sockaddr_port(struct sockaddr *psa, uint16_t port)
795 {
796 #if defined(HAVE_IPV6)
797         if (psa->sa_family == AF_INET6) {
798                 ((struct sockaddr_in6 *)psa)->sin6_port = htons(port);
799         }
800 #endif
801         if (psa->sa_family == AF_INET) {
802                 ((struct sockaddr_in *)psa)->sin_port = htons(port);
803         }
804 }
805
806
807 /****************************************************************************
808  Get a port number in host byte order from a sockaddr_storage.
809 ****************************************************************************/
810
811 uint16_t get_sockaddr_port(const struct sockaddr_storage *pss)
812 {
813         uint16_t port = 0;
814
815         if (pss->ss_family != AF_INET) {
816 #if defined(HAVE_IPV6)
817                 /* IPv6 */
818                 const struct sockaddr_in6 *sa6 =
819                         (const struct sockaddr_in6 *)pss;
820                 port = ntohs(sa6->sin6_port);
821 #endif
822         } else {
823                 const struct sockaddr_in *sa =
824                         (const struct sockaddr_in *)pss;
825                 port = ntohs(sa->sin_port);
826         }
827         return port;
828 }
829
830 /****************************************************************************
831  Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
832 ****************************************************************************/
833
834 char *print_sockaddr_len(char *dest,
835                          size_t destlen,
836                         const struct sockaddr *psa,
837                         socklen_t psalen)
838 {
839         if (destlen > 0) {
840                 dest[0] = '\0';
841         }
842         (void)sys_getnameinfo(psa,
843                         psalen,
844                         dest, destlen,
845                         NULL, 0,
846                         NI_NUMERICHOST);
847         return dest;
848 }
849
850 /****************************************************************************
851  Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
852 ****************************************************************************/
853
854 char *print_sockaddr(char *dest,
855                         size_t destlen,
856                         const struct sockaddr_storage *psa)
857 {
858         return print_sockaddr_len(dest, destlen, (const struct sockaddr *)psa,
859                         sizeof(struct sockaddr_storage));
860 }
861
862 /****************************************************************************
863  Print out a canonical IPv4 or IPv6 address from a struct sockaddr_storage.
864 ****************************************************************************/
865
866 char *print_canonical_sockaddr(TALLOC_CTX *ctx,
867                         const struct sockaddr_storage *pss)
868 {
869         char addr[INET6_ADDRSTRLEN];
870         char *dest = NULL;
871         int ret;
872
873         /* Linux getnameinfo() man pages says port is unitialized if
874            service name is NULL. */
875
876         ret = sys_getnameinfo((const struct sockaddr *)pss,
877                         sizeof(struct sockaddr_storage),
878                         addr, sizeof(addr),
879                         NULL, 0,
880                         NI_NUMERICHOST);
881         if (ret != 0) {
882                 return NULL;
883         }
884
885         if (pss->ss_family != AF_INET) {
886 #if defined(HAVE_IPV6)
887                 dest = talloc_asprintf(ctx, "[%s]", addr);
888 #else
889                 return NULL;
890 #endif
891         } else {
892                 dest = talloc_asprintf(ctx, "%s", addr);
893         }
894
895         return dest;
896 }
897
898 /****************************************************************************
899  Return the port number we've bound to on a socket.
900 ****************************************************************************/
901
902 int get_socket_port(int fd)
903 {
904         struct sockaddr_storage sa;
905         socklen_t length = sizeof(sa);
906
907         if (fd == -1) {
908                 return -1;
909         }
910
911         if (getsockname(fd, (struct sockaddr *)&sa, &length) < 0) {
912                 int level = (errno == ENOTCONN) ? 2 : 0;
913                 DEBUG(level, ("getsockname failed. Error was %s\n",
914                                strerror(errno)));
915                 return -1;
916         }
917
918 #if defined(HAVE_IPV6)
919         if (sa.ss_family == AF_INET6) {
920                 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&sa;
921                 return ntohs(sa_in6->sin6_port);
922         }
923 #endif
924         if (sa.ss_family == AF_INET) {
925                 struct sockaddr_in *sa_in = (struct sockaddr_in *)&sa;
926                 return ntohs(sa_in->sin_port);
927         }
928         return -1;
929 }
930
931 /****************************************************************************
932  Return the string of an IP address (IPv4 or IPv6).
933 ****************************************************************************/
934
935 static const char *get_socket_addr(int fd, char *addr_buf, size_t addr_len)
936 {
937         struct sockaddr_storage sa;
938         socklen_t length = sizeof(sa);
939
940         /* Ok, returning a hard coded IPv4 address
941          * is bogus, but it's just as bogus as a
942          * zero IPv6 address. No good choice here.
943          */
944
945         if (strlcpy(addr_buf, "0.0.0.0", addr_len) >= addr_len) {
946                 /* Truncate ! */
947                 return NULL;
948         }
949
950         if (fd == -1) {
951                 return addr_buf;
952         }
953
954         if (getsockname(fd, (struct sockaddr *)&sa, &length) < 0) {
955                 DEBUG(0,("getsockname failed. Error was %s\n",
956                         strerror(errno) ));
957                 return addr_buf;
958         }
959
960         return print_sockaddr_len(addr_buf, addr_len, (struct sockaddr *)&sa, length);
961 }
962
963 const char *client_socket_addr(int fd, char *addr, size_t addr_len)
964 {
965         return get_socket_addr(fd, addr, addr_len);
966 }
967
968
969 enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
970
971 typedef struct smb_socket_option {
972         const char *name;
973         int level;
974         int option;
975         int value;
976         int opttype;
977 } smb_socket_option;
978
979 static const smb_socket_option socket_options[] = {
980   {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
981   {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
982   {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
983 #ifdef TCP_NODELAY
984   {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
985 #endif
986 #ifdef TCP_KEEPCNT
987   {"TCP_KEEPCNT", IPPROTO_TCP, TCP_KEEPCNT, 0, OPT_INT},
988 #endif
989 #ifdef TCP_KEEPIDLE
990   {"TCP_KEEPIDLE", IPPROTO_TCP, TCP_KEEPIDLE, 0, OPT_INT},
991 #endif
992 #ifdef TCP_KEEPINTVL
993   {"TCP_KEEPINTVL", IPPROTO_TCP, TCP_KEEPINTVL, 0, OPT_INT},
994 #endif
995 #ifdef IPTOS_LOWDELAY
996   {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
997 #endif
998 #ifdef IPTOS_THROUGHPUT
999   {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
1000 #endif
1001 #ifdef SO_REUSEPORT
1002   {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
1003 #endif
1004 #ifdef SO_SNDBUF
1005   {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
1006 #endif
1007 #ifdef SO_RCVBUF
1008   {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
1009 #endif
1010 #ifdef SO_SNDLOWAT
1011   {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
1012 #endif
1013 #ifdef SO_RCVLOWAT
1014   {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
1015 #endif
1016 #ifdef SO_SNDTIMEO
1017   {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
1018 #endif
1019 #ifdef SO_RCVTIMEO
1020   {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
1021 #endif
1022 #ifdef TCP_FASTACK
1023   {"TCP_FASTACK", IPPROTO_TCP, TCP_FASTACK, 0, OPT_INT},
1024 #endif
1025 #ifdef TCP_QUICKACK
1026   {"TCP_QUICKACK", IPPROTO_TCP, TCP_QUICKACK, 0, OPT_BOOL},
1027 #endif
1028 #ifdef TCP_NODELAYACK
1029   {"TCP_NODELAYACK", IPPROTO_TCP, TCP_NODELAYACK, 0, OPT_BOOL},
1030 #endif
1031 #ifdef TCP_KEEPALIVE_THRESHOLD
1032   {"TCP_KEEPALIVE_THRESHOLD", IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, 0, OPT_INT},
1033 #endif
1034 #ifdef TCP_KEEPALIVE_ABORT_THRESHOLD
1035   {"TCP_KEEPALIVE_ABORT_THRESHOLD", IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, 0, OPT_INT},
1036 #endif
1037 #ifdef TCP_DEFER_ACCEPT
1038   {"TCP_DEFER_ACCEPT", IPPROTO_TCP, TCP_DEFER_ACCEPT, 0, OPT_INT},
1039 #endif
1040   {NULL,0,0,0,0}};
1041
1042 /****************************************************************************
1043  Print socket options.
1044 ****************************************************************************/
1045
1046 static void print_socket_options(int s)
1047 {
1048         int value;
1049         socklen_t vlen = 4;
1050         const smb_socket_option *p = &socket_options[0];
1051
1052         /* wrapped in if statement to prevent streams
1053          * leak in SCO Openserver 5.0 */
1054         /* reported on samba-technical  --jerry */
1055         if ( DEBUGLEVEL >= 5 ) {
1056                 DEBUG(5,("Socket options:\n"));
1057                 for (; p->name != NULL; p++) {
1058                         if (getsockopt(s, p->level, p->option,
1059                                                 (void *)&value, &vlen) == -1) {
1060                                 DEBUGADD(5,("\tCould not test socket option %s.\n",
1061                                                         p->name));
1062                         } else {
1063                                 DEBUGADD(5,("\t%s = %d\n",
1064                                                         p->name,value));
1065                         }
1066                 }
1067         }
1068  }
1069
1070 /****************************************************************************
1071  Set user socket options.
1072 ****************************************************************************/
1073
1074 void set_socket_options(int fd, const char *options)
1075 {
1076         TALLOC_CTX *ctx = talloc_new(NULL);
1077         char *tok;
1078
1079         while (next_token_talloc(ctx, &options, &tok," \t,")) {
1080                 int ret=0,i;
1081                 int value = 1;
1082                 char *p;
1083                 bool got_value = false;
1084
1085                 if ((p = strchr_m(tok,'='))) {
1086                         *p = 0;
1087                         value = atoi(p+1);
1088                         got_value = true;
1089                 }
1090
1091                 for (i=0;socket_options[i].name;i++)
1092                         if (strequal(socket_options[i].name,tok))
1093                                 break;
1094
1095                 if (!socket_options[i].name) {
1096                         DEBUG(0,("Unknown socket option %s\n",tok));
1097                         continue;
1098                 }
1099
1100                 switch (socket_options[i].opttype) {
1101                 case OPT_BOOL:
1102                 case OPT_INT:
1103                         ret = setsockopt(fd,socket_options[i].level,
1104                                         socket_options[i].option,
1105                                         (char *)&value,sizeof(int));
1106                         break;
1107
1108                 case OPT_ON:
1109                         if (got_value)
1110                                 DEBUG(0,("syntax error - %s "
1111                                         "does not take a value\n",tok));
1112
1113                         {
1114                                 int on = socket_options[i].value;
1115                                 ret = setsockopt(fd,socket_options[i].level,
1116                                         socket_options[i].option,
1117                                         (char *)&on,sizeof(int));
1118                         }
1119                         break;
1120                 }
1121
1122                 if (ret != 0) {
1123                         /* be aware that some systems like Solaris return
1124                          * EINVAL to a setsockopt() call when the client
1125                          * sent a RST previously - no need to worry */
1126                         DEBUG(2,("Failed to set socket option %s (Error %s)\n",
1127                                 tok, strerror(errno) ));
1128                 }
1129         }
1130
1131         TALLOC_FREE(ctx);
1132         print_socket_options(fd);
1133 }