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))