Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH] avformat: enable UDP IPv6 multicast interface selection
@ 2024-03-14 12:04 Ignjatović, Lazar (RS)
  2024-03-14 21:13 ` Michael Niedermayer
  0 siblings, 1 reply; 38+ messages in thread
From: Ignjatović, Lazar (RS) @ 2024-03-14 12:04 UTC (permalink / raw)
  To: ffmpeg-devel

localaddr option now properly works with IPv6 addresses. Properly
resolved interface index in places where default 0 interface index is
used (marked with TODO: within udp.c). Added SO_BINDTODEVICE for mcast
sockets that are used for reading from the network. Need for this
arises from the fact that [ffx1::*] and [ffx2::*] mcast addresses need
to have a defined interface for binding to avoid ambiguity between
multiple link-local networks on the same host. Failing to set this
option causes errors on Linux systems for interface and link-local
scopes.

For mcast addresses, bind to mcast address is attempted as before.
In case that this fails, which will happen on Windows, socket is bound
to INADDR_ANY/IN6ADDR_ANY_INIT depending on address family. Actual
interface selection is performed using udp_set_multicast_interface to
point to the desired interface for sending/listening.

Utilization of sin6_scope_id field enables usage and adequate resolving
of IPv6 addresses that utilize zone index
(e.g. fe80::1ff:fe23:4567:890a%eth2)
This is not fully supported on Windows, thus relying on this field
is not done on Windows systems.

Closes: #368

Signed-off-by: Lazar Ignjatovic <Lazar.Ignjatovic@cubic.com>
---
 configure             |  3 ++
 libavformat/ip.c      | 45 ++++++++++++++++++++++++
 libavformat/ip.h      |  6 ++++
 libavformat/network.h |  6 ++++
 libavformat/udp.c     | 80 ++++++++++++++++++++++++++++++++++++++-----
 5 files changed, 132 insertions(+), 8 deletions(-)

diff --git a/configure b/configure
index c34bdd13f5..77f03948ce 100755
--- a/configure
+++ b/configure
@@ -2256,6 +2256,7 @@ HEADERS_LIST="
     valgrind_valgrind_h
     windows_h
     winsock2_h
+    iphlpapi_h
 "

 INTRINSICS_LIST="
@@ -6408,6 +6409,8 @@ if ! disabled network; then
         check_struct winsock2.h "struct sockaddr" sa_len
         check_type ws2tcpip.h "struct sockaddr_in6"
         check_type ws2tcpip.h "struct sockaddr_storage"
+        check_headers iphlpapi.h && network_extralibs+=" -liphlpapi" || disable iphlpapi_h
+        check_func_headers iphlpapi.h GetBestInterfaceEx
     else
         disable network
     fi
diff --git a/libavformat/ip.c b/libavformat/ip.c
index b2c7ef07e5..4f2d998c34 100644
--- a/libavformat/ip.c
+++ b/libavformat/ip.c
@@ -18,6 +18,9 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */

+#define _DEFAULT_SOURCE
+#define _SVID_SOURCE
+
 #include <string.h>
 #include "ip.h"
 #include "libavutil/avstring.h"
@@ -159,3 +162,45 @@ void ff_ip_reset_filters(IPSourceFilters *filters)
     filters->nb_include_addrs = 0;
     filters->nb_exclude_addrs = 0;
 }
+
+unsigned int ff_ip_resolve_interface_index(struct sockaddr_storage *local_addr)
+{
+#if HAVE_WINSOCK2_H && HAVE_IPHLPAPI_H
+    DWORD retval;
+    unsigned long iface;
+
+    if (local_addr == NULL)
+        return 0;
+
+    retval = GetBestInterfaceEx((struct sockaddr*)local_addr, &iface);
+    if (retval == NO_ERROR)
+        return iface;
+
+    return 0;
+#elif !HAVE_WINSOCK2_H
+    struct ifaddrs *ifaddr, *ifa;
+
+    if (local_addr == NULL)
+        return 0;
+
+    /* Special case for link-local addresses, relevant interface is stored in sin6_scope_id */
+#if HAVE_STRUCT_SOCKADDR_IN6 && defined(IN6_IS_ADDR_LINKLOCAL)
+    if (local_addr->ss_family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6*)local_addr)->sin6_addr)) {
+        unsigned int interface;
+        interface = ((struct sockaddr_in6*)local_addr)->sin6_scope_id;
+
+        if (interface != 0)
+            return interface;
+    }
+#endif
+    if (getifaddrs(&ifaddr) == -1)
+        return 0;
+
+    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+        if (ifa->ifa_addr != NULL && compare_addr((struct sockaddr_storage*)ifa->ifa_addr, local_addr) == 0)
+            return if_nametoindex(ifa->ifa_name);
+    }
+
+    return 0;
+#endif
+}
diff --git a/libavformat/ip.h b/libavformat/ip.h
index b76cdab91c..4085e96f08 100644
--- a/libavformat/ip.h
+++ b/libavformat/ip.h
@@ -69,4 +69,10 @@ int ff_ip_parse_blocks(void *log_ctx, const char *buf, IPSourceFilters *filters)
  */
 void ff_ip_reset_filters(IPSourceFilters *filters);

+/**
+ * Resolves IP address to an associated interface index
+ * @return interface index, 0 as default interface value on error
+ */
+unsigned int ff_ip_resolve_interface_index(struct sockaddr_storage *local_addr);
+
 #endif /* AVFORMAT_IP_H */
diff --git a/libavformat/network.h b/libavformat/network.h
index ca214087fc..2461b651d4 100644
--- a/libavformat/network.h
+++ b/libavformat/network.h
@@ -38,6 +38,10 @@
 #include <winsock2.h>
 #include <ws2tcpip.h>

+#if HAVE_IPHLPAPI_H
+#include <iphlpapi.h>
+#endif
+
 #ifndef EPROTONOSUPPORT
 #define EPROTONOSUPPORT WSAEPROTONOSUPPORT
 #endif
@@ -64,6 +68,8 @@ int ff_neterrno(void);
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <netdb.h>
+#include <net/if.h>
+#include <ifaddrs.h>

 #define ff_neterrno() AVERROR(errno)
 #endif /* HAVE_WINSOCK2_H */
diff --git a/libavformat/udp.c b/libavformat/udp.c
index d9514f5026..a603a9961e 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -220,8 +220,7 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
         struct ipv6_mreq mreq6;

         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
-        //TODO: Interface index should be looked up from local_addr
-        mreq6.ipv6mr_interface = 0;
+        mreq6.ipv6mr_interface = ff_ip_resolve_interface_index((struct sockaddr_storage *)local_addr);
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP)");
             return ff_neterrno();
@@ -231,6 +230,38 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
     return 0;
 }

+static int udp_set_multicast_interface(int sockfd, struct sockaddr *addr,
+                                    struct sockaddr *local_addr, void *logctx)
+{
+#ifdef IP_MULTICAST_IF
+    if (addr->sa_family == AF_INET) {
+        struct ip_mreq mreq;
+
+        mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
+        if (local_addr)
+            mreq.imr_interface = ((struct sockaddr_in *)local_addr)->sin_addr;
+        else
+            mreq.imr_interface.s_addr = INADDR_ANY;
+
+        if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, (const void *)&mreq, sizeof(mreq)) < 0) {
+            ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_IF)");
+            return ff_neterrno();
+        }
+    }
+#endif
+#if defined(IPV6_MULTICAST_IF) && defined(IPPROTO_IPV6)
+    if (addr->sa_family == AF_INET6) {
+        unsigned int iface = ff_ip_resolve_interface_index((struct sockaddr_storage *)local_addr);
+
+        if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &iface, sizeof(unsigned int)) < 0) {
+            ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_IF)");
+            return ff_neterrno();
+        }
+    }
+#endif
+    return 0;
+}
+
 static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
                                      struct sockaddr *local_addr, void *logctx)
 {
@@ -254,8 +285,7 @@ static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
         struct ipv6_mreq mreq6;

         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
-        //TODO: Interface index should be looked up from local_addr
-        mreq6.ipv6mr_interface = 0;
+        mreq6.ipv6mr_interface = ff_ip_resolve_interface_index((struct sockaddr_storage *)local_addr);
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP)");
             return -1;
@@ -282,8 +312,7 @@ static int udp_set_multicast_sources(URLContext *h,
             struct group_source_req mreqs;
             int level = addr->sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;

-            //TODO: Interface index should be looked up from local_addr
-            mreqs.gsr_interface = 0;
+            mreqs.gsr_interface = ff_ip_resolve_interface_index(local_addr);
             memcpy(&mreqs.gsr_group, addr, addr_len);
             memcpy(&mreqs.gsr_source, &sources[i], sizeof(*sources));

@@ -839,10 +868,39 @@ static int udp_open(URLContext *h, const char *uri, int flags)
      * port. This fails on windows. This makes sending to the same address
      * using sendto() fail, so only do it if we're opened in read-only mode. */
     if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) {
+#if defined(SO_BINDTODEVICE) && !HAVE_WINSOCK2_H
+        {
+            struct ifreq ifr;
+            unsigned int iface;
+            iface = ff_ip_resolve_interface_index((struct sockaddr_storage *)&s->local_addr_storage);
+            memset(&ifr, 0, sizeof(ifr));
+
+            if (if_indextoname(iface, ifr.ifr_name)) {
+                if (setsockopt(udp_fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {
+                    ff_log_net_error(h, AV_LOG_ERROR, "setsockopt(SO_BINDTODEVICE)");
+                }
+            }
+        }
+#endif // defined(SO_BINDTODEVICE) && !HAVE_WINSOCK2_H
         bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len);
     }
-    /* bind to the local address if not multicast or if the multicast
-     * bind failed */
+
+    /* bind to ADDR_ANY if the multicast bind failed */
+    if (s->is_multicast && bind_ret < 0) {
+        struct addrinfo *res;
+
+        if (s->dest_addr.ss_family == AF_INET)
+            res = ff_ip_resolve_host(h, "0.0.0.0", 0, SOCK_DGRAM, AF_UNSPEC, 0);
+        else if (s->dest_addr.ss_family == AF_INET6)
+            res = ff_ip_resolve_host(h, "::", 0, SOCK_DGRAM, AF_UNSPEC, 0);
+
+        if (res && res->ai_addr) {
+            bind_ret = bind(udp_fd, res->ai_addr, res->ai_addrlen);
+        }
+
+        freeaddrinfo(res);
+    }
+
     /* the bind is needed to give a port to the socket now */
     if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) {
         ff_log_net_error(h, AV_LOG_ERROR, "bind failed");
@@ -855,6 +913,12 @@ static int udp_open(URLContext *h, const char *uri, int flags)
     s->local_port = udp_port(&my_addr, len);

     if (s->is_multicast) {
+        if ((ret = udp_set_multicast_interface(udp_fd,
+                                        (struct sockaddr *)&s->dest_addr,
+                                        (struct sockaddr *)&s->local_addr_storage,
+                                        h)) < 0)
+            goto fail;
+
         if (h->flags & AVIO_FLAG_WRITE) {
             /* output */
             if ((ret = udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr, h)) < 0)
--
2.41.0.windows.2


This message has been marked as Public on 03/14/2024 12:04Z.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH] avformat: enable UDP IPv6 multicast interface selection
  2024-03-14 12:04 [FFmpeg-devel] [PATCH] avformat: enable UDP IPv6 multicast interface selection Ignjatović, Lazar (RS)
@ 2024-03-14 21:13 ` Michael Niedermayer
  2024-03-18 13:45   ` Ignjatović, Lazar (RS)
  0 siblings, 1 reply; 38+ messages in thread
From: Michael Niedermayer @ 2024-03-14 21:13 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


[-- Attachment #1.1: Type: text/plain, Size: 2364 bytes --]

On Thu, Mar 14, 2024 at 12:04:47PM +0000, Ignjatović, Lazar (RS) wrote:
> localaddr option now properly works with IPv6 addresses. Properly
> resolved interface index in places where default 0 interface index is
> used (marked with TODO: within udp.c). Added SO_BINDTODEVICE for mcast
> sockets that are used for reading from the network. Need for this
> arises from the fact that [ffx1::*] and [ffx2::*] mcast addresses need
> to have a defined interface for binding to avoid ambiguity between
> multiple link-local networks on the same host. Failing to set this
> option causes errors on Linux systems for interface and link-local
> scopes.
> 
> For mcast addresses, bind to mcast address is attempted as before.
> In case that this fails, which will happen on Windows, socket is bound
> to INADDR_ANY/IN6ADDR_ANY_INIT depending on address family. Actual
> interface selection is performed using udp_set_multicast_interface to
> point to the desired interface for sending/listening.
> 
> Utilization of sin6_scope_id field enables usage and adequate resolving
> of IPv6 addresses that utilize zone index
> (e.g. fe80::1ff:fe23:4567:890a%eth2)
> This is not fully supported on Windows, thus relying on this field
> is not done on Windows systems.
> 
> Closes: #368
> 
> Signed-off-by: Lazar Ignjatovic <Lazar.Ignjatovic@cubic.com>
> ---
>  configure             |  3 ++
>  libavformat/ip.c      | 45 ++++++++++++++++++++++++
>  libavformat/ip.h      |  6 ++++
>  libavformat/network.h |  6 ++++
>  libavformat/udp.c     | 80 ++++++++++++++++++++++++++++++++++++++-----
>  5 files changed, 132 insertions(+), 8 deletions(-)

breaks mingw64 build

CC	libavformat/ip.o
src/libavformat/ip.c: In function ‘ff_ip_resolve_interface_index’:
src/libavformat/ip.c:206:1: error: control reaches end of non-void function [-Werror=return-type]
 }
 ^
cc1: some warnings being treated as errors
src/ffbuild/common.mak:81: recipe for target 'libavformat/ip.o' failed
make: *** [libavformat/ip.o] Error 1

also configure produces
../configure: 6415: ../configure: network_extralibs+= -liphlpapi: not found


[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

I have never wished to cater to the crowd; for what I know they do not
approve, and what they approve I do not know. -- Epicurus

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

[-- Attachment #2: Type: text/plain, Size: 251 bytes --]

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH] avformat: enable UDP IPv6 multicast interface selection
  2024-03-14 21:13 ` Michael Niedermayer
@ 2024-03-18 13:45   ` Ignjatović, Lazar (RS)
  2024-03-19  1:23     ` Michael Niedermayer
  0 siblings, 1 reply; 38+ messages in thread
From: Ignjatović, Lazar (RS) @ 2024-03-18 13:45 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


This message has been marked as Public on 03/18/2024 13:45Z.
On Thursday, March 14, 2024 10:14 PM, Michael Niedermayer wrote:

> breaks mingw64 build
>
> CC      libavformat/ip.o
> src/libavformat/ip.c: In function ‘ff_ip_resolve_interface_index’:
> src/libavformat/ip.c:206:1: error: control reaches end of non-void function [-Werror=return-type]  }  ^
> cc1: some warnings being treated as errors
> src/ffbuild/common.mak:81: recipe for target 'libavformat/ip.o' failed
> make: *** [libavformat/ip.o] Error 1

I see the problem, when building for windows without iphlpapi.h, mentioned function has no code within.
Will account for such case.

> also configure produces
> ../configure: 6415: ../configure: network_extralibs+= -liphlpapi: not found

Problem here is that "+=" operator is a bashism, probably causing the previous error by not including iphlpapi properly.

Some questions I have:
Should I send another patch within this thread to address these comments, or should I create a V2 of the patch?
Also, if creating a V2, should the patch be sent within this thread, or should a new thread be opened?

Thank you for your time!

Sincirely,
Lazar Ignjatović
Associate Software Engineer

Cubic Defense
cubic.com
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH] avformat: enable UDP IPv6 multicast interface selection
  2024-03-18 13:45   ` Ignjatović, Lazar (RS)
@ 2024-03-19  1:23     ` Michael Niedermayer
  2024-03-20  9:28       ` [FFmpeg-devel] [PATCH v2] " Ignjatović, Lazar (RS)
  0 siblings, 1 reply; 38+ messages in thread
From: Michael Niedermayer @ 2024-03-19  1:23 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


[-- Attachment #1.1: Type: text/plain, Size: 1555 bytes --]

Hi

On Mon, Mar 18, 2024 at 01:45:00PM +0000, Ignjatović, Lazar (RS)� wrote:
> 
> This message has been marked as Public on 03/18/2024 13:45Z.
> On Thursday, March 14, 2024 10:14 PM, Michael Niedermayer wrote:
> 
> > breaks mingw64 build
> >
> > CC      libavformat/ip.o
> > src/libavformat/ip.c: In function ‘ff_ip_resolve_interface_index’:
> > src/libavformat/ip.c:206:1: error: control reaches end of non-void function [-Werror=return-type]  }  ^
> > cc1: some warnings being treated as errors
> > src/ffbuild/common.mak:81: recipe for target 'libavformat/ip.o' failed
> > make: *** [libavformat/ip.o] Error 1
> 
> I see the problem, when building for windows without iphlpapi.h, mentioned function has no code within.
> Will account for such case.
> 
> > also configure produces
> > ../configure: 6415: ../configure: network_extralibs+= -liphlpapi: not found
> 
> Problem here is that "+=" operator is a bashism, probably causing the previous error by not including iphlpapi properly.
> 
> Some questions I have:
> Should I send another patch within this thread to address these comments, or should I create a V2 of the patch?
> Also, if creating a V2, should the patch be sent within this thread, or should a new thread be opened?

new patch with "V2"
it can be sent in the same or a new thread, developers are not consistent with
that.

thx

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

There will always be a question for which you do not know the correct answer.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

[-- Attachment #2: Type: text/plain, Size: 251 bytes --]

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection
  2024-03-19  1:23     ` Michael Niedermayer
@ 2024-03-20  9:28       ` Ignjatović, Lazar (RS)
  2024-03-20 10:51         ` Rémi Denis-Courmont
  0 siblings, 1 reply; 38+ messages in thread
From: Ignjatović, Lazar (RS) @ 2024-03-20  9:28 UTC (permalink / raw)
  To: ffmpeg-devel

avformat: enable UDP IPv6 multicast interface selection

localaddr option now properly works with IPv6 addresses. Properly
resolved interface index in places where default 0 interface index is
used (marked with TODO: within udp.c). Adjusted binding for multicast
sockets that are used for reading from the network. Need for this
arises from the fact that [ffx1::*] and [ffx2::*] mcast addresses need
to have a defined interface for binding to avoid ambiguity between
multiple link-local networks on the same host. Failing to set this
option causes errors on Linux systems for interface and link-local
scopes.

For mcast addresses, bind to mcast address is attempted as before.
In case that this fails, which will happen on Windows, socket is bound
to INADDR_ANY/IN6ADDR_ANY_INIT depending on address family. Actual
interface selection is performed using udp_set_multicast_interface to
point to the desired interface for sending.

Utilization of sin6_scope_id field enables usage and adequate resolving
of localaddr IPv6 addresses that utilize zone index
(e.g. fe80::1ff:fe23:4567:890a%eth2)
This is not fully supported on Windows, thus relying on this field
is not done on Windows systems.

Closes: #368

Signed-off-by: Lazar Ignjatovic <Lazar.Ignjatovic@cubic.com>
---
V1 -> V2: SO_BINDTODEVICE -> sin6_scope_id, addressed comments

 configure             |  3 ++
 libavformat/ip.c      | 49 ++++++++++++++++++++++++++
 libavformat/ip.h      |  6 ++++
 libavformat/network.h |  6 ++++
 libavformat/udp.c     | 81 ++++++++++++++++++++++++++++++++++++++-----
 5 files changed, 137 insertions(+), 8 deletions(-)

diff --git a/configure b/configure
index e019d1b996..08f35bbd25 100755
--- a/configure
+++ b/configure
@@ -2258,6 +2258,7 @@ HEADERS_LIST="
     valgrind_valgrind_h
     windows_h
     winsock2_h
+    iphlpapi_h
 "

 INTRINSICS_LIST="
@@ -6406,6 +6407,8 @@ if ! disabled network; then
         check_struct winsock2.h "struct sockaddr" sa_len
         check_type ws2tcpip.h "struct sockaddr_in6"
         check_type ws2tcpip.h "struct sockaddr_storage"
+        check_headers iphlpapi.h -liphlpapi && network_extralibs="$network_extralibs -liphlpapi" || disable iphlpapi_h
+        check_func_headers iphlpapi.h GetBestInterfaceEx $network_extralibs
     else
         disable network
     fi
diff --git a/libavformat/ip.c b/libavformat/ip.c
index b2c7ef07e5..4b83e79298 100644
--- a/libavformat/ip.c
+++ b/libavformat/ip.c
@@ -18,6 +18,9 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */

+#define _DEFAULT_SOURCE
+#define _SVID_SOURCE
+
 #include <string.h>
 #include "ip.h"
 #include "libavutil/avstring.h"
@@ -159,3 +162,49 @@ void ff_ip_reset_filters(IPSourceFilters *filters)
     filters->nb_include_addrs = 0;
     filters->nb_exclude_addrs = 0;
 }
+
+unsigned int ff_ip_resolve_interface_index(struct sockaddr_storage *local_addr)
+{
+#if HAVE_WINSOCK2_H
+#if HAVE_IPHLPAPI_H
+    DWORD retval;
+    unsigned long iface;
+
+    if (local_addr == NULL)
+        return 0;
+
+    retval = GetBestInterfaceEx((struct sockaddr*)local_addr, &iface);
+    if (retval == NO_ERROR)
+        return iface;
+#endif /* HAVE_IPHLPAPI_H */
+    return 0;
+#else /* HAVE_WINSOCK2_H */
+    struct ifaddrs *ifaddr, *ifa;
+    unsigned int iface;
+
+    if (local_addr == NULL)
+        return 0;
+
+#if HAVE_STRUCT_SOCKADDR_IN6 && defined(IN6_IS_ADDR_LINKLOCAL)
+    /* Special case for link-local addresses, relevant interface is stored in sin6_scope_id */
+    if (local_addr->ss_family == AF_INET6) {
+        iface = ((struct sockaddr_in6*)local_addr)->sin6_scope_id;
+        if (iface != 0)
+            return iface;
+    }
+#endif /* HAVE_STRUCT_SOCKADDR_IN6 && defined(IN6_IS_ADDR_LINKLOCAL) */
+    if (getifaddrs(&ifaddr) == -1)
+        return 0;
+
+    iface = 0;
+    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+        if (ifa->ifa_addr != NULL && compare_addr((struct sockaddr_storage*)ifa->ifa_addr, local_addr) == 0) {
+            iface = if_nametoindex(ifa->ifa_name);
+            break;
+        }
+    }
+
+    freeifaddrs(ifaddr);
+    return iface;
+#endif /* HAVE_WINSOCK2_H */
+}
diff --git a/libavformat/ip.h b/libavformat/ip.h
index b76cdab91c..4085e96f08 100644
--- a/libavformat/ip.h
+++ b/libavformat/ip.h
@@ -69,4 +69,10 @@ int ff_ip_parse_blocks(void *log_ctx, const char *buf, IPSourceFilters *filters)
  */
 void ff_ip_reset_filters(IPSourceFilters *filters);

+/**
+ * Resolves IP address to an associated interface index
+ * @return interface index, 0 as default interface value on error
+ */
+unsigned int ff_ip_resolve_interface_index(struct sockaddr_storage *local_addr);
+
 #endif /* AVFORMAT_IP_H */
diff --git a/libavformat/network.h b/libavformat/network.h
index ca214087fc..2461b651d4 100644
--- a/libavformat/network.h
+++ b/libavformat/network.h
@@ -38,6 +38,10 @@
 #include <winsock2.h>
 #include <ws2tcpip.h>

+#if HAVE_IPHLPAPI_H
+#include <iphlpapi.h>
+#endif
+
 #ifndef EPROTONOSUPPORT
 #define EPROTONOSUPPORT WSAEPROTONOSUPPORT
 #endif
@@ -64,6 +68,8 @@ int ff_neterrno(void);
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <netdb.h>
+#include <net/if.h>
+#include <ifaddrs.h>

 #define ff_neterrno() AVERROR(errno)
 #endif /* HAVE_WINSOCK2_H */
diff --git a/libavformat/udp.c b/libavformat/udp.c
index d9514f5026..c2420a7f0d 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -220,8 +220,7 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
         struct ipv6_mreq mreq6;

         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
-        //TODO: Interface index should be looked up from local_addr
-        mreq6.ipv6mr_interface = 0;
+        mreq6.ipv6mr_interface = ff_ip_resolve_interface_index((struct sockaddr_storage *)local_addr);
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP)");
             return ff_neterrno();
@@ -231,6 +230,43 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
     return 0;
 }

+static int udp_set_multicast_interface(int sockfd, struct sockaddr *addr,
+                                    struct sockaddr *local_addr, void *logctx)
+{
+#ifdef IP_MULTICAST_IF
+    if (addr->sa_family == AF_INET) {
+        struct ip_mreq mreq;
+
+        mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
+        if (local_addr)
+            mreq.imr_interface = ((struct sockaddr_in *)local_addr)->sin_addr;
+        else
+            mreq.imr_interface.s_addr = INADDR_ANY;
+
+        if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, (const void *)&mreq, sizeof(mreq)) < 0) {
+            ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_IF)");
+            return ff_neterrno();
+        }
+    }
+#endif
+#if defined(IPV6_MULTICAST_IF) && defined(IPPROTO_IPV6)
+    if (addr->sa_family == AF_INET6) {
+        unsigned int iface;
+
+        if (local_addr)
+            iface = ff_ip_resolve_interface_index((struct sockaddr_storage *)local_addr);
+        else
+            iface = ((struct sockaddr_in6*)local_addr)->sin6_scope_id;
+
+        if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &iface, sizeof(unsigned int)) < 0) {
+            ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_IF)");
+            return ff_neterrno();
+        }
+    }
+#endif
+    return 0;
+}
+
 static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
                                      struct sockaddr *local_addr, void *logctx)
 {
@@ -254,8 +290,7 @@ static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
         struct ipv6_mreq mreq6;

         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
-        //TODO: Interface index should be looked up from local_addr
-        mreq6.ipv6mr_interface = 0;
+        mreq6.ipv6mr_interface = ff_ip_resolve_interface_index((struct sockaddr_storage *)local_addr);
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP)");
             return -1;
@@ -282,8 +317,7 @@ static int udp_set_multicast_sources(URLContext *h,
             struct group_source_req mreqs;
             int level = addr->sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;

-            //TODO: Interface index should be looked up from local_addr
-            mreqs.gsr_interface = 0;
+            mreqs.gsr_interface = ff_ip_resolve_interface_index(local_addr);
             memcpy(&mreqs.gsr_group, addr, addr_len);
             memcpy(&mreqs.gsr_source, &sources[i], sizeof(*sources));

@@ -839,10 +873,35 @@ static int udp_open(URLContext *h, const char *uri, int flags)
      * port. This fails on windows. This makes sending to the same address
      * using sendto() fail, so only do it if we're opened in read-only mode. */
     if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) {
+#if HAVE_STRUCT_SOCKADDR_IN6 && !HAVE_WINSOCK2_H
+        if (s->dest_addr.ss_family == AF_INET6) {
+            unsigned int iface;
+            struct sockaddr_in6 *addr;
+            addr = (struct sockaddr_in6 *)&s->dest_addr;
+            iface = ff_ip_resolve_interface_index(&s->local_addr_storage);
+            if (iface)
+                addr->sin6_scope_id = iface;
+        }
+#endif
         bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len);
     }
-    /* bind to the local address if not multicast or if the multicast
-     * bind failed */
+
+    /* bind to ADDR_ANY if the multicast bind failed */
+    if (s->is_multicast && bind_ret < 0) {
+        struct addrinfo *res;
+
+        if (s->dest_addr.ss_family == AF_INET)
+            res = ff_ip_resolve_host(h, "0.0.0.0", 0, SOCK_DGRAM, AF_UNSPEC, 0);
+        else if (s->dest_addr.ss_family == AF_INET6)
+            res = ff_ip_resolve_host(h, "::", 0, SOCK_DGRAM, AF_UNSPEC, 0);
+
+        if (res && res->ai_addr) {
+            bind_ret = bind(udp_fd, res->ai_addr, res->ai_addrlen);
+        }
+
+        freeaddrinfo(res);
+    }
+
     /* the bind is needed to give a port to the socket now */
     if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) {
         ff_log_net_error(h, AV_LOG_ERROR, "bind failed");
@@ -855,6 +914,12 @@ static int udp_open(URLContext *h, const char *uri, int flags)
     s->local_port = udp_port(&my_addr, len);

     if (s->is_multicast) {
+        if ((ret = udp_set_multicast_interface(udp_fd,
+                                        (struct sockaddr *)&s->dest_addr,
+                                        (struct sockaddr *)&s->local_addr_storage,
+                                        h)) < 0)
+            goto fail;
+
         if (h->flags & AVIO_FLAG_WRITE) {
             /* output */
             if ((ret = udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr, h)) < 0)
--
2.41.0.windows.2


This message has been marked as Public on 03/20/2024 09:28Z.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection
  2024-03-20  9:28       ` [FFmpeg-devel] [PATCH v2] " Ignjatović, Lazar (RS)
@ 2024-03-20 10:51         ` Rémi Denis-Courmont
  2024-03-20 11:09           ` Ignjatović, Lazar (RS)
  0 siblings, 1 reply; 38+ messages in thread
From: Rémi Denis-Courmont @ 2024-03-20 10:51 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Same fundamental problem as previous version, AFAICT.

-1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection
  2024-03-20 10:51         ` Rémi Denis-Courmont
@ 2024-03-20 11:09           ` Ignjatović, Lazar (RS)
  2024-03-20 11:29             ` Rémi Denis-Courmont
  0 siblings, 1 reply; 38+ messages in thread
From: Ignjatović, Lazar (RS) @ 2024-03-20 11:09 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


This message has been marked as Public on 03/20/2024 11:09Z.
On Wednesday, March 20, 2024 11:51 AM Rémi Denis-Courmont wrote:

> Same fundamental problem as previous version, AFAICT.
>
> -1

Would you mind being more specific?
There are 2 problems you pointed out, one about SO_BINDTODEVICE, and another in respect to casting `sockaddr* ` to `sockaddr_in6*` and `sockaddr_storage*` to `sockaddr_in6*`.
Assuming you are reffering to the cast comment, I've addressed this in the other thread. That should not be an issue to my knowledge, and is done on multiple places throughout the codebase.
Also I've assked you for additional comments, which I'm doing again.

Lazar Ignjatović
Associate Software Engineer

Cubic Defense
cubic.com
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection
  2024-03-20 11:09           ` Ignjatović, Lazar (RS)
@ 2024-03-20 11:29             ` Rémi Denis-Courmont
  2024-03-20 11:45               ` Ignjatović, Lazar (RS)
  0 siblings, 1 reply; 38+ messages in thread
From: Rémi Denis-Courmont @ 2024-03-20 11:29 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



Le 20 mars 2024 13:09:15 GMT+02:00, "Ignjatović, Lazar (RS)" <Lazar.Ignjatovic@cubic.com> a écrit :
>
>This message has been marked as Public on 03/20/2024 11:09Z.
>On Wednesday, March 20, 2024 11:51 AM Rémi Denis-Courmont wrote:
>
>> Same fundamental problem as previous version, AFAICT.
>>
>> -1
>
>Would you mind being more specific?

You're not supposed to guess the link ID from the local address. This is counter-sensical. And it's entirely possible to have the same LL address assigned to two interfaces (e.g. using a software bridge) anyway.

Either you know the interface you want to use and you should pass it on directly. Or you don't and using link-local doesn't make sense.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection
  2024-03-20 11:29             ` Rémi Denis-Courmont
@ 2024-03-20 11:45               ` Ignjatović, Lazar (RS)
  2024-03-20 12:17                 ` Rémi Denis-Courmont
  0 siblings, 1 reply; 38+ messages in thread
From: Ignjatović, Lazar (RS) @ 2024-03-20 11:45 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


This message has been marked as Public on 03/20/2024 11:45Z.
On Wednesday, March 20, 2024 12:30 PM Rémi Denis-Courmont wrote:

> You're not supposed to guess the link ID from the local address. This is counter-sensical. And it's entirely possible to have the same LL address assigned to two interfaces (e.g. using a software bridge) anyway.

You are right about the same LL on multiple interfaces, that’s why the `sin6_scope_id` is used. For specifying LL address, a scoped address format should be used to avoid ambiguity. In all other cases, determining the interface ID by address should be ok, while keeping the same functionality that `localaddr` param has with IPv6. Currently, I don't see any other way of specifying IPv6 multicast interface without the introduction of another query param like `iface` or something.

Let me know what you think.

Sincirely,
Lazar Ignjatović
Associate Software Engineer

Cubic Defense
cubic.com
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection
  2024-03-20 11:45               ` Ignjatović, Lazar (RS)
@ 2024-03-20 12:17                 ` Rémi Denis-Courmont
  2024-03-20 12:35                   ` Ignjatović, Lazar (RS)
  0 siblings, 1 reply; 38+ messages in thread
From: Rémi Denis-Courmont @ 2024-03-20 12:17 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



Le 20 mars 2024 13:45:10 GMT+02:00, "Ignjatović, Lazar (RS)" <Lazar.Ignjatovic@cubic.com> a écrit :
>
>This message has been marked as Public on 03/20/2024 11:45Z.
>On Wednesday, March 20, 2024 12:30 PM Rémi Denis-Courmont wrote:
>
>> You're not supposed to guess the link ID from the local address. This is counter-sensical. And it's entirely possible to have the same LL address assigned to two interfaces (e.g. using a software bridge) anyway.
>
>You are right about the same LL on multiple interfaces, that’s why the `sin6_scope_id` is used. For specifying LL address, a scoped address format should be used to avoid ambiguity.

Yes, the whole point is that LL addresses are ambiguous.

> In all other cases, determining the interface ID by address should be ok,

No! The only other case is non-LL addressing, which does not require link ID at all.

Still -1.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection
  2024-03-20 12:17                 ` Rémi Denis-Courmont
@ 2024-03-20 12:35                   ` Ignjatović, Lazar (RS)
  2024-03-21  7:26                     ` Rémi Denis-Courmont
  0 siblings, 1 reply; 38+ messages in thread
From: Ignjatović, Lazar (RS) @ 2024-03-20 12:35 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


This message has been marked as Public on 03/20/2024 12:35Z.
On Wednesday, March 20, 2024 1:18 PM Rémi Denis-Courmont wrote:

>> In all other cases, determining the interface ID by address should be
>> ok,
>
> No! The only other case is non-LL addressing, which does not require link ID at all.

For IPv4 that is certainly true, but it differs for v6. Specifying egress interface is done by setting the setsockopt(IPV6_MULTICAST_IF) to the value of the interface, not address. On the other hand v4 for the similar option setsockopt(IP_MULTICAST_IF) sets it by definig an address (not interface). Without setting IPV6_MULTICAST_IF to the appropriate interface, default interface is chosen. We want to have control over this, and I cant se how this can be achieved without knowing the interface id.

For ingress IPv6 traffic, the way to filter on which interface is being listened on is by binding to a mcast addres, which has sin6_scope_id properly set.

Lazar Ignjatović
Associate Software Engineer

Cubic Defense
cubic.com
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection
  2024-03-20 12:35                   ` Ignjatović, Lazar (RS)
@ 2024-03-21  7:26                     ` Rémi Denis-Courmont
  2024-03-21 13:01                       ` Ignjatović, Lazar (RS)
  0 siblings, 1 reply; 38+ messages in thread
From: Rémi Denis-Courmont @ 2024-03-21  7:26 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



Le 20 mars 2024 14:35:28 GMT+02:00, "Ignjatović, Lazar (RS)" <Lazar.Ignjatovic@cubic.com> a écrit :
> Specifying egress interface is done by setting the setsockopt(IPV6_MULTICAST_IF) to the value of the interface, not address. On the other hand v4 for the similar option setsockopt(IP_MULTICAST_IF) sets it by definig an address (not interface). Without setting IPV6_MULTICAST_IF to the appropriate interface, default interface is chosen. We want to have control over this, and I cant se how this can be achieved without knowing the interface id.

>For ingress IPv6 traffic, the way to filter on which interface is being listened on is by binding to a mcast addres, which has sin6_scope_id properly set.

Your MR makes even less sense for multicast. For multicast there is no local address to match to an interface. So you just have to have the interface specified explicitly in addition to the LL group address. This is true for both egress and ingress.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection
  2024-03-21  7:26                     ` Rémi Denis-Courmont
@ 2024-03-21 13:01                       ` Ignjatović, Lazar (RS)
  2024-03-21 19:44                         ` Rémi Denis-Courmont
  0 siblings, 1 reply; 38+ messages in thread
From: Ignjatović, Lazar (RS) @ 2024-03-21 13:01 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

> Your MR makes even less sense for multicast. For multicast there is no local address to match to an interface. So you just have to have the interface specified explicitly in addition to the LL group address. This is true for both egress and ingress.

I've compared ffmpeg 5.1.2 against my MR on IPv6 multicast. Here are the results:

Recv (on interface other than default)

|     Address    |     localaddr     | 5.1.2 | MR  |
| -------------- | ----------------- | ----- | --- |
| FF11::1        | null              | NO    | NO  |
| FF11::1        | iface addr        | NO    | YES |
| FF11::1%eth0   | null              | NO    | YES |
| FF12::1        | null              | NO    | NO  |
| FF12::1        | iface addr        | NO    | YES |
| FF12::1%eth0   | null              | NO    | YES |
| FF14::1        | null              | NO    | NO  |
| FF14::1        | iface addr        | NO    | YES |
| FF14::1%eth0   | null              | NO    | NO  |
| FF15::1        | null              | NO    | NO  |
| FF15::1        | iface addr        | NO    | YES |
| FF15::1%eth0   | null              | NO    | NO  |
| FF18::1        | null              | NO    | NO  |
| FF18::1        | iface addr        | NO    | YES |
| FF18::1%eth0   | null              | NO    | NO  |

Send (on interface other than default)

|     Address    |     localaddr     | 5.1.2 | MR  |
| -------------- | ----------------- | ----- | --- |
| FF11::1        | null              | NO    | NO  |
| FF11::1        | iface addr        | NO    | YES |
| FF11::1%eth0   | null              | YES   | YES |
| FF12::1        | null              | NO    | NO  |
| FF12::1        | iface addr        | NO    | YES |
| FF12::1%eth0   | null              | YES   | YES |
| FF14::1        | null              | NO    | NO  |
| FF14::1        | iface addr        | NO    | YES |
| FF14::1%eth0   | null              | NO    | NO  |
| FF15::1        | null              | NO    | NO  |
| FF15::1        | iface addr        | NO    | YES |
| FF15::1%eth0   | null              | NO    | NO  |
| FF18::1        | null              | NO    | NO  |
| FF18::1        | iface addr        | NO    | YES |
| FF18::1%eth0   | null              | NO    | NO  |

Here are the reasons why the combinations marked NO under my MR don’t work:

FF11::1      -> ambiguous interface on which to listen/send
FF12::1      -> ambiguous interface on which to listen/send
FF14::1      -> ambiguous interface on which to listen/send, uses only default iface
FF14::1%eth0 -> getaddrinfo errors as it supports %scope only for link-local
FF15::1      -> ambiguous interface on which to listen/send, uses only default iface
FF15::1%eth0 -> getaddrinfo errors as it supports %scope only for link-local
FF18::1      -> ambiguous interface on which to listen/send, uses only default iface
FF18::1%eth0 -> getaddrinfo errors as it supports %scope only for link-local

So the problem to overcome here is controlling on which interface we listen/send multicat IPv6.
For link local yes, %scope is the way to go.

I proposed this MR as the solution to the problem, keepeng the `localaddr` parameter semantics the same as with IPv4.

Other solution could be introduction of a new parameter, as I said before. In this case then, the documentation should
be changed to reflect that `localaddr` is only used for IPv4 addresses, and that same functionality can be obtained with
this new parameter under IPv6.

There will certainly be V3 of the patch, as I've identified minor changes needed for this approach.
If you have any other ideas, I'm open to hearing them.

Lazar Ignjatović
Associate Software Engineer

Cubic Defense
cubic.com

This message has been marked as Public on 03/21/2024 13:01Z.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection
  2024-03-21 13:01                       ` Ignjatović, Lazar (RS)
@ 2024-03-21 19:44                         ` Rémi Denis-Courmont
  2024-03-22  9:31                           ` Ignjatović, Lazar (RS)
  0 siblings, 1 reply; 38+ messages in thread
From: Rémi Denis-Courmont @ 2024-03-21 19:44 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Le torstaina 21. maaliskuuta 2024, 15.01.09 EET Ignjatović, Lazar (RS) a écrit 
:
> > Your MR makes even less sense for multicast. For multicast there is no
> > local address to match to an interface. So you just have to have the
> > interface specified explicitly in addition to the LL group address. This
> > is true for both egress and ingress.
> 
> I've compared ffmpeg 5.1.2 against my MR on IPv6 multicast. Here are the
> results:

I don't care. That does not make your MR any less counter-sensical.

If you could infer the scope ID from the IPv6 address, there wouldn't be a 
scope ID field in the socket address in the first place. Is it that hard to 
understand?

If you tests show anything, it's that LL addressing is not intended for 
application protocols. This is consistent with the fact that nobody cared to 
support this combination in FFmpeg after 28 years of IPv6. Now I don't mind 
adding proper support, but not kludges.

> So the problem to overcome here is controlling on which interface we
> listen/send multicat IPv6.

That "problem" was solved before FFmpeg existed by adding a separate parameter 
(ping6) or prepending the interface name after a percent sign (glibc).

-- 
Rémi Denis-Courmont
http://www.remlab.net/



_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection
  2024-03-21 19:44                         ` Rémi Denis-Courmont
@ 2024-03-22  9:31                           ` Ignjatović, Lazar (RS)
  2024-03-22  9:55                             ` Rémi Denis-Courmont
  0 siblings, 1 reply; 38+ messages in thread
From: Ignjatović, Lazar (RS) @ 2024-03-22  9:31 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

>> I've compared ffmpeg 5.1.2 against my MR on IPv6 multicast. Here are
>> the
>> results:
>
> I don't care. That does not make your MR any less counter-sensical.

If I may cite Marton Balint
```
d3bda871f033be4825ecb69d444b3396bf2a2eb7
avformat/udp: specify the local address for some source filtered multicast joins

We already use localaddr for the multicast joins without source filters, so we
should use them for source filters as well. This patch only fixes the
IP_ADD_SOURCE_MEMBERSHIP and the IP_BLOCK_SOURCE case.

Unless we do this, the kernel automatically selects an interface based on the
source address, and that interface might be different from the one set in
localaddr. For blocked sources this even casues EINVAL because we joined the
multicast group on a different interface.

Signed-off-by: Marton Balint <cus@passwd.hu>
---
 ...
//TODO: Interface index should be looked up from local_addr
...
```

And another commit
```
ab0812c1a8925a95315354b88b41256faad5faa8
avformat/udp: always use IP_ADD_SOURCE_MEMBERSHIP for subscribing to an UDP multicast source group in IPv4

That alone supports specifying the interface based on its address. Getting the
interface index from the local address seems quite a bit of work in a platform
independent way...

Obviously for IPv6 we still always use MCAST_JOIN_SOURCE_GROUP.

As a side effect this also fixes ticket #7459.

Signed-off-by: Marton Balint <cus@passwd.hu>
```

From this I understand that the intention is to still use localaddr parameter
with the same semantics as with IPv4

> If you could infer the scope ID from the IPv6 address, there wouldn't be a
> scope ID field in the socket address in the first place. Is it that hard to
> understand?

Well, it's not that simple. Here I have to cite ipv6(7) — Linux manual page
```
       sin6_scope_id
       is an ID depending on the scope of the address.  It is new in
       Linux 2.4.  Linux supports it only for link-local addresses, in
       that case sin6_scope_id contains the interface index (see
       netdevice(7))
```

> That "problem" was solved before FFmpeg existed by adding a separate parameter
> (ping6) or prepending the interface name after a percent sign (glibc).

And this is the closest you've got to providing an alternate solution to the proposed.
Which is adding another parameter, or relying on % for every type of multicast.

> If you tests show anything, it's that LL addressing is not intended for application protocols.

And just to clarify
FF11::1%eth0 is an interface-local multicast, thus supported
FF12::1%eth0 is a link-local multicast, thus supported

All other multicast scopes are not supported by Linux in respect to %scope.

If we choose to support ff15::1%eth0 for example, we are introducing something that
is not normally supported on Linux, potentially creating confusion among users.
Interface parameter seems like a better option than the %scope for everything.

Can someone else agree with this?

If this is, in fact, the preferred way, then okay. I will propose the v3 of the patch
done this way. Still, I prefer keeping the IPv4 semantics for v6.

Lazar Ignjatović
Associate Software Engineer

Cubic Defense
cubic.com

This message has been marked as Public on 03/22/2024 09:31Z.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection
  2024-03-22  9:31                           ` Ignjatović, Lazar (RS)
@ 2024-03-22  9:55                             ` Rémi Denis-Courmont
  2024-03-22 10:16                               ` Ignjatović, Lazar (RS)
  0 siblings, 1 reply; 38+ messages in thread
From: Rémi Denis-Courmont @ 2024-03-22  9:55 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



Le 22 mars 2024 11:31:28 GMT+02:00, "Ignjatović, Lazar (RS)" <Lazar.Ignjatovic@cubic.com> a écrit :
>>> I've compared ffmpeg 5.1.2 against my MR on IPv6 multicast. Here are
>>> the
>>> results:
>>
>> I don't care. That does not make your MR any less counter-sensical.
>
>If I may cite Marton Balint

I am not answerable for something somebody else did.

And yes, IPv4 selects multicast interfaces by IPv4 address. That was a poor design choice in hindsight and IPv6 was instead designed to select multicast interfaces by local link ID.

You've made it clear up-thread that you know all of this, as well as you know how to specify link IDs (with % or an additional parameter). So why are you arguing now?
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection
  2024-03-22  9:55                             ` Rémi Denis-Courmont
@ 2024-03-22 10:16                               ` Ignjatović, Lazar (RS)
  2024-03-26 12:34                                 ` [FFmpeg-devel] [PATCH v3] avformat: enable UDP IPv6 multicast interface selection using localaddr Ignjatović, Lazar (RS)
                                                   ` (2 more replies)
  0 siblings, 3 replies; 38+ messages in thread
From: Ignjatović, Lazar (RS) @ 2024-03-22 10:16 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


This message has been marked as Public on 03/22/2024 10:16Z.
On Friday, March 22, 2024 10:55 AM Rémi Denis-Courmont wrote:

> So why are you arguing now?

Because I still belive that using localaddr is the better approach.
However, I will create and submit v3 of this patch and also create
another patch following your suggestions of either using a new param
or using scope_id.

Both will be available, so the maintainers can choose. I think that’s fair.

Lazar Ignjatović
Associate Software Engineer

Cubic Defense
cubic.com
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [FFmpeg-devel] [PATCH v3] avformat: enable UDP IPv6 multicast interface selection using localaddr
  2024-03-22 10:16                               ` Ignjatović, Lazar (RS)
@ 2024-03-26 12:34                                 ` Ignjatović, Lazar (RS)
  2024-03-26 18:25                                   ` Rémi Denis-Courmont
  2024-03-26 12:34                                 ` [FFmpeg-devel] [PATCH] " Ignjatović, Lazar (RS)
  2024-03-26 18:24                                 ` [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection Rémi Denis-Courmont
  2 siblings, 1 reply; 38+ messages in thread
From: Ignjatović, Lazar (RS) @ 2024-03-26 12:34 UTC (permalink / raw)
  To: ffmpeg-devel

avformat: enable UDP IPv6 multicast interface selection using localaddr

localaddr option now properly works with IPv6 addresses. Properly
resolved interface index in places where default 0 interface index is
used (marked with TODO: within udp.c). Adjusted binding for multicast
sockets that are used for reading from the network. Need for this
arises from the fact that link-local multicast addresses need to have a
defined interface for binding to avoid ambiguity between multiple
link-local networks on the same host. Failing to set this option causes
errors on Linux systems for interface and link-local scopes.

For mcast addresses, bind to mcast address is attempted as before.
In case that this fails, which will happen on Windows, socket is bound
to INADDR_ANY/IN6ADDR_ANY_INIT depending on address family. Actual
interface selection is performed using udp_set_multicast_interface to
point to the desired interface for sending.

Utilization of sin6_scope_id field enables usage and adequate resolving
of IPv6 addresses that utilize zone index (e.g. fe80::1%eth2)

Closes: #368

Signed-off-by: Lazar Ignjatovic <Lazar.Ignjatovic@cubic.com>
---
V1 -> V2: SO_BINDTODEVICE -> sin6_scope_id, addressed comments
V2 -> V3: mcast check sin6_scope_id for iface specification
NOTE: Due to comments, this patch is proposed as one of two alternatives
The other alternative uses exclusively %scope format for defining
interfaces. This patch can handle scoped IPv6 link-local addresses


 configure             |  3 ++
 libavformat/ip.c      | 48 ++++++++++++++++++++++++
 libavformat/ip.h      |  6 +++
 libavformat/network.h |  6 +++
 libavformat/udp.c     | 85 +++++++++++++++++++++++++++++++++++++++----
 5 files changed, 140 insertions(+), 8 deletions(-)

diff --git a/configure b/configure
index e019d1b996..08f35bbd25 100755
--- a/configure
+++ b/configure
@@ -2258,6 +2258,7 @@ HEADERS_LIST="
     valgrind_valgrind_h
     windows_h
     winsock2_h
+    iphlpapi_h
 "

 INTRINSICS_LIST="
@@ -6406,6 +6407,8 @@ if ! disabled network; then
         check_struct winsock2.h "struct sockaddr" sa_len
         check_type ws2tcpip.h "struct sockaddr_in6"
         check_type ws2tcpip.h "struct sockaddr_storage"
+        check_headers iphlpapi.h -liphlpapi && network_extralibs="$network_extralibs -liphlpapi" || disable iphlpapi_h
+        check_func_headers iphlpapi.h GetBestInterfaceEx $network_extralibs
     else
         disable network
     fi
diff --git a/libavformat/ip.c b/libavformat/ip.c
index b2c7ef07e5..821595edc5 100644
--- a/libavformat/ip.c
+++ b/libavformat/ip.c
@@ -18,6 +18,9 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */

+#define _DEFAULT_SOURCE
+#define _SVID_SOURCE
+
 #include <string.h>
 #include "ip.h"
 #include "libavutil/avstring.h"
@@ -159,3 +162,48 @@ void ff_ip_reset_filters(IPSourceFilters *filters)
     filters->nb_include_addrs = 0;
     filters->nb_exclude_addrs = 0;
 }
+
+unsigned int ff_ip_resolve_interface_index(struct sockaddr_storage *local_addr)
+{
+#if HAVE_WINSOCK2_H
+#if HAVE_IPHLPAPI_H
+    DWORD retval;
+    unsigned long iface;
+
+    if (local_addr == NULL)
+        return 0;
+
+    retval = GetBestInterfaceEx((struct sockaddr*)local_addr, &iface);
+    if (retval == NO_ERROR)
+        return iface;
+#endif /* HAVE_IPHLPAPI_H */
+    return 0;
+#else /* HAVE_WINSOCK2_H */
+    struct ifaddrs *ifaddr, *ifa;
+    unsigned int iface;
+
+    if (local_addr == NULL)
+        return 0;
+
+#if HAVE_STRUCT_SOCKADDR_IN6
+    if (local_addr->ss_family == AF_INET6) {
+        iface = ((struct sockaddr_in6*)local_addr)->sin6_scope_id;
+        if (iface)
+            return iface;
+    }
+#endif /* HAVE_STRUCT_SOCKADDR_IN6 */
+    if (getifaddrs(&ifaddr) == -1)
+        return 0;
+
+    iface = 0;
+    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+        if (ifa->ifa_addr != NULL && compare_addr((struct sockaddr_storage*)ifa->ifa_addr, local_addr) == 0) {
+            iface = if_nametoindex(ifa->ifa_name);
+            break;
+        }
+    }
+
+    freeifaddrs(ifaddr);
+    return iface;
+#endif /* HAVE_WINSOCK2_H */
+}
diff --git a/libavformat/ip.h b/libavformat/ip.h
index b76cdab91c..4085e96f08 100644
--- a/libavformat/ip.h
+++ b/libavformat/ip.h
@@ -69,4 +69,10 @@ int ff_ip_parse_blocks(void *log_ctx, const char *buf, IPSourceFilters *filters)
  */
 void ff_ip_reset_filters(IPSourceFilters *filters);

+/**
+ * Resolves IP address to an associated interface index
+ * @return interface index, 0 as default interface value on error
+ */
+unsigned int ff_ip_resolve_interface_index(struct sockaddr_storage *local_addr);
+
 #endif /* AVFORMAT_IP_H */
diff --git a/libavformat/network.h b/libavformat/network.h
index ca214087fc..2461b651d4 100644
--- a/libavformat/network.h
+++ b/libavformat/network.h
@@ -38,6 +38,10 @@
 #include <winsock2.h>
 #include <ws2tcpip.h>

+#if HAVE_IPHLPAPI_H
+#include <iphlpapi.h>
+#endif
+
 #ifndef EPROTONOSUPPORT
 #define EPROTONOSUPPORT WSAEPROTONOSUPPORT
 #endif
@@ -64,6 +68,8 @@ int ff_neterrno(void);
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <netdb.h>
+#include <net/if.h>
+#include <ifaddrs.h>

 #define ff_neterrno() AVERROR(errno)
 #endif /* HAVE_WINSOCK2_H */
diff --git a/libavformat/udp.c b/libavformat/udp.c
index d9514f5026..69ef93bfed 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -220,8 +220,10 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
         struct ipv6_mreq mreq6;

         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
-        //TODO: Interface index should be looked up from local_addr
-        mreq6.ipv6mr_interface = 0;
+        mreq6.ipv6mr_interface = ff_ip_resolve_interface_index((struct sockaddr_storage *)local_addr);
+        if (!mreq6.ipv6mr_interface)
+            mreq6.ipv6mr_interface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
+
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP)");
             return ff_neterrno();
@@ -231,6 +233,41 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
     return 0;
 }

+static int udp_set_multicast_interface(int sockfd, struct sockaddr *addr,
+                                    struct sockaddr *local_addr, void *logctx)
+{
+#ifdef IP_MULTICAST_IF
+    if (addr->sa_family == AF_INET) {
+        struct ip_mreq mreq;
+
+        mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
+        if (local_addr)
+            mreq.imr_interface = ((struct sockaddr_in *)local_addr)->sin_addr;
+        else
+            mreq.imr_interface.s_addr = INADDR_ANY;
+
+        if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, (const void *)&mreq, sizeof(mreq)) < 0) {
+            ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_IF)");
+            return ff_neterrno();
+        }
+    }
+#endif
+#if defined(IPV6_MULTICAST_IF) && defined(IPPROTO_IPV6)
+    if (addr->sa_family == AF_INET6) {
+        unsigned int iface;
+        iface = ff_ip_resolve_interface_index((struct sockaddr_storage *)local_addr);
+        if (!iface)
+            iface= ((struct sockaddr_in6 *)addr)->sin6_scope_id;
+
+        if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &iface, sizeof(unsigned int)) < 0) {
+            ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_IF)");
+            return ff_neterrno();
+        }
+    }
+#endif
+    return 0;
+}
+
 static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
                                      struct sockaddr *local_addr, void *logctx)
 {
@@ -254,8 +291,10 @@ static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
         struct ipv6_mreq mreq6;

         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
-        //TODO: Interface index should be looked up from local_addr
-        mreq6.ipv6mr_interface = 0;
+        mreq6.ipv6mr_interface = ff_ip_resolve_interface_index((struct sockaddr_storage *)local_addr);
+        if (!mreq6.ipv6mr_interface)
+            mreq6.ipv6mr_interface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
+
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP)");
             return -1;
@@ -282,8 +321,7 @@ static int udp_set_multicast_sources(URLContext *h,
             struct group_source_req mreqs;
             int level = addr->sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;

-            //TODO: Interface index should be looked up from local_addr
-            mreqs.gsr_interface = 0;
+            mreqs.gsr_interface = ff_ip_resolve_interface_index(local_addr);
             memcpy(&mreqs.gsr_group, addr, addr_len);
             memcpy(&mreqs.gsr_source, &sources[i], sizeof(*sources));

@@ -839,10 +877,35 @@ static int udp_open(URLContext *h, const char *uri, int flags)
      * port. This fails on windows. This makes sending to the same address
      * using sendto() fail, so only do it if we're opened in read-only mode. */
     if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) {
+#if HAVE_STRUCT_SOCKADDR_IN6 && !HAVE_WINSOCK2_H
+        if (s->dest_addr.ss_family == AF_INET6) {
+            unsigned int iface;
+            struct sockaddr_in6 *addr;
+            addr = (struct sockaddr_in6 *)&s->dest_addr;
+            iface = ff_ip_resolve_interface_index(&s->local_addr_storage);
+            if (iface)
+                addr->sin6_scope_id = iface;
+        }
+#endif
         bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len);
     }
-    /* bind to the local address if not multicast or if the multicast
-     * bind failed */
+
+    /* bind to ADDR_ANY if the multicast bind failed */
+    if (s->is_multicast && bind_ret < 0) {
+        struct addrinfo *res;
+
+        if (s->dest_addr.ss_family == AF_INET)
+            res = ff_ip_resolve_host(h, "0.0.0.0", 0, SOCK_DGRAM, AF_UNSPEC, 0);
+        else if (s->dest_addr.ss_family == AF_INET6)
+            res = ff_ip_resolve_host(h, "::", 0, SOCK_DGRAM, AF_UNSPEC, 0);
+
+        if (res && res->ai_addr) {
+            bind_ret = bind(udp_fd, res->ai_addr, res->ai_addrlen);
+        }
+
+        freeaddrinfo(res);
+    }
+
     /* the bind is needed to give a port to the socket now */
     if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) {
         ff_log_net_error(h, AV_LOG_ERROR, "bind failed");
@@ -855,6 +918,12 @@ static int udp_open(URLContext *h, const char *uri, int flags)
     s->local_port = udp_port(&my_addr, len);

     if (s->is_multicast) {
+        if ((ret = udp_set_multicast_interface(udp_fd,
+                                        (struct sockaddr *)&s->dest_addr,
+                                        (struct sockaddr *)&s->local_addr_storage,
+                                        h)) < 0)
+            goto fail;
+
         if (h->flags & AVIO_FLAG_WRITE) {
             /* output */
             if ((ret = udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr, h)) < 0)
--
2.41.0.windows.2


This message has been marked as Public on 03/26/2024 12:34Z.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [FFmpeg-devel] [PATCH] avformat: enable UDP IPv6 multicast interface selection using zone index
  2024-03-22 10:16                               ` Ignjatović, Lazar (RS)
  2024-03-26 12:34                                 ` [FFmpeg-devel] [PATCH v3] avformat: enable UDP IPv6 multicast interface selection using localaddr Ignjatović, Lazar (RS)
@ 2024-03-26 12:34                                 ` Ignjatović, Lazar (RS)
  2024-03-26 18:24                                 ` [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection Rémi Denis-Courmont
  2 siblings, 0 replies; 38+ messages in thread
From: Ignjatović, Lazar (RS) @ 2024-03-26 12:34 UTC (permalink / raw)
  To: ffmpeg-devel

avformat: enable UDP IPv6 multicast interface selection using zone index

Enabled IPv6 interface selection using zone index. Properly resolved
interface index in places where default 0 interface index is used
(marked with TODO: within udp.c). Adjusted binding for multicast sockets
that are used for reading from the network.

For mcast addresses, bind to mcast address is attempted as before.
In case that this fails, which will happen on Windows, socket is bound
to INADDR_ANY/IN6ADDR_ANY_INIT depending on address family. Actual
interface selection is performed using udp_set_multicast_interface to
point to the desired interface for sending.

IPv6 interfaces are resolved based on sin6_scope_id field, while IPv4
interface resolution is performed based on address.

Closes: #368

Signed-off-by: Lazar Ignjatovic <Lazar.Ignjatovic@cubic.com>
---
NOTE: Due to comments, this patch is proposed as one of two alternatives
The other alternative uses `localaddr` for defining interfaces.

 configure             |  3 ++
 doc/protocols.texi    |  2 +-
 libavformat/ip.c      | 48 ++++++++++++++++++++++++
 libavformat/ip.h      |  6 +++
 libavformat/network.h |  6 +++
 libavformat/udp.c     | 87 ++++++++++++++++++++++++++++++++++++++-----
 6 files changed, 142 insertions(+), 10 deletions(-)

diff --git a/configure b/configure
index 2a1d22310b..35d6a0b78c 100755
--- a/configure
+++ b/configure
@@ -2307,6 +2307,7 @@ HEADERS_LIST="
     valgrind_valgrind_h
     windows_h
     winsock2_h
+    iphlpapi_h
 "

 INTRINSICS_LIST="
@@ -6475,6 +6476,8 @@ if ! disabled network; then
         check_struct winsock2.h "struct sockaddr" sa_len
         check_type ws2tcpip.h "struct sockaddr_in6"
         check_type ws2tcpip.h "struct sockaddr_storage"
+        check_headers iphlpapi.h -liphlpapi && network_extralibs="$network_extralibs -liphlpapi" || disable iphlpapi_h
+        check_func_headers iphlpapi.h GetBestInterfaceEx $network_extralibs
     else
         disable network
     fi
diff --git a/doc/protocols.texi b/doc/protocols.texi
index f54600b846..a8892845d3 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -2027,7 +2027,7 @@ packet bursts.
 Override the local UDP port to bind with.

 @item localaddr=@var{addr}
-Local IP address of a network interface used for sending packets or joining
+Local IPv4 address of a network interface used for sending packets or joining
 multicast groups.

 @item pkt_size=@var{size}
diff --git a/libavformat/ip.c b/libavformat/ip.c
index b2c7ef07e5..dc488b12c2 100644
--- a/libavformat/ip.c
+++ b/libavformat/ip.c
@@ -18,6 +18,9 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */

+#define _DEFAULT_SOURCE
+#define _SVID_SOURCE
+
 #include <string.h>
 #include "ip.h"
 #include "libavutil/avstring.h"
@@ -159,3 +162,48 @@ void ff_ip_reset_filters(IPSourceFilters *filters)
     filters->nb_include_addrs = 0;
     filters->nb_exclude_addrs = 0;
 }
+
+unsigned int ff_ip_resolve_interface_index(struct sockaddr_storage *local_addr)
+{
+#if HAVE_WINSOCK2_H
+#if HAVE_IPHLPAPI_H
+    DWORD retval;
+    unsigned long iface;
+
+    if (local_addr == NULL)
+        return 0;
+
+    retval = GetBestInterfaceEx((struct sockaddr*)local_addr, &iface);
+    if (retval == NO_ERROR)
+        return iface;
+#endif /* HAVE_IPHLPAPI_H */
+    return 0;
+#else /* HAVE_WINSOCK2_H */
+    struct ifaddrs *ifaddr, *ifa;
+    unsigned int iface;
+
+    if (local_addr == NULL)
+        return 0;
+
+#if HAVE_STRUCT_SOCKADDR_IN6
+    if (local_addr->ss_family == AF_INET6) {
+        iface = ((struct sockaddr_in6*)local_addr)->sin6_scope_id;
+        if (iface)
+            return iface;
+    }
+#endif /* HAVE_STRUCT_SOCKADDR_IN6 */
+    if (getifaddrs(&ifaddr) == -1)
+        return 0;
+
+    iface = 0;
+    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+        if (ifa->ifa_addr != NULL && compare_addr((struct sockaddr_storage*)ifa->ifa_addr, local_addr) == 0) {
+            iface = if_nametoindex(ifa->ifa_name);
+            break;
+        }
+    }
+
+    freeifaddrs(ifaddr);
+    return iface;
+#endif /* HAVE_WINSOCK2_H */
+}
\ No newline at end of file
diff --git a/libavformat/ip.h b/libavformat/ip.h
index b76cdab91c..4085e96f08 100644
--- a/libavformat/ip.h
+++ b/libavformat/ip.h
@@ -69,4 +69,10 @@ int ff_ip_parse_blocks(void *log_ctx, const char *buf, IPSourceFilters *filters)
  */
 void ff_ip_reset_filters(IPSourceFilters *filters);

+/**
+ * Resolves IP address to an associated interface index
+ * @return interface index, 0 as default interface value on error
+ */
+unsigned int ff_ip_resolve_interface_index(struct sockaddr_storage *local_addr);
+
 #endif /* AVFORMAT_IP_H */
diff --git a/libavformat/network.h b/libavformat/network.h
index ca214087fc..2461b651d4 100644
--- a/libavformat/network.h
+++ b/libavformat/network.h
@@ -38,6 +38,10 @@
 #include <winsock2.h>
 #include <ws2tcpip.h>

+#if HAVE_IPHLPAPI_H
+#include <iphlpapi.h>
+#endif
+
 #ifndef EPROTONOSUPPORT
 #define EPROTONOSUPPORT WSAEPROTONOSUPPORT
 #endif
@@ -64,6 +68,8 @@ int ff_neterrno(void);
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <netdb.h>
+#include <net/if.h>
+#include <ifaddrs.h>

 #define ff_neterrno() AVERROR(errno)
 #endif /* HAVE_WINSOCK2_H */
diff --git a/libavformat/udp.c b/libavformat/udp.c
index d9514f5026..415377e032 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -35,6 +35,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/log.h"
 #include "libavutil/time.h"
+#include "libavutil/avstring.h"
 #include "internal.h"
 #include "network.h"
 #include "os_support.h"
@@ -220,8 +221,7 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
         struct ipv6_mreq mreq6;

         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
-        //TODO: Interface index should be looked up from local_addr
-        mreq6.ipv6mr_interface = 0;
+        mreq6.ipv6mr_interface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP)");
             return ff_neterrno();
@@ -231,6 +231,39 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
     return 0;
 }

+static int udp_set_multicast_interface(int sockfd, struct sockaddr *addr,
+                                    struct sockaddr *local_addr, void *logctx)
+{
+#ifdef IP_MULTICAST_IF
+    if (addr->sa_family == AF_INET) {
+        struct ip_mreq mreq;
+
+        mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
+        if (local_addr)
+            mreq.imr_interface = ((struct sockaddr_in *)local_addr)->sin_addr;
+        else
+            mreq.imr_interface.s_addr = INADDR_ANY;
+
+        if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, (const void *)&mreq, sizeof(mreq)) < 0) {
+            ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_IF)");
+            return ff_neterrno();
+        }
+    }
+#endif
+#if defined(IPV6_MULTICAST_IF) && defined(IPPROTO_IPV6)
+    if (addr->sa_family == AF_INET6) {
+        unsigned int iface;
+        iface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
+
+        if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &iface, sizeof(unsigned int)) < 0) {
+            ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_IF)");
+            return ff_neterrno();
+        }
+    }
+#endif
+    return 0;
+}
+
 static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
                                      struct sockaddr *local_addr, void *logctx)
 {
@@ -254,8 +287,7 @@ static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
         struct ipv6_mreq mreq6;

         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
-        //TODO: Interface index should be looked up from local_addr
-        mreq6.ipv6mr_interface = 0;
+        mreq6.ipv6mr_interface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP)");
             return -1;
@@ -282,8 +314,11 @@ static int udp_set_multicast_sources(URLContext *h,
             struct group_source_req mreqs;
             int level = addr->sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;

-            //TODO: Interface index should be looked up from local_addr
-            mreqs.gsr_interface = 0;
+            if (level == IPPROTO_IPV6)
+                mreqs.gsr_interface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
+            else
+                mreqs.gsr_interface = ff_ip_resolve_interface_index(local_addr);
+
             memcpy(&mreqs.gsr_group, addr, addr_len);
             memcpy(&mreqs.gsr_source, &sources[i], sizeof(*sources));

@@ -340,9 +375,22 @@ static int udp_set_url(URLContext *h,
 {
     struct addrinfo *res0;
     int addr_len;
+    const char *host, *sc;
+    char address[1024], scope[1024];

-    res0 = ff_ip_resolve_host(h, hostname, port, SOCK_DGRAM, AF_UNSPEC, 0);
+    if (sc = strchr(hostname, '%')) {
+        av_strlcpy(address, hostname, FFMIN(1024, sc - hostname + 1));
+        av_strlcpy(scope, sc + 1, FFMIN(1024, strlen(hostname) - (sc - hostname)));
+        host = address;
+    } else {
+        host = hostname;
+    }
+
+    res0 = ff_ip_resolve_host(h, host, port, SOCK_DGRAM, AF_UNSPEC, 0);
     if (!res0) return AVERROR(EIO);
+    if (res0->ai_family== AF_INET6 && strlen(scope) > 0) {
+        ((struct sockaddr_in6*)res0->ai_addr)->sin6_scope_id = if_nametoindex(scope);
+    }
     memcpy(addr, res0->ai_addr, res0->ai_addrlen);
     addr_len = res0->ai_addrlen;
     freeaddrinfo(res0);
@@ -841,8 +889,23 @@ static int udp_open(URLContext *h, const char *uri, int flags)
     if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) {
         bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len);
     }
-    /* bind to the local address if not multicast or if the multicast
-     * bind failed */
+
+    /* bind to ADDR_ANY if the multicast bind failed */
+    if (s->is_multicast && bind_ret < 0) {
+        struct addrinfo *res;
+
+        if (s->dest_addr.ss_family == AF_INET)
+            res = ff_ip_resolve_host(h, "0.0.0.0", 0, SOCK_DGRAM, AF_UNSPEC, 0);
+        else if (s->dest_addr.ss_family == AF_INET6)
+            res = ff_ip_resolve_host(h, "::", 0, SOCK_DGRAM, AF_UNSPEC, 0);
+
+        if (res && res->ai_addr) {
+            bind_ret = bind(udp_fd, res->ai_addr, res->ai_addrlen);
+        }
+
+        freeaddrinfo(res);
+    }
+
     /* the bind is needed to give a port to the socket now */
     if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) {
         ff_log_net_error(h, AV_LOG_ERROR, "bind failed");
@@ -855,6 +918,12 @@ static int udp_open(URLContext *h, const char *uri, int flags)
     s->local_port = udp_port(&my_addr, len);

     if (s->is_multicast) {
+        if ((ret = udp_set_multicast_interface(udp_fd,
+                                        (struct sockaddr *)&s->dest_addr,
+                                        (struct sockaddr *)&s->local_addr_storage,
+                                        h)) < 0)
+            goto fail;
+
         if (h->flags & AVIO_FLAG_WRITE) {
             /* output */
             if ((ret = udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr, h)) < 0)
--
2.41.0.windows.2


This message has been marked as Public on 03/26/2024 12:34Z.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection
  2024-03-22 10:16                               ` Ignjatović, Lazar (RS)
  2024-03-26 12:34                                 ` [FFmpeg-devel] [PATCH v3] avformat: enable UDP IPv6 multicast interface selection using localaddr Ignjatović, Lazar (RS)
  2024-03-26 12:34                                 ` [FFmpeg-devel] [PATCH] " Ignjatović, Lazar (RS)
@ 2024-03-26 18:24                                 ` Rémi Denis-Courmont
  2 siblings, 0 replies; 38+ messages in thread
From: Rémi Denis-Courmont @ 2024-03-26 18:24 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Le perjantaina 22. maaliskuuta 2024, 12.16.30 EET Ignjatović, Lazar (RS) a 
écrit :
> This message has been marked as Public on 03/22/2024 10:16Z.
> 
> On Friday, March 22, 2024 10:55 AM Rémi Denis-Courmont wrote:
> > So why are you arguing now?
> 
> Because I still belive that using localaddr is the better approach.

You're entitled to your opinion. That won't change the fact that:

1) The rest of the industry disagrees with you. And by that, I mean the IETF 
(see the advanced IPv6 socket API specifications), the OS and IP stacks and as 
well as existing software other than FFmpeg.

2) It is obvjectively far simpler and more user-friendly to request an 
interface name than a link-local address. Back when link-local addresses were 
derived from the MAC address, you would have had to remember the MAC, which 
nobody in its right mind did. But nowadays, link-local addresses are actually 
random, so that's moot.

In other words, this is ridiculous.

-- 
Rémi Denis-Courmont
http://www.remlab.net/



_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v3] avformat: enable UDP IPv6 multicast interface selection using localaddr
  2024-03-26 12:34                                 ` [FFmpeg-devel] [PATCH v3] avformat: enable UDP IPv6 multicast interface selection using localaddr Ignjatović, Lazar (RS)
@ 2024-03-26 18:25                                   ` Rémi Denis-Courmont
  2024-03-27  8:53                                     ` Ignjatović, Lazar (RS)
  0 siblings, 1 reply; 38+ messages in thread
From: Rémi Denis-Courmont @ 2024-03-26 18:25 UTC (permalink / raw)
  To: ffmpeg-devel

Both patches -1 for same reasons as before and that's unnecessary, 
functionally incorrect and potentially racy, enumeration of local interfaces.

-- 
レミ・デニ-クールモン
http://www.remlab.net/
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v3] avformat: enable UDP IPv6 multicast interface selection using localaddr
  2024-03-26 18:25                                   ` Rémi Denis-Courmont
@ 2024-03-27  8:53                                     ` Ignjatović, Lazar (RS)
  2024-03-27 15:31                                       ` Rémi Denis-Courmont
  0 siblings, 1 reply; 38+ messages in thread
From: Ignjatović, Lazar (RS) @ 2024-03-27  8:53 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


This message has been marked as Public on 03/27/2024 08:53Z.
On Tuesday, March 26, 2024 7:26 PM Rémi Denis-Courmont wrote:

> Both patches -1 for same reasons as before and that's unnecessary, functionally incorrect and potentially racy, enumeration of local interfaces.

Enumeration of interfaces is done only for IPv4 MCAST_JOIN_SOURCE_GROUP/MCAST_BLOCK_SOURCE within zone index patch.
Adding a separate parameter just for this seems pointless to me. Would removal of this, and reverting back to how it was
( = 0; // default interface in every case), address your concerns?

Lazar Ignjatović
Associate Software Engineer

Cubic Defense
cubic.com
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v3] avformat: enable UDP IPv6 multicast interface selection using localaddr
  2024-03-27  8:53                                     ` Ignjatović, Lazar (RS)
@ 2024-03-27 15:31                                       ` Rémi Denis-Courmont
  2024-03-27 15:38                                         ` [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection using zone index Ignjatović, Lazar (RS)
  2024-04-11  7:45                                         ` Ignjatović, Lazar (RS)
  0 siblings, 2 replies; 38+ messages in thread
From: Rémi Denis-Courmont @ 2024-03-27 15:31 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Le keskiviikkona 27. maaliskuuta 2024, 10.53.25 EET Ignjatović, Lazar (RS) a 
écrit :
> This message has been marked as Public on 03/27/2024 08:53Z.
> 
> On Tuesday, March 26, 2024 7:26 PM Rémi Denis-Courmont wrote:
> > Both patches -1 for same reasons as before and that's unnecessary,
> > functionally incorrect and potentially racy, enumeration of local
> > interfaces.
> Enumeration of interfaces is done only for IPv4
> MCAST_JOIN_SOURCE_GROUP/MCAST_BLOCK_SOURCE within zone index patch. Adding
> a separate parameter just for this seems pointless to me. Would removal of
> this, and reverting back to how it was ( = 0; // default interface in every
> case), address your concerns?

I have mixed feelings about changing how IPv4 works. Sure, it provides better 
consistency, and it is easier to remember an interface name than an IP address 
(especially if it is dynamically assigned). But it will also break backward 
compatibility. Not that I care about this specific hypothetical breakage, but 
somebody else very well might.

Either way, if you change how IPv4 works, you need to do it as a separate 
patch to adding IPv6 support. Avoiding reviewer confusion is just one of 
several reasons.

-- 
雷米‧德尼-库尔蒙
http://www.remlab.net/



_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection using zone index
  2024-03-27 15:31                                       ` Rémi Denis-Courmont
@ 2024-03-27 15:38                                         ` Ignjatović, Lazar (RS)
  2024-04-11  7:45                                         ` Ignjatović, Lazar (RS)
  1 sibling, 0 replies; 38+ messages in thread
From: Ignjatović, Lazar (RS) @ 2024-03-27 15:38 UTC (permalink / raw)
  To: ffmpeg-devel

avformat: enable UDP IPv6 multicast interface selection using zone index

Enabled IPv6 interface selection using zone index. Properly resolved
interface index in places where default 0 interface index is used
(marked with TODO: within udp.c). Adjusted binding for multicast sockets
that are used for reading from the network.

For mcast addresses, bind to mcast address is attempted as before.
In case that this fails, which will happen on Windows, socket is bound
to INADDR_ANY/IN6ADDR_ANY_INIT depending on address family. Actual
interface selection is performed using udp_set_multicast_interface to
point to the desired interface for sending.

Closes: #368

Signed-off-by: Lazar Ignjatovic <Lazar.Ignjatovic@cubic.com>
---
V1 -> V2 reverted iface resolution for IPv4 MCAST_JOIN_SOURCE_GROUP
NOTE: Due to comments, this patch is proposed as one of two alternatives
The other alternative uses `localaddr` for defining interfaces.


 configure             |  3 ++
 doc/protocols.texi    |  2 +-
 libavformat/network.h |  6 +++
 libavformat/udp.c     | 85 +++++++++++++++++++++++++++++++++++++++----
 4 files changed, 88 insertions(+), 8 deletions(-)

diff --git a/configure b/configure
index 2a1d22310b..35d6a0b78c 100755
--- a/configure
+++ b/configure
@@ -2307,6 +2307,7 @@ HEADERS_LIST="
     valgrind_valgrind_h
     windows_h
     winsock2_h
+    iphlpapi_h
 "

 INTRINSICS_LIST="
@@ -6475,6 +6476,8 @@ if ! disabled network; then
         check_struct winsock2.h "struct sockaddr" sa_len
         check_type ws2tcpip.h "struct sockaddr_in6"
         check_type ws2tcpip.h "struct sockaddr_storage"
+        check_headers iphlpapi.h -liphlpapi && network_extralibs="$network_extralibs -liphlpapi" || disable iphlpapi_h
+        check_func_headers iphlpapi.h GetBestInterfaceEx $network_extralibs
     else
         disable network
     fi
diff --git a/doc/protocols.texi b/doc/protocols.texi
index f54600b846..a8892845d3 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -2027,7 +2027,7 @@ packet bursts.
 Override the local UDP port to bind with.

 @item localaddr=@var{addr}
-Local IP address of a network interface used for sending packets or joining
+Local IPv4 address of a network interface used for sending packets or joining
 multicast groups.

 @item pkt_size=@var{size}
diff --git a/libavformat/network.h b/libavformat/network.h
index ca214087fc..2461b651d4 100644
--- a/libavformat/network.h
+++ b/libavformat/network.h
@@ -38,6 +38,10 @@
 #include <winsock2.h>
 #include <ws2tcpip.h>

+#if HAVE_IPHLPAPI_H
+#include <iphlpapi.h>
+#endif
+
 #ifndef EPROTONOSUPPORT
 #define EPROTONOSUPPORT WSAEPROTONOSUPPORT
 #endif
@@ -64,6 +68,8 @@ int ff_neterrno(void);
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <netdb.h>
+#include <net/if.h>
+#include <ifaddrs.h>

 #define ff_neterrno() AVERROR(errno)
 #endif /* HAVE_WINSOCK2_H */
diff --git a/libavformat/udp.c b/libavformat/udp.c
index d9514f5026..00c73f9ec9 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -35,6 +35,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/log.h"
 #include "libavutil/time.h"
+#include "libavutil/avstring.h"
 #include "internal.h"
 #include "network.h"
 #include "os_support.h"
@@ -220,8 +221,7 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
         struct ipv6_mreq mreq6;

         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
-        //TODO: Interface index should be looked up from local_addr
-        mreq6.ipv6mr_interface = 0;
+        mreq6.ipv6mr_interface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP)");
             return ff_neterrno();
@@ -231,6 +231,39 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
     return 0;
 }

+static int udp_set_multicast_interface(int sockfd, struct sockaddr *addr,
+                                    struct sockaddr *local_addr, void *logctx)
+{
+#ifdef IP_MULTICAST_IF
+    if (addr->sa_family == AF_INET) {
+        struct ip_mreq mreq;
+
+        mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
+        if (local_addr)
+            mreq.imr_interface = ((struct sockaddr_in *)local_addr)->sin_addr;
+        else
+            mreq.imr_interface.s_addr = INADDR_ANY;
+
+        if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, (const void *)&mreq, sizeof(mreq)) < 0) {
+            ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_IF)");
+            return ff_neterrno();
+        }
+    }
+#endif
+#if defined(IPV6_MULTICAST_IF) && defined(IPPROTO_IPV6)
+    if (addr->sa_family == AF_INET6) {
+        unsigned int iface;
+        iface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
+
+        if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &iface, sizeof(unsigned int)) < 0) {
+            ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_IF)");
+            return ff_neterrno();
+        }
+    }
+#endif
+    return 0;
+}
+
 static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
                                      struct sockaddr *local_addr, void *logctx)
 {
@@ -254,8 +287,7 @@ static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
         struct ipv6_mreq mreq6;

         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
-        //TODO: Interface index should be looked up from local_addr
-        mreq6.ipv6mr_interface = 0;
+        mreq6.ipv6mr_interface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP)");
             return -1;
@@ -284,6 +316,9 @@ static int udp_set_multicast_sources(URLContext *h,

             //TODO: Interface index should be looked up from local_addr
             mreqs.gsr_interface = 0;
+            if (level == IPPROTO_IPV6)
+                mreqs.gsr_interface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
+
             memcpy(&mreqs.gsr_group, addr, addr_len);
             memcpy(&mreqs.gsr_source, &sources[i], sizeof(*sources));

@@ -340,9 +375,24 @@ static int udp_set_url(URLContext *h,
 {
     struct addrinfo *res0;
     int addr_len;
+    const char *host, *sc;
+    char address[1024], scope[1024];

-    res0 = ff_ip_resolve_host(h, hostname, port, SOCK_DGRAM, AF_UNSPEC, 0);
+    if (sc = strchr(hostname, '%')) {
+        av_strlcpy(address, hostname, FFMIN(1024, sc - hostname + 1));
+        av_strlcpy(scope, sc + 1, FFMIN(1024, strlen(hostname) - (sc - hostname)));
+        host = address;
+    } else {
+        host = hostname;
+    }
+
+    res0 = ff_ip_resolve_host(h, host, port, SOCK_DGRAM, AF_UNSPEC, 0);
     if (!res0) return AVERROR(EIO);
+#if HAVE_IPHLPAPI_H || !HAVE_WINSOCK2_H
+    if (res0->ai_family== AF_INET6 && strlen(scope) > 0) {
+        ((struct sockaddr_in6*)res0->ai_addr)->sin6_scope_id = if_nametoindex(scope);
+    }
+#endif
     memcpy(addr, res0->ai_addr, res0->ai_addrlen);
     addr_len = res0->ai_addrlen;
     freeaddrinfo(res0);
@@ -841,8 +891,23 @@ static int udp_open(URLContext *h, const char *uri, int flags)
     if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) {
         bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len);
     }
-    /* bind to the local address if not multicast or if the multicast
-     * bind failed */
+
+    /* bind to ADDR_ANY if the multicast bind failed */
+    if (s->is_multicast && bind_ret < 0) {
+        struct addrinfo *res;
+
+        if (s->dest_addr.ss_family == AF_INET)
+            res = ff_ip_resolve_host(h, "0.0.0.0", 0, SOCK_DGRAM, AF_UNSPEC, 0);
+        else if (s->dest_addr.ss_family == AF_INET6)
+            res = ff_ip_resolve_host(h, "::", 0, SOCK_DGRAM, AF_UNSPEC, 0);
+
+        if (res && res->ai_addr) {
+            bind_ret = bind(udp_fd, res->ai_addr, res->ai_addrlen);
+        }
+
+        freeaddrinfo(res);
+    }
+
     /* the bind is needed to give a port to the socket now */
     if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) {
         ff_log_net_error(h, AV_LOG_ERROR, "bind failed");
@@ -855,6 +920,12 @@ static int udp_open(URLContext *h, const char *uri, int flags)
     s->local_port = udp_port(&my_addr, len);

     if (s->is_multicast) {
+        if ((ret = udp_set_multicast_interface(udp_fd,
+                                        (struct sockaddr *)&s->dest_addr,
+                                        (struct sockaddr *)&s->local_addr_storage,
+                                        h)) < 0)
+            goto fail;
+
         if (h->flags & AVIO_FLAG_WRITE) {
             /* output */
             if ((ret = udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr, h)) < 0)
--
2.41.0.windows.2


This message has been marked as Public on 03/27/2024 15:38Z.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection using zone index
  2024-03-27 15:31                                       ` Rémi Denis-Courmont
  2024-03-27 15:38                                         ` [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection using zone index Ignjatović, Lazar (RS)
@ 2024-04-11  7:45                                         ` Ignjatović, Lazar (RS)
  2024-04-11  7:50                                           ` Lynne
  1 sibling, 1 reply; 38+ messages in thread
From: Ignjatović, Lazar (RS) @ 2024-04-11  7:45 UTC (permalink / raw)
  To: ffmpeg-devel

avformat: enable UDP IPv6 multicast interface selection using zone index

Enabled IPv6 interface selection using zone index. Properly resolved
interface index in places where default 0 interface index is used
(marked with TODO: within udp.c). Adjusted binding for multicast sockets
that are used for reading from the network.

For mcast addresses, bind to mcast address is attempted as before.
In case that this fails, which will happen on Windows, socket is bound
to INADDR_ANY/IN6ADDR_ANY_INIT depending on address family. Actual
interface selection is performed using udp_set_multicast_interface to
point to the desired interface for sending.

Closes: #368

Signed-off-by: Lazar Ignjatovic <Lazar.Ignjatovic@cubic.com>
---
V1 -> V2 reverted iface resolution for IPv4 MCAST_JOIN_SOURCE_GROUP
NOTE: Due to comments, this patch is proposed as one of two alternatives
The other alternative uses `localaddr` for defining interfaces.


 configure             |  3 ++
 doc/protocols.texi    |  2 +-
 libavformat/network.h |  6 +++
 libavformat/udp.c     | 85 +++++++++++++++++++++++++++++++++++++++----
 4 files changed, 88 insertions(+), 8 deletions(-)

diff --git a/configure b/configure
index 2a1d22310b..35d6a0b78c 100755
--- a/configure
+++ b/configure
@@ -2307,6 +2307,7 @@ HEADERS_LIST="
     valgrind_valgrind_h
     windows_h
     winsock2_h
+    iphlpapi_h
 "

 INTRINSICS_LIST="
@@ -6475,6 +6476,8 @@ if ! disabled network; then
         check_struct winsock2.h "struct sockaddr" sa_len
         check_type ws2tcpip.h "struct sockaddr_in6"
         check_type ws2tcpip.h "struct sockaddr_storage"
+        check_headers iphlpapi.h -liphlpapi && network_extralibs="$network_extralibs -liphlpapi" || disable iphlpapi_h
+        check_func_headers iphlpapi.h GetBestInterfaceEx $network_extralibs
     else
         disable network
     fi
diff --git a/doc/protocols.texi b/doc/protocols.texi
index f54600b846..a8892845d3 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -2027,7 +2027,7 @@ packet bursts.
 Override the local UDP port to bind with.

 @item localaddr=@var{addr}
-Local IP address of a network interface used for sending packets or joining
+Local IPv4 address of a network interface used for sending packets or joining
 multicast groups.

 @item pkt_size=@var{size}
diff --git a/libavformat/network.h b/libavformat/network.h
index ca214087fc..2461b651d4 100644
--- a/libavformat/network.h
+++ b/libavformat/network.h
@@ -38,6 +38,10 @@
 #include <winsock2.h>
 #include <ws2tcpip.h>

+#if HAVE_IPHLPAPI_H
+#include <iphlpapi.h>
+#endif
+
 #ifndef EPROTONOSUPPORT
 #define EPROTONOSUPPORT WSAEPROTONOSUPPORT
 #endif
@@ -64,6 +68,8 @@ int ff_neterrno(void);
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <netdb.h>
+#include <net/if.h>
+#include <ifaddrs.h>

 #define ff_neterrno() AVERROR(errno)
 #endif /* HAVE_WINSOCK2_H */
diff --git a/libavformat/udp.c b/libavformat/udp.c
index d9514f5026..00c73f9ec9 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -35,6 +35,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/log.h"
 #include "libavutil/time.h"
+#include "libavutil/avstring.h"
 #include "internal.h"
 #include "network.h"
 #include "os_support.h"
@@ -220,8 +221,7 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
         struct ipv6_mreq mreq6;

         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
-        //TODO: Interface index should be looked up from local_addr
-        mreq6.ipv6mr_interface = 0;
+        mreq6.ipv6mr_interface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP)");
             return ff_neterrno();
@@ -231,6 +231,39 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
     return 0;
 }

+static int udp_set_multicast_interface(int sockfd, struct sockaddr *addr,
+                                    struct sockaddr *local_addr, void *logctx)
+{
+#ifdef IP_MULTICAST_IF
+    if (addr->sa_family == AF_INET) {
+        struct ip_mreq mreq;
+
+        mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
+        if (local_addr)
+            mreq.imr_interface = ((struct sockaddr_in *)local_addr)->sin_addr;
+        else
+            mreq.imr_interface.s_addr = INADDR_ANY;
+
+        if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, (const void *)&mreq, sizeof(mreq)) < 0) {
+            ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_IF)");
+            return ff_neterrno();
+        }
+    }
+#endif
+#if defined(IPV6_MULTICAST_IF) && defined(IPPROTO_IPV6)
+    if (addr->sa_family == AF_INET6) {
+        unsigned int iface;
+        iface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
+
+        if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &iface, sizeof(unsigned int)) < 0) {
+            ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_IF)");
+            return ff_neterrno();
+        }
+    }
+#endif
+    return 0;
+}
+
 static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
                                      struct sockaddr *local_addr, void *logctx)
 {
@@ -254,8 +287,7 @@ static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
         struct ipv6_mreq mreq6;

         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
-        //TODO: Interface index should be looked up from local_addr
-        mreq6.ipv6mr_interface = 0;
+        mreq6.ipv6mr_interface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP)");
             return -1;
@@ -284,6 +316,9 @@ static int udp_set_multicast_sources(URLContext *h,

             //TODO: Interface index should be looked up from local_addr
             mreqs.gsr_interface = 0;
+            if (level == IPPROTO_IPV6)
+                mreqs.gsr_interface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
+
             memcpy(&mreqs.gsr_group, addr, addr_len);
             memcpy(&mreqs.gsr_source, &sources[i], sizeof(*sources));

@@ -340,9 +375,24 @@ static int udp_set_url(URLContext *h,
 {
     struct addrinfo *res0;
     int addr_len;
+    const char *host, *sc;
+    char address[1024], scope[1024];

-    res0 = ff_ip_resolve_host(h, hostname, port, SOCK_DGRAM, AF_UNSPEC, 0);
+    if (sc = strchr(hostname, '%')) {
+        av_strlcpy(address, hostname, FFMIN(1024, sc - hostname + 1));
+        av_strlcpy(scope, sc + 1, FFMIN(1024, strlen(hostname) - (sc - hostname)));
+        host = address;
+    } else {
+        host = hostname;
+    }
+
+    res0 = ff_ip_resolve_host(h, host, port, SOCK_DGRAM, AF_UNSPEC, 0);
     if (!res0) return AVERROR(EIO);
+#if HAVE_IPHLPAPI_H || !HAVE_WINSOCK2_H
+    if (res0->ai_family== AF_INET6 && strlen(scope) > 0) {
+        ((struct sockaddr_in6*)res0->ai_addr)->sin6_scope_id = if_nametoindex(scope);
+    }
+#endif
     memcpy(addr, res0->ai_addr, res0->ai_addrlen);
     addr_len = res0->ai_addrlen;
     freeaddrinfo(res0);
@@ -841,8 +891,23 @@ static int udp_open(URLContext *h, const char *uri, int flags)
     if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) {
         bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len);
     }
-    /* bind to the local address if not multicast or if the multicast
-     * bind failed */
+
+    /* bind to ADDR_ANY if the multicast bind failed */
+    if (s->is_multicast && bind_ret < 0) {
+        struct addrinfo *res;
+
+        if (s->dest_addr.ss_family == AF_INET)
+            res = ff_ip_resolve_host(h, "0.0.0.0", 0, SOCK_DGRAM, AF_UNSPEC, 0);
+        else if (s->dest_addr.ss_family == AF_INET6)
+            res = ff_ip_resolve_host(h, "::", 0, SOCK_DGRAM, AF_UNSPEC, 0);
+
+        if (res && res->ai_addr) {
+            bind_ret = bind(udp_fd, res->ai_addr, res->ai_addrlen);
+        }
+
+        freeaddrinfo(res);
+    }
+
     /* the bind is needed to give a port to the socket now */
     if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) {
         ff_log_net_error(h, AV_LOG_ERROR, "bind failed");
@@ -855,6 +920,12 @@ static int udp_open(URLContext *h, const char *uri, int flags)
     s->local_port = udp_port(&my_addr, len);

     if (s->is_multicast) {
+        if ((ret = udp_set_multicast_interface(udp_fd,
+                                        (struct sockaddr *)&s->dest_addr,
+                                        (struct sockaddr *)&s->local_addr_storage,
+                                        h)) < 0)
+            goto fail;
+
         if (h->flags & AVIO_FLAG_WRITE) {
             /* output */
             if ((ret = udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr, h)) < 0)
--
2.41.0.windows.2


This message has been marked as Public on 04/11/2024 07:45Z.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection using zone index
  2024-04-11  7:45                                         ` Ignjatović, Lazar (RS)
@ 2024-04-11  7:50                                           ` Lynne
  2024-04-11  7:58                                             ` Ignjatović, Lazar (RS)
  2024-04-28 18:15                                             ` [FFmpeg-devel] [PATCH v2] " Rémi Denis-Courmont
  0 siblings, 2 replies; 38+ messages in thread
From: Lynne @ 2024-04-11  7:50 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Apr 11, 2024, 09:45 by Lazar.Ignjatovic@cubic.com:

> avformat: enable UDP IPv6 multicast interface selection using zone index
>
> Enabled IPv6 interface selection using zone index. Properly resolved
> interface index in places where default 0 interface index is used
> (marked with TODO: within udp.c). Adjusted binding for multicast sockets
> that are used for reading from the network.
>
> For mcast addresses, bind to mcast address is attempted as before.
> In case that this fails, which will happen on Windows, socket is bound
> to INADDR_ANY/IN6ADDR_ANY_INIT depending on address family. Actual
> interface selection is performed using udp_set_multicast_interface to
> point to the desired interface for sending.
>
> Closes: #368
>
> Signed-off-by: Lazar Ignjatovic <Lazar.Ignjatovic@cubic.com>
> ---
> V1 -> V2 reverted iface resolution for IPv4 MCAST_JOIN_SOURCE_GROUP
> NOTE: Due to comments, this patch is proposed as one of two alternatives
> The other alternative uses `localaddr` for defining interfaces.
>
>
>  configure             |  3 ++
>  doc/protocols.texi    |  2 +-
>  libavformat/network.h |  6 +++
>  libavformat/udp.c     | 85 +++++++++++++++++++++++++++++++++++++++----
>  4 files changed, 88 insertions(+), 8 deletions(-)
>
> diff --git a/configure b/configure
> index 2a1d22310b..35d6a0b78c 100755
> --- a/configure
> +++ b/configure
> @@ -2307,6 +2307,7 @@ HEADERS_LIST="
>  valgrind_valgrind_h
>  windows_h
>  winsock2_h
> +    iphlpapi_h
>  "
>
>  INTRINSICS_LIST="
> @@ -6475,6 +6476,8 @@ if ! disabled network; then
>  check_struct winsock2.h "struct sockaddr" sa_len
>  check_type ws2tcpip.h "struct sockaddr_in6"
>  check_type ws2tcpip.h "struct sockaddr_storage"
> +        check_headers iphlpapi.h -liphlpapi && network_extralibs="$network_extralibs -liphlpapi" || disable iphlpapi_h
> +        check_func_headers iphlpapi.h GetBestInterfaceEx $network_extralibs
>  else
>  disable network
>  fi
> diff --git a/doc/protocols.texi b/doc/protocols.texi
> index f54600b846..a8892845d3 100644
> --- a/doc/protocols.texi
> +++ b/doc/protocols.texi
> @@ -2027,7 +2027,7 @@ packet bursts.
>  Override the local UDP port to bind with.
>
>  @item localaddr=@var{addr}
> -Local IP address of a network interface used for sending packets or joining
> +Local IPv4 address of a network interface used for sending packets or joining
>  multicast groups.
>
>  @item pkt_size=@var{size}
> diff --git a/libavformat/network.h b/libavformat/network.h
> index ca214087fc..2461b651d4 100644
> --- a/libavformat/network.h
> +++ b/libavformat/network.h
> @@ -38,6 +38,10 @@
>  #include <winsock2.h>
>  #include <ws2tcpip.h>
>
> +#if HAVE_IPHLPAPI_H
> +#include <iphlpapi.h>
> +#endif
> +
>  #ifndef EPROTONOSUPPORT
>  #define EPROTONOSUPPORT WSAEPROTONOSUPPORT
>  #endif
> @@ -64,6 +68,8 @@ int ff_neterrno(void);
>  #include <netinet/in.h>
>  #include <netinet/tcp.h>
>  #include <netdb.h>
> +#include <net/if.h>
> +#include <ifaddrs.h>
>
>  #define ff_neterrno() AVERROR(errno)
>  #endif /* HAVE_WINSOCK2_H */
> diff --git a/libavformat/udp.c b/libavformat/udp.c
> index d9514f5026..00c73f9ec9 100644
> --- a/libavformat/udp.c
> +++ b/libavformat/udp.c
> @@ -35,6 +35,7 @@
>  #include "libavutil/opt.h"
>  #include "libavutil/log.h"
>  #include "libavutil/time.h"
> +#include "libavutil/avstring.h"
>  #include "internal.h"
>  #include "network.h"
>  #include "os_support.h"
> @@ -220,8 +221,7 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
>  struct ipv6_mreq mreq6;
>
>  memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
> -        //TODO: Interface index should be looked up from local_addr
> -        mreq6.ipv6mr_interface = 0;
> +        mreq6.ipv6mr_interface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
>  if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
>  ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP)");
>  return ff_neterrno();
> @@ -231,6 +231,39 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
>  return 0;
>  }
>
> +static int udp_set_multicast_interface(int sockfd, struct sockaddr *addr,
> +                                    struct sockaddr *local_addr, void *logctx)
> +{
> +#ifdef IP_MULTICAST_IF
> +    if (addr->sa_family == AF_INET) {
> +        struct ip_mreq mreq;
> +
> +        mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
> +        if (local_addr)
> +            mreq.imr_interface = ((struct sockaddr_in *)local_addr)->sin_addr;
> +        else
> +            mreq.imr_interface.s_addr = INADDR_ANY;
> +
> +        if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, (const void *)&mreq, sizeof(mreq)) < 0) {
> +            ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_IF)");
> +            return ff_neterrno();
> +        }
> +    }
> +#endif
> +#if defined(IPV6_MULTICAST_IF) && defined(IPPROTO_IPV6)
> +    if (addr->sa_family == AF_INET6) {
> +        unsigned int iface;
> +        iface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
> +
> +        if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &iface, sizeof(unsigned int)) < 0) {
> +            ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_IF)");
> +            return ff_neterrno();
> +        }
> +    }
> +#endif
> +    return 0;
> +}
> +
>  static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
>  struct sockaddr *local_addr, void *logctx)
>  {
> @@ -254,8 +287,7 @@ static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
>  struct ipv6_mreq mreq6;
>
>  memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
> -        //TODO: Interface index should be looked up from local_addr
> -        mreq6.ipv6mr_interface = 0;
> +        mreq6.ipv6mr_interface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
>  if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
>  ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP)");
>  return -1;
> @@ -284,6 +316,9 @@ static int udp_set_multicast_sources(URLContext *h,
>
>  //TODO: Interface index should be looked up from local_addr
>  mreqs.gsr_interface = 0;
> +            if (level == IPPROTO_IPV6)
> +                mreqs.gsr_interface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
> +
>  memcpy(&mreqs.gsr_group, addr, addr_len);
>  memcpy(&mreqs.gsr_source, &sources[i], sizeof(*sources));
>
> @@ -340,9 +375,24 @@ static int udp_set_url(URLContext *h,
>  {
>  struct addrinfo *res0;
>  int addr_len;
> +    const char *host, *sc;
> +    char address[1024], scope[1024];
>
> -    res0 = ff_ip_resolve_host(h, hostname, port, SOCK_DGRAM, AF_UNSPEC, 0);
> +    if (sc = strchr(hostname, '%')) {
> +        av_strlcpy(address, hostname, FFMIN(1024, sc - hostname + 1));
> +        av_strlcpy(scope, sc + 1, FFMIN(1024, strlen(hostname) - (sc - hostname)));
> +        host = address;
> +    } else {
> +        host = hostname;
> +    }
> +
> +    res0 = ff_ip_resolve_host(h, host, port, SOCK_DGRAM, AF_UNSPEC, 0);
>  if (!res0) return AVERROR(EIO);
> +#if HAVE_IPHLPAPI_H || !HAVE_WINSOCK2_H
> +    if (res0->ai_family== AF_INET6 && strlen(scope) > 0) {
> +        ((struct sockaddr_in6*)res0->ai_addr)->sin6_scope_id = if_nametoindex(scope);
> +    }
> +#endif
>  memcpy(addr, res0->ai_addr, res0->ai_addrlen);
>  addr_len = res0->ai_addrlen;
>  freeaddrinfo(res0);
> @@ -841,8 +891,23 @@ static int udp_open(URLContext *h, const char *uri, int flags)
>  if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) {
>  bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len);
>  }
> -    /* bind to the local address if not multicast or if the multicast
> -     * bind failed */
> +
> +    /* bind to ADDR_ANY if the multicast bind failed */
> +    if (s->is_multicast && bind_ret < 0) {
> +        struct addrinfo *res;
> +
> +        if (s->dest_addr.ss_family == AF_INET)
> +            res = ff_ip_resolve_host(h, "0.0.0.0", 0, SOCK_DGRAM, AF_UNSPEC, 0);
> +        else if (s->dest_addr.ss_family == AF_INET6)
> +            res = ff_ip_resolve_host(h, "::", 0, SOCK_DGRAM, AF_UNSPEC, 0);
> +
> +        if (res && res->ai_addr) {
> +            bind_ret = bind(udp_fd, res->ai_addr, res->ai_addrlen);
> +        }
> +
> +        freeaddrinfo(res);
> +    }
> +
>  /* the bind is needed to give a port to the socket now */
>  if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) {
>  ff_log_net_error(h, AV_LOG_ERROR, "bind failed");
> @@ -855,6 +920,12 @@ static int udp_open(URLContext *h, const char *uri, int flags)
>  s->local_port = udp_port(&my_addr, len);
>
>  if (s->is_multicast) {
> +        if ((ret = udp_set_multicast_interface(udp_fd,
> +                                        (struct sockaddr *)&s->dest_addr,
> +                                        (struct sockaddr *)&s->local_addr_storage,
> +                                        h)) < 0)
> +            goto fail;
> +
>  if (h->flags & AVIO_FLAG_WRITE) {
>  /* output */
>  if ((ret = udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr, h)) < 0)
> --
> 2.41.0.windows.2
>

Is there a reason why we can't switch to IPv4 addresses mapped
in IPv6 and just use the IPv6 API everywhere?
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection using zone index
  2024-04-11  7:50                                           ` Lynne
@ 2024-04-11  7:58                                             ` Ignjatović, Lazar (RS)
  2024-04-11 13:01                                               ` [FFmpeg-devel] [PATCH v3] " Ignjatović, Lazar (RS)
  2024-04-28 18:15                                             ` [FFmpeg-devel] [PATCH v2] " Rémi Denis-Courmont
  1 sibling, 1 reply; 38+ messages in thread
From: Ignjatović, Lazar (RS) @ 2024-04-11  7:58 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


This message has been marked as Public on 04/11/2024 07:58Z.
On Thursday, April 11, 2024 9:50 AM Lynne wrote:

> Is there a reason why we can't switch to IPv4 addresses mapped in IPv6 and just use the IPv6 API everywhere?

I'm not the person to give you that answer.
My guess is that due to API discrepancies between v4 and v6 it would
require a _lot_ of work to make that jump. Also, different levels of IPv6
support across kernels doesn't make it any easier.

Lazar Ignjatović
Associate Software Engineer

Cubic Defense
cubic.com
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [FFmpeg-devel] [PATCH v3] avformat: enable UDP IPv6 multicast interface selection using zone index
  2024-04-11  7:58                                             ` Ignjatović, Lazar (RS)
@ 2024-04-11 13:01                                               ` Ignjatović, Lazar (RS)
  2024-04-19 10:23                                                 ` Ignjatović, Lazar (RS)
  0 siblings, 1 reply; 38+ messages in thread
From: Ignjatović, Lazar (RS) @ 2024-04-11 13:01 UTC (permalink / raw)
  To: ffmpeg-devel

avformat: enable UDP IPv6 multicast interface selection using zone index

Enabled IPv6 interface selection using zone index. Properly resolved
interface index in places where default 0 interface index is used
(marked with TODO: within udp.c). Adjusted binding for multicast sockets
that are used for reading from the network.

For mcast addresses, bind to mcast address is attempted as before.
In case that this fails, which will happen on Windows, socket is bound
to INADDR_ANY/IN6ADDR_ANY_INIT depending on address family. Actual
interface selection is performed using udp_set_multicast_interface to
point to the desired interface for sending.

Closes: #368

Signed-off-by: Lazar Ignjatovic <Lazar.Ignjatovic@cubic.com>
---
NOTE: Due to comments, this patch is proposed as one of two alternatives
The other alternative uses `localaddr` for defining interfaces.
V1 -> V2 reverted iface resolution for IPv4 MCAST_JOIN_SOURCE_GROUP
V2 -> V3 resolved conflicts


 configure             |  3 ++
 doc/protocols.texi    |  2 +-
 libavformat/network.h |  6 +++
 libavformat/udp.c     | 85 +++++++++++++++++++++++++++++++++++++++----
 4 files changed, 88 insertions(+), 8 deletions(-)

diff --git a/configure b/configure
index 55f1fc354d..96183e58b3 100755
--- a/configure
+++ b/configure
@@ -2311,6 +2311,7 @@ HEADERS_LIST="
     valgrind_valgrind_h
     windows_h
     winsock2_h
+    iphlpapi_h
 "

 INTRINSICS_LIST="
@@ -6483,6 +6484,8 @@ if ! disabled network; then
         check_struct winsock2.h "struct sockaddr" sa_len
         check_type ws2tcpip.h "struct sockaddr_in6"
         check_type ws2tcpip.h "struct sockaddr_storage"
+        check_headers iphlpapi.h -liphlpapi && network_extralibs="$network_extralibs -liphlpapi" || disable iphlpapi_h
+        check_func_headers iphlpapi.h GetBestInterfaceEx $network_extralibs
     else
         disable network
     fi
diff --git a/doc/protocols.texi b/doc/protocols.texi
index f54600b846..a8892845d3 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -2027,7 +2027,7 @@ packet bursts.
 Override the local UDP port to bind with.

 @item localaddr=@var{addr}
-Local IP address of a network interface used for sending packets or joining
+Local IPv4 address of a network interface used for sending packets or joining
 multicast groups.

 @item pkt_size=@var{size}
diff --git a/libavformat/network.h b/libavformat/network.h
index ca214087fc..2461b651d4 100644
--- a/libavformat/network.h
+++ b/libavformat/network.h
@@ -38,6 +38,10 @@
 #include <winsock2.h>
 #include <ws2tcpip.h>

+#if HAVE_IPHLPAPI_H
+#include <iphlpapi.h>
+#endif
+
 #ifndef EPROTONOSUPPORT
 #define EPROTONOSUPPORT WSAEPROTONOSUPPORT
 #endif
@@ -64,6 +68,8 @@ int ff_neterrno(void);
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <netdb.h>
+#include <net/if.h>
+#include <ifaddrs.h>

 #define ff_neterrno() AVERROR(errno)
 #endif /* HAVE_WINSOCK2_H */
diff --git a/libavformat/udp.c b/libavformat/udp.c
index c1ebdd1222..fa2f62b0b7 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -36,6 +36,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/log.h"
 #include "libavutil/time.h"
+#include "libavutil/avstring.h"
 #include "network.h"
 #include "os_support.h"
 #include "url.h"
@@ -220,8 +221,7 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
         struct ipv6_mreq mreq6;

         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
-        //TODO: Interface index should be looked up from local_addr
-        mreq6.ipv6mr_interface = 0;
+        mreq6.ipv6mr_interface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP)");
             return ff_neterrno();
@@ -231,6 +231,39 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
     return 0;
 }

+static int udp_set_multicast_interface(int sockfd, struct sockaddr *addr,
+                                    struct sockaddr *local_addr, void *logctx)
+{
+#ifdef IP_MULTICAST_IF
+    if (addr->sa_family == AF_INET) {
+        struct ip_mreq mreq;
+
+        mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
+        if (local_addr)
+            mreq.imr_interface = ((struct sockaddr_in *)local_addr)->sin_addr;
+        else
+            mreq.imr_interface.s_addr = INADDR_ANY;
+
+        if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, (const void *)&mreq, sizeof(mreq)) < 0) {
+            ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_IF)");
+            return ff_neterrno();
+        }
+    }
+#endif
+#if defined(IPV6_MULTICAST_IF) && defined(IPPROTO_IPV6)
+    if (addr->sa_family == AF_INET6) {
+        unsigned int iface;
+        iface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
+
+        if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &iface, sizeof(unsigned int)) < 0) {
+            ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_IF)");
+            return ff_neterrno();
+        }
+    }
+#endif
+    return 0;
+}
+
 static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
                                      struct sockaddr *local_addr, void *logctx)
 {
@@ -254,8 +287,7 @@ static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
         struct ipv6_mreq mreq6;

         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
-        //TODO: Interface index should be looked up from local_addr
-        mreq6.ipv6mr_interface = 0;
+        mreq6.ipv6mr_interface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP)");
             return -1;
@@ -284,6 +316,9 @@ static int udp_set_multicast_sources(URLContext *h,

             //TODO: Interface index should be looked up from local_addr
             mreqs.gsr_interface = 0;
+            if (level == IPPROTO_IPV6)
+                mreqs.gsr_interface = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
+
             memcpy(&mreqs.gsr_group, addr, addr_len);
             memcpy(&mreqs.gsr_source, &sources[i], sizeof(*sources));

@@ -340,9 +375,24 @@ static int udp_set_url(URLContext *h,
 {
     struct addrinfo *res0;
     int addr_len;
+    const char *host, *sc;
+    char address[1024], scope[1024];

-    res0 = ff_ip_resolve_host(h, hostname, port, SOCK_DGRAM, AF_UNSPEC, 0);
+    if (sc = strchr(hostname, '%')) {
+        av_strlcpy(address, hostname, FFMIN(1024, sc - hostname + 1));
+        av_strlcpy(scope, sc + 1, FFMIN(1024, strlen(hostname) - (sc - hostname)));
+        host = address;
+    } else {
+        host = hostname;
+    }
+
+    res0 = ff_ip_resolve_host(h, host, port, SOCK_DGRAM, AF_UNSPEC, 0);
     if (!res0) return AVERROR(EIO);
+#if HAVE_IPHLPAPI_H || !HAVE_WINSOCK2_H
+    if (res0->ai_family== AF_INET6 && strlen(scope) > 0) {
+        ((struct sockaddr_in6*)res0->ai_addr)->sin6_scope_id = if_nametoindex(scope);
+    }
+#endif
     memcpy(addr, res0->ai_addr, res0->ai_addrlen);
     addr_len = res0->ai_addrlen;
     freeaddrinfo(res0);
@@ -841,8 +891,23 @@ static int udp_open(URLContext *h, const char *uri, int flags)
     if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) {
         bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len);
     }
-    /* bind to the local address if not multicast or if the multicast
-     * bind failed */
+
+    /* bind to ADDR_ANY if the multicast bind failed */
+    if (s->is_multicast && bind_ret < 0) {
+        struct addrinfo *res;
+
+        if (s->dest_addr.ss_family == AF_INET)
+            res = ff_ip_resolve_host(h, "0.0.0.0", 0, SOCK_DGRAM, AF_UNSPEC, 0);
+        else if (s->dest_addr.ss_family == AF_INET6)
+            res = ff_ip_resolve_host(h, "::", 0, SOCK_DGRAM, AF_UNSPEC, 0);
+
+        if (res && res->ai_addr) {
+            bind_ret = bind(udp_fd, res->ai_addr, res->ai_addrlen);
+        }
+
+        freeaddrinfo(res);
+    }
+
     /* the bind is needed to give a port to the socket now */
     if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) {
         ff_log_net_error(h, AV_LOG_ERROR, "bind failed");
@@ -855,6 +920,12 @@ static int udp_open(URLContext *h, const char *uri, int flags)
     s->local_port = udp_port(&my_addr, len);

     if (s->is_multicast) {
+        if ((ret = udp_set_multicast_interface(udp_fd,
+                                        (struct sockaddr *)&s->dest_addr,
+                                        (struct sockaddr *)&s->local_addr_storage,
+                                        h)) < 0)
+            goto fail;
+
         if (h->flags & AVIO_FLAG_WRITE) {
             /* output */
             if ((ret = udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr, h)) < 0)
--
2.41.0.windows.2


This message has been marked as Public on 04/11/2024 13:01Z.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v3] avformat: enable UDP IPv6 multicast interface selection using zone index
  2024-04-11 13:01                                               ` [FFmpeg-devel] [PATCH v3] " Ignjatović, Lazar (RS)
@ 2024-04-19 10:23                                                 ` Ignjatović, Lazar (RS)
  0 siblings, 0 replies; 38+ messages in thread
From: Ignjatović, Lazar (RS) @ 2024-04-19 10:23 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


This message has been marked as Public on 04/19/2024 10:23Z.
On Thursday, April 11, 2024 3:01 PM Ignjatović, Lazar (RS) wrote:

> avformat: enable UDP IPv6 multicast interface selection using zone index
>
> Enabled IPv6 interface selection using zone index. Properly resolved
> interface index in places where default 0 interface index is used
> (marked with TODO: within udp.c). Adjusted binding for multicast
> sockets that are used for reading from the network.
>
> For mcast addresses, bind to mcast address is attempted as before.
> In case that this fails, which will happen on Windows, socket is bound
> to INADDR_ANY/IN6ADDR_ANY_INIT depending on address family. Actual
> interface selection is performed using udp_set_multicast_interface to
> point to the desired interface for sending.

Anyone got a chance to take a look at the final version of this patch?
Any comments?

Lazar Ignjatović
Associate Software Engineer

Cubic Defense // Digital Intelligence
cubic.com
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection using zone index
  2024-04-11  7:50                                           ` Lynne
  2024-04-11  7:58                                             ` Ignjatović, Lazar (RS)
@ 2024-04-28 18:15                                             ` Rémi Denis-Courmont
  2024-04-28 20:11                                               ` Lynne
  2024-04-29  0:01                                               ` Brad Smith
  1 sibling, 2 replies; 38+ messages in thread
From: Rémi Denis-Courmont @ 2024-04-28 18:15 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Le torstaina 11. huhtikuuta 2024, 10.50.01 EEST Lynne a écrit :
> Is there a reason why we can't switch to IPv4 addresses mapped
> in IPv6 and just use the IPv6 API everywhere?

IPv6-mapped IPv4 addresses are pretty much deprecated, if supported anymore. 
Some people consider them insecure. But even if you don't agree with that 
assessment, the fact of the matter is that they are not portable.


-- 
Rémi Denis-Courmont
http://www.remlab.net/



_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection using zone index
  2024-04-28 18:15                                             ` [FFmpeg-devel] [PATCH v2] " Rémi Denis-Courmont
@ 2024-04-28 20:11                                               ` Lynne
  2024-04-29  7:33                                                 ` Rémi Denis-Courmont
  2024-04-29  0:01                                               ` Brad Smith
  1 sibling, 1 reply; 38+ messages in thread
From: Lynne @ 2024-04-28 20:11 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Apr 28, 2024, 20:15 by remi@remlab.net:

> Le torstaina 11. huhtikuuta 2024, 10.50.01 EEST Lynne a écrit :
>
>> Is there a reason why we can't switch to IPv4 addresses mapped
>> in IPv6 and just use the IPv6 API everywhere?
>>
>
> IPv6-mapped IPv4 addresses are pretty much deprecated, if supported anymore. 
> Some people consider them insecure. But even if you don't agree with that 
> assessment, the fact of the matter is that they are not portable.
>

They were they deprecated? Why would they not be portable?
They seem to work fine in libavtransport.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection using zone index
  2024-04-28 18:15                                             ` [FFmpeg-devel] [PATCH v2] " Rémi Denis-Courmont
  2024-04-28 20:11                                               ` Lynne
@ 2024-04-29  0:01                                               ` Brad Smith
  1 sibling, 0 replies; 38+ messages in thread
From: Brad Smith @ 2024-04-29  0:01 UTC (permalink / raw)
  To: FFmpeg development discussions and patches, Rémi Denis-Courmont

On 2024-04-28 2:15 p.m., Rémi Denis-Courmont wrote:
> Le torstaina 11. huhtikuuta 2024, 10.50.01 EEST Lynne a écrit :
>> Is there a reason why we can't switch to IPv4 addresses mapped
>> in IPv6 and just use the IPv6 API everywhere?
> IPv6-mapped IPv4 addresses are pretty much deprecated, if supported anymore.
> Some people consider them insecure. But even if you don't agree with that
> assessment, the fact of the matter is that they are not portable.

OpenBSD does not support IPv4-mapped IPv6 addresses and has a split stack.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection using zone index
  2024-04-28 20:11                                               ` Lynne
@ 2024-04-29  7:33                                                 ` Rémi Denis-Courmont
  2024-04-29  8:20                                                   ` Lynne
  0 siblings, 1 reply; 38+ messages in thread
From: Rémi Denis-Courmont @ 2024-04-29  7:33 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



Le 28 avril 2024 23:11:48 GMT+03:00, Lynne <dev@lynne.ee> a écrit :
>Apr 28, 2024, 20:15 by remi@remlab.net:
>
>> Le torstaina 11. huhtikuuta 2024, 10.50.01 EEST Lynne a écrit :
>>
>>> Is there a reason why we can't switch to IPv4 addresses mapped
>>> in IPv6 and just use the IPv6 API everywhere?
>>>
>>
>> IPv6-mapped IPv4 addresses are pretty much deprecated, if supported anymore. 
>> Some people consider them insecure. But even if you don't agree with that 
>> assessment, the fact of the matter is that they are not portable.
>>
>
>They were they deprecated?

They caused more bugs than they solved problems (because what we need is to add IPv6 to IPv4 apps, not IPv4 to IPv6 apps).

> Why would they not be portable?

Some OS just don't support them, or have a privileged setting to disable them globally. As a user process, you can't rely on them.

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection using zone index
  2024-04-29  7:33                                                 ` Rémi Denis-Courmont
@ 2024-04-29  8:20                                                   ` Lynne
  2024-04-29  9:56                                                     ` Rémi Denis-Courmont
  0 siblings, 1 reply; 38+ messages in thread
From: Lynne @ 2024-04-29  8:20 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Apr 29, 2024, 09:34 by remi@remlab.net:

>
>
> Le 28 avril 2024 23:11:48 GMT+03:00, Lynne <dev@lynne.ee> a écrit :
> >Apr 28, 2024, 20:15 by remi@remlab.net:
>
>>> Le torstaina 11. huhtikuuta 2024, 10.50.01 EEST Lynne a écrit :
>>>
>>>> Is there a reason why we can't switch to IPv4 addresses mapped
>>>> in IPv6 and just use the IPv6 API everywhere?
>>>>
>>>
>>> IPv6-mapped IPv4 addresses are pretty much deprecated, if supported anymore. 
>>> Some people consider them insecure. But even if you don't agree with that 
>>> assessment, the fact of the matter is that they are not portable.
>>>
> >They were they deprecated?
>
> They caused more bugs than they solved problems (because what we need is to add IPv6 to IPv4 apps, not IPv4 to IPv6 apps).
>

What bugs did they cause? I know they're not very well used, because the
documentation is very lacking, but given that it's a feature of the standard
network stack of both Linux and Windows, surely it's fuzzed and unit tested
more than enough.


>> Why would they not be portable?
>>
>
> Some OS just don't support them, or have a privileged setting to disable them globally. As a user process, you can't rely on them.
>

Which ones have a setting?
Some have a setting to disable IPv6 globally which must be fairly more used,
but I haven't heard ones which have that setting in.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection using zone index
  2024-04-29  8:20                                                   ` Lynne
@ 2024-04-29  9:56                                                     ` Rémi Denis-Courmont
  2024-04-29 10:32                                                       ` Lynne
  0 siblings, 1 reply; 38+ messages in thread
From: Rémi Denis-Courmont @ 2024-04-29  9:56 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



Le 29 avril 2024 11:20:24 GMT+03:00, Lynne <dev@lynne.ee> a écrit :
>> >They were they deprecated?
>>
>> They caused more bugs than they solved problems (because what we need is to add IPv6 to IPv4 apps, not IPv4 to IPv6 apps).
>>
>
>What bugs did they cause?

Obviously anything that assumes IPv6 semantics is prone to breaking.

> i know they're not very well used, because the
>documentation is very lacking,

No, they're not used because they are officially deprecated for 15+ years (see RFC5156).
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection using zone index
  2024-04-29  9:56                                                     ` Rémi Denis-Courmont
@ 2024-04-29 10:32                                                       ` Lynne
  2024-04-29 11:34                                                         ` Rémi Denis-Courmont
  0 siblings, 1 reply; 38+ messages in thread
From: Lynne @ 2024-04-29 10:32 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Apr 29, 2024, 11:56 by remi@remlab.net:

>
>
> Le 29 avril 2024 11:20:24 GMT+03:00, Lynne <dev@lynne.ee> a écrit :
>
>>> >They were they deprecated?
>>>
>>> They caused more bugs than they solved problems (because what we need is to add IPv6 to IPv4 apps, not IPv4 to IPv6 apps).
>>>
> >What bugs did they cause?
>
> Obviously anything that assumes IPv6 semantics is prone to breaking.
>
>> i know they're not very well used, because the
>>
> >documentation is very lacking,
>
> No, they're not used because they are officially deprecated for 15+ years (see RFC5156).
>

The RFC says that IPv4-Compatible addresses are deprecated,
but doesn't say that about IPv4-Mapped addresses.

The kernel would have dropped support for them if that had happened,
they started doing a cleanup of the whole stack a year ago and even
dropped UDP-Lite.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection using zone index
  2024-04-29 10:32                                                       ` Lynne
@ 2024-04-29 11:34                                                         ` Rémi Denis-Courmont
  2024-04-29 12:03                                                           ` Lynne
  0 siblings, 1 reply; 38+ messages in thread
From: Rémi Denis-Courmont @ 2024-04-29 11:34 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



Le 29 avril 2024 13:32:41 GMT+03:00, Lynne <dev@lynne.ee> a écrit :
>Apr 29, 2024, 11:56 by remi@remlab.net:
>
>>
>>
>> Le 29 avril 2024 11:20:24 GMT+03:00, Lynne <dev@lynne.ee> a écrit :
>>
>>>> >They were they deprecated?
>>>>
>>>> They caused more bugs than they solved problems (because what we need is to add IPv6 to IPv4 apps, not IPv4 to IPv6 apps).
>>>>
>> >What bugs did they cause?
>>
>> Obviously anything that assumes IPv6 semantics is prone to breaking.
>>
>>> i know they're not very well used, because the
>>>
>> >documentation is very lacking,
>>
>> No, they're not used because they are officially deprecated for 15+ years (see RFC5156).
>>
>
>The RFC says that IPv4-Compatible addresses are deprecated,
>but doesn't say that about IPv4-Mapped addresses.

Ah, yeah, the case against mapped addresses did not make it to RFC status, likely because the main author tragically died, see draft-itojun-v6ops-v4mapped-harmful.

But anyway, I am not a vendor of IP stacks. I am just the messenger here: mapped addresses are not portable and so you should not rely on them in portable code.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection using zone index
  2024-04-29 11:34                                                         ` Rémi Denis-Courmont
@ 2024-04-29 12:03                                                           ` Lynne
  0 siblings, 0 replies; 38+ messages in thread
From: Lynne @ 2024-04-29 12:03 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Apr 29, 2024, 13:34 by remi@remlab.net:

>
>
> Le 29 avril 2024 13:32:41 GMT+03:00, Lynne <dev@lynne.ee> a écrit :
> >Apr 29, 2024, 11:56 by remi@remlab.net:
>
>>>
>>>
>>> Le 29 avril 2024 11:20:24 GMT+03:00, Lynne <dev@lynne.ee> a écrit :
>>>
>>>>> >They were they deprecated?
>>>>>
>>>>> They caused more bugs than they solved problems (because what we need is to add IPv6 to IPv4 apps, not IPv4 to IPv6 apps).
>>>>>
>>> >What bugs did they cause?
>>>
>>> Obviously anything that assumes IPv6 semantics is prone to breaking.
>>>
>>>> i know they're not very well used, because the
>>>>
>>> >documentation is very lacking,
>>>
>>> No, they're not used because they are officially deprecated for 15+ years (see RFC5156).
>>>
> >The RFC says that IPv4-Compatible addresses are deprecated,
> >but doesn't say that about IPv4-Mapped addresses.
>
> Ah, yeah, the case against mapped addresses did not make it to RFC status, likely because the main author tragically died, see draft-itojun-v6ops-v4mapped-harmful.
>

The draft recommends that their use on the wire is forbidden,
which is a niche use-case some vendors did.


> But anyway, I am not a vendor of IP stacks. I am just the messenger here: mapped addresses are not portable and so you should not rely on them in portable code.
>

Fair enough, thanks for looking into it, will keep it in mind that
OpenBSD doesn't implement this yet.
I'm sure IPv4 will be deprecated soon. The Czech government is
so optimistic it announced it'll stop hosting its website under it
in just 8 years from now.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2024-04-29 12:03 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-14 12:04 [FFmpeg-devel] [PATCH] avformat: enable UDP IPv6 multicast interface selection Ignjatović, Lazar (RS)
2024-03-14 21:13 ` Michael Niedermayer
2024-03-18 13:45   ` Ignjatović, Lazar (RS)
2024-03-19  1:23     ` Michael Niedermayer
2024-03-20  9:28       ` [FFmpeg-devel] [PATCH v2] " Ignjatović, Lazar (RS)
2024-03-20 10:51         ` Rémi Denis-Courmont
2024-03-20 11:09           ` Ignjatović, Lazar (RS)
2024-03-20 11:29             ` Rémi Denis-Courmont
2024-03-20 11:45               ` Ignjatović, Lazar (RS)
2024-03-20 12:17                 ` Rémi Denis-Courmont
2024-03-20 12:35                   ` Ignjatović, Lazar (RS)
2024-03-21  7:26                     ` Rémi Denis-Courmont
2024-03-21 13:01                       ` Ignjatović, Lazar (RS)
2024-03-21 19:44                         ` Rémi Denis-Courmont
2024-03-22  9:31                           ` Ignjatović, Lazar (RS)
2024-03-22  9:55                             ` Rémi Denis-Courmont
2024-03-22 10:16                               ` Ignjatović, Lazar (RS)
2024-03-26 12:34                                 ` [FFmpeg-devel] [PATCH v3] avformat: enable UDP IPv6 multicast interface selection using localaddr Ignjatović, Lazar (RS)
2024-03-26 18:25                                   ` Rémi Denis-Courmont
2024-03-27  8:53                                     ` Ignjatović, Lazar (RS)
2024-03-27 15:31                                       ` Rémi Denis-Courmont
2024-03-27 15:38                                         ` [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection using zone index Ignjatović, Lazar (RS)
2024-04-11  7:45                                         ` Ignjatović, Lazar (RS)
2024-04-11  7:50                                           ` Lynne
2024-04-11  7:58                                             ` Ignjatović, Lazar (RS)
2024-04-11 13:01                                               ` [FFmpeg-devel] [PATCH v3] " Ignjatović, Lazar (RS)
2024-04-19 10:23                                                 ` Ignjatović, Lazar (RS)
2024-04-28 18:15                                             ` [FFmpeg-devel] [PATCH v2] " Rémi Denis-Courmont
2024-04-28 20:11                                               ` Lynne
2024-04-29  7:33                                                 ` Rémi Denis-Courmont
2024-04-29  8:20                                                   ` Lynne
2024-04-29  9:56                                                     ` Rémi Denis-Courmont
2024-04-29 10:32                                                       ` Lynne
2024-04-29 11:34                                                         ` Rémi Denis-Courmont
2024-04-29 12:03                                                           ` Lynne
2024-04-29  0:01                                               ` Brad Smith
2024-03-26 12:34                                 ` [FFmpeg-devel] [PATCH] " Ignjatović, Lazar (RS)
2024-03-26 18:24                                 ` [FFmpeg-devel] [PATCH v2] avformat: enable UDP IPv6 multicast interface selection Rémi Denis-Courmont

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git