Subject: RFC: local address selection
To: None <tech-net@netbsd.org>
From: Emmanuel Dreyfus <manu@netbsd.org>
List: tech-net
Date: 11/07/2004 19:02:30
Hi

Following up my recent troubles with the VPN setup where the local
address used for outgoing TCP and ICMP packets was different:

If no bind() is not used to choose a particular local address, TCP and
UDP packets will have their local address chosen from
src/sys/netinet/in_pcb.c:in_pcbconnect(). A call is made to
in_selectsrc() to pick up a local address. The address used is the first
appropriate address for the outgoing interface found in the routing
table. 

ICMP packets don't set the local address before getting down to
src/sys/netinet/ip_output.c:ip_output(). The address is chosen there,
but differently. in_selectsrc() is not called there. The address used is
directly found in the routing table (no interface is involved)

Calling in_selectsrc() from ip_output() would indeed fix the incoherency
problem, TCP, UDP and ICMP packets would select the same source address.
But this adds a bit of overhead to fix a problem that might not be a
problem at all for most users. Moreover, in my problem, ICMP is taking
the right way, and TCP/UDP go wrong. Thus this fix would make any
protocol go wrong for me, so that does not fix my own problem.

Beside having the same local address selected for any protocol, I really
need to be able to set a "prefered" local address. At the user interface
level, I think of two ways of doing this:

Each interface could have its prefered local address. This would be
implemented through a prefered parameter to ifconfig:
ifconfig ex0 alias 10.0.12.7 prefered

Or each route could have its prefered local address:
route add default 10.0.12.1 -localaddr 10.0.12.7   

The latter sounds the most general, so it might be the best way to go.
It will probably mean adding a field to struct route: 
        struct sockaddr *ro_localaddr;

If set to a non NULL value, this could be used from ip_output() and
in_selectsrc() to set the local address.

The memory cost is a pointer on each routing entry. The code path cost
is a check that this pointer is != NULL.

Communication between route(8) and the kernel: We could add a
RTM_LOCALADDR message just to set the route prefered address, that way
we wouldn't have to modify the RTM_ADD message at all.

RTM_LOCALADDR message would just contain two struct sockadddr: for the
route destination and the local address.

Opinions?

-- 
Emmanuel Dreyfus
Il y a 10 sortes de personnes dans le monde: ceux qui comprennent 
le binaire et ceux qui ne le comprennent pas.
manu@netbsd.org