[FFmpeg-devel] [PATCH] Avoid sending packets to network when multicast ttl is 0 in udp

Omid Ghaffarinia omid.ghaffarinia at gmail.com
Tue Jul 12 17:01:36 EEST 2016


When using ffmpeg to start a local-only server (i.e. setting ttl=0)
using multicast ip (i.e. 224.1.1.1) you can see packets going to
network.
Bug is due to kernel handling multicast ttl 0 differently (as noted in
kernel code net/ipv4/route.c:2191 see:
https://github.com/torvalds/linux/blob/master/net/ipv4/route.c )
    /* Special hack: user can direct multicasts
       and limited broadcast via necessary interface
       without fiddling with IP_MULTICAST_IF or IP_PKTINFO.
       This hack is not just for fun, it allows
       vic,vat and friends to work.
       They bind socket to loopback, set ttl to zero
       and expect that it will work.
       From the viewpoint of routing cache they are broken,
       because we are not allowed to build multicast path
       with loopback source addr (look, routing cache
       cannot know, that ttl is zero, so that packet
       will not leave this host and route is valid).
       Luckily, this hack is good workaround.
     */


Signed-off-by: Omid Ghaffarinia <omid.ghaffarinia at gmail.com>
---
 libavformat/sdp.c |    2 +-
 libavformat/udp.c |   28 ++++++++++++++++++++++++++++
 2 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/libavformat/sdp.c b/libavformat/sdp.c
index 01b564b..0401f7a 100644
--- a/libavformat/sdp.c
+++ b/libavformat/sdp.c
@@ -61,7 +61,7 @@ static void sdp_write_address(char *buff, int size,
const char *dest_addr,
     if (dest_addr) {
         if (!dest_type)
             dest_type = "IP4";
-        if (ttl > 0 && !strcmp(dest_type, "IP4")) {
+        if (ttl >= 0 && !strcmp(dest_type, "IP4")) {
             /* The TTL should only be specified for IPv4 multicast addresses,
              * not for IPv6. */
             av_strlcatf(buff, size, "c=IN %s %s/%d\r\n", dest_type,
dest_addr, ttl);
diff --git a/libavformat/udp.c b/libavformat/udp.c
index 8699c1c..fe46ba5 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -176,6 +176,28 @@ static int udp_set_multicast_ttl(int sockfd, int mcastTTL,
         }
     }
 #endif
+    if (mcastTTL == 0) {
+#ifdef IP_MULTICAST_IF
+        if (addr->sa_family == AF_INET) {
+            struct in_addr localhost_addr;
+            inet_pton(AF_INET, "127.0.0.1", &localhost_addr);
+            if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF,
&localhost_addr, sizeof(localhost_addr)) < 0) {
+                log_net_error(NULL, AV_LOG_ERROR,
"setsockopt(IP_MULTICAST_IF)");
+                return -1;
+            }
+        }
+#endif
+#if defined(IPPROTO_IPV6) && defined(IPV6_MULTICAST_IF)
+        if (addr->sa_family == AF_INET6) {
+            struct in6_addr localhost_addr;
+            inet_pton(AF_INET6, "::1", &localhost_addr);
+            if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
&localhost_addr, sizeof(localhost_addr)) < 0) {
+                log_net_error(NULL, AV_LOG_ERROR,
"setsockopt(IPV6_MULTICAST_IF)");
+                return -1;
+            }
+        }
+#endif
+    }
     return 0;
 }

@@ -882,6 +904,12 @@ static int udp_open(URLContext *h, const char
*uri, int flags)
         }
         if (h->flags & AVIO_FLAG_READ) {
             /* input */
+            if (s->ttl == 0) {
+                if (s->dest_addr.ss_family == AF_INET)
+                    inet_pton(AF_INET, "127.0.0.1", &((struct
sockaddr_in *)&s->local_addr_storage)->sin_addr);
+                else
+                    inet_pton(AF_INET6, "::1", &((struct sockaddr_in6
*)&s->local_addr_storage)->sin6_addr);
+            }
             if (num_include_sources && num_exclude_sources) {
                 av_log(h, AV_LOG_ERROR, "Simultaneously including and
excluding multicast sources is not supported\n");
                 goto fail;
-- 
1.7.9.5


More information about the ffmpeg-devel mailing list