Hi,

With pf divert raw sockets behave differently than TCP or UDP.

TCP and UDP first make an exact match without divert in_pcbhashlookup().
Then they do the divert-to match in in_pcblookup_listen().

This diff makes it consistent.  Search for bound and connected
sockets in raw_input() also if diverted, only use unconnected sockets
with divert-to.

ok?

bluhm

Index: netinet/raw_ip.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/raw_ip.c,v
retrieving revision 1.108
diff -u -p -r1.108 raw_ip.c
--- netinet/raw_ip.c    4 Dec 2017 13:40:34 -0000       1.108
+++ netinet/raw_ip.c    15 Dec 2017 12:59:29 -0000
@@ -121,7 +121,7 @@ rip_input(struct mbuf **mp, int *offp, i
        struct mbuf *m = *mp;
        struct ip *ip = mtod(m, struct ip *);
        struct inpcb *inp, *last = NULL;
-       struct in_addr *key;
+       struct in_addr *key = NULL;
        struct mbuf *opts = NULL;
        struct counters_ref ref;
        uint64_t *counters;
@@ -129,7 +129,6 @@ rip_input(struct mbuf **mp, int *offp, i
        KASSERT(af == AF_INET);
 
        ripsrc.sin_addr = ip->ip_src;
-       key = &ip->ip_dst;
 #if NPF > 0
        if (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) {
                struct pf_divert *divert;
@@ -163,7 +162,10 @@ rip_input(struct mbuf **mp, int *offp, i
                if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
                        continue;
                if (inp->inp_laddr.s_addr &&
-                   inp->inp_laddr.s_addr != key->s_addr)
+                   inp->inp_laddr.s_addr != ip->ip_dst.s_addr &&
+                   /* divert-to matches on bound but unconnected socket */
+                   (key == NULL || inp->inp_faddr.s_addr ||
+                   inp->inp_laddr.s_addr != key->s_addr))
                        continue;
                if (inp->inp_faddr.s_addr &&
                    inp->inp_faddr.s_addr != ip->ip_src.s_addr)
Index: netinet6/raw_ip6.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/raw_ip6.c,v
retrieving revision 1.125
diff -u -p -r1.125 raw_ip6.c
--- netinet6/raw_ip6.c  4 Dec 2017 13:40:35 -0000       1.125
+++ netinet6/raw_ip6.c  15 Dec 2017 12:59:29 -0000
@@ -122,7 +122,7 @@ rip6_input(struct mbuf **mp, int *offp, 
        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
        struct inpcb *in6p;
        struct inpcb *last = NULL;
-       struct in6_addr *key;
+       struct in6_addr *key = NULL;
        struct sockaddr_in6 rip6src;
        struct mbuf *opts = NULL;
 
@@ -137,7 +137,6 @@ rip6_input(struct mbuf **mp, int *offp, 
        /* KAME hack: recover scopeid */
        in6_recoverscope(&rip6src, &ip6->ip6_src);
 
-       key = &ip6->ip6_dst;
 #if NPF > 0
        if (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) {
                struct pf_divert *divert;
@@ -167,7 +166,10 @@ rip6_input(struct mbuf **mp, int *offp, 
                    in6p->inp_ipv6.ip6_nxt != proto)
                        continue;
                if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->inp_laddr6) &&
-                   !IN6_ARE_ADDR_EQUAL(&in6p->inp_laddr6, key))
+                   !IN6_ARE_ADDR_EQUAL(&in6p->inp_laddr6, &ip6->ip6_dst) &&
+                   /* divert-to matches on bound but unconnected socket */
+                   (key == NULL || !IN6_IS_ADDR_UNSPECIFIED(&in6p->inp_faddr6)
+                   || !IN6_ARE_ADDR_EQUAL(&in6p->inp_laddr6, key)))
                        continue;
                if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->inp_faddr6) &&
                    !IN6_ARE_ADDR_EQUAL(&in6p->inp_faddr6, &ip6->ip6_src))

Reply via email to