Coverage Report

Created: 2025-12-31 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/lib/util/util_net.c
Line
Count
Source
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
 * Interpret an internet address or name into an IP address in 4 byte form.
331
 * RETURNS IN NETWORK BYTE ORDER (big endian).
332
 */
333
334
uint32_t interpret_addr(const char *str)
335
0
{
336
0
  uint32_t ret;
337
338
  /* If it's in the form of an IP address then
339
   * get the lib to interpret it */
340
0
  if (is_ipaddress_v4(str)) {
341
0
    struct in_addr dest;
342
343
0
    if (inet_pton(AF_INET, str, &dest) <= 0) {
344
      /* Error - this shouldn't happen ! */
345
0
      DEBUG(0,("interpret_addr: inet_pton failed "
346
0
        "host %s\n",
347
0
        str));
348
0
      return 0;
349
0
    }
350
0
    ret = dest.s_addr; /* NETWORK BYTE ORDER ! */
351
0
  } else {
352
    /* Otherwise assume it's a network name of some sort and use
353
      getaddrinfo. */
354
0
    struct addrinfo *res = NULL;
355
0
    struct addrinfo *res_list = NULL;
356
0
    if (!interpret_string_addr_internal(&res_list,
357
0
          str,
358
0
          AI_ADDRCONFIG)) {
359
0
      DEBUG(3,("interpret_addr: Unknown host. %s\n",str));
360
0
      return 0;
361
0
    }
362
363
    /* Find the first IPv4 address. */
364
0
    for (res = res_list; res; res = res->ai_next) {
365
0
      if (res->ai_family != AF_INET) {
366
0
        continue;
367
0
      }
368
0
      if (res->ai_addr == NULL) {
369
0
        continue;
370
0
      }
371
0
      break;
372
0
    }
373
0
    if(res == NULL) {
374
0
      DEBUG(3,("interpret_addr: host address is "
375
0
        "invalid for host %s\n",str));
376
0
      if (res_list) {
377
0
        freeaddrinfo(res_list);
378
0
      }
379
0
      return 0;
380
0
    }
381
0
    memcpy((char *)&ret,
382
0
      &((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr,
383
0
      sizeof(ret));
384
0
    if (res_list) {
385
0
      freeaddrinfo(res_list);
386
0
    }
387
0
  }
388
389
  /* This is so bogus - all callers need fixing... JRA. */
390
0
  if (ret == (uint32_t)-1) {
391
0
    return 0;
392
0
  }
393
394
0
  return ret;
395
0
}
396
397
/**
398
 A convenient addition to interpret_addr().
399
**/
400
_PUBLIC_ struct in_addr interpret_addr2(const char *str)
401
0
{
402
0
  struct in_addr ret;
403
0
  uint32_t a = interpret_addr(str);
404
0
  ret.s_addr = a;
405
0
  return ret;
406
0
}
407
408
/**
409
 Check if an IP is the 0.0.0.0.
410
**/
411
412
_PUBLIC_ bool is_zero_ip_v4(struct in_addr ip)
413
0
{
414
0
  return ip.s_addr == 0;
415
0
}
416
417
/**
418
 Are two IPs on the same subnet?
419
**/
420
421
_PUBLIC_ bool same_net_v4(struct in_addr ip1, struct in_addr ip2, struct in_addr mask)
422
0
{
423
0
  uint32_t net1,net2,nmask;
424
425
0
  nmask = ntohl(mask.s_addr);
426
0
  net1  = ntohl(ip1.s_addr);
427
0
  net2  = ntohl(ip2.s_addr);
428
429
0
  return((net1 & nmask) == (net2 & nmask));
430
0
}
431
432
/**
433
 * Return true if a string could be an IPv4 address.
434
 */
435
436
bool is_ipaddress_v4(const char *str)
437
2.98M
{
438
2.98M
  int ret = -1;
439
2.98M
  struct in_addr dest;
440
441
2.98M
  ret = inet_pton(AF_INET, str, &dest);
442
2.98M
  if (ret > 0) {
443
2.72M
    return true;
444
2.72M
  }
445
261k
  return false;
446
2.98M
}
447
448
bool is_ipv6_literal(const char *str)
449
0
{
450
0
#if defined(HAVE_IPV6)
451
0
  char buf[INET6_ADDRSTRLEN*2] = { 0, };
452
0
  size_t len = strlen(str);
453
0
  char *p = NULL;
454
455
0
  if (len >= sizeof(buf)) {
456
0
    return false;
457
0
  }
458
459
0
  p = normalize_ipv6_literal(str, buf, &len);
460
0
  if (p == NULL) {
461
0
    return false;
462
0
  }
463
464
0
  return true;
465
#else
466
  return false;
467
#endif
468
0
}
469
470
/**
471
 * Return true if a string could be a IPv6 address.
472
 */
473
474
bool is_ipaddress_v6(const char *str)
475
262k
{
476
262k
#if defined(HAVE_IPV6)
477
262k
  int ret = -1;
478
262k
  char *p = NULL;
479
262k
  char buf[INET6_ADDRSTRLEN] = { 0, };
480
262k
  size_t len;
481
262k
  const char *addr = str;
482
262k
  const char *idxs = NULL;
483
262k
  unsigned int idx = 0;
484
262k
  struct in6_addr ip6;
485
486
262k
  p = strchr_m(str, ':');
487
262k
  if (p == NULL) {
488
0
    return is_ipv6_literal(str);
489
0
  }
490
491
262k
  p = strchr_m(str, SCOPE_DELIMITER);
492
262k
  if (p && (p > str)) {
493
57
    len = PTR_DIFF(p, str);
494
57
    idxs = p + 1;
495
262k
  } else {
496
262k
    len = strlen(str);
497
262k
  }
498
499
262k
  if (len >= sizeof(buf)) {
500
9
    return false;
501
9
  }
502
262k
  if (idxs != NULL) {
503
57
    strncpy(buf, str, len);
504
57
    addr = buf;
505
57
  }
506
507
  /*
508
   * Cope with link-local.
509
   * This is IP:v6:addr%ifidx.
510
   */
511
262k
  if (idxs != NULL) {
512
57
    char c;
513
514
57
    ret = sscanf(idxs, "%5u%c", &idx, &c);
515
57
    if (ret != 1) {
516
9
      idx = 0;
517
9
    }
518
519
57
    if (idx > 0 && idx < UINT16_MAX) {
520
      /* a valid index */
521
28
      idxs = NULL;
522
28
    }
523
57
  }
524
525
  /*
526
   * Cope with link-local.
527
   * This is IP:v6:addr%ifname.
528
   */
529
262k
  if (idxs != NULL) {
530
29
    idx = if_nametoindex(idxs);
531
532
29
    if (idx > 0) {
533
      /* a valid index */
534
1
      idxs = NULL;
535
1
    }
536
29
  }
537
538
262k
  if (idxs != NULL) {
539
28
    return false;
540
28
  }
541
542
262k
  ret = inet_pton(AF_INET6, addr, &ip6);
543
262k
  if (ret <= 0) {
544
640
    return false;
545
640
  }
546
547
261k
  return true;
548
#else
549
  return false;
550
#endif
551
262k
}
552
553
/**
554
 * Return true if a string could be an IPv4 or IPv6 address.
555
 */
556
557
bool is_ipaddress(const char *str)
558
261k
{
559
261k
  return is_ipaddress_v4(str) || is_ipaddress_v6(str);
560
261k
}
561
562
/**
563
 * Is a sockaddr a broadcast address ?
564
 */
565
566
bool is_broadcast_addr(const struct sockaddr *pss)
567
0
{
568
0
#if defined(HAVE_IPV6)
569
0
  if (pss->sa_family == AF_INET6) {
570
0
    const struct in6_addr *sin6 =
571
0
      &((const struct sockaddr_in6 *)pss)->sin6_addr;
572
0
    return IN6_IS_ADDR_MULTICAST(sin6);
573
0
  }
574
0
#endif
575
0
  if (pss->sa_family == AF_INET) {
576
0
    uint32_t addr =
577
0
    ntohl(((const struct sockaddr_in *)pss)->sin_addr.s_addr);
578
0
    return addr == INADDR_BROADCAST;
579
0
  }
580
0
  return false;
581
0
}
582
583
/**
584
 * Check if an IPv7 is 127.0.0.1
585
 */
586
bool is_loopback_ip_v4(struct in_addr ip)
587
0
{
588
0
  struct in_addr a;
589
0
  a.s_addr = htonl(INADDR_LOOPBACK);
590
0
  return(ip.s_addr == a.s_addr);
591
0
}
592
593
/**
594
 * Check if a struct sockaddr is the loopback address.
595
 */
596
bool is_loopback_addr(const struct sockaddr *pss)
597
0
{
598
0
#if defined(HAVE_IPV6)
599
0
  if (pss->sa_family == AF_INET6) {
600
0
    const struct in6_addr *pin6 =
601
0
      &((const struct sockaddr_in6 *)pss)->sin6_addr;
602
0
    return IN6_IS_ADDR_LOOPBACK(pin6);
603
0
  }
604
0
#endif
605
0
  if (pss->sa_family == AF_INET) {
606
0
    const struct in_addr *pin = &((const struct sockaddr_in *)pss)->sin_addr;
607
0
    return is_loopback_ip_v4(*pin);
608
0
  }
609
0
  return false;
610
0
}
611
612
/**
613
 * Check if a struct sockaddr has an unspecified address.
614
 */
615
bool is_zero_addr(const struct sockaddr_storage *pss)
616
0
{
617
0
#if defined(HAVE_IPV6)
618
0
  if (pss->ss_family == AF_INET6) {
619
0
    const struct in6_addr *pin6 =
620
0
      &((const struct sockaddr_in6 *)pss)->sin6_addr;
621
0
    return IN6_IS_ADDR_UNSPECIFIED(pin6);
622
0
  }
623
0
#endif
624
0
  if (pss->ss_family == AF_INET) {
625
0
    const struct in_addr *pin = &((const struct sockaddr_in *)pss)->sin_addr;
626
0
    return is_zero_ip_v4(*pin);
627
0
  }
628
0
  if (pss->ss_family == AF_UNSPEC) {
629
0
    return true;
630
0
  }
631
0
  return false;
632
0
}
633
634
/**
635
 * Set an IP to 0.0.0.0.
636
 */
637
void zero_ip_v4(struct in_addr *ip)
638
0
{
639
0
  ZERO_STRUCTP(ip);
640
0
}
641
642
bool is_linklocal_addr(const struct sockaddr_storage *pss)
643
0
{
644
0
#ifdef HAVE_IPV6
645
0
  if (pss->ss_family == AF_INET6) {
646
0
    const struct in6_addr *pin6 =
647
0
      &((const struct sockaddr_in6 *)pss)->sin6_addr;
648
0
    return IN6_IS_ADDR_LINKLOCAL(pin6);
649
0
  }
650
0
#endif
651
0
  if (pss->ss_family == AF_INET) {
652
0
    const struct in_addr *pin =
653
0
      &((const struct sockaddr_in *)pss)->sin_addr;
654
0
    struct in_addr ll_addr;
655
0
    struct in_addr mask_addr;
656
657
    /* 169.254.0.0/16, is link local, see RFC 3927 */
658
0
    ll_addr.s_addr = 0xa9fe0000;
659
0
    mask_addr.s_addr = 0xffff0000;
660
0
    return same_net_v4(*pin, ll_addr, mask_addr);
661
0
  }
662
0
  return false;
663
0
}
664
665
/**
666
 * Convert an IPv4 struct in_addr to a struct sockaddr_storage.
667
 */
668
void in_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
669
    struct in_addr ip)
670
0
{
671
0
  struct sockaddr_in *sa = (struct sockaddr_in *)ss;
672
0
  ZERO_STRUCTP(ss);
673
0
  sa->sin_family = AF_INET;
674
0
  sa->sin_addr = ip;
675
0
}
676
677
#if defined(HAVE_IPV6)
678
/**
679
 * Convert an IPv6 struct in_addr to a struct sockaddr_storage.
680
 */
681
void in6_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
682
    struct in6_addr ip)
683
0
{
684
0
  struct sockaddr_in6 *sa = (struct sockaddr_in6 *)ss;
685
0
  memset(ss, '\0', sizeof(*ss));
686
0
  sa->sin6_family = AF_INET6;
687
0
  sa->sin6_addr = ip;
688
0
}
689
#endif
690
691
/**
692
 * Are two IPs on the same subnet?
693
 */
694
bool same_net(const struct sockaddr *ip1,
695
    const struct sockaddr *ip2,
696
    const struct sockaddr *mask)
697
0
{
698
0
  if (ip1->sa_family != ip2->sa_family) {
699
    /* Never on the same net. */
700
0
    return false;
701
0
  }
702
703
0
#if defined(HAVE_IPV6)
704
0
  if (ip1->sa_family == AF_INET6) {
705
0
    struct sockaddr_in6 ip1_6 = *(const struct sockaddr_in6 *)ip1;
706
0
    struct sockaddr_in6 ip2_6 = *(const struct sockaddr_in6 *)ip2;
707
0
    struct sockaddr_in6 mask_6 = *(const struct sockaddr_in6 *)mask;
708
0
    char *p1 = (char *)&ip1_6.sin6_addr;
709
0
    char *p2 = (char *)&ip2_6.sin6_addr;
710
0
    char *m = (char *)&mask_6.sin6_addr;
711
0
    size_t i;
712
713
0
    for (i = 0; i < sizeof(struct in6_addr); i++) {
714
0
      *p1++ &= *m;
715
0
      *p2++ &= *m;
716
0
      m++;
717
0
    }
718
0
    return (memcmp(&ip1_6.sin6_addr,
719
0
        &ip2_6.sin6_addr,
720
0
        sizeof(struct in6_addr)) == 0);
721
0
  }
722
0
#endif
723
0
  if (ip1->sa_family == AF_INET) {
724
0
    return same_net_v4(((const struct sockaddr_in *)ip1)->sin_addr,
725
0
        ((const struct sockaddr_in *)ip2)->sin_addr,
726
0
        ((const struct sockaddr_in *)mask)->sin_addr);
727
0
  }
728
0
  return false;
729
0
}
730
731
/**
732
 * Are two sockaddr 's the same family and address ? Ignore port etc.
733
 */
734
735
bool sockaddr_equal(const struct sockaddr *ip1,
736
    const struct sockaddr *ip2)
737
0
{
738
0
  if (ip1->sa_family != ip2->sa_family) {
739
    /* Never the same. */
740
0
    return false;
741
0
  }
742
743
0
#if defined(HAVE_IPV6)
744
0
  if (ip1->sa_family == AF_INET6) {
745
0
    return (memcmp(&((const struct sockaddr_in6 *)ip1)->sin6_addr,
746
0
        &((const struct sockaddr_in6 *)ip2)->sin6_addr,
747
0
        sizeof(struct in6_addr)) == 0);
748
0
  }
749
0
#endif
750
0
  if (ip1->sa_family == AF_INET) {
751
0
    return (memcmp(&((const struct sockaddr_in *)ip1)->sin_addr,
752
0
        &((const struct sockaddr_in *)ip2)->sin_addr,
753
0
        sizeof(struct in_addr)) == 0);
754
0
  }
755
0
  return false;
756
0
}
757
758
/**
759
 * Is an IP address the INADDR_ANY or in6addr_any value ?
760
 */
761
bool is_address_any(const struct sockaddr *psa)
762
0
{
763
0
#if defined(HAVE_IPV6)
764
0
  if (psa->sa_family == AF_INET6) {
765
0
    const struct sockaddr_in6 *si6 = (const struct sockaddr_in6 *)psa;
766
0
    if (memcmp(&in6addr_any,
767
0
        &si6->sin6_addr,
768
0
        sizeof(in6addr_any)) == 0) {
769
0
      return true;
770
0
    }
771
0
    return false;
772
0
  }
773
0
#endif
774
0
  if (psa->sa_family == AF_INET) {
775
0
    const struct sockaddr_in *si = (const struct sockaddr_in *)psa;
776
0
    if (si->sin_addr.s_addr == INADDR_ANY) {
777
0
      return true;
778
0
    }
779
0
    return false;
780
0
  }
781
0
  return false;
782
0
}
783
784
void set_sockaddr_port(struct sockaddr *psa, uint16_t port)
785
0
{
786
0
#if defined(HAVE_IPV6)
787
0
  if (psa->sa_family == AF_INET6) {
788
0
    ((struct sockaddr_in6 *)psa)->sin6_port = htons(port);
789
0
  }
790
0
#endif
791
0
  if (psa->sa_family == AF_INET) {
792
0
    ((struct sockaddr_in *)psa)->sin_port = htons(port);
793
0
  }
794
0
}
795
796
797
/****************************************************************************
798
 Get a port number in host byte order from a sockaddr_storage.
799
****************************************************************************/
800
801
uint16_t get_sockaddr_port(const struct sockaddr_storage *pss)
802
0
{
803
0
  uint16_t port = 0;
804
805
0
  if (pss->ss_family != AF_INET) {
806
0
#if defined(HAVE_IPV6)
807
    /* IPv6 */
808
0
    const struct sockaddr_in6 *sa6 =
809
0
      (const struct sockaddr_in6 *)pss;
810
0
    port = ntohs(sa6->sin6_port);
811
0
#endif
812
0
  } else {
813
0
    const struct sockaddr_in *sa =
814
0
      (const struct sockaddr_in *)pss;
815
0
    port = ntohs(sa->sin_port);
816
0
  }
817
0
  return port;
818
0
}
819
820
/****************************************************************************
821
 Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
822
****************************************************************************/
823
824
char *print_sockaddr_len(char *dest,
825
       size_t destlen,
826
      const struct sockaddr *psa,
827
      socklen_t psalen)
828
0
{
829
0
  if (destlen > 0) {
830
0
    dest[0] = '\0';
831
0
  }
832
0
  (void)sys_getnameinfo(psa,
833
0
      psalen,
834
0
      dest, destlen,
835
0
      NULL, 0,
836
0
      NI_NUMERICHOST);
837
0
  return dest;
838
0
}
839
840
/****************************************************************************
841
 Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
842
****************************************************************************/
843
844
char *print_sockaddr(char *dest,
845
      size_t destlen,
846
      const struct sockaddr_storage *psa)
847
0
{
848
0
  return print_sockaddr_len(dest, destlen, (const struct sockaddr *)psa,
849
0
      sizeof(struct sockaddr_storage));
850
0
}
851
852
/****************************************************************************
853
 Print out a canonical IPv4 or IPv6 address from a struct sockaddr_storage.
854
****************************************************************************/
855
856
char *print_canonical_sockaddr(TALLOC_CTX *ctx,
857
      const struct sockaddr_storage *pss)
858
0
{
859
0
  char addr[INET6_ADDRSTRLEN];
860
0
  char *dest = NULL;
861
0
  int ret;
862
863
  /* Linux getnameinfo() man pages says port is uninitialized if
864
     service name is NULL. */
865
866
0
  ret = sys_getnameinfo((const struct sockaddr *)pss,
867
0
      sizeof(struct sockaddr_storage),
868
0
      addr, sizeof(addr),
869
0
      NULL, 0,
870
0
      NI_NUMERICHOST);
871
0
  if (ret != 0) {
872
0
    return NULL;
873
0
  }
874
875
0
  if (pss->ss_family != AF_INET) {
876
0
#if defined(HAVE_IPV6)
877
0
    dest = talloc_asprintf(ctx, "[%s]", addr);
878
#else
879
    return NULL;
880
#endif
881
0
  } else {
882
0
    dest = talloc_asprintf(ctx, "%s", addr);
883
0
  }
884
885
0
  return dest;
886
0
}
887
888
enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
889
890
typedef struct smb_socket_option {
891
  const char *name;
892
  int level;
893
  int option;
894
  int value;
895
  int opttype;
896
} smb_socket_option;
897
898
static const smb_socket_option socket_options[] = {
899
  {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
900
  {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
901
  {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
902
#ifdef TCP_NODELAY
903
  {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
904
#endif
905
#ifdef TCP_KEEPCNT
906
  {"TCP_KEEPCNT", IPPROTO_TCP, TCP_KEEPCNT, 0, OPT_INT},
907
#endif
908
#ifdef TCP_KEEPIDLE
909
  {"TCP_KEEPIDLE", IPPROTO_TCP, TCP_KEEPIDLE, 0, OPT_INT},
910
#endif
911
#ifdef TCP_KEEPINTVL
912
  {"TCP_KEEPINTVL", IPPROTO_TCP, TCP_KEEPINTVL, 0, OPT_INT},
913
#endif
914
#ifdef IPTOS_LOWDELAY
915
  {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
916
#endif
917
#ifdef IPTOS_THROUGHPUT
918
  {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
919
#endif
920
#ifdef SO_REUSEPORT
921
  {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
922
#endif
923
#ifdef SO_SNDBUF
924
  {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
925
#endif
926
#ifdef SO_RCVBUF
927
  {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
928
#endif
929
#ifdef SO_SNDLOWAT
930
  {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
931
#endif
932
#ifdef SO_RCVLOWAT
933
  {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
934
#endif
935
#ifdef SO_SNDTIMEO
936
  {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
937
#endif
938
#ifdef SO_RCVTIMEO
939
  {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
940
#endif
941
#ifdef TCP_FASTACK
942
  {"TCP_FASTACK", IPPROTO_TCP, TCP_FASTACK, 0, OPT_INT},
943
#endif
944
#ifdef TCP_QUICKACK
945
  {"TCP_QUICKACK", IPPROTO_TCP, TCP_QUICKACK, 0, OPT_BOOL},
946
#endif
947
#ifdef TCP_NODELAYACK
948
  {"TCP_NODELAYACK", IPPROTO_TCP, TCP_NODELAYACK, 0, OPT_BOOL},
949
#endif
950
#ifdef TCP_KEEPALIVE_THRESHOLD
951
  {"TCP_KEEPALIVE_THRESHOLD", IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, 0, OPT_INT},
952
#endif
953
#ifdef TCP_KEEPALIVE_ABORT_THRESHOLD
954
  {"TCP_KEEPALIVE_ABORT_THRESHOLD", IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, 0, OPT_INT},
955
#endif
956
#ifdef TCP_DEFER_ACCEPT
957
  {"TCP_DEFER_ACCEPT", IPPROTO_TCP, TCP_DEFER_ACCEPT, 0, OPT_INT},
958
#endif
959
#ifdef TCP_USER_TIMEOUT
960
  {"TCP_USER_TIMEOUT", IPPROTO_TCP, TCP_USER_TIMEOUT, 0, OPT_INT},
961
#endif
962
  {NULL,0,0,0,0}};
963
964
/****************************************************************************
965
 Print socket options.
966
****************************************************************************/
967
968
static void print_socket_options(TALLOC_CTX *ctx, int s)
969
0
{
970
0
  const smb_socket_option *p = &socket_options[0];
971
0
  char *str = NULL;
972
973
0
  if (DEBUGLEVEL < 5) {
974
0
    return;
975
0
  }
976
977
0
  str = talloc_strdup(ctx, "");
978
0
  if (str == NULL) {
979
0
    DBG_WARNING("talloc failed\n");
980
0
    goto done;
981
0
  }
982
983
0
  for (; p->name != NULL; p++) {
984
0
    int ret, val;
985
0
    socklen_t vlen = sizeof(val);
986
987
0
    ret = getsockopt(s, p->level, p->option, (void *)&val, &vlen);
988
0
    if (ret == -1) {
989
0
      DBG_INFO("Could not test socket option %s: %s.\n",
990
0
         p->name, strerror(errno));
991
0
      continue;
992
0
    }
993
994
0
    talloc_asprintf_addbuf(
995
0
      &str,
996
0
      "%s%s=%d",
997
0
      str[0] != '\0' ? ", " : "",
998
0
      p->name,
999
0
      val);
1000
0
  }
1001
1002
0
  DEBUG(5, ("socket options: %s\n", str));
1003
0
done:
1004
0
  TALLOC_FREE(str);
1005
0
 }
1006
1007
/****************************************************************************
1008
 Set user socket options.
1009
****************************************************************************/
1010
1011
void set_socket_options(int fd, const char *options)
1012
0
{
1013
0
  TALLOC_CTX *ctx = talloc_new(NULL);
1014
0
  char *tok;
1015
1016
0
  while (next_token_talloc(ctx, &options, &tok," \t,")) {
1017
0
    int ret=0,i;
1018
0
    int value = 1;
1019
0
    char *p;
1020
0
    bool got_value = false;
1021
1022
0
    if ((p = strchr_m(tok,'='))) {
1023
0
      *p = 0;
1024
0
      value = atoi(p+1);
1025
0
      got_value = true;
1026
0
    }
1027
1028
0
    for (i=0;socket_options[i].name;i++)
1029
0
      if (strequal(socket_options[i].name,tok))
1030
0
        break;
1031
1032
0
    if (!socket_options[i].name) {
1033
0
      DEBUG(0,("Unknown socket option %s\n",tok));
1034
0
      continue;
1035
0
    }
1036
1037
0
    switch (socket_options[i].opttype) {
1038
0
    case OPT_BOOL:
1039
0
    case OPT_INT:
1040
0
      ret = setsockopt(fd,socket_options[i].level,
1041
0
          socket_options[i].option,
1042
0
          (char *)&value,sizeof(int));
1043
0
      break;
1044
1045
0
    case OPT_ON:
1046
0
      if (got_value)
1047
0
        DEBUG(0,("syntax error - %s "
1048
0
          "does not take a value\n",tok));
1049
1050
0
      {
1051
0
        int on = socket_options[i].value;
1052
0
        ret = setsockopt(fd,socket_options[i].level,
1053
0
          socket_options[i].option,
1054
0
          (char *)&on,sizeof(int));
1055
0
      }
1056
0
      break;
1057
0
    }
1058
1059
0
    if (ret != 0) {
1060
      /* be aware that some systems like Solaris return
1061
       * EINVAL to a setsockopt() call when the client
1062
       * sent a RST previously - no need to worry */
1063
0
      DEBUG(2,("Failed to set socket option %s (Error %s)\n",
1064
0
        tok, strerror(errno) ));
1065
0
    }
1066
0
  }
1067
1068
0
  print_socket_options(ctx, fd);
1069
0
  TALLOC_FREE(ctx);
1070
0
}
1071
1072
/*
1073
 * Utility function that copes only with AF_INET and AF_INET6
1074
 * as that's all we're going to get out of DNS / NetBIOS / WINS
1075
 * name resolution functions.
1076
 */
1077
1078
bool sockaddr_storage_to_samba_sockaddr(
1079
  struct samba_sockaddr *sa, const struct sockaddr_storage *ss)
1080
0
{
1081
0
  sa->u.ss = *ss;
1082
1083
0
  switch (ss->ss_family) {
1084
0
  case AF_INET:
1085
0
    sa->sa_socklen = sizeof(struct sockaddr_in);
1086
0
    break;
1087
0
#ifdef HAVE_IPV6
1088
0
  case AF_INET6:
1089
0
    sa->sa_socklen = sizeof(struct sockaddr_in6);
1090
0
    break;
1091
0
#endif
1092
0
  default:
1093
0
    return false;
1094
0
  }
1095
0
  return true;
1096
0
}
1097
1098
bool samba_sockaddr_set_port(struct samba_sockaddr *sa, uint16_t port)
1099
0
{
1100
0
  if (sa->u.sa.sa_family == AF_INET) {
1101
0
    sa->u.in.sin_port = htons(port);
1102
0
    return true;
1103
0
  }
1104
0
#ifdef HAVE_IPV6
1105
0
  if (sa->u.sa.sa_family == AF_INET6) {
1106
0
    sa->u.in6.sin6_port = htons(port);
1107
0
    return true;
1108
0
  }
1109
0
#endif
1110
0
  return false;
1111
0
}
1112
1113
bool samba_sockaddr_get_port(const struct samba_sockaddr *sa, uint16_t *port)
1114
0
{
1115
0
  if (sa->u.sa.sa_family == AF_INET) {
1116
0
    *port = ntohs(sa->u.in.sin_port);
1117
0
    return true;
1118
0
  }
1119
0
#ifdef HAVE_IPV6
1120
0
  if (sa->u.sa.sa_family == AF_INET6) {
1121
0
    *port = ntohs(sa->u.in6.sin6_port);
1122
0
    return true;
1123
0
  }
1124
0
#endif
1125
0
  return false;
1126
0
}