Coverage Report

Created: 2025-07-23 07:04

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