[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openbsd-tech
Subject:    Re: pf_create_state() is sometimes better to use pf_unlink_state()
From:       Alexandr Nedvedicky <alexandr.nedvedicky () oracle ! com>
Date:       2015-05-28 21:46:14
Message-ID: 20150528214614.GP13938 () tbd ! cz ! oracle ! com
[Download RAW message or body]

</snip>
> >>
> >> But we'll drop this "reference" in pf_src_tree_remove_state,
> >> then how will sns[PF_SN_NAT] and sns[PF_SN_ROUTE] be different?
> >
> > I think I should take PF class again ;-) I've just realized there
> > is a test in pf_remove_src_node():
> >
> >     572         if (sn->states > 0 || sn->expire > time_uptime)
> >     573                 return;
> >
> > so it will do the right thing. This is the piece I was missing.
> >
> >>
> >> sns[] array was prepared for this state so if we can't insert
> >> the state, sns entries must be cleaned up.  pf_remove_src_node
> >> checks the number of associated states and if source node should
> >> expire some time later.
> >
> > yes, it seems more clear to me now.
> >
> 
> Good! At least I wasn't blind this time! (:
> 
> >>
> >> Speaking of PF_SN_ROUTE, pf_set_rt_ifp should be probably called
> >> before we insert the state for the very same reason, plus it
> >> should check the pf_map_addr return value and do the cleanup.
> >
> > I don't feel entirely qualified now, to discuss the matter ;-)
> 
> Hey, don't worry about it.  Half of the people reading this have
> zero clue as to what the hell are we talking about.
> 
> > however
> > pf_set_rt_ifp() should indeed test return value of pf_map_addr(), In case of
> > failure the error should be thrown further up, so pf_create_state() can handle
> > it. Probably jumping to csfailed: should be sufficient.
> >
> 
> You can't just jump to csfailed unless you do a pf_set_rt_ifp
> before the pf_state_insert, but then it needs an attached key
> to only get it's address family.

true, because once pf_state_insert() succeeds, it's no longer job for csfailed:
branch to clean up a state.  I currently have no better suggestion than taking
the easiest move:

	add  af argument to pf_set_rt_ifp() and fetch it from skw,
	in pf_create_state().

Actually there is an option: 
	remove KASSERT() at 655 in pf_state_key_attach().
    659 pf_state_key_attach(struct pf_state_key *sk, struct pf_state *s, int idx)
    660 {
    661         struct pf_state_item    *si;
    662         struct pf_state_key     *cur;
    663         struct pf_state         *olds = NULL;
    664
    665         KASSERT(s->key[idx] == NULL);
	Then we can simply do:
		 s->key[PF_SK_WIRE] = skw;
	in pf_create_state(), so pf_set_rt_ifp() will get what it expects.

adding af argument to pf_set_rt_if() seems more clean approach to me.
below is your patch with reshuffled pf_create_state(), so pf_set_rt_ifp()
gets called before, pf_state_insert(). I've introduced a new reason:
	PFRES_NOROUTE
however I'm not sure if it is descriptive enough...

regards
sasha


? create_state.diff
? pf.c.diff
? pf.c.patch
Index: pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.916
diff -u -r1.916 pf.c
--- pf.c	26 May 2015 16:17:51 -0000	1.916
+++ pf.c	28 May 2015 21:38:09 -0000
@@ -204,8 +204,8 @@
 u_int16_t		 pf_get_mss(struct pf_pdesc *);
 u_int16_t		 pf_calc_mss(struct pf_addr *, sa_family_t, int,
 				u_int16_t);
-void			 pf_set_rt_ifp(struct pf_state *,
-			    struct pf_addr *);
+int			 pf_set_rt_ifp(struct pf_state *,
+			    struct pf_addr *, sa_family_t);
 struct pf_divert	*pf_get_divert(struct mbuf *);
 int			 pf_walk_option6(struct pf_pdesc *, struct ip6_hdr *,
 			    int, int, u_short *);
@@ -2958,32 +2958,39 @@
 	return (mss);
 }
 
-void
-pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
+int
+pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr, sa_family_t af)
 {
 	struct pf_rule *r = s->rule.ptr;
 	struct pf_src_node *sns[PF_SN_MAX];
+	int	rv;
 
 	s->rt_kif = NULL;
 	if (!r->rt)
-		return;
+		return (0);
+
 	bzero(sns, sizeof(sns));
-	switch (s->key[PF_SK_WIRE]->af) {
+	switch (af) {
 	case AF_INET:
-		pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL, sns,
+		rv = pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL, sns,
 		    &r->route, PF_SN_ROUTE);
-		s->rt_kif = r->route.kif;
-		s->natrule.ptr = r;
 		break;
 #ifdef INET6
 	case AF_INET6:
-		pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL, sns,
+		rv = pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL, sns,
 		    &r->route, PF_SN_ROUTE);
-		s->rt_kif = r->route.kif;
-		s->natrule.ptr = r;
 		break;
 #endif /* INET6 */
+	default:
+		rv = 1;
 	}
+
+	if (rv == 0) {
+		s->rt_kif = r->route.kif;
+		s->natrule.ptr = r;
+	}
+
+	return (rv);
 }
 
 u_int32_t
@@ -3557,16 +3564,6 @@
 		goto csfailed;
 	}
 
-	if (pf_state_insert(BOUND_IFACE(r, pd->kif), skw, sks, s)) {
-		pf_state_key_detach(s, PF_SK_STACK);
-		pf_state_key_detach(s, PF_SK_WIRE);
-		*sks = *skw = NULL;
-		REASON_SET(&reason, PFRES_STATEINS);
-		goto csfailed;
-	} else
-		*sm = s;
-
-	/* attach src nodes late, otherwise cleanup on error nontrivial */
 	for (i = 0; i < PF_SN_MAX; i++)
 		if (sns[i] != NULL) {
 			struct pf_sn_item	*sni;
@@ -3574,17 +3571,26 @@
 			sni = pool_get(&pf_sn_item_pl, PR_NOWAIT);
 			if (sni == NULL) {
 				REASON_SET(&reason, PFRES_MEMORY);
-				pf_src_tree_remove_state(s);
-				STATE_DEC_COUNTERS(s);
-				pool_put(&pf_state_pl, s);
-				return (PF_DROP);
+				goto csfailed;
 			}
 			sni->sn = sns[i];
 			SLIST_INSERT_HEAD(&s->src_nodes, sni, next);
 			sni->sn->states++;
 		}
 
-	pf_set_rt_ifp(s, pd->src);	/* needs s->state_key set */
+	if (pf_set_rt_ifp(s, pd->src, (*skw)->af) != 0) {
+		REASON_SET(&reason, PFRES_NOROUTE);
+		goto csfailed;
+	}
+
+	if (pf_state_insert(BOUND_IFACE(r, pd->kif), skw, sks, s)) {
+		pf_detach_state(s);
+		*sks = *skw = NULL;
+		REASON_SET(&reason, PFRES_STATEINS);
+		goto csfailed;
+	} else
+		*sm = s;
+
 	if (tag > 0) {
 		pf_tag_ref(tag);
 		s->tag = tag;
@@ -3612,12 +3618,16 @@
 	return (PF_PASS);
 
 csfailed:
+	if (s) {
+		pf_normalize_tcp_cleanup(s);	/* safe even w/o init */
+		pf_src_tree_remove_state(s);
+	}
+
 	for (i = 0; i < PF_SN_MAX; i++)
 		if (sns[i] != NULL)
 			pf_remove_src_node(sns[i]);
+
 	if (s) {
-		pf_normalize_tcp_cleanup(s);	/* safe even w/o init */
-		pf_src_tree_remove_state(s);
 		STATE_DEC_COUNTERS(s);
 		pool_put(&pf_state_pl, s);
 	}
Index: pfvar.h
===================================================================
RCS file: /cvs/src/sys/net/pfvar.h,v
retrieving revision 1.414
diff -u -r1.414 pfvar.h
--- pfvar.h	11 Apr 2015 13:00:12 -0000	1.414
+++ pfvar.h	28 May 2015 21:38:09 -0000
@@ -1316,7 +1316,8 @@
 #define PFRES_SRCLIMIT	13		/* Source node/conn limit */
 #define PFRES_SYNPROXY	14		/* SYN proxy */
 #define PFRES_TRANSLATE	15		/* No translation address available */
-#define PFRES_MAX	16		/* total+1 */
+#define	PFRES_NOROUTE	16		/* No route found for PBR action */
+#define PFRES_MAX	17		/* total+1 */
 
 #define PFRES_NAMES { \
 	"match", \
@@ -1335,6 +1336,7 @@
 	"src-limit", \
 	"synproxy", \
 	"translate", \
+	"no-route", \
 	NULL \
 }
 

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic