In my anycast setup for our DNS cache, I use addresses configured on
loopback interfaces of the hosts (the addresses are announced to the
IGP as host routes). I also prefer to let unbound listen on all
interfaces by specifying
interface: 0.0.0.0
interface: ::
in the configuration file. The main reason is that the instances on
different hosts are easier to maintain if the configuration doesn't
contain explicit addresses (we presently use two distinct anycast
address both for IPv4 and IPv6).
With this setup, when unbound receives a query on the loopback
interface, it sends the reply with a source address of one of the
physical interfaces of the host. In other words, it appears that
unbound lets the kernel chose the source address, which is always
wrong in this case.
There is a simple workaround by using this configuration instead:
However, since DNS clients expect replies to come from the same
address to which the query was sent, I'd expect unbound to *always*
request a specific address for replies from the kernel. I'm wondering
why unbound doesn't enforce this?
In case I'm overlooking something here and this is in fact a useful
feature, I'd ask for a configuration option that allows me to force
source address selection for query replies to always match the
destination address in the query. That would allow me to keep the
simpler configuration mentioned above.
The problem is what interfaces to bind to. 0.0.0.0 is everything and
thus good on a 'normal' setup. When the kernel makes bad routing
decisions (I know, anycast configuration is hell), this gives wrong
source address on replies, and DNS requires it. Really, the kernel
should make good routing decisions, but anyway.
Unbound does not know what interfaces you have. There is no nice posix
'list of interfaces', as far as I know. So, the problem for me is a
portability, "0.0.0.0" is very portable. Listing the interfaces is hard
and likely to encounter portability problems.
With some ioctl and fun, I could probably support *BSD, Linux, Solaris
for such a feature. The feature might not be available on other
platforms (if the ioctl doesn't work). Something like 'probe_interfaces:
yes', except with a better name?
With this setup, when unbound receives a query on the loopback
interface, it sends the reply with a source address of one of the
physical interfaces of the host. In other words, it appears that
unbound lets the kernel chose the source address, which is always
wrong in this case.
On our anycast setup (Solaris) we are configuring the anycast
adresses on the physical interfaces as aliases rather then the
loopbacks and then the kernel puts the correct address in the
answer packet. This however requires to configure an
outgoing-interface, as querying with anycast IPs isn't a good
idea.
The problem is what interfaces to bind to. 0.0.0.0 is everything and
thus good on a 'normal' setup. When the kernel makes bad routing
decisions (I know, anycast configuration is hell), this gives wrong
Actually, I find anycast with loopback interfaces pretty simple to
configure and use (I'm using Linux and Solaris).
source address on replies, and DNS requires it. Really, the kernel
should make good routing decisions, but anyway.
But you can't leave this decision to the kernel anyway. The semantics
that the source address of the reply must match the destination
address in the query is imposed by the DNS spec, not UDP. How can you
expect the kernel to do the right thing?
Unbound does not know what interfaces you have. There is no nice posix
'list of interfaces', as far as I know. So, the problem for me is a
portability, "0.0.0.0" is very portable. Listing the interfaces is hard
and likely to encounter portability problems.
With some ioctl and fun, I could probably support *BSD, Linux, Solaris
for such a feature. The feature might not be available on other
platforms (if the ioctl doesn't work). Something like 'probe_interfaces:
yes', except with a better name?
I think the new dual-stack socket API introduced for IPv6 should take
care of all of this. You should be able to do an anonymous (wildcard)
bind on a single socket (IPv4 addresses will be represented as IPv6
addresses in the "mapped" format). The source address is available
through ancillary data from the socket. The beauty of it is that you
don't have to worry about interfaces at all and you should pick up new
interfaces automatically.
Unfortunatley, some operating systems do not support this or require a
global configuration or a socket option to fully use this mechanism.
But I think it is the way to go on all systems that support it.
With this setup, when unbound receives a query on the loopback
interface, it sends the reply with a source address of one of the
physical interfaces of the host. In other words, it appears that
unbound lets the kernel chose the source address, which is always
wrong in this case.
On our anycast setup (Solaris) we are configuring the anycast
adresses on the physical interfaces as aliases rather then the
loopbacks and then the kernel puts the correct address in the
answer packet.
That's a bit of a hack, though. You lose redundancy as well, when
that interface fails (an address on the loopback interface is
reachable through all interfaces).
This however requires to configure an
outgoing-interface, as querying with anycast IPs isn't a good
idea.
Note that this is a snapshot from trunk since the changes are
substantial, and required lots of porting effort. Please consider that
this version has access-control, and you will need to configure access
control (only localhost enabled by default). It also has AS112 blocking,
which may be nice for you, and limited authority support. Please ignore
the unbound-as-a-library development code in there, it is not done.
Can you try this Alexander? Tell me if it works or not
Note that this is a snapshot from trunk since the changes are
substantial, and required lots of porting effort. Please consider that
this version has access-control, and you will need to configure access
control (only localhost enabled by default). It also has AS112 blocking,
which may be nice for you, and limited authority support. Please ignore
the unbound-as-a-library development code in there, it is not done.
Thanks. It compiles fine on Linux, but only when I use LIBS="-lldns
-lcrypto" with make. I didn't track this down in the Makefile, but
these options appear to be missing in some linker rules. The 0.7.2
release only required LIBS=-ldns.
Can you try this Alexander? Tell me if it works or not
The code seems to work on Linux (kernel 2.6.12, glibc 2.3.6) as
expecyed. Great!
However, the query replies still use the wrong source address if the
query was directed to a loopback address. This is a bit orthogonal to
the issue with the sockets, but I believe you need to *always* request
the source address specifically and not rely on the kernel source
address selection as dicussed earlier.
Interestingly, I see a single socket for UDP but two for TCP (IPv4,
IPv6). Just wondering why.