On Sun, Oct 18, 2020 at 08:57:34PM +0100, Stuart Henderson wrote:
> On 2020/10/18 14:04, David Gwynne wrote:
> > the problem i'm hitting is that i have a multihomed box where the
> > service it provides listens on an IP address that's assigned to lo1.
> > it's a host running a service, it's not a router, so the
> > net.inet.ip.forwarding sysctl is not set to 1.
>
> I ran into this, I just turned on the forwarding sysctl to avoid the
> problem.
>
> > i came up with this diff, which adds even more special casing for
> > loopback interfaces. it says addreesses on loopbacks are globally
> > reachable, even if ip forwarding is disabled.
>
> I don't see why loopbacks should be special. Another place this
> might show up is services running on carp addresses (I haven't updated
> those machines yet but there's a fair chance they'll be affected too).
> I would prefer an explicit sysctl to disable "strong host model".
loopback is already special. if a packet comes from an loopback
interface, we allow it to talk to any IP on the local machine. i think
this is mostly to cope with the semantic we've had where local traffic
get's tied to a loopback interface instead of going anywhere near the
physical ones.
carp is also special.
let me paste the ip_laddr function instead of the diff to it, it's a bit
more obvious what's going on:
int
ip_laddr(struct ifnet *ifp, struct mbuf *m, struct rtentry *rt)
{
struct ifnet *rtifp;
int match = 0;
if (rt->rt_ifidx == ifp->if_index ||
ifp->if_type == IFT_ENC ||
ISSET(ifp->if_flags, IFF_LOOPBACK) ||
ISSET(m->m_pkthdr.pf.flags, PF_TAG_TRANSLATE_LOCALHOST))
return (1);
/* received on a different interface. */
rtifp = if_get(rt->rt_ifidx);
if (rtifp != NULL) {
if (ISSET(rtifp->if_flags, IFF_LOOPBACK))
match = 1;
#if NCARP > 0
/*
* Virtual IPs on carp interfaces need to be checked also
* against the parent interface and other carp interfaces
* sharing the same parent.
*/
else if (carp_strict_addr_chk(rtifp, ifp))
match = 1;
#endif
}
if_put(rtifp);
return (match);
}
the only thing i've added above is the
ISSET(rtifp->if_flags, IFF_LOOPBACK) check. everything else is already
in place.
here's the code for carp_strict_addr_chk:
/*
* If two carp interfaces share same physical interface, then we pretend all IP
* addresses belong to single interface.
*/
static inline int
carp_strict_addr_chk(struct ifnet *ifp_a, struct ifnet *ifp_b)
{
return ((ifp_a->if_type == IFT_CARP &&
ifp_b->if_index == ifp_a->if_carpdevidx) ||
(ifp_b->if_type == IFT_CARP &&
ifp_a->if_index == ifp_b->if_carpdevidx) ||
(ifp_a->if_type == IFT_CARP && ifp_b->if_type == IFT_CARP &&
ifp_a->if_carpdevidx == ifp_b->if_carpdevidx));
}
back to loopback and receiving packets. loopback is special because it
is not connected to the outside world. it is impossible to send a packet
via a loopback interface from another host, so configuring a globally
(externally) routable IP on it is currently pointless unless you enable
forwarding. i think making loopback more special and allowing it
to be globally reachable makes sense. i can't think of any downsides to
this at the moment, except that the behaviour would be subtle/not
obvious
is there a need to configure a globally reachable IP on a non-loopback
interface on a host (not router)? if so, then i'd be more convinced that
we need a separate lever to pull.