diff options
-rw-r--r-- | sys/net/pf_lb.c | 101 |
1 files changed, 78 insertions, 23 deletions
diff --git a/sys/net/pf_lb.c b/sys/net/pf_lb.c index 70e6d9dc3f0..d129a54eaf6 100644 --- a/sys/net/pf_lb.c +++ b/sys/net/pf_lb.c @@ -1,4 +1,4 @@ -/* $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 @@ -106,6 +106,10 @@ int pf_get_sport(struct pf_pdesc *, struct pf_rule *, 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 { \ @@ -268,6 +272,76 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_rule *r, } 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) @@ -276,34 +350,15 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, 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); |