diff --git a/CHANGES b/CHANGES
index effcf1e8b1..7633bded32 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+4109. [port] linux: support reading the local port range from
+ net.ipv4.ip_local_port_range. [RT # 39379]
+
4108. [func] An additional NXDOMAIN redirect method (option
"nxdomain-redirect") has been added, allowing
redirection to a specified DNS namespace instead
diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml
index 012bcf6dd8..2dea1edc92 100644
--- a/doc/arm/notes.xml
+++ b/doc/arm/notes.xml
@@ -488,6 +488,12 @@
to be configured on the server is now available.
+
+
+ Retrieving the local port range from net.ipv4.ip_local_port_range
+ on Linux is now supported.
+
+
diff --git a/lib/isc/unix/net.c b/lib/isc/unix/net.c
index 0fa038885a..9bcd189225 100644
--- a/lib/isc/unix/net.c
+++ b/lib/isc/unix/net.c
@@ -778,12 +778,12 @@ getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
sysctlname_lowport = SYSCTL_V6PORTRANGE_LOW;
sysctlname_hiport = SYSCTL_V6PORTRANGE_HIGH;
}
- portlen = sizeof(portlen);
+ portlen = sizeof(port_low);
if (sysctlbyname(sysctlname_lowport, &port_low, &portlen,
NULL, 0) < 0) {
return (ISC_R_FAILURE);
}
- portlen = sizeof(portlen);
+ portlen = sizeof(port_high);
if (sysctlbyname(sysctlname_hiport, &port_high, &portlen,
NULL, 0) < 0) {
return (ISC_R_FAILURE);
@@ -817,12 +817,12 @@ getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
miblen = sizeof(mib_lo6) / sizeof(mib_lo6[0]);
}
- portlen = sizeof(portlen);
+ portlen = sizeof(port_low);
if (sysctl(mib_lo, miblen, &port_low, &portlen, NULL, 0) < 0) {
return (ISC_R_FAILURE);
}
- portlen = sizeof(portlen);
+ portlen = sizeof(port_high);
if (sysctl(mib_hi, miblen, &port_high, &portlen, NULL, 0) < 0) {
return (ISC_R_FAILURE);
}
@@ -841,11 +841,34 @@ getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
isc_result_t
isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
int result = ISC_R_FAILURE;
+#if !defined(USE_SYSCTL_PORTRANGE) && defined(__linux)
+ FILE *fp;
+#endif
REQUIRE(low != NULL && high != NULL);
#if defined(USE_SYSCTL_PORTRANGE)
result = getudpportrange_sysctl(af, low, high);
+#elif defined(__linux)
+
+ UNUSED(af);
+
+ /*
+ * Linux local ports are address family agnostic.
+ */
+ fp = fopen("/proc/sys/net/ipv4/ip_local_port_range", "r");
+ if (fp != NULL) {
+ int n;
+ unsigned int l, h;
+
+ n = fscanf(fp, "%u %u", &l, &h);
+ if (n == 2 && (l & ~0xffff) == 0 && (h & ~0xffff) == 0) {
+ *low = l;
+ *high = h;
+ result = ISC_R_SUCCESS;
+ }
+ fclose(fp);
+ }
#else
UNUSED(af);
#endif