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.

Reply via email to