Skip to content
This repository has been archived by the owner on Oct 2, 2019. It is now read-only.

Binding a socket to a local interface when it is not specifically specified. #36

Open
ClaesNilsson opened this issue Aug 27, 2013 · 5 comments

Comments

@ClaesNilsson
Copy link
Contributor

[Paatric]:

  • the concept of an isolated "default local interface" (used in a few
    different places) doesn't really align with networking.. generally
    when a local interface isn't specified for a socket the one it is
    assigned is derived from looking up the remote address in the routing
    table and taking the address of the interface with the most preferred
    route to the remote address.. This is equally true of TCP and UDP.

think about a case where you've got 3 interfaces defined on your
machine - 192.168.16.1 which is a natted address used to connect to
the internet, 130.215.21.5 which is an address assigned to you while
you're connected to your university's VPN, and 127.0.0.1 (localhost).

Without additional context - none of those qualify as the default
local interface. What generally happens is that when you ask to
connect to
8.8.8.8 your local address is assigned to be 192.168.16.1 because your
Internet route will be used for 8.8.8.8.. but if you ask to connect to
130.215.21.1 your local address is assigned to be 130.215.21.5.. and
if you want to connect to 127.0.0.1 your local address is also 127.0.0.1.
So the remote address and the routing table matter - there really
isn't a default local address outside of that context.

so in general whenever you want a local interface (and you did not
explicitly provide one) it can only be determined after your provide
the remote address and a system call is made to consult the routing
table.

you specifically asked about
#24 .. I'm not concerned
about blocking IO here.. the address lookup will require a system call
but its just another kernel service with a quick response.. no
different than gettimeofday() or something really. To me the issue is
really just that the concept of assigning a local address is
nonsensical until you have assigned the remote one.

[Ke-Fong]: When you bind with INADDR_ANY, that is indeed the behavior:
Use the network interface according to routing.
We're a bit higher level from this, having a specified default network
interface makes sense and would be needed.
Suppose my smartphone has 3G, wifi, and bluetooth, they can all act as
network interfaces.
Yet, I may don't want to use 3G because it's usually expensive and use
wifi instead.

[Claes] So this means that for TCP a better description on the process for allocating a local address is needed in the case when a specific local address is not defined by the web application but I don't think that the API itself has to change?

For the case when a local interface needs to be stated by the web application I refer to the latest comments in #24, i.e. that the phase 2 SysApps API, Network Interface API, should be used to list the available networks so that a specific interface can be selected by the application.

However, your description above on how the routing table is used to set the local address based on the remote address to connect to works for TCP. What applies then to UDP? With the constructor's options argument we can set an optional "default remote address" for subsequent send() calls. So if this option is used I assume that the routing table can be used in the same manner as for TCP. However, which is the procedure if we don't set this option? Does that mean that the local address can't be determined until we issue a send() call?

Regarding setting the localAddress attribute I assume that Patrick means that for TCP the localAddress attribute immediately could be set to the actual value during the execution of the constructor, not to null, even if it is not explicitly specified in the constructor. Correct?

@ClaesNilsson
Copy link
Contributor Author

Regarding UDP I got feedback from an expert colleague based on investigations on his Linux machine:

  • If the UDPSocket is not bound to any specific local address then the system will select a sender address based on the remote address that the datagram is sent to.
  • Each call to endTo() gives a local address that depends on the remote address that the datagram is sent to.
  • Calling connect() or bind() means that a local address is bound to the socket.
  • When a local address has been bound to a socket it can not be used to send datagrams to all receivers.

My conclusion is that for our API this means for UDP:

  • If no local address is defined, i.e. UDPOptions localAddress field is not present and/or UDPOptions remoteAddress is not present then there is no fixed local address bound to the socket. Each send() will have a local (sender) address that depends on the remote address. So the UDPSocket’s localAddress attribute will stay null.
  • If a local address is defined, i.e. UDPOptions localAddress field is present and/or UDPOptions remoteAddress is present then there is a fixed local address bound to the socket. The UDPSocket’s localAddress attribute will be set to the allocated local address and:
    • If remoteAddress was set the socket can only be used to send to this address.
    • If localAddress was set but not remoteAddress the socket can only be used to send to peers accessible through this specific local interface.

@anotherlin
Copy link

The description is that of Berkeley socket behavior. This is pretty much what everyone's used to. However, I don't think it's acceptable for a mobile device with several interfaces (3g, wifi, bluetooth) to have a local address depending on the address of the datagram sent. Besides, it would make the localAddress attribute irrelevant. So I really we should, as for TCP, use a well specified default interface for any UDP socket (i.e. a call to bind() is always done).

However, it's probably a good idea to have same behavior when a remote address is specified (connect() called) : Can only send to the specified remote address and datagrams are filtered : only datagrams from the specified remoteAddress are received, all others are dropped (ignored).

@ClaesNilsson
Copy link
Contributor Author

I think that we have to find a combination of using the routing table as Patrick states and sometimes using a default interface as Ke-Fong suggests.

Just to remind everyone, we are here just talking about the case when the application does not explictly bind the socket to a specific local address, i.e. the application does not speciffy a localAddress field in the options argument in the call to the UDP or TCP socket constructor.

To me it sounds logical to use the routing table as a starting point. For example, if the remote address is local host another local interface must be used compared to the case when the remote address is an internet address. However, the problem occurs if the are more than one way to reach the internet, for example if the device is a desktop computer with more than one network card or a mobile device running 3G and wifi simultaneously. In this case one of these must be considered as "the default interface".

So I propose a wording in the specification that says that:

  • For TCP the localAddress attribute is defined based on the remote address to connect to by using the routing table. If there are more than one interface that provides access to a remote address then the "default interface" of these should be used.
  • For UDP the localAddress attribute will be null as the local address may vary depending on the remote address for the send() call.

I can make an update to the specification according to above.

WDYT?

@ClaesNilsson
Copy link
Contributor Author

Any objections to the update I propose above?

@ClaesNilsson
Copy link
Contributor Author

Please review PR 51.

I am not sure on the approach for server sockets. node.js states "If the host is omitted, the server will accept connections directed to any IPv4 address (INADDR_ANY). ".
So if local address is not stated for a TCPServer socket should it listen on all interfaces at the device?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants