Message ID | AS8P193MB199764BC4A5BFA35B588F2B98D052@AS8P193MB1997.EURP193.PROD.OUTLOOK.COM |
---|---|
State | New |
Headers | show |
Series | [FFmpeg-devel,v2] avformat: enable UDP IPv6 multicast interface selection using zone index | expand |
Context | Check | Description |
---|---|---|
yinshiyou/configure_loongarch64 | warning | Failed to apply patch |
andriy/configure_x86 | warning | Failed to apply patch |
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?
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
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.
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.
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.
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.
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.
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).
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.
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.
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.
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)
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(-) -- 2.41.0.windows.2 This message has been marked as Public on 04/11/2024 07:45Z.