obs-studio icon indicating copy to clipboard operation
obs-studio copied to clipboard

Add network interface binding for RTMP on Linux

Open tytan652 opened this issue 4 years ago • 19 comments

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.

new_binder_default

new_binder_enp6s0

new_binder_enp6s0_IP_list

Old description I added the possibility to bind the RTMP socket directly to a network interface (not an address) on Linux system. FreeBSD and macOS systems will need the official implementation of `IP_SENDIF`.

bind_iface_default

Motivation and Context

On my Linux system, I want to use 2 internet connection simultaneously, my ADSL (enp4s0) and my phone's 4G (enp6s0). ip_route Here, OBS will use enp4s0 by default but I want OBS to use enp6s0 and other apps use enp4s0.

But when I do this: bind_ip_enp6s0 I obtain this with the auto-conf wizard: bind_ip_enp6s0_result Same with a ping by binding the address: ping_10 42 0 206 But if I bind the interface: ping_enp6s0

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

More details

How Has This Been Tested?

I use the auto-conf wizard, to see if it use the right interface with terminal outputs.

neofetch

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.

tytan652 avatar Feb 11 '21 21:02 tytan652

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 avatar Feb 11 '21 22:02 WizardCM

@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

tytan652 avatar Feb 11 '21 22:02 tytan652

@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. ping_192 168 0 3

tytan652 avatar Feb 12 '21 08:02 tytan652

~~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.

tytan652 avatar Feb 12 '21 16:02 tytan652

@WizardCM And about the Bug fix label, like I demonstrated, it's not a bug because ping show the same behavior.

So binding to an IP is expected to just.. not function at all on the system level? That seems useless. :/

WizardCM avatar Feb 13 '21 00:02 WizardCM

@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)

tytan652 avatar Feb 13 '21 07:02 tytan652

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.

tytan652 avatar Feb 13 '21 13:02 tytan652

@WizardCM Can you put Linux tag on this PR ? And also Seeking testers if you think it's worth it (only me tested it).

tytan652 avatar Feb 18 '21 10:02 tytan652

Thank you Jim (@jp9000)

tytan652 avatar Feb 18 '21 13:02 tytan652

~~Switch to draft, waiting #5143 to be merged. The network UI change may need some change.~~

tytan652 avatar Aug 18 '21 06:08 tytan652

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:

  1. 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]
  1. 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.

RytoEX avatar May 22 '22 06:05 RytoEX

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.

tt2468 avatar Jun 26 '22 06:06 tt2468

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.

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.

tytan652 avatar Jun 26 '22 08:06 tytan652

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.

tytan652 avatar Aug 31 '22 12:08 tytan652

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.

PatTheMav avatar Jan 10 '24 15:01 PatTheMav

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.

tytan652 avatar Jan 10 '24 15:01 tytan652

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.

tt2468 avatar Jan 15 '24 22:01 tt2468

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?

PatTheMav avatar Jan 16 '24 17:01 PatTheMav

in case of built in mobile broadband network interface, it seems that the IP will re-assigned whenever it switches cellular tower (?)

mmn6d6d6e avatar Feb 07 '24 22:02 mmn6d6d6e