Commits

Anonymous committed a8bf041

make sure the entry from tree_src_tracking is still in the pool;
fixes nat with sticky address and ip address change on pppoe(4) for example;
ok henning@, zinke@; mikeb@

  • Participants
  • Parent commits a2d8653

Comments (0)

Files changed (1)

File sys/net/pf_lb.c

-/*	$OpenBSD: pf_lb.c,v 1.23 2012/12/29 14:54:45 markus Exp $ */
+/*	$OpenBSD: pf_lb.c,v 1.24 2012/12/29 14:59:52 markus Exp $ */
 
 /*
  * Copyright (c) 2001 Daniel Hartmeier
 			    u_int16_t, struct pf_src_node **);
 int			 pf_get_transaddr_af(struct pf_rule *,
 			    struct pf_pdesc *, struct pf_src_node **);
+int			 pf_map_addr_sticky(sa_family_t, struct pf_rule *,
+			    struct pf_addr *, struct pf_addr *,
+			    struct pf_src_node **, struct pf_pool *,
+			    enum pf_sn_types);
 
 #define mix(a,b,c) \
 	do {					\
 }
 
 int
+pf_map_addr_sticky(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
+    struct pf_addr *naddr, struct pf_src_node **sns, struct pf_pool *rpool,
+    enum pf_sn_types type)
+{
+	struct pf_addr		*raddr, *rmask, *cached;
+	struct pf_state		*s;
+	struct pf_src_node	 k;
+	int			 valid;
+
+	k.af = af;
+	k.type = type;
+	PF_ACPY(&k.addr, saddr, af);
+	k.rule.ptr = r;
+	pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
+	sns[type] = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
+	if (sns[type] == NULL)
+		return (-1);
+
+	/* check if the cached entry is still valid */
+	cached = &(sns[type])->raddr;
+	valid = 0;
+	if (PF_AZERO(cached, af)) {
+		valid = 1;
+	} else if (rpool->addr.type == PF_ADDR_DYNIFTL) {
+		if (pfr_kentry_byaddr(rpool->addr.p.dyn->pfid_kt, cached,
+		    af, 0))
+			valid = 1;
+	} else if (rpool->addr.type == PF_ADDR_TABLE) {
+		if (pfr_kentry_byaddr(rpool->addr.p.tbl, cached, af, 0))
+			valid = 1;
+	} else if (rpool->addr.type != PF_ADDR_NOROUTE) {
+		raddr = &rpool->addr.v.a.addr;
+		rmask = &rpool->addr.v.a.mask;
+		valid = pf_match_addr(0, raddr, rmask, cached, af);
+	}
+	if (!valid) {
+		if (pf_status.debug >= LOG_DEBUG) {
+			log(LOG_DEBUG, "pf: pf_map_addr: "
+			    "stale src tracking (%u) ", type);
+			pf_print_host(&k.addr, 0, af);
+			addlog(" to ");
+			pf_print_host(cached, 0, af);
+			addlog("\n");
+		}
+		if (sns[type]->states != 0) {
+			/* XXX expensive */
+			RB_FOREACH(s, pf_state_tree_id,
+			   &tree_id)
+				pf_state_rm_src_node(s,
+				    sns[type]);
+		}
+		sns[type]->expire = 1;
+		pf_remove_src_node(sns[type]);
+		sns[type] = NULL;
+		return (-1);
+	}
+	if (!PF_AZERO(cached, af))
+		PF_ACPY(naddr, cached, af);
+	if (pf_status.debug >= LOG_DEBUG) {
+		log(LOG_DEBUG, "pf: pf_map_addr: "
+		    "src tracking (%u) maps ", type);
+		pf_print_host(&k.addr, 0, af);
+		addlog(" to ");
+		pf_print_host(naddr, 0, af);
+		addlog("\n");
+	}
+	return (0);
+}
+
+int
 pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
     struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sns,
     struct pf_pool *rpool, enum pf_sn_types type)
 	struct pf_addr		 faddr;
 	struct pf_addr		*raddr = &rpool->addr.v.a.addr;
 	struct pf_addr		*rmask = &rpool->addr.v.a.mask;
-	struct pf_src_node	 k;
 	u_int64_t		 states;
 	u_int16_t		 weight;
 	u_int64_t		 load;
 	u_int64_t		 cload;
 
 	if (sns[type] == NULL && rpool->opts & PF_POOL_STICKYADDR &&
-	    (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
-		k.af = af;
-		k.type = type;
-		PF_ACPY(&k.addr, saddr, af);
-		k.rule.ptr = r;
-		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
-		sns[type] = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
-		if (sns[type] != NULL) {
-			if (!PF_AZERO(&(sns[type])->raddr, af))
-				PF_ACPY(naddr, &(sns[type])->raddr, af);
-			if (pf_status.debug >= LOG_DEBUG) {
-				log(LOG_DEBUG, "pf: pf_map_addr: "
-				    "src tracking (%u) maps ", type);
-				pf_print_host(&k.addr, 0, af);
-				addlog(" to ");
-				pf_print_host(naddr, 0, af);
-				addlog("\n");
-			}
-			return (0);
-		}
-	}
+	    (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE &&
+	    pf_map_addr_sticky(af, r, saddr, naddr, sns, rpool, type) == 0)
+		return (0);
 
 	if (rpool->addr.type == PF_ADDR_NOROUTE)
 		return (1);