PR #25310 opened by Marti2203
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25310
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25310.patch

When the tcp protocol is given `local_port` without `local_addr`, 
`customize_fd()` resolves the bind address with `getaddrinfo(NULL, port)` and 
no `AI_PASSIVE`. Without that flag a NULL node resolves to the loopback 
address, so the socket is bound to 127.0.0.1:port and every connection to a 
non-local host fails at `connect()` with EINVAL:

```
ffprobe -v error "tcp://192.0.2.1:80?local_port=40123&timeout=2000000"
bind(3, {sa_family=AF_INET, sin_port=htons(40123), 
sin_addr=inet_addr("127.0.0.1")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), 
sin_addr=inet_addr("192.0.2.1")}, 16) = -1 EINVAL (Invalid argument)
tcp://192.0.2.1:80?local_port=40123&timeout=2000000: Invalid argument
```

(192.0.2.1 is TEST-NET-1; any non-local address behaves the same, no traffic is 
needed because the kernel rejects the connect immediately.) Connections to an 
address of the local host still go through, but arrive from 127.0.0.1 instead 
of the host's address. Adding `local_addr=0.0.0.0` works around it, so only the 
`local_port`-only case is affected.

The patch sets `AI_PASSIVE` when `local_addr` is not set, as the listen path in 
`tcp_open()` and udp.c already do. With it the socket binds to 0.0.0.0:40123 
and the connect goes ahead (`EINPROGRESS`, then "Connection timed out" for the 
unreachable test address); a connection to a listener on this host's LAN 
address arrives from that address and the requested port instead of from 
127.0.0.1. IPv6 connections to ::1 with `local_port` work before and after. 
When `local_addr` is set, nothing changes, since getaddrinfo ignores 
`AI_PASSIVE` for a non-NULL node.

Testing: strace and a local listener on the host's LAN address as above, plus 
the mov/mp4/flv FATE tests and fate-source, all passing; there is no FATE 
coverage for tcp connections.

Open PR #24565 makes hls/dash/imf child connections inherit `local_addr` and 
`local_port`; it does not touch this path, and with it a `local_port`-only 
setting would also reach those child connections.

This issue was found by an LLM-Enhanced Static Analysis Engine and verified 
manually.

🤖 Generated with [Claude Code](https://claude.com/claude-code)



From 660da2b2f1948ead2783be7902b6e1e279c54dff Mon Sep 17 00:00:00 2001
From: Martin Mirchev <[email protected]>
Date: Wed, 21 Oct 2026 19:01:45 +0800
Subject: [PATCH] avformat/tcp: bind to the wildcard address when only
 local_port is set

When local_port is given without local_addr, customize_fd() resolves the
bind address with getaddrinfo(NULL, port) without AI_PASSIVE, which
returns the loopback address. The socket is then bound to 127.0.0.1, so
a connection to any non-local host fails with EINVAL ("Invalid
argument"), and connections to a local non-loopback address appear to
come from 127.0.0.1.

Set AI_PASSIVE when local_addr is not set, as the listen path in
tcp_open() and udp.c already do, so that only the local port is fixed.

Signed-off-by: Martin Mirchev <[email protected]>
---
 libavformat/tcp.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index 09dc8a96796..98e7122854a 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -87,6 +87,9 @@ static int customize_fd(void *ctx, int fd, int family)
 
         hints.ai_family = family;
         hints.ai_socktype = SOCK_STREAM;
+        /* With only local_port set, bind to the wildcard address rather than 
loopback. */
+        if (!s->local_addr)
+            hints.ai_flags |= AI_PASSIVE;
 
         ret = getaddrinfo(s->local_addr, s->local_port, &hints, &ai);
         if (ret) {
-- 
2.54.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to