]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
rtp/rtcp: Configure dual-stack behavior via IPV6_V6ONLY
authorJustin T. Gibbs <gibbs@scsiguy.com>
Mon, 22 Dec 2025 01:30:10 +0000 (18:30 -0700)
committergithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Mon, 29 Dec 2025 18:04:57 +0000 (18:04 +0000)
Dual-stack behavior (simultaneous listening for IPV4 and IPV6
connections on a single socket) is required by Asterisk's ICE
implementation.  On systems with the IPV6_V6ONLY sockopt, set
the option to 0 (dual-stack enabled) when binding to the IPV6
any address. This ensures correct behavior regardless of the
system's default dual-stack configuration.

configure
configure.ac
include/asterisk/autoconfig.h.in
res/res_rtp_asterisk.c

index d35e13c1d56d7158e688b29c496f345fac9c81d2..f32eecd79ba89cb92700ca40401e2698e1616ab1 100755 (executable)
--- a/configure
+++ b/configure
@@ -31433,6 +31433,40 @@ esac
 fi
 
 
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if setsockopt() accepts the IPV6_V6ONLY socket option" >&5
+printf %s "checking if setsockopt() accepts the IPV6_V6ONLY socket option... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+          #include <sys/socket.h>
+          #include <netinet/in.h>
+
+int
+main (void)
+{
+
+          int opt = IPV6_V6ONLY;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+printf "%s\n" "#define HAVE_SOCK_IPV6_V6ONLY 1" >>confdefs.h
+
+else case e in #(
+  e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+
+
 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can increase the maximum select-able file descriptor" >&5
 printf %s "checking if we can increase the maximum select-able file descriptor... " >&6; }
 if test "$cross_compiling" = yes
index 2a16142b98b4548a13f6f905240b414c6de7774d..b0dd1946c4cbdc53711ff17aa5365451ff78a673 100644 (file)
@@ -1248,6 +1248,19 @@ AC_RUN_IFELSE(
        AC_MSG_RESULT(cross-compile)
 )
 
+AC_MSG_CHECKING([if setsockopt() accepts the IPV6_V6ONLY socket option])
+AC_COMPILE_IFELSE(
+[AC_LANG_PROGRAM([
+          #include <sys/socket.h>
+          #include <netinet/in.h>
+       ], [
+          int opt = IPV6_V6ONLY;
+       ])],
+        AC_MSG_RESULT(yes)
+        AC_DEFINE(HAVE_SOCK_IPV6_V6ONLY, 1, [Define to 1 if your socket() implementation has the IPV6_V6ONLY socket option.]),
+       AC_MSG_RESULT(no)
+)
+
 AC_MSG_CHECKING(if we can increase the maximum select-able file descriptor)
 AC_RUN_IFELSE(
 [AC_LANG_PROGRAM([
index 1df046852d349b2223951e282fc67ff5d7b3bd56..a3c1fc719fab445495ff2174e52e95ba9bbcadbf 100644 (file)
 /* Define to 1 if your socket() implementation can accept SOCK_NONBLOCK. */
 #undef HAVE_SOCK_NONBLOCK
 
+/* Define to 1 if your socket() implementation has the IPV6_V6ONLY socket option. */
+#undef HAVE_SOCK_IPV6_V6ONLY
+
 /* Define to 1 if your system has soxmix application. */
 #undef HAVE_SOXMIX
 
index f258b41fd90245e76053674de6a56532e77680ca..2a8489d4f1729fcd20d02b2207406db79f8be89f 100644 (file)
@@ -3565,9 +3565,13 @@ static void calc_mean_and_standard_deviation(double new_sample, double *mean, do
        *std_dev = sqrt((last_sum_of_squares + (delta1 * delta2)) / *count);
 }
 
-static int create_new_socket(const char *type, int af)
+static int create_new_socket(const char *type, struct ast_sockaddr *bind_addr)
 {
-       int sock = ast_socket_nonblock(af, SOCK_DGRAM, 0);
+       int af, sock;
+
+       af = ast_sockaddr_is_ipv4(bind_addr) ? AF_INET  :
+            ast_sockaddr_is_ipv6(bind_addr) ? AF_INET6 : -1;
+       sock = ast_socket_nonblock(af, SOCK_DGRAM, 0);
 
        if (sock < 0) {
                ast_log(LOG_WARNING, "Unable to allocate %s socket: %s\n", type, strerror(errno));
@@ -3580,6 +3584,15 @@ static int create_new_socket(const char *type, int af)
        }
 #endif
 
+#ifdef HAVE_SOCK_IPV6_V6ONLY
+       if (AF_INET6 == af && ast_sockaddr_is_any(bind_addr)) {
+               /* ICE relies on dual-stack behavior. Ensure it is enabled. */
+               if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof(int)) != 0) {
+                       ast_log(LOG_WARNING, "setsockopt IPV6_V6ONLY=0 failed: %s\n", strerror(errno));
+               }
+       }
+#endif
+
        return sock;
 }
 
@@ -4041,10 +4054,7 @@ static int rtp_allocate_transport(struct ast_rtp_instance *instance, struct ast_
        rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_CLOSED : STRICT_RTP_OPEN);
 
        /* Create a new socket for us to listen on and use */
-       if ((rtp->s =
-            create_new_socket("RTP",
-                              ast_sockaddr_is_ipv4(&rtp->bind_address) ? AF_INET  :
-                              ast_sockaddr_is_ipv6(&rtp->bind_address) ? AF_INET6 : -1)) < 0) {
+       if ((rtp->s = create_new_socket("RTP", &rtp->bind_address)) < 0) {
                ast_log(LOG_WARNING, "Failed to create a new socket for RTP instance '%p'\n", instance);
                return -1;
        }
@@ -8938,12 +8948,7 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro
                                 * switching from MUX. Either way, we won't have
                                 * a socket set up, and we need to set it up
                                 */
-                               if ((rtp->rtcp->s =
-                                    create_new_socket("RTCP",
-                                                      ast_sockaddr_is_ipv4(&rtp->rtcp->us) ?
-                                                      AF_INET :
-                                                      ast_sockaddr_is_ipv6(&rtp->rtcp->us) ?
-                                                      AF_INET6 : -1)) < 0) {
+                               if ((rtp->rtcp->s = create_new_socket("RTCP", &rtp->rtcp->us)) < 0) {
                                        ast_debug_rtcp(1, "(%p) RTCP failed to create a new socket\n", instance);
                                        ast_free(rtp->rtcp->local_addr_str);
                                        ast_free(rtp->rtcp);