Coverage Report

Created: 2025-07-18 07:02

/src/bind9/lib/isc/net.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
#include <errno.h>
15
#include <fcntl.h>
16
#include <netdb.h>
17
#include <stdbool.h>
18
#include <sys/param.h>
19
#include <sys/types.h>
20
#include <sys/uio.h>
21
#include <unistd.h>
22
23
#if HAVE_SYS_SYSCTL_H && !defined(__linux__)
24
#include <sys/sysctl.h>
25
#endif
26
27
#include <isc/log.h>
28
#include <isc/net.h>
29
#include <isc/once.h>
30
#include <isc/strerr.h>
31
#include <isc/string.h>
32
#include <isc/util.h>
33
34
/*%
35
 * Definitions about UDP port range specification.  This is a total mess of
36
 * portability variants: some use sysctl (but the sysctl names vary), some use
37
 * system-specific interfaces, some have the same interface for IPv4 and IPv6,
38
 * some separate them, etc...
39
 */
40
41
/*%
42
 * The last resort defaults: use all non well known port space
43
 */
44
#ifndef ISC_NET_PORTRANGELOW
45
0
#define ISC_NET_PORTRANGELOW 1024
46
#endif /* ISC_NET_PORTRANGELOW */
47
#ifndef ISC_NET_PORTRANGEHIGH
48
0
#define ISC_NET_PORTRANGEHIGH 65535
49
#endif /* ISC_NET_PORTRANGEHIGH */
50
51
#ifdef HAVE_SYSCTLBYNAME
52
53
/*%
54
 * sysctl variants
55
 */
56
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
57
#define USE_SYSCTL_PORTRANGE
58
#define SYSCTL_V4PORTRANGE_LOW  "net.inet.ip.portrange.hifirst"
59
#define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.portrange.hilast"
60
#define SYSCTL_V6PORTRANGE_LOW  "net.inet.ip.portrange.hifirst"
61
#define SYSCTL_V6PORTRANGE_HIGH "net.inet.ip.portrange.hilast"
62
#endif /* if defined(__FreeBSD__) || defined(__APPLE__) || \
63
  * defined(__DragonFly__) */
64
65
#ifdef __NetBSD__
66
#define USE_SYSCTL_PORTRANGE
67
#define SYSCTL_V4PORTRANGE_LOW  "net.inet.ip.anonportmin"
68
#define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.anonportmax"
69
#define SYSCTL_V6PORTRANGE_LOW  "net.inet6.ip6.anonportmin"
70
#define SYSCTL_V6PORTRANGE_HIGH "net.inet6.ip6.anonportmax"
71
#endif /* ifdef __NetBSD__ */
72
73
#else /* !HAVE_SYSCTLBYNAME */
74
75
#ifdef __OpenBSD__
76
#define USE_SYSCTL_PORTRANGE
77
#define SYSCTL_V4PORTRANGE_LOW \
78
  { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_IPPORT_HIFIRSTAUTO }
79
#define SYSCTL_V4PORTRANGE_HIGH \
80
  { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_IPPORT_HILASTAUTO }
81
/* Same for IPv6 */
82
#define SYSCTL_V6PORTRANGE_LOW  SYSCTL_V4PORTRANGE_LOW
83
#define SYSCTL_V6PORTRANGE_HIGH SYSCTL_V4PORTRANGE_HIGH
84
#endif /* ifdef __OpenBSD__ */
85
86
#endif /* HAVE_SYSCTLBYNAME */
87
88
static isc_result_t ipv4_result = ISC_R_SUCCESS;
89
static isc_result_t ipv6_result = ISC_R_SUCCESS;
90
91
isc_result_t
92
0
isc_net_probeipv4(void) {
93
0
  return ipv4_result;
94
0
}
95
96
isc_result_t
97
0
isc_net_probeipv6(void) {
98
0
  return ipv6_result;
99
0
}
100
101
#if defined(USE_SYSCTL_PORTRANGE)
102
#if defined(HAVE_SYSCTLBYNAME)
103
static isc_result_t
104
getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
105
  int port_low, port_high;
106
  size_t portlen;
107
  const char *sysctlname_lowport, *sysctlname_hiport;
108
109
  if (af == AF_INET) {
110
    sysctlname_lowport = SYSCTL_V4PORTRANGE_LOW;
111
    sysctlname_hiport = SYSCTL_V4PORTRANGE_HIGH;
112
  } else {
113
    sysctlname_lowport = SYSCTL_V6PORTRANGE_LOW;
114
    sysctlname_hiport = SYSCTL_V6PORTRANGE_HIGH;
115
  }
116
  portlen = sizeof(port_low);
117
  if (sysctlbyname(sysctlname_lowport, &port_low, &portlen, NULL, 0) < 0)
118
  {
119
    return ISC_R_FAILURE;
120
  }
121
  portlen = sizeof(port_high);
122
  if (sysctlbyname(sysctlname_hiport, &port_high, &portlen, NULL, 0) < 0)
123
  {
124
    return ISC_R_FAILURE;
125
  }
126
  if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0) {
127
    return ISC_R_RANGE;
128
  }
129
130
  *low = (in_port_t)port_low;
131
  *high = (in_port_t)port_high;
132
133
  return ISC_R_SUCCESS;
134
}
135
#else  /* !HAVE_SYSCTLBYNAME */
136
static isc_result_t
137
getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
138
  int mib_lo4[4] = SYSCTL_V4PORTRANGE_LOW;
139
  int mib_hi4[4] = SYSCTL_V4PORTRANGE_HIGH;
140
  int mib_lo6[4] = SYSCTL_V6PORTRANGE_LOW;
141
  int mib_hi6[4] = SYSCTL_V6PORTRANGE_HIGH;
142
  int *mib_lo, *mib_hi, miblen;
143
  int port_low, port_high;
144
  size_t portlen;
145
146
  if (af == AF_INET) {
147
    mib_lo = mib_lo4;
148
    mib_hi = mib_hi4;
149
    miblen = sizeof(mib_lo4) / sizeof(mib_lo4[0]);
150
  } else {
151
    mib_lo = mib_lo6;
152
    mib_hi = mib_hi6;
153
    miblen = sizeof(mib_lo6) / sizeof(mib_lo6[0]);
154
  }
155
156
  portlen = sizeof(port_low);
157
  if (sysctl(mib_lo, miblen, &port_low, &portlen, NULL, 0) < 0) {
158
    return ISC_R_FAILURE;
159
  }
160
161
  portlen = sizeof(port_high);
162
  if (sysctl(mib_hi, miblen, &port_high, &portlen, NULL, 0) < 0) {
163
    return ISC_R_FAILURE;
164
  }
165
166
  if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0) {
167
    return ISC_R_RANGE;
168
  }
169
170
  *low = (in_port_t)port_low;
171
  *high = (in_port_t)port_high;
172
173
  return ISC_R_SUCCESS;
174
}
175
#endif /* HAVE_SYSCTLBYNAME */
176
#endif /* USE_SYSCTL_PORTRANGE */
177
178
isc_result_t
179
0
isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
180
0
  int result = ISC_R_FAILURE;
181
0
#if !defined(USE_SYSCTL_PORTRANGE) && defined(__linux)
182
0
  FILE *fp;
183
0
#endif /* if !defined(USE_SYSCTL_PORTRANGE) && defined(__linux) */
184
185
0
  REQUIRE(low != NULL && high != NULL);
186
187
#if defined(USE_SYSCTL_PORTRANGE)
188
  result = getudpportrange_sysctl(af, low, high);
189
#elif defined(__linux)
190
191
0
  UNUSED(af);
192
193
  /*
194
   * Linux local ports are address family agnostic.
195
   */
196
0
  fp = fopen("/proc/sys/net/ipv4/ip_local_port_range", "r");
197
0
  if (fp != NULL) {
198
0
    int n;
199
0
    unsigned int l, h;
200
201
0
    n = fscanf(fp, "%u %u", &l, &h);
202
0
    if (n == 2 && (l & ~0xffff) == 0 && (h & ~0xffff) == 0) {
203
0
      *low = l;
204
0
      *high = h;
205
0
      result = ISC_R_SUCCESS;
206
0
    }
207
0
    fclose(fp);
208
0
  }
209
#else  /* if defined(USE_SYSCTL_PORTRANGE) */
210
  UNUSED(af);
211
#endif /* if defined(USE_SYSCTL_PORTRANGE) */
212
213
0
  if (result != ISC_R_SUCCESS) {
214
0
    *low = ISC_NET_PORTRANGELOW;
215
0
    *high = ISC_NET_PORTRANGEHIGH;
216
0
  }
217
218
0
  return ISC_R_SUCCESS; /* we currently never fail in this function */
219
0
}
220
221
void
222
0
isc_net_disableipv4(void) {
223
0
  if (ipv4_result == ISC_R_SUCCESS) {
224
0
    ipv4_result = ISC_R_DISABLED;
225
0
  }
226
0
}
227
228
void
229
0
isc_net_disableipv6(void) {
230
0
  if (ipv6_result == ISC_R_SUCCESS) {
231
0
    ipv6_result = ISC_R_DISABLED;
232
0
  }
233
0
}
234
235
void
236
0
isc_net_enableipv4(void) {
237
0
  if (ipv4_result == ISC_R_DISABLED) {
238
0
    ipv4_result = ISC_R_SUCCESS;
239
0
  }
240
0
}
241
242
void
243
0
isc_net_enableipv6(void) {
244
0
  if (ipv6_result == ISC_R_DISABLED) {
245
0
    ipv6_result = ISC_R_SUCCESS;
246
0
  }
247
0
}