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