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