support divert-to when pf applies it to a packet.
authordlg <dlg@openbsd.org>
Wed, 26 May 2021 02:38:01 +0000 (02:38 +0000)
committerdlg <dlg@openbsd.org>
Wed, 26 May 2021 02:38:01 +0000 (02:38 +0000)
when a divert-to rule applies to a packet, pf doesnt take the packet
away and shove it in the socket directly. pf marks the packet, and
then ip (or ipv6) input processing looks at the mark and picks the
local socket to queue it on. because veb operates at layer 2, ip
input processing only occurred if the packet was destined to go
into a vport interface.

bridge(4) handles this by checking if the packet has the pf divert
to mark set on it and calls ip input if it's set. this copies the
semantic to veb.

this allows divert-to to steal (take?) packets going over a veb and
process them on a local socket.

reported by ajacatot@

sys/net/if_veb.c

index 6b141bf..32a0146 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_veb.c,v 1.16 2021/03/10 10:21:48 jsg Exp $ */
+/*     $OpenBSD: if_veb.c,v 1.17 2021/05/26 02:38:01 dlg Exp $ */
 
 /*
  * Copyright (c) 2021 David Gwynne <dlg@openbsd.org>
@@ -500,6 +500,7 @@ veb_pf(struct ifnet *ifp0, int dir, struct mbuf *m)
 {
        struct ether_header *eh, copy;
        sa_family_t af = AF_UNSPEC;
+       void (*ip_input)(struct ifnet *, struct mbuf *) = NULL;
 
        /*
         * pf runs on vport interfaces when they enter or leave the
@@ -515,10 +516,14 @@ veb_pf(struct ifnet *ifp0, int dir, struct mbuf *m)
        switch (ntohs(eh->ether_type)) {
        case ETHERTYPE_IP:
                af = AF_INET;
+               ip_input = ipv4_input;
                break;
+#ifdef INET6
        case ETHERTYPE_IPV6:
                af = AF_INET6;
+               ip_input = ipv6_input;
                break;
+#endif
        default:
                return (m);
        }
@@ -533,6 +538,11 @@ veb_pf(struct ifnet *ifp0, int dir, struct mbuf *m)
        if (m == NULL)
                return (NULL);
 
+       if (dir == PF_IN && ISSET(m->m_pkthdr.pf.flags, PF_TAG_DIVERTED)) {
+               (*ip_input)(ifp0, m);
+               return (NULL);
+       }
+
        m = m_prepend(m, sizeof(*eh), M_DONTWAIT);
        if (m == NULL)
                return (NULL);