obs-studio
                                
                                
                                
                                    obs-studio copied to clipboard
                            
                            
                            
                        Add network interface binding for RTMP on Linux
ArchLinux/Manjaro users: if you want to test this feature, you can by building the obs-studio-tytan652 AUR package
Description
I added the possibility to bind the RTMP socket directly to a network interface (not an address) on Linux system.
Then the user can bind to a network interface and if he want bind to an address too. But he can't bind an address without binding an interface. If the user set "Bind to interface" to "Default", it will also set "Bind to IP" to "Default". It will also reset "Bind to IP" property on old version after updating to a newer version with this feature.
Some translations may need to be updated like the french one, where the Network section is very only IP address oriented/centered.



Old description
I added the possibility to bind the RTMP socket directly to a network interface (not an address) on Linux system.
Motivation and Context
On my Linux system, I want to use 2 internet connection simultaneously, my ADSL (enp4s0) and my phone's 4G (enp6s0).
Here, OBS will use enp4s0 by default but I want OBS to use enp6s0 and other apps use enp4s0.
But when I do this:
I obtain this with the auto-conf wizard:
Same with a ping by binding the address:
But if I bind the interface:

Then I tried to implement interface binding and now when I do this:
I obtain this:
With my ADSL, I usually obtain this:

How Has This Been Tested?
I use the auto-conf wizard, to see if it use the right interface with terminal outputs.

Types of changes
- New feature (non-breaking change which adds functionality)
 
Checklist:
- [x] My code has been run through clang-format.
 - [x] I have read the contributing document.
 - [x] My code is not on the master branch.
 - [x] The code has been tested.
 - [x] All commit messages are properly formatted and commits squashed where appropriate.
 - [ ] I have included updates to all appropriate documentation.
 
I would personally vote that we keep one dropdown, and that the IP binding should also bind to the interface internally. This to me sounds like a bug with the Bind IP functions rather than a missing feature.
@WizardCM From my point of view, there is no need to force the user to choose between IPv4 and IPv6 for interface binding.
Edit: under Linux
@WizardCM And about the Bug fix label, like I demonstrated, it's not a bug because ping show the same behavior. If I bind an address of enp4s0 it will work for OBS and ping.

~~This functionality could work on macOS and FreeBSD systems, if SO_BINDTODEVICE analogue IP_SENDIF is one day implemented.
So I'm asking, should I keep the future possible implementation of interface binding for FreeBSD and "lock it" as Linux only feature, or rework it to make it completely Linux only ?~~
Edit: No emergency and no need to implement it for macOS and FreeBSD and those two don't have this issue. Then let's make it Linux only.
@WizardCM And about the Bug fix label, like I demonstrated, it's not a bug because
pingshow the same behavior.
So binding to an IP is expected to just.. not function at all on the system level? That seems useless. :/
@WizardCM On my computer, binding a address not "owned" by my "default" interface will cause this issue, but if I bind an interface and bind one of his address it will work.
I don't know if it's the same behavior happen on other Linux system. But binding address seems to allow the user to force the use of IPv4 or IPv6, but don't force an interface to be used and try with the "default" one on my system.
EDIT: I did nothing to obtain this behavior. EDIT: Same behavior with a fresh Manjaro VM with two virtual networks (but it's also a arch based)
The issue here seems that on Linux system, the gateway chosen for the socket is the one of the "default" interface (the one with the lowest metrics), it doesn't matter if the two interface are in the same network, but in my situation it matters and then OBS (or ping) use my second connection with the wrong gateway.
Behavior tested on ArchLinux, Ubuntu and Fedora with ping command.
@WizardCM Can you put Linux tag on this PR ? And also Seeking testers if you think it's worth it (only me tested it).
Thank you Jim (@jp9000)
~~Switch to draft, waiting #5143 to be merged. The network UI change may need some change.~~
Circling back around to this because it's labeled bug fix...
@WizardCM @tytan652 and I discussed this off-thread. We think that this doesn't need two separate dropdowns. We think the better options are one of these:
- One dropdown that lists the contents shown in the proposed "Bind to IP" dropdown in the PR description containing:
 
- [interface] Default
 - [interface] [IPv4 address]
 - [interface] [IPv6 address]
 
- One dropdown that lists only interfaces combined with a checkbox that says "Prefer IPv6".
 
@Warchamp7 may still need to approve the UX change, and it would be good if @notr1ch could check the librtmp changes.
In terms of interface binding, I think that using the linux-specific SO_BINDTODEVICE parameter is unnecessary. I would recommend displaying a dropdown of IP addresses only, with the interface name only serving as a hint to the user.
I say that using SO_BINDTODEVICE is unnecessary because most implementations of interface binding that I see for streaming purposes bind only to an IP address. I'm a nerd for using cool Linux socket features, but I think the complexity is likely not worth it.
I say that using
SO_BINDTODEVICEis unnecessary because most implementations of interface binding that I see for streaming purposes bind only to an IP address. I'm a nerd for using cool Linux socket features, but I think the complexity is likely not worth it.
In my messages in this PR, I reproduce the same issue with ping on multiple fresh installation. Which mean that OBS will have the same issue.
https://github.com/obsproject/obs-studio/pull/4219#issuecomment-778574689 https://github.com/obsproject/obs-studio/pull/4219#issuecomment-778616386
If it was unnecessary, I would have never done this PR.
This PR is drafted, the plan in the future is to reintroduce service and output property view thanks to the RFC39 and then rework this PR to be only in the rtmp_output code.
This PR is still kept up to date with the current implementation.
Forgive my ignorance, but why is OBS binding to an IP in the first place? I'm mostly familiar with binding a service to an interface, but not a specific IP. Partially that's because with IPv6 and privacy extensions my devices get to have lots of IP addresses in a single day, so binding it to a specific one is a bit of a moot exercise.
Right now on my Mac, that dropdown has almost 30 entries because of all the dynamic IP bindings macOS generates for all its ad-hoc inter-device communication features, so it's a bit of a mess UX-wise already.
Being able to select a device (use my Ethernet/use my WiFi) would make much more sense UX wise (because that's what users understand) and if a user does custom IP bindings they would know which device has a specific IP and select it accordingly (the currently valid IP could be displayed in parens in the dropdown as a hint).
@tytan652 Could you explain the issue you face without this fix to me again? Right now I don't fully understand why just binding the IP doesn't work for you.
Forgive my ignorance, but why is OBS binding to an IP in the first place?
One of the reason was that Happy Eyeball was not implemented yet. Someone else might have a more accurate answer.
I did not test, but high chance that the it still there after Happy Eyeball changes since it does not bind interfaces.
Could you explain the issue you face without this fix to me again?
Linux use the wrong gateway (use the one with the lowest metric) since we don't bind an interface beforehand.
Right now on my Mac, that dropdown has almost 30 entries because of all the dynamic IP bindings macOS generates for all its ad-hoc inter-device communication features, so it's a bit of a mess UX-wise already.
It may have changed since then, but BSD didn't look like it supports interface binding.
Ok so I did a bunch of research here, since there's a lot of conflicting information on the internet about how to achieve this stuff.
One very important thing to know about as a prerequisite is RFC 1122, which describes the concept of "weak" and "strong" ES models. To summarize, this describes the behavior of address binding depending on the two models. Linux uses the "weak" model, and most other OSes (including Windows) use the "strong" model.
As a result of this, on Linux, we do need to implement SO_BINDTODEVICE alongside the address bind, as tytan has currently. This feature working is also highly dependent on the configuration of the users' system and routing table, so we will need to make sure we label the feature as advanced and without support.
Other than that, what needs updating is:
- Happy eyeballs dep requires implementation of 
happy_eyeballs_set_bind_device()in order to pass through the device string for the worker sockets - The librtmp commit requires modifying to pass the bound device string to happy eyeballs
 - I think a more "reliable" UI implementation for linux would be to select a bind interface, then have the address dropdown below that, and only display addresses available on the selected interface. This would likely prevent a majority of user error cases.
 
EDIT: I also want to mention that this feature is most reliably used when interfaces capable of accessing internet destinations (default route or full internet routing table) are isolated using linux namespaces. This isolation ensures that various conditions in the routing table cannot route outgoing packets in unintended ways. Unfortunately though, this configuration requires the user to have quite advanced knowledge of IP and IP routing.
EDIT: I also want to mention that this feature is most reliably used when interfaces capable of accessing internet destinations (default route or full internet routing table) are isolated using linux namespaces. This isolation ensures that various conditions in the routing table cannot route outgoing packets in unintended ways. Unfortunately though, this configuration requires the user to have quite advanced knowledge of IP and IP routing.
What's a high-level setup that requires this kind of setting? Like when would one have different IP addresses with different routing assigned to the same device?
in case of built in mobile broadband network interface, it seems that the IP will re-assigned whenever it switches cellular tower (?)