4

I'm trying to set a socket's output interface on a system with two interfaces. I've googled a lot and I found divergent answers. Some people say that I can bind a socket before calling connect to choose a specific interface (as in How does a socket know which network interface controller to use?). But other people say that this isn't enough (as in http://codingrelic.geekhold.com/2009/10/code-snippet-sobindtodevice.html or How to open a socket on a specific interface and receive both IPv4 and IPv6 traffic).

I have a working implementation using SO_BINDTODEVICE. However the bind before connect solution isn't working. It seems that the source address doesn't affect routing and only the routing table is considered in this case. Someone said that this is caused by Linux's Weak end system model. According to http://wiki.treck.com/Appendix_C:_Strong_End_System_Model_/_Weak_End_System_Model the Source Address does not specify the output interface.

If possible I would like to have a portable solution. I know that SO_BINDTODEVICE is available only in Linux.

Community
  • 1
  • 1
Gustavo Santos
  • 126
  • 1
  • 8
  • I run a test binding to an interface with bind. It should work, you should show your code in order to figure out where the problem is. – rodolk Nov 25 '15 at 23:30

2 Answers2

2

Source address doesn't affect routing of a packet. The interface will be selected based on the destination address and host's router table. You can modify it with route command.

route default gw [gateway IP]

No matter which interface the socket is bound, the packet is to be routed based on route table. The interface to which the socket is bound will determine the source ip address.

Now, I run some tests binding to loopback interface and connecting the socket to other address in the Internet and in that case connect failed with errno 22 (EINVAL). However, in other tests with two interfaces (none was loopback), and connecting to a server in the Internet, no matter which interface I bound the socket to, the packet was sent out according to the routing table, in my case following the default rule. The sources address depended on the bind.

rodolk
  • 5,606
  • 3
  • 28
  • 34
2

Whether binding affects routing depend on the fact if a system uses the weak ES model or the strong ES model. Linux uses the weak ES model, whereas all BSD based systems (including macOS) uses the strong ES model. Windows used the weak ES model up to Vista, then switched to the strong ES model.

Microsoft has a very detailed page about that topic, explaining the two modes and also how binding will affect routing and packet receiving in either mode:

https://learn.microsoft.com/en-us/previous-versions/technet-magazine/cc137807(v=msdn.10)?redirectedfrom=MSDN

So on BSD based systems and Windows Vista and later, you can select an interface using bind but not on Linux. On Linux you have to use SO_BINDTODEVICE for that. A solution that would support either one of these two modes would thus be very portable.

There is one pitfall, though: If the system allows that multiple interface can have the same address, then bind will not really select an interface, it will only limit the choices for interfaces. The final choice is then either performed by consulting the routing table or by some system specific interface order.

Mecki
  • 125,244
  • 33
  • 244
  • 253