From 67a1d3615dd7403a8ea982ba32d62d7dbd19ad1b Mon Sep 17 00:00:00 2001 From: Alexander Bluhm Date: Sat, 18 Jan 2014 21:14:47 +0000 Subject: There was an awkward behaviour after a connection had been diverted to a socket. When the application removed the socket, the pf state would persist. A new connection did not hit the divert rule as the state still grabed the packet. The solution is to unlink the associated divert state when the socket gets destroyed. This is possible as both are linked together and a divert state without socket does not make sense. OK mikeb@ --- sys/netinet/in_pcb.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'sys/netinet/in_pcb.c') diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 0c57d1140b4..67333ec24d2 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in_pcb.c,v 1.146 2013/12/20 02:04:08 krw Exp $ */ +/* $OpenBSD: in_pcb.c,v 1.147 2014/01/18 21:14:46 bluhm Exp $ */ /* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */ /* @@ -495,8 +495,21 @@ in_pcbdetach(struct inpcb *inp) ipsec_delete_policy(inp->inp_ipo); #endif #if NPF > 0 - if (inp->inp_pf_sk) - inp->inp_pf_sk->inp = NULL; + if (inp->inp_pf_sk) { + struct pf_state_key *sk; + struct pf_state_item *si; + + sk = inp->inp_pf_sk; + TAILQ_FOREACH(si, &sk->states, entry) + if (sk == si->s->key[PF_SK_STACK] && si->s->rule.ptr && + si->s->rule.ptr->divert.port) { + pf_unlink_state(si->s); + break; + } + /* pf_unlink_state() may have detached the state */ + if (inp->inp_pf_sk) + inp->inp_pf_sk->inp = NULL; + } #endif s = splnet(); LIST_REMOVE(inp, inp_lhash); -- cgit v1.2.3