in releases prior to 15.0 we followed RFC3513, which did not allow
sending any packets from an anycast address, by forbidding any attempt
to bind to an anycast address and rejecting incoming TCP connections to
a local anycast address.
recently this was changed to allow binding to an anycast address so that
UDP services could use an anycast address. however, TCP anycast was
still forbidden.
D50019 proposed removing the TCP restriction to allow full use of
anycast addresses by applications, but the consensus was that this is
too permissive and introduces the risk of a user configuring a stateful
service over an anycast address without understanding the implications.
however, we do want to permit TCP anycast for e.g. DNS servers, which
require both UDP and TCP, and where TCP anycast is in wide use at
scale[0]. so, introduce a new sysctl net.inet6.ip6.ip6_rfc4291_anycast,
which controls the behaviour of anycast addresses.
if the sysctl is set to 0, which is the default:
- binding a UDP socket to an anycast address is permitted; this allows UDP services to receive data sent to an anycast address (e.g., for anycast monitoring or data collection services).
- sending UDP packets with an anycast source address is forbidden.
- binding a TCP socket to an anycast address is forbidden.
- incoming TCP connections to an anycast address are rejected.
except for the first point, this largely matches the pre-15.0 behaviour,
but we now reject TCP connections with a RST rather than an ICMP error
because according to RFC4291 we're allowed to do that.
if the sysctl is set to 1:
- outgoing UDP packets from an anycast address are permitted.
- binding a TCP socket to an anycast address is permitted.
- incoming TCP connections to an anycast address are permitted.
this allows the user to use anycast addresses for stateful protocols
when they understand the risks, but protects them from doing this
accidentally.
in both cases, raw sockets are treated the same as UDP, i.e. by default
they can receive traffic but not send it.
this does not change the default source selection logic: an anycast
address will never be chosen as the default source address. the user
has to explicitly bind the socket regardless of the sysctl setting.
document this behaviour in inet6.4, and add a pointer there from the
'anycast' option in ifconfig.8.
add some basic tests for TCP and raw sockets.