Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 20 Apr 2002 01:47:50 -0700
From:      Terry Lambert <tlambert2@mindspring.com>
To:        Brett Glass <brett@lariat.org>
Cc:        chat@freebsd.org
Subject:   Re: How to control address used by INADDR_ANY?
Message-ID:  <3CC12B36.E9DC0040@mindspring.com>
References:  <4.3.2.7.2.20020419144005.0358c610@nospam.lariat.org> <4.3.2.7.2.20020419152309.035a96d0@nospam.lariat.org>

next in thread | previous in thread | raw e-mail | index | archive | help
Brett Glass wrote:
> >INADDR_ANY means "I don't care".  FreeBSD's "I don't care" is a
> >bit different in implementation than Cisco's "I don't care".  8-(.
> >
> >Since you apparently *do* care, you must bind a specific address
> >for outbound connections.
> 
> Unfortunately, "you" consists of any application that might be
> running on the box.

Yes.

> And few, if any, of the standard apps one is
> likely to use in administration offer you the option of specifying
> a source address explicitly. For example, suppose I want to bring
> in a patch or some code via anonymous FTP. I can't, because the
> Berkeley FTP client doesn't let you specify a source address.

All FTP servers allow it, and so do "bind" and "sendmail".  The
code that doesn't allow it could be said to be broken.


> >It picks the first address on the first interface on the subnet
> >for the destination address in question,
> 
> When the machine is going out to the Internet at large, the
> destination isn't on any of those subnets.

Then it goes out the interface whose IP address is on the same
subnet as the default route.  In your case, this will unavoidably
be a 10.x address.


> >Probably you can make it work by setting the IP address to the
> >one for the bridged network,
> 
> I'm not sure I follow. There's no bridged network here.

Then I don't understand how the ISP is tunneling packets from
the assigned published IP addresses out to the real internet,
or back.  It *must* be doinging bridging for you.  The 10.x
addresses you are using are, by definition, non-routable.


> >and then setting the 10. address
> >to be the alias, instead of the bridged address.
> 
> The only addresses that are "legal" on the ISP's
> internal subnet are 10. addresses, by policy. I
> could try something like specifying the address as
> 127.0.0.2 with the 10. address as an alias.... The
> default IPFW rules would keep any packets with a source
> address of 127.0.0.2 from actually leaving the interface.
> But this is kinda dicey... and I don't know what the
> stack will do. Will apps wind up with sockets that have
> 127.0.0.2 as a source address?

They might.  This will not work.  I would have to know how
your ISP expects things to work, for me to be able to tell
you how to configure your FreeBSD box to work they way they
expect things to work (if it's even possible).


> >Really, this is a bug in the FreeBSD code, in that it is not
> >treating the IP address/port pair on the destination as the
> >route to choose the "proper" origin address.
> 
> Actually, it may just be an omission. Just as we can set a
> default gateway, it might be nice to be able to set a default
> IP for outbound sockets. (INADDR_ANY has different semantics when
> one is listening, of course, so it's only the outbound case
> that we need to worry about.) Or we might be able to set a flag
> that disqualifies an interface from having its address(es) used as
> the source address when INADDR_ANY is used. (This is probably done
> for lo0 now. I don't know for sure, but I'll bet that the code
> notices the LOOPBACK flag and disqualifies the interface.) The
> new flag could be set and viewed via ifconfig.

No.  It is a bug.

The problem is that the route code does not distinguish multiple
default routes, nor does it distinguish aliases from their
interfaces.  Because of this, you route out an interface, not
out a source IP address on an interface.  Without routing out a
specific source IP, your packets get the first IP address on the
interface.

It's somewhat more complicated than that because of your use of
multiple local routable subnets.  Really, the BSD code does two
things:

1)	Routes packets destined for a local subnet out of the
	interface whose netmask of the IP address that you are
	sending too applied to the IP address of the interface
	result in the "best match".  THat is, if you have two
	interfaces that match, and one is a /24 and the other
	is a /28, it will pick the /28 to send.  For equal
	interfaces, the one it picks is round-robin'ed.

2)	Routes all other packets out the default route (and it
	has only a single default route, which is not a good
	thing, in a lot of ways).

The easiest way to see the deficiency in the FreeBSD networking
code is to ask yourself "If I buy a system, put a single gigabit
interface in it, and add 2 4 port 10/100 cards, how can I build
a FreeBSD based switch, using this hardware?".

The first thing you need to realize is that switches don't have
assigned IP addresses to ports; a lot of the obvious problems
will fall out at you from that point forward.


> >Short of rewriting a lot of the stack to reorder the anonymous
> >address handling (e.g. to make it work like Cisco equipment
> >does),
> 
> There may be a single assignment statement somewhere that could
> be made to grab the address from a sysctl variable. Terry, you
> know the network code better than I.... In what file is INADDR_ANY
> converted into a specific source address? What logic is used to
> determine which addresses are suitable?

You could pound on the code, and abuse it in such a way as
to make it do what you suggest,at the same time putting
enough special cases into the code path that you bloat the
normal 94 instructions for the TCP/IP fastpath into some
huge number that would prevent your suggested changes ever
being committed back to FreeBSD.

I would not recommend doing that.

The issue is the routing code, which identifies an interface,
not an IP address, on the target network, or, if one does not
exist, then clones one for the default route.

This is ~line 950 of /sys/netinet/ip_output.c; the "ro" is
passed in as a parameter, which is sent down as a result of
the inp_route element of the inpcb for the tcpcb for the TCP
connection (the "internet protocol control block"; see Stevens).

Changing this is not easy; you can't "just do it", because
there is a pseudo-header in the TCP packet that is considered
as part of the checksum, which contains the source and
destination addresses.  The route selection occurs at the TCP
output layer, not the IP.  It affects both the TCP and the IP
checksums.  Therefore, if you wish to interfere with the source
IP address selection, you have to do it in the tcp_output
code... or, more properly, before the call to tcp_fillheaders().
Probably, it would make the most sense to set it at connection
time, which is (and should be) an incredibly difficult thing
to do, for an unbound socket.


> >it's probably best to just bind outgoing interfaces
> >manually, and deal with the netmask in your proxy app.
> 
> I won't want to rewrite every application I might use on the
> box! Adding a mod to the stack would be easier... unless there's
> some way to get the existing code to do The Right Thing.

The suggestion in the "sockets2" working group has been to add
a "sendfrom" and "sendfromto" system call to allow specification
of a source IP address from which the packet is intended to have
originated.

For obvious reasons, I think this is a bad idea.

But either way has you rewriting applications...

-- Terry

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-chat" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3CC12B36.E9DC0040>