Blob Blame History Raw
diff --git a/config.h.in b/config.h.in
index 103ad9f..0bb29d9 100644
--- a/config.h.in
+++ b/config.h.in
@@ -847,6 +847,14 @@
 /* Define if you enable libevent */
 #undef USE_LIBEVENT
 
+/* WARNING! This is only for the libunbound on Linux and does not affect
+   unbound resolving daemon itself. This may severely limit the number of
+   available outgoing ports and thus decrease randomness. Define this only
+   when the target system restricts (e.g. some of SELinux enabled
+   distributions) the use of non-ephemeral ports. Define this to enable use of
+   /proc/sys/net/ipv4/ip_local_port_range as a default outgoing port range. */
+#undef USE_LINUX_IP_LOCAL_PORT_RANGE
+
 /* Define if you want to use internal select based events */
 #undef USE_MINI_EVENT
 
diff --git a/configure b/configure
index c91e8a3..826dce9 100755
--- a/configure
+++ b/configure
@@ -898,6 +898,7 @@ enable_ipsecmod
 enable_ipset
 with_libmnl
 enable_explicit_port_randomisation
+enable_linux_ip_local_port_range
 with_libunbound_only
 '
       ac_precious_vars='build_alias
@@ -1590,6 +1591,16 @@ Optional Features:
   --disable-explicit-port-randomisation
                           disable explicit source port randomisation and rely
                           on the kernel to provide random source ports
+  --enable-linux-ip-local-port-range
+                          WARNING! This is only for the libunbound on Linux
+                          and does not affect unbound resolving daemon itself.
+                          This may severely limit the number of available
+                          outgoing ports and thus decrease randomness. Use
+                          this option only when the target system restricts
+                          the use of non-ephemeral ports. (e.g. some of
+                          SELinux enabled distributions) Enable this option to
+                          use /proc/sys/net/ipv4/ip_local_port_range as a
+                          default outgoing port range
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -4202,6 +4213,13 @@ else
 	else on_mingw="no"; fi
 fi
 
+# are we on Linux?
+if uname -s 2>&1 | grep -i linux >/dev/null; then on_linux="yes"
+else
+	if echo $host $target | grep linux >/dev/null; then on_linux="yes"
+	else on_linux="no"; fi
+fi
+
 #
 # Determine configuration file
 # the eval is to evaluate shell expansion twice
@@ -21588,6 +21606,23 @@ $as_echo "#define DISABLE_EXPLICIT_PORT_RANDOMISATION 1" >>confdefs.h
 		;;
 esac
 
+if test $on_linux = "yes"; then
+	# Check whether --enable-linux-ip-local-port-range was given.
+if test "${enable_linux_ip_local_port_range+set}" = set; then :
+  enableval=$enable_linux_ip_local_port_range;
+fi
+
+	case "$enable_linux_ip_local_port_range" in
+		yes)
+
+$as_echo "#define USE_LINUX_IP_LOCAL_PORT_RANGE 1" >>confdefs.h
+
+			;;
+		no|*)
+			;;
+	esac
+fi
+
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if ${MAKE:-make} supports $< with implicit rule in scope" >&5
 $as_echo_n "checking if ${MAKE:-make} supports $< with implicit rule in scope... " >&6; }
diff --git a/configure.ac b/configure.ac
index 2d88048..1207047 100644
--- a/configure.ac
+++ b/configure.ac
@@ -152,6 +152,13 @@ else
 	else on_mingw="no"; fi
 fi
 
+# are we on Linux?
+if uname -s 2>&1 | grep -i linux >/dev/null; then on_linux="yes"
+else
+	if echo $host $target | grep linux >/dev/null; then on_linux="yes"
+	else on_linux="no"; fi
+fi
+
 #
 # Determine configuration file
 # the eval is to evaluate shell expansion twice
@@ -1847,6 +1854,17 @@ case "$enable_explicit_port_randomisation" in
 		;;
 esac
 
+if test $on_linux = "yes"; then
+	AC_ARG_ENABLE(linux-ip-local-port-range, AC_HELP_STRING([--enable-linux-ip-local-port-range], [WARNING! This is only for the libunbound on Linux and does not affect unbound resolving daemon itself. This may severely limit the number of available outgoing ports and thus decrease randomness. Use this option only when the target system restricts the use of non-ephemeral ports. (e.g. some of SELinux enabled distributions) Enable this option to use /proc/sys/net/ipv4/ip_local_port_range as a default outgoing port range]))
+	case "$enable_linux_ip_local_port_range" in
+		yes)
+			AC_DEFINE([USE_LINUX_IP_LOCAL_PORT_RANGE], [1], [WARNING! This is only for the libunbound on Linux and does not affect unbound resolving daemon itself. This may severely limit the number of available outgoing ports and thus decrease randomness. Define this only when the target system restricts (e.g. some of SELinux enabled distributions) the use of non-ephemeral ports. Define this to enable use of /proc/sys/net/ipv4/ip_local_port_range as a default outgoing port range.])
+			;;
+		no|*)
+			;;
+	esac
+fi
+
 
 AC_MSG_CHECKING([if ${MAKE:-make} supports $< with implicit rule in scope])
 # on openBSD, the implicit rule make $< work.
diff --git a/libunbound/context.c b/libunbound/context.c
index cff2831..48d76d9 100644
--- a/libunbound/context.c
+++ b/libunbound/context.c
@@ -69,6 +69,7 @@ context_finalize(struct ub_ctx* ctx)
 	} else {
 		log_init(cfg->logfile, cfg->use_syslog, NULL);
 	}
+	cfg_apply_local_port_policy(cfg, 65536);
 	config_apply(cfg);
 	if(!modstack_setup(&ctx->mods, cfg->module_conf, ctx->env))
 		return UB_INITFAIL;
diff --git a/util/config_file.c b/util/config_file.c
index 4d87dee..6b90e48 100644
--- a/util/config_file.c
+++ b/util/config_file.c
@@ -1681,6 +1681,37 @@ int cfg_condense_ports(struct config_file* cfg, int** avail)
 	return num;
 }
 
+void cfg_apply_local_port_policy(struct config_file* cfg, int num) {
+(void)cfg;
+(void)num;
+#ifdef USE_LINUX_IP_LOCAL_PORT_RANGE
+	{
+		int i = 0;
+		FILE* range_fd;
+		if ((range_fd = fopen(LINUX_IP_LOCAL_PORT_RANGE_PATH, "r")) != NULL) {
+			int min_port = 0;
+			int max_port = num - 1;
+			if (fscanf(range_fd, "%d %d", &min_port, &max_port) == 2) {
+				for(i=0; i<min_port; i++) {
+					cfg->outgoing_avail_ports[i] = 0;
+				}
+				for(i=max_port+1; i<num; i++) {
+					cfg->outgoing_avail_ports[i] = 0;
+				}
+			} else {
+				log_err("unexpected port range in %s",
+						LINUX_IP_LOCAL_PORT_RANGE_PATH);
+			}
+			fclose(range_fd);
+		} else {
+			log_warn("failed to read from file: %s (%s)",
+					LINUX_IP_LOCAL_PORT_RANGE_PATH,
+					strerror(errno));
+		}
+	}
+#endif
+}
+
 /** print error with file and line number */
 static void ub_c_error_va_list(const char *fmt, va_list args)
 {
diff --git a/util/config_file.h b/util/config_file.h
index 7cf27cc..d091ef7 100644
--- a/util/config_file.h
+++ b/util/config_file.h
@@ -1172,6 +1172,13 @@ int cfg_mark_ports(const char* str, int allow, int* avail, int num);
  */
 int cfg_condense_ports(struct config_file* cfg, int** avail);
 
+/**
+ * Apply system specific port range policy.
+ * @param cfg: config file.
+ * @param num: size of the array (65536).
+ */
+void cfg_apply_local_port_policy(struct config_file* cfg, int num);
+
 /**
  * Scan ports available
  * @param avail: the array from cfg.
@@ -1301,5 +1308,9 @@ void w_config_adjust_directory(struct config_file* cfg);
 /** debug option for unit tests. */
 extern int fake_dsa, fake_sha1;
 
+#ifdef USE_LINUX_IP_LOCAL_PORT_RANGE
+#define LINUX_IP_LOCAL_PORT_RANGE_PATH "/proc/sys/net/ipv4/ip_local_port_range"
+#endif
+
 #endif /* UTIL_CONFIG_FILE_H */