Coverage Report

Created: 2023-05-19 06:16

/src/ntp-dev/lib/isc/unix/net.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2004, 2005, 2007, 2008, 2012  Internet Systems Consortium, Inc. ("ISC")
3
 * Copyright (C) 1999-2003  Internet Software Consortium.
4
 *
5
 * Permission to use, copy, modify, and/or distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
 * PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
/* $Id$ */
19
20
#include <config.h>
21
22
#include <sys/types.h>
23
24
#if defined(HAVE_SYS_SYSCTL_H)
25
#if defined(HAVE_SYS_PARAM_H)
26
#include <sys/param.h>
27
#endif
28
#include <sys/sysctl.h>
29
#endif
30
31
#include <errno.h>
32
#include <unistd.h>
33
34
#include <isc/log.h>
35
#include <isc/msgs.h>
36
#include <isc/net.h>
37
#include <isc/once.h>
38
#include <isc/strerror.h>
39
#include <isc/string.h>
40
#include <isc/util.h>
41
42
/*%
43
 * Definitions about UDP port range specification.  This is a total mess of
44
 * portability variants: some use sysctl (but the sysctl names vary), some use
45
 * system-specific interfaces, some have the same interface for IPv4 and IPv6,
46
 * some separate them, etc...
47
 */
48
49
/*%
50
 * The last resort defaults: use all non well known port space
51
 */
52
#ifndef ISC_NET_PORTRANGELOW
53
0
#define ISC_NET_PORTRANGELOW 1024
54
#endif  /* ISC_NET_PORTRANGELOW */
55
#ifndef ISC_NET_PORTRANGEHIGH
56
0
#define ISC_NET_PORTRANGEHIGH 65535
57
#endif  /* ISC_NET_PORTRANGEHIGH */
58
59
#ifdef HAVE_SYSCTLBYNAME
60
61
/*%
62
 * sysctl variants
63
 */
64
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
65
#define USE_SYSCTL_PORTRANGE
66
#define SYSCTL_V4PORTRANGE_LOW  "net.inet.ip.portrange.hifirst"
67
#define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.portrange.hilast"
68
#define SYSCTL_V6PORTRANGE_LOW  "net.inet.ip.portrange.hifirst"
69
#define SYSCTL_V6PORTRANGE_HIGH "net.inet.ip.portrange.hilast"
70
#endif
71
72
#ifdef __NetBSD__
73
#define USE_SYSCTL_PORTRANGE
74
#define SYSCTL_V4PORTRANGE_LOW  "net.inet.ip.anonportmin"
75
#define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.anonportmax"
76
#define SYSCTL_V6PORTRANGE_LOW  "net.inet6.ip6.anonportmin"
77
#define SYSCTL_V6PORTRANGE_HIGH "net.inet6.ip6.anonportmax"
78
#endif
79
80
#else /* !HAVE_SYSCTLBYNAME */
81
82
#ifdef __OpenBSD__
83
#define USE_SYSCTL_PORTRANGE
84
#define SYSCTL_V4PORTRANGE_LOW  { CTL_NET, PF_INET, IPPROTO_IP, \
85
          IPCTL_IPPORT_HIFIRSTAUTO }
86
#define SYSCTL_V4PORTRANGE_HIGH { CTL_NET, PF_INET, IPPROTO_IP, \
87
          IPCTL_IPPORT_HILASTAUTO }
88
/* Same for IPv6 */
89
#define SYSCTL_V6PORTRANGE_LOW  SYSCTL_V4PORTRANGE_LOW
90
#define SYSCTL_V6PORTRANGE_HIGH SYSCTL_V4PORTRANGE_HIGH
91
#endif
92
93
#endif /* HAVE_SYSCTLBYNAME */
94
95
#if defined(ISC_PLATFORM_NEEDIN6ADDRANY)
96
const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
97
#endif
98
99
#if defined(ISC_PLATFORM_HAVEIPV6)
100
101
# if defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
102
const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT;
103
# endif
104
105
# if defined(WANT_IPV6)
106
static isc_once_t   once_ipv6only = ISC_ONCE_INIT;
107
# endif
108
109
# if defined(ISC_PLATFORM_HAVEIPV6) && \
110
     defined(WANT_IPV6) && defined(ISC_PLATFORM_HAVEIN6PKTINFO)
111
static isc_once_t   once_ipv6pktinfo = ISC_ONCE_INIT;
112
# endif
113
#endif /* ISC_PLATFORM_HAVEIPV6 */
114
115
static isc_once_t   once = ISC_ONCE_INIT;
116
117
static isc_result_t ipv4_result = ISC_R_NOTFOUND;
118
static isc_result_t ipv6_result = ISC_R_NOTFOUND;
119
static isc_result_t unix_result = ISC_R_NOTFOUND;
120
static isc_result_t ipv6only_result = ISC_R_NOTFOUND;
121
static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND;
122
123
static isc_result_t
124
2
try_proto(int domain) {
125
2
  int s;
126
2
  isc_result_t result = ISC_R_SUCCESS;
127
2
  char strbuf[ISC_STRERRORSIZE];
128
129
2
  s = socket(domain, SOCK_STREAM, 0);
130
2
  if (s == -1) {
131
0
    switch (errno) {
132
0
#ifdef EAFNOSUPPORT
133
0
    case EAFNOSUPPORT:
134
0
#endif
135
0
#ifdef EPROTONOSUPPORT
136
0
    case EPROTONOSUPPORT:
137
0
#endif
138
0
#ifdef EINVAL
139
0
    case EINVAL:
140
0
#endif
141
0
      return (ISC_R_NOTFOUND);
142
0
    default:
143
0
      isc__strerror(errno, strbuf, sizeof(strbuf));
144
0
      UNEXPECTED_ERROR(__FILE__, __LINE__,
145
0
           "socket() %s: %s",
146
0
           isc_msgcat_get(isc_msgcat,
147
0
              ISC_MSGSET_GENERAL,
148
0
              ISC_MSG_FAILED,
149
0
              "failed"),
150
0
           strbuf);
151
0
      return (ISC_R_UNEXPECTED);
152
0
    }
153
0
  }
154
155
2
#ifdef ISC_PLATFORM_HAVEIPV6
156
2
#ifdef WANT_IPV6
157
2
#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
158
2
  if (domain == PF_INET6) {
159
1
    struct sockaddr_in6 sin6;
160
1
    GETSOCKNAME_SOCKLEN_TYPE len; /* NTP local change */
161
162
    /*
163
     * Check to see if IPv6 is broken, as is common on Linux.
164
     */
165
1
    len = sizeof(sin6);
166
1
    if (getsockname(s, (struct sockaddr *)&sin6, &len) < 0)
167
0
    {
168
0
      isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
169
0
              ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
170
0
              "retrieving the address of an IPv6 "
171
0
              "socket from the kernel failed.");
172
0
      isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
173
0
              ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
174
0
              "IPv6 is not supported.");
175
0
      result = ISC_R_NOTFOUND;
176
1
    } else {
177
1
      if (len == sizeof(struct sockaddr_in6))
178
1
        result = ISC_R_SUCCESS;
179
0
      else {
180
0
        isc_log_write(isc_lctx,
181
0
                ISC_LOGCATEGORY_GENERAL,
182
0
                ISC_LOGMODULE_SOCKET,
183
0
                ISC_LOG_ERROR,
184
0
                "IPv6 structures in kernel and "
185
0
                "user space do not match.");
186
0
        isc_log_write(isc_lctx,
187
0
                ISC_LOGCATEGORY_GENERAL,
188
0
                ISC_LOGMODULE_SOCKET,
189
0
                ISC_LOG_ERROR,
190
0
                "IPv6 is not supported.");
191
0
        result = ISC_R_NOTFOUND;
192
0
      }
193
1
    }
194
1
  }
195
2
#endif
196
2
#endif
197
2
#endif
198
199
2
  (void)close(s);
200
201
2
  return (result);
202
2
}
203
204
static void
205
1
initialize_action(void) {
206
1
  ipv4_result = try_proto(PF_INET);
207
1
#ifdef ISC_PLATFORM_HAVEIPV6
208
1
#ifdef WANT_IPV6
209
1
#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
210
1
  ipv6_result = try_proto(PF_INET6);
211
1
#endif
212
1
#endif
213
1
#endif
214
#ifdef ISC_PLATFORM_HAVESYSUNH
215
  unix_result = try_proto(PF_UNIX);
216
#endif
217
1
}
218
219
static void
220
3
initialize(void) {
221
3
  RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
222
3
}
223
224
isc_result_t
225
1
isc_net_probeipv4(void) {
226
1
  initialize();
227
1
  return (ipv4_result);
228
1
}
229
230
isc_result_t
231
2
isc_net_probeipv6(void) {
232
2
  initialize();
233
2
  return (ipv6_result);
234
2
}
235
236
isc_result_t
237
0
isc_net_probeunix(void) {
238
0
  initialize();
239
0
  return (unix_result);
240
0
}
241
242
#ifdef ISC_PLATFORM_HAVEIPV6
243
#ifdef WANT_IPV6
244
static void
245
1
try_ipv6only(void) {
246
1
#ifdef IPV6_V6ONLY
247
1
  int s, on;
248
1
  char strbuf[ISC_STRERRORSIZE];
249
1
#endif
250
1
  isc_result_t result;
251
252
1
  result = isc_net_probeipv6();
253
1
  if (result != ISC_R_SUCCESS) {
254
0
    ipv6only_result = result;
255
0
    return;
256
0
  }
257
258
#ifndef IPV6_V6ONLY
259
  ipv6only_result = ISC_R_NOTFOUND;
260
  return;
261
#else
262
  /* check for TCP sockets */
263
1
  s = socket(PF_INET6, SOCK_STREAM, 0);
264
1
  if (s == -1) {
265
0
    isc__strerror(errno, strbuf, sizeof(strbuf));
266
0
    UNEXPECTED_ERROR(__FILE__, __LINE__,
267
0
         "socket() %s: %s",
268
0
         isc_msgcat_get(isc_msgcat,
269
0
            ISC_MSGSET_GENERAL,
270
0
            ISC_MSG_FAILED,
271
0
            "failed"),
272
0
         strbuf);
273
0
    ipv6only_result = ISC_R_UNEXPECTED;
274
0
    return;
275
0
  }
276
277
1
  on = 1;
278
1
  if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
279
0
    ipv6only_result = ISC_R_NOTFOUND;
280
0
    goto close;
281
0
  }
282
283
1
  close(s);
284
285
  /* check for UDP sockets */
286
1
  s = socket(PF_INET6, SOCK_DGRAM, 0);
287
1
  if (s == -1) {
288
0
    isc__strerror(errno, strbuf, sizeof(strbuf));
289
0
    UNEXPECTED_ERROR(__FILE__, __LINE__,
290
0
         "socket() %s: %s",
291
0
         isc_msgcat_get(isc_msgcat,
292
0
            ISC_MSGSET_GENERAL,
293
0
            ISC_MSG_FAILED,
294
0
            "failed"),
295
0
         strbuf);
296
0
    ipv6only_result = ISC_R_UNEXPECTED;
297
0
    return;
298
0
  }
299
300
1
  on = 1;
301
1
  if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
302
0
    ipv6only_result = ISC_R_NOTFOUND;
303
0
    goto close;
304
0
  }
305
306
1
  ipv6only_result = ISC_R_SUCCESS;
307
308
1
close:
309
1
  close(s);
310
1
  return;
311
1
#endif /* IPV6_V6ONLY */
312
1
}
313
314
static void
315
1
initialize_ipv6only(void) {
316
1
  RUNTIME_CHECK(isc_once_do(&once_ipv6only,
317
1
          try_ipv6only) == ISC_R_SUCCESS);
318
1
}
319
320
#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
321
static void
322
0
try_ipv6pktinfo(void) {
323
0
  int s, on;
324
0
  char strbuf[ISC_STRERRORSIZE];
325
0
  isc_result_t result;
326
0
  int optname;
327
328
0
  result = isc_net_probeipv6();
329
0
  if (result != ISC_R_SUCCESS) {
330
0
    ipv6pktinfo_result = result;
331
0
    return;
332
0
  }
333
334
  /* we only use this for UDP sockets */
335
0
  s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
336
0
  if (s == -1) {
337
0
    isc__strerror(errno, strbuf, sizeof(strbuf));
338
0
    UNEXPECTED_ERROR(__FILE__, __LINE__,
339
0
         "socket() %s: %s",
340
0
         isc_msgcat_get(isc_msgcat,
341
0
            ISC_MSGSET_GENERAL,
342
0
            ISC_MSG_FAILED,
343
0
            "failed"),
344
0
         strbuf);
345
0
    ipv6pktinfo_result = ISC_R_UNEXPECTED;
346
0
    return;
347
0
  }
348
349
0
#ifdef IPV6_RECVPKTINFO
350
0
  optname = IPV6_RECVPKTINFO;
351
#else
352
  optname = IPV6_PKTINFO;
353
#endif
354
0
  on = 1;
355
0
  if (setsockopt(s, IPPROTO_IPV6, optname, &on, sizeof(on)) < 0) {
356
0
    ipv6pktinfo_result = ISC_R_NOTFOUND;
357
0
    goto close;
358
0
  }
359
360
0
  ipv6pktinfo_result = ISC_R_SUCCESS;
361
362
0
close:
363
0
  close(s);
364
0
  return;
365
0
}
366
367
static void
368
0
initialize_ipv6pktinfo(void) {
369
0
  RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
370
0
          try_ipv6pktinfo) == ISC_R_SUCCESS);
371
0
}
372
#endif /* ISC_PLATFORM_HAVEIN6PKTINFO */
373
#endif /* WANT_IPV6 */
374
#endif /* ISC_PLATFORM_HAVEIPV6 */
375
376
isc_result_t
377
1
isc_net_probe_ipv6only(void) {
378
1
#ifdef ISC_PLATFORM_HAVEIPV6
379
1
#ifdef WANT_IPV6
380
1
  initialize_ipv6only();
381
#else
382
  ipv6only_result = ISC_R_NOTFOUND;
383
#endif
384
1
#endif
385
1
  return (ipv6only_result);
386
1
}
387
388
isc_result_t
389
0
isc_net_probe_ipv6pktinfo(void) {
390
0
#ifdef ISC_PLATFORM_HAVEIPV6
391
0
#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
392
0
#ifdef WANT_IPV6
393
0
  initialize_ipv6pktinfo();
394
#else
395
  ipv6pktinfo_result = ISC_R_NOTFOUND;
396
#endif
397
0
#endif
398
0
#endif
399
0
  return (ipv6pktinfo_result);
400
0
}
401
402
#if defined(USE_SYSCTL_PORTRANGE)
403
#if defined(HAVE_SYSCTLBYNAME)
404
static isc_result_t
405
getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
406
  int port_low, port_high;
407
  size_t portlen;
408
  const char *sysctlname_lowport, *sysctlname_hiport;
409
410
  if (af == AF_INET) {
411
    sysctlname_lowport = SYSCTL_V4PORTRANGE_LOW;
412
    sysctlname_hiport = SYSCTL_V4PORTRANGE_HIGH;
413
  } else {
414
    sysctlname_lowport = SYSCTL_V6PORTRANGE_LOW;
415
    sysctlname_hiport = SYSCTL_V6PORTRANGE_HIGH;
416
  }
417
  portlen = sizeof(portlen);
418
  if (sysctlbyname(sysctlname_lowport, &port_low, &portlen,
419
       NULL, 0) < 0) {
420
    return (ISC_R_FAILURE);
421
  }
422
  portlen = sizeof(portlen);
423
  if (sysctlbyname(sysctlname_hiport, &port_high, &portlen,
424
       NULL, 0) < 0) {
425
    return (ISC_R_FAILURE);
426
  }
427
  if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
428
    return (ISC_R_RANGE);
429
430
  *low = (in_port_t)port_low;
431
  *high = (in_port_t)port_high;
432
433
  return (ISC_R_SUCCESS);
434
}
435
#else /* !HAVE_SYSCTLBYNAME */
436
static isc_result_t
437
getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
438
  int mib_lo4[4] = SYSCTL_V4PORTRANGE_LOW;
439
  int mib_hi4[4] = SYSCTL_V4PORTRANGE_HIGH;
440
  int mib_lo6[4] = SYSCTL_V6PORTRANGE_LOW;
441
  int mib_hi6[4] = SYSCTL_V6PORTRANGE_HIGH;
442
  int *mib_lo, *mib_hi, miblen;
443
  int port_low, port_high;
444
  size_t portlen;
445
446
  if (af == AF_INET) {
447
    mib_lo = mib_lo4;
448
    mib_hi = mib_hi4;
449
    miblen = sizeof(mib_lo4) / sizeof(mib_lo4[0]);
450
  } else {
451
    mib_lo = mib_lo6;
452
    mib_hi = mib_hi6;
453
    miblen = sizeof(mib_lo6) / sizeof(mib_lo6[0]);
454
  }
455
456
  portlen = sizeof(portlen);
457
  if (sysctl(mib_lo, miblen, &port_low, &portlen, NULL, 0) < 0) {
458
    return (ISC_R_FAILURE);
459
  }
460
461
  portlen = sizeof(portlen);
462
  if (sysctl(mib_hi, miblen, &port_high, &portlen, NULL, 0) < 0) {
463
    return (ISC_R_FAILURE);
464
  }
465
466
  if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
467
    return (ISC_R_RANGE);
468
469
  *low = (in_port_t) port_low;
470
  *high = (in_port_t) port_high;
471
472
  return (ISC_R_SUCCESS);
473
}
474
#endif /* HAVE_SYSCTLBYNAME */
475
#endif /* USE_SYSCTL_PORTRANGE */
476
477
isc_result_t
478
0
isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
479
0
  int result = ISC_R_FAILURE;
480
481
0
  REQUIRE(low != NULL && high != NULL);
482
483
#if defined(USE_SYSCTL_PORTRANGE)
484
  result = getudpportrange_sysctl(af, low, high);
485
#else
486
0
  UNUSED(af);
487
0
#endif
488
489
0
  if (result != ISC_R_SUCCESS) {
490
0
    *low = ISC_NET_PORTRANGELOW;
491
0
    *high = ISC_NET_PORTRANGEHIGH;
492
0
  }
493
494
0
  return (ISC_R_SUCCESS);  /* we currently never fail in this function */
495
0
}
496
497
void
498
0
isc_net_disableipv4(void) {
499
0
  initialize();
500
0
  if (ipv4_result == ISC_R_SUCCESS)
501
0
    ipv4_result = ISC_R_DISABLED;
502
0
}
503
504
void
505
0
isc_net_disableipv6(void) {
506
0
  initialize();
507
0
  if (ipv6_result == ISC_R_SUCCESS)
508
0
    ipv6_result = ISC_R_DISABLED;
509
0
}
510
511
void
512
0
isc_net_enableipv4(void) {
513
0
  initialize();
514
0
  if (ipv4_result == ISC_R_DISABLED)
515
0
    ipv4_result = ISC_R_SUCCESS;
516
0
}
517
518
void
519
0
isc_net_enableipv6(void) {
520
0
  initialize();
521
0
  if (ipv6_result == ISC_R_DISABLED)
522
0
    ipv6_result = ISC_R_SUCCESS;
523
0
}