summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/pfctl/pfctl_parser.c28
-rw-r--r--sys/net/if_pfsync.c4
-rw-r--r--sys/net/pf.c231
-rw-r--r--sys/net/pf_ioctl.c20
-rw-r--r--sys/net/pf_lb.c53
-rw-r--r--sys/net/pfvar.h60
6 files changed, 244 insertions, 152 deletions
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 99c5b04164e..04c05d56ba8 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.c,v 1.252 2009/11/23 21:29:21 henning Exp $ */
+/* $OpenBSD: pfctl_parser.c,v 1.253 2009/12/14 12:31:45 henning Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -619,9 +619,20 @@ print_src_node(struct pf_src_node *sn, int opts)
aw.v.a.addr = sn->addr;
print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2);
- printf(" -> ");
- aw.v.a.addr = sn->raddr;
- print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2);
+
+ if (!PF_AZERO(&sn->raddr, sn->af)) {
+ if (sn->type == PF_SN_NAT)
+ printf(" nat-to ");
+ else if (sn->type == PF_SN_RDR)
+ printf(" rdr-to ");
+ else if (sn->type == PF_SN_ROUTE)
+ printf(" route-to ");
+ else
+ printf(" ??? (%u) ", sn->type);
+ aw.v.a.addr = sn->raddr;
+ print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2);
+ }
+
printf(" ( states %u, connections %u, rate %u.%u/%us )\n", sn->states,
sn->conn, sn->conn_rate.count / 1000,
(sn->conn_rate.count % 1000) / 100, sn->conn_rate.seconds);
@@ -642,13 +653,8 @@ print_src_node(struct pf_src_node *sn, int opts)
printf(", %llu pkts, %llu bytes",
sn->packets[0] + sn->packets[1],
sn->bytes[0] + sn->bytes[1]);
- switch (sn->ruletype) {
- case PF_PASS:
- case PF_MATCH:
- if (sn->rule.nr != -1)
- printf(", filter rule %u", sn->rule.nr);
- break;
- }
+ if (sn->rule.nr != -1)
+ printf(", rule %u", sn->rule.nr);
printf("\n");
}
}
diff --git a/sys/net/if_pfsync.c b/sys/net/if_pfsync.c
index 57d9a768e20..3f19771e2e8 100644
--- a/sys/net/if_pfsync.c
+++ b/sys/net/if_pfsync.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_pfsync.c,v 1.134 2009/12/03 12:23:52 otto Exp $ */
+/* $OpenBSD: if_pfsync.c,v 1.135 2009/12/14 12:31:45 henning Exp $ */
/*
* Copyright (c) 2002 Michael Shalayeff
@@ -429,7 +429,7 @@ pfsync_state_export(struct pfsync_state *sp, struct pf_state *st)
sp->log = st->log;
sp->timeout = st->timeout;
sp->state_flags = st->state_flags;
- if (st->src_node)
+ if (!SLIST_EMPTY(&st->src_nodes))
sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
bcopy(&st->id, &sp->id, sizeof(sp->id));
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 295542377cf..6602cb57b69 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.678 2009/12/08 08:26:33 sthen Exp $ */
+/* $OpenBSD: pf.c,v 1.679 2009/12/14 12:31:45 henning Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -129,7 +129,7 @@ struct pf_anchor_stackframe {
struct pool pf_src_tree_pl, pf_rule_pl, pf_pooladdr_pl;
struct pool pf_state_pl, pf_state_key_pl, pf_state_item_pl;
-struct pool pf_altq_pl, pf_rule_item_pl;
+struct pool pf_altq_pl, pf_rule_item_pl, pf_sn_item_pl;
void pf_init_threshold(struct pf_threshold *, u_int32_t,
u_int32_t);
@@ -175,7 +175,7 @@ static __inline int pf_create_state(struct pf_rule *, struct pf_rule *,
u_int16_t, int *, struct pfi_kif *,
struct pf_state **, int, u_int16_t, u_int16_t,
int, struct pf_rule_slist *,
- struct pf_rule_actions *);
+ struct pf_rule_actions *, struct pf_src_node *[]);
void pf_translate(struct pf_pdesc *, struct pf_addr *,
u_int16_t, struct pf_addr *, u_int16_t, u_int16_t,
int, struct mbuf *, int);
@@ -316,6 +316,8 @@ pf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
return (1);
if (a->rule.ptr < b->rule.ptr)
return (-1);
+ if ((diff = a->type - b->type) != 0)
+ return (diff);
if ((diff = a->af - b->af) != 0)
return (diff);
switch (a->af) {
@@ -404,21 +406,24 @@ pf_check_threshold(struct pf_threshold *threshold)
int
pf_src_connlimit(struct pf_state **state)
{
- int bad = 0;
+ int bad = 0;
+ struct pf_src_node *sn;
+
+ if ((sn = pf_get_src_node((*state), PF_SN_NONE)) == NULL)
+ return (0);
- (*state)->src_node->conn++;
+ sn->conn++;
(*state)->src.tcp_est = 1;
- pf_add_threshold(&(*state)->src_node->conn_rate);
+ pf_add_threshold(&sn->conn_rate);
if ((*state)->rule.ptr->max_src_conn &&
- (*state)->rule.ptr->max_src_conn <
- (*state)->src_node->conn) {
+ (*state)->rule.ptr->max_src_conn < sn->conn) {
pf_status.lcounters[LCNT_SRCCONN]++;
bad++;
}
if ((*state)->rule.ptr->max_src_conn_rate.limit &&
- pf_check_threshold(&(*state)->src_node->conn_rate)) {
+ pf_check_threshold(&sn->conn_rate)) {
pf_status.lcounters[LCNT_SRCCONNRATE]++;
bad++;
}
@@ -433,7 +438,7 @@ pf_src_connlimit(struct pf_state **state)
pf_status.lcounters[LCNT_OVERLOAD_TABLE]++;
if (pf_status.debug >= PF_DEBUG_MISC) {
printf("pf_src_connlimit: blocking address ");
- pf_print_host(&(*state)->src_node->addr, 0,
+ pf_print_host(&sn->addr, 0,
(*state)->key[PF_SK_WIRE]->af);
}
@@ -443,13 +448,13 @@ pf_src_connlimit(struct pf_state **state)
#ifdef INET
case AF_INET:
p.pfra_net = 32;
- p.pfra_ip4addr = (*state)->src_node->addr.v4;
+ p.pfra_ip4addr = sn->addr.v4;
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
p.pfra_net = 128;
- p.pfra_ip6addr = (*state)->src_node->addr.v6;
+ p.pfra_ip6addr = sn->addr.v6;
break;
#endif /* INET6 */
}
@@ -473,11 +478,9 @@ pf_src_connlimit(struct pf_state **state)
if (sk->af ==
(*state)->key[PF_SK_WIRE]->af &&
(((*state)->direction == PF_OUT &&
- PF_AEQ(&(*state)->src_node->addr,
- &sk->addr[0], sk->af)) ||
+ PF_AEQ(&sn->addr, &sk->addr[0], sk->af)) ||
((*state)->direction == PF_IN &&
- PF_AEQ(&(*state)->src_node->addr,
- &sk->addr[1], sk->af))) &&
+ PF_AEQ(&sn->addr, &sk->addr[1], sk->af))) &&
((*state)->rule.ptr->flush &
PF_FLUSH_GLOBAL ||
(*state)->rule.ptr == st->rule.ptr)) {
@@ -502,19 +505,19 @@ pf_src_connlimit(struct pf_state **state)
int
pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
- struct pf_addr *src, sa_family_t af)
+ enum pf_sn_types type, sa_family_t af, struct pf_addr *src,
+ struct pf_addr *raddr, int global)
{
struct pf_src_node k;
if (*sn == NULL) {
k.af = af;
+ k.type = type;
PF_ACPY(&k.addr, src, af);
- if (rule->rule_flag & PFRULE_RULESRCTRACK ||
- rule->nat.opts & PF_POOL_STICKYADDR ||
- rule->rdr.opts & PF_POOL_STICKYADDR)
- k.rule.ptr = rule;
- else
+ if (global)
k.rule.ptr = NULL;
+ else
+ k.rule.ptr = rule;
pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
*sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
}
@@ -531,14 +534,15 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
rule->max_src_conn_rate.limit,
rule->max_src_conn_rate.seconds);
+ (*sn)->type = type;
(*sn)->af = af;
- if (rule->rule_flag & PFRULE_RULESRCTRACK ||
- rule->nat.opts & PF_POOL_STICKYADDR ||
- rule->rdr.opts & PF_POOL_STICKYADDR)
- (*sn)->rule.ptr = rule;
- else
+ if (global)
(*sn)->rule.ptr = NULL;
+ else
+ (*sn)->rule.ptr = rule;
PF_ACPY(&(*sn)->addr, src, af);
+ if (raddr)
+ PF_ACPY(&(*sn)->raddr, raddr, af);
if (RB_INSERT(pf_src_tree,
&tree_src_tracking, *sn) != NULL) {
if (pf_status.debug >= PF_DEBUG_MISC) {
@@ -550,7 +554,6 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
return (-1);
}
(*sn)->creation = time_second;
- (*sn)->ruletype = rule->action;
if ((*sn)->rule.ptr != NULL)
(*sn)->rule.ptr->src_nodes++;
pf_status.scounters[SCNT_SRC_NODE_INSERT]++;
@@ -565,6 +568,54 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
return (0);
}
+void
+pf_remove_src_node(struct pf_src_node *sn)
+{
+ if (sn->states > 0 || sn->expire > time_second)
+ return;
+
+ if (sn->rule.ptr != NULL) {
+ sn->rule.ptr->src_nodes--;
+ if (sn->rule.ptr->states_cur <= 0 &&
+ sn->rule.ptr->max_src_nodes <= 0)
+ pf_rm_rule(NULL, sn->rule.ptr);
+ RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
+ pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
+ pf_status.src_nodes--;
+ pool_put(&pf_src_tree_pl, sn);
+ }
+}
+
+struct pf_src_node *
+pf_get_src_node(struct pf_state *s, enum pf_sn_types type)
+{
+ struct pf_sn_item *sni;
+
+ SLIST_FOREACH(sni, &s->src_nodes, next)
+ if (sni->sn->type == type)
+ return (sni->sn);
+ return (NULL);
+}
+
+void
+pf_state_rm_src_node(struct pf_state *s, struct pf_src_node *sn)
+{
+ struct pf_sn_item *sni, *snin, *snip = NULL;
+
+ for (sni = SLIST_FIRST(&s->src_nodes); sni; sni = snin) {
+ snin = SLIST_NEXT(sni, next);
+ if (sni->sn == sn) {
+ if (snip)
+ SLIST_REMOVE_NEXT(&s->src_nodes, snip, next);
+ else
+ SLIST_REMOVE_HEAD(&s->src_nodes, next);
+ pool_put(&pf_sn_item_pl, sni);
+ sn->states--;
+ }
+ snip = sni;
+ }
+}
+
/* state table stuff */
static __inline int
@@ -1063,16 +1114,7 @@ pf_purge_expired_src_nodes(int waslocked)
&tree_src_tracking, cur);
locked = 1;
}
- if (cur->rule.ptr != NULL) {
- cur->rule.ptr->src_nodes--;
- if (cur->rule.ptr->states_cur <= 0 &&
- cur->rule.ptr->max_src_nodes <= 0)
- pf_rm_rule(NULL, cur->rule.ptr);
- }
- RB_REMOVE(pf_src_tree, &tree_src_tracking, cur);
- pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
- pf_status.src_nodes--;
- pool_put(&pf_src_tree_pl, cur);
+ pf_remove_src_node(cur);
}
}
@@ -1083,20 +1125,22 @@ pf_purge_expired_src_nodes(int waslocked)
void
pf_src_tree_remove_state(struct pf_state *s)
{
- u_int32_t timeout;
+ u_int32_t timeout;
+ struct pf_sn_item *sni;
- if (s->src_node != NULL) {
+ while ((sni = SLIST_FIRST(&s->src_nodes)) != NULL) {
+ SLIST_REMOVE_HEAD(&s->src_nodes, next);
if (s->src.tcp_est)
- --s->src_node->conn;
- if (--s->src_node->states <= 0) {
+ --sni->sn->conn;
+ if (--sni->sn->states <= 0) {
timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
if (!timeout)
timeout =
pf_default_rule.timeout[PFTM_SRC_NODE];
- s->src_node->expire = time_second + timeout;
+ sni->sn->expire = time_second + timeout;
}
+ pool_put(&pf_sn_item_pl, sni);
}
- s->src_node = NULL;
}
/* callers should be at splsoftnet */
@@ -2586,14 +2630,14 @@ pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
#ifdef INET
case AF_INET:
pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL, &sn,
- &r->route);
+ &r->route, PF_SN_ROUTE);
s->rt_kif = r->route.cur->kif;
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL, &sn,
- &r->route);
+ &r->route, PF_SN_ROUTE);
s->rt_kif = r->route.cur->kif;
break;
#endif /* INET6 */
@@ -2662,6 +2706,7 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pf_ruleset *ruleset = NULL;
struct pf_rule_slist rules;
struct pf_rule_item *ri;
+ struct pf_src_node *sns[PF_SN_MAX];
struct tcphdr *th = pd->hdr.tcp;
struct pf_state_key *skw = NULL, *sks = NULL;
struct pf_rule_actions act;
@@ -2679,6 +2724,7 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
PF_ACPY(&daddr, pd->dst, pd->af);
bzero(&act, sizeof(act));
+ bzero(sns, sizeof(sns));
act.rtableid = -1;
SLIST_INIT(&rules);
@@ -2819,7 +2865,7 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
SLIST_INSERT_HEAD(&rules, ri, entry);
pf_rule_to_actions(r, &act);
pf_get_transaddr(r, pd, &saddr, &sport,
- &daddr, &dport);
+ &daddr, &dport, sns);
} else {
match = 1;
*rm = r;
@@ -2845,7 +2891,8 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
/* apply actions for last matching rule */
if (lastr && lastr->action != PF_MATCH) {
pf_rule_to_actions(lastr, &act);
- pf_get_transaddr(lastr, pd, &saddr, &sport, &daddr, &dport);
+ pf_get_transaddr(lastr, pd, &saddr, &sport, &daddr, &dport,
+ sns);
}
REASON_SET(&reason, PFRES_MATCH);
@@ -2853,6 +2900,7 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
if (act.log) {
struct pf_rule_item *mr;
+ /* XXX this is BEFORE nat/rdr are actually applied! */
if (r->log)
PFLOG_PACKET(kif, h, m, af, direction, reason,
r, a, ruleset, pd);
@@ -2922,9 +2970,17 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
if (!state_icmp && r->keep_state) {
int action;
+
+ if (r->rule_flag & PFRULE_SRCTRACK &&
+ pf_insert_src_node(&sns[PF_SN_NONE], r, PF_SN_NONE, pd->af,
+ pd->src, NULL, 0) != 0) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
+ goto cleanup;
+ }
+
action = pf_create_state(r, a, pd, &skw, &sks, m,
off, &saddr, sport, &daddr, dport, &rewrite, kif, sm, tag,
- bproto_sum, bip_sum, hdrlen, &rules, &act);
+ bproto_sum, bip_sum, hdrlen, &rules, &act, sns);
if (action != PF_PASS)
return (action);
@@ -2983,13 +3039,14 @@ pf_create_state(struct pf_rule *r, struct pf_rule *a, struct pf_pdesc *pd,
int off, struct pf_addr *saddr, u_int16_t sport, struct pf_addr *daddr,
u_int16_t dport, int *rewrite, struct pfi_kif *kif, struct pf_state **sm,
int tag, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen,
- struct pf_rule_slist *rules, struct pf_rule_actions *act)
+ struct pf_rule_slist *rules, struct pf_rule_actions *act,
+ struct pf_src_node *sns[PF_SN_MAX])
{
struct pf_state *s = NULL;
- struct pf_src_node *sn = NULL;
struct tcphdr *th = pd->hdr.tcp;
u_int16_t mss = tcp_mssdflt;
u_short reason;
+ u_int i;
/* check maximums */
if (r->max_states && (r->states_cur >= r->max_states)) {
@@ -2997,14 +3054,7 @@ pf_create_state(struct pf_rule *r, struct pf_rule *a, struct pf_pdesc *pd,
REASON_SET(&reason, PFRES_MAXSTATES);
return (PF_DROP);
}
- /* src node for filter rule */
- if ((r->rule_flag & PFRULE_SRCTRACK ||
- r->rdr.opts & PF_POOL_STICKYADDR ||
- r->nat.opts & PF_POOL_STICKYADDR) &&
- pf_insert_src_node(&sn, r, pd->src, pd->af) != 0) {
- REASON_SET(&reason, PFRES_SRCLIMIT);
- goto csfailed;
- }
+
s = pool_get(&pf_state_pl, PR_NOWAIT | PR_ZERO);
if (s == NULL) {
REASON_SET(&reason, PFRES_MEMORY);
@@ -3086,10 +3136,7 @@ pf_create_state(struct pf_rule *r, struct pf_rule *a, struct pf_pdesc *pd,
s->creation = time_second;
s->expire = time_second;
- if (sn != NULL) {
- s->src_node = sn;
- s->src_node->states++;
- }
+ /* XXX on error all these should goto csfailed after extra cleanup */
if (pd->proto == IPPROTO_TCP) {
if (s->state_flags & PFSTATE_SCRUB_TCP &&
pf_normalize_tcp_init(m, off, pd, th, &s->src, &s->dst)) {
@@ -3116,7 +3163,7 @@ pf_create_state(struct pf_rule *r, struct pf_rule *a, struct pf_pdesc *pd,
if (pf_state_key_setup(pd, skw, sks, &saddr, &daddr, &sport, &dport,
act->rtableid))
- goto csfailed;
+ goto csfailed; /* XXX leaks */
if (pf_state_insert(BOUND_IFACE(r, kif), *skw, *sks, s)) {
if (pd->proto == IPPROTO_TCP)
@@ -3129,6 +3176,24 @@ pf_create_state(struct pf_rule *r, struct pf_rule *a, struct pf_pdesc *pd,
} 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;
+
+ 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);
+ }
+ 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 (tag > 0) {
pf_tag_ref(tag);
@@ -3154,6 +3219,7 @@ pf_create_state(struct pf_rule *r, struct pf_rule *a, struct pf_pdesc *pd,
return (PF_PASS);
csfailed:
+ /* skw/sks checks obsolete */
if (*skw != NULL) {
pool_put(&pf_state_key_pl, *skw);
*skw = NULL;
@@ -3163,12 +3229,10 @@ csfailed:
*sks = NULL;
}
- if (sn != NULL && sn->states == 0 && sn->expire == 0) {
- RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
- pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
- pf_status.src_nodes--;
- pool_put(&pf_src_tree_pl, sn);
- }
+ for (i = 0; i < PF_SN_MAX; i++)
+ if (sns[i] != NULL)
+ pf_remove_src_node(sns[i]);
+
return (PF_DROP);
}
@@ -3533,7 +3597,7 @@ pf_tcp_track_full(struct pf_state_peer *src, struct pf_state_peer *dst,
if (dst->state == TCPS_SYN_SENT) {
dst->state = TCPS_ESTABLISHED;
if (src->state == TCPS_ESTABLISHED &&
- (*state)->src_node != NULL &&
+ !SLIST_EMPTY(&(*state)->src_nodes) &&
pf_src_connlimit(state)) {
REASON_SET(reason, PFRES_SRCLIMIT);
return (PF_DROP);
@@ -3689,7 +3753,7 @@ pf_tcp_track_sloppy(struct pf_state_peer *src, struct pf_state_peer *dst,
if (dst->state == TCPS_SYN_SENT) {
dst->state = TCPS_ESTABLISHED;
if (src->state == TCPS_ESTABLISHED &&
- (*state)->src_node != NULL &&
+ !SLIST_EMPTY(&(*state)->src_nodes) &&
pf_src_connlimit(state)) {
REASON_SET(reason, PFRES_SRCLIMIT);
return (PF_DROP);
@@ -3705,7 +3769,7 @@ pf_tcp_track_sloppy(struct pf_state_peer *src, struct pf_state_peer *dst,
* the destination, set the connection to established.
*/
dst->state = src->state = TCPS_ESTABLISHED;
- if ((*state)->src_node != NULL &&
+ if (!SLIST_EMPTY(&(*state)->src_nodes) &&
pf_src_connlimit(state)) {
REASON_SET(reason, PFRES_SRCLIMIT);
return (PF_DROP);
@@ -3804,7 +3868,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
(ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
REASON_SET(reason, PFRES_SYNPROXY);
return (PF_DROP);
- } else if ((*state)->src_node != NULL &&
+ } else if (!SLIST_EMPTY(&(*state)->src_nodes) &&
pf_src_connlimit(state)) {
REASON_SET(reason, PFRES_SRCLIMIT);
return (PF_DROP);
@@ -5021,7 +5085,7 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
}
if (s == NULL) {
pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src,
- &naddr, NULL, &sn, &r->route);
+ &naddr, NULL, &sn, &r->route, PF_SN_ROUTE);
if (!PF_AZERO(&naddr, AF_INET))
dst->sin_addr.s_addr = naddr.v4.s_addr;
ifp = r->route.cur->kif ?
@@ -5203,7 +5267,7 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
}
if (s == NULL) {
pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
- &naddr, NULL, &sn, &r->route);
+ &naddr, NULL, &sn, &r->route, PF_SN_ROUTE);
if (!PF_AZERO(&naddr, AF_INET6))
PF_ACPY((struct pf_addr *)&dst->sin6_addr,
&naddr, AF_INET6);
@@ -5685,10 +5749,11 @@ done:
}
if (s != NULL) {
struct pf_rule_item *ri;
+ struct pf_sn_item *sni;
- if (s->src_node != NULL) {
- s->src_node->packets[dirndx]++;
- s->src_node->bytes[dirndx] += pd.tot_len;
+ SLIST_FOREACH(sni, &s->src_nodes, next) {
+ sni->sn->packets[dirndx]++;
+ sni->sn->bytes[dirndx] += pd.tot_len;
}
dirndx = (dir == s->direction) ? 0 : 1;
s->packets[dirndx]++;
@@ -6126,9 +6191,11 @@ done:
a->bytes[dirndx] += pd.tot_len;
}
if (s != NULL) {
- if (s->src_node != NULL) {
- s->src_node->packets[dirndx]++;
- s->src_node->bytes[dirndx] += pd.tot_len;
+ struct pf_sn_item *sni;
+
+ SLIST_FOREACH(sni, &s->src_nodes, next) {
+ sni->sn->packets[dirndx]++;
+ sni->sn->bytes[dirndx] += pd.tot_len;
}
dirndx = (dir == s->direction) ? 0 : 1;
s->packets[dirndx]++;
diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c
index 1d51adef25b..30a5a0fc091 100644
--- a/sys/net/pf_ioctl.c
+++ b/sys/net/pf_ioctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_ioctl.c,v 1.228 2009/11/24 13:23:55 henning Exp $ */
+/* $OpenBSD: pf_ioctl.c,v 1.229 2009/12/14 12:31:45 henning Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -159,6 +159,8 @@ pfattach(int num)
&pool_allocator_nointr);
pool_init(&pf_src_tree_pl, sizeof(struct pf_src_node), 0, 0, 0,
"pfsrctrpl", NULL);
+ pool_init(&pf_sn_item_pl, sizeof(struct pf_sn_item), 0, 0, 0,
+ "pfsnitempl", NULL);
pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl",
NULL);
pool_init(&pf_state_key_pl, sizeof(struct pf_state_key), 0, 0, 0,
@@ -2793,13 +2795,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
struct pf_state *state;
RB_FOREACH(state, pf_state_tree_id, &tree_id)
- state->src_node = NULL;
- RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
+ pf_src_tree_remove_state(state);
+ RB_FOREACH(n, pf_src_tree, &tree_src_tracking)
n->expire = 1;
- n->states = 0;
- }
pf_purge_expired_src_nodes(1);
- pf_status.src_nodes = 0;
break;
}
@@ -2820,13 +2819,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
&psnk->psnk_dst.addr.v.a.mask,
&sn->raddr, sn->af)) {
/* Handle state to src_node linkage */
- if (sn->states != 0) {
+ if (sn->states != 0)
RB_FOREACH(s, pf_state_tree_id,
- &tree_id)
- if (s->src_node == sn)
- s->src_node = NULL;
- sn->states = 0;
- }
+ &tree_id)
+ pf_state_rm_src_node(s, sn);
sn->expire = 1;
killed++;
}
diff --git a/sys/net/pf_lb.c b/sys/net/pf_lb.c
index d426e96dbc0..ee502e22035 100644
--- a/sys/net/pf_lb.c
+++ b/sys/net/pf_lb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_lb.c,v 1.8 2009/11/03 10:59:04 claudio Exp $ */
+/* $OpenBSD: pf_lb.c,v 1.9 2009/12/14 12:31:45 henning Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -174,7 +174,8 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
u_int16_t cut;
bzero(&init_addr, sizeof(init_addr));
- if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn, &r->nat))
+ if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn, &r->nat,
+ PF_SN_NAT))
return (1);
if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) {
@@ -247,7 +248,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
case PF_POOL_RANDOM:
case PF_POOL_ROUNDROBIN:
if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn,
- &r->nat))
+ &r->nat, PF_SN_NAT))
return (1);
break;
case PF_POOL_NONE:
@@ -262,8 +263,8 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
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 **sn,
- struct pf_pool *rpool)
+ struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sns,
+ struct pf_pool *rpool, enum pf_sn_types type)
{
unsigned char hash[16];
struct pf_addr *raddr = &rpool->cur->addr.v.a.addr;
@@ -271,21 +272,20 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
struct pf_pooladdr *acur = rpool->cur;
struct pf_src_node k;
- if (*sn == NULL && rpool->opts & PF_POOL_STICKYADDR &&
+ 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);
- if (r->rule_flag & PFRULE_RULESRCTRACK ||
- rpool->opts & PF_POOL_STICKYADDR)
- k.rule.ptr = r;
- else
- k.rule.ptr = NULL;
+ k.rule.ptr = r;
pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
- *sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
- if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, af)) {
- PF_ACPY(naddr, &(*sn)->raddr, af);
+ 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 >= PF_DEBUG_MISC) {
- printf("pf_map_addr: src tracking maps ");
+ printf("pf_map_addr: src tracking (%u) maps ",
+ type);
pf_print_host(&k.addr, 0, af);
printf(" to ");
pf_print_host(naddr, 0, af);
@@ -428,8 +428,16 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
PF_AINC(&rpool->counter, af);
break;
}
- if (*sn != NULL)
- PF_ACPY(&(*sn)->raddr, naddr, af);
+
+ if (rpool->opts & PF_POOL_STICKYADDR) {
+ if (sns[type] != NULL) {
+ pf_remove_src_node(sns[type]);
+ sns[type] = NULL;
+ }
+ if (pf_insert_src_node(&sns[type], r, type, af, saddr, naddr,
+ 0))
+ return (1);
+ }
if (pf_status.debug >= PF_DEBUG_NOISY &&
(rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
@@ -443,19 +451,18 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
int
pf_get_transaddr(struct pf_rule *r, struct pf_pdesc *pd, struct pf_addr *saddr,
- u_int16_t *sport, struct pf_addr *daddr, u_int16_t *dport)
+ u_int16_t *sport, struct pf_addr *daddr, u_int16_t *dport,
+ struct pf_src_node **sns)
{
struct pf_addr naddr;
u_int16_t nport = 0;
- struct pf_src_node srcnode, *sn = &srcnode;
-
if (!TAILQ_EMPTY(&r->nat.list)) {
/* XXX is this right? what if rtable is changed at the same
* XXX time? where do I need to figure out the sport? */
if (pf_get_sport(pd->af, pd->proto, r, saddr,
daddr, *dport, &naddr, &nport, r->nat.proxy_port[0],
- r->nat.proxy_port[1], &sn, pd->rdomain)) {
+ r->nat.proxy_port[1], sns, pd->rdomain)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: NAT proxy port allocation "
"(%u-%u) failed\n",
@@ -468,7 +475,8 @@ pf_get_transaddr(struct pf_rule *r, struct pf_pdesc *pd, struct pf_addr *saddr,
*sport = nport;
}
if (!TAILQ_EMPTY(&r->rdr.list)) {
- if (pf_map_addr(pd->af, r, saddr, &naddr, NULL, &sn, &r->rdr))
+ if (pf_map_addr(pd->af, r, saddr, &naddr, NULL, sns, &r->rdr,
+ PF_SN_RDR))
return (-1);
if ((r->rdr.opts & PF_POOL_TYPEMASK) == PF_POOL_BITMASK)
PF_POOLMASK(&naddr, &naddr, &r->rdr.cur->addr.v.a.mask,
@@ -497,4 +505,3 @@ pf_get_transaddr(struct pf_rule *r, struct pf_pdesc *pd, struct pf_addr *saddr,
return (0);
}
-
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 1bd5304a288..0be8bd29c10 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfvar.h,v 1.301 2009/11/24 13:23:55 henning Exp $ */
+/* $OpenBSD: pfvar.h,v 1.302 2009/12/14 12:31:45 henning Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -658,23 +658,32 @@ struct pf_rule_item {
SLIST_HEAD(pf_rule_slist, pf_rule_item);
+enum pf_sn_types { PF_SN_NONE, PF_SN_NAT, PF_SN_RDR, PF_SN_ROUTE, PF_SN_MAX };
+
struct pf_src_node {
- RB_ENTRY(pf_src_node) entry;
- struct pf_addr addr;
- struct pf_addr raddr;
- union pf_rule_ptr rule;
- struct pfi_kif *kif;
- u_int64_t bytes[2];
- u_int64_t packets[2];
- u_int32_t states;
- u_int32_t conn;
- struct pf_threshold conn_rate;
- u_int32_t creation;
- u_int32_t expire;
- sa_family_t af;
- u_int8_t ruletype;
+ RB_ENTRY(pf_src_node) entry;
+ struct pf_addr addr;
+ struct pf_addr raddr;
+ union pf_rule_ptr rule;
+ struct pfi_kif *kif;
+ u_int64_t bytes[2];
+ u_int64_t packets[2];
+ u_int32_t states;
+ u_int32_t conn;
+ struct pf_threshold conn_rate;
+ u_int32_t creation;
+ u_int32_t expire;
+ sa_family_t af;
+ u_int8_t type;
};
+struct pf_sn_item {
+ SLIST_ENTRY(pf_sn_item) next;
+ struct pf_src_node *sn;
+};
+
+SLIST_HEAD(pf_sn_head, pf_sn_item);
+
#define PFSNODE_HIWAT 10000 /* default source node table size */
struct pf_state_scrub {
@@ -766,10 +775,10 @@ struct pf_state {
union pf_rule_ptr rule;
union pf_rule_ptr anchor;
struct pf_addr rt_addr;
+ struct pf_sn_head src_nodes;
struct pf_state_key *key[2]; /* addresses stack and wire */
struct pfi_kif *kif;
struct pfi_kif *rt_kif;
- struct pf_src_node *src_node;
u_int64_t packets[2];
u_int64_t bytes[2];
u_int32_t creation;
@@ -1649,7 +1658,7 @@ extern int pf_tbladdr_setup(struct pf_ruleset *,
extern void pf_tbladdr_remove(struct pf_addr_wrap *);
extern void pf_tbladdr_copyout(struct pf_addr_wrap *);
extern void pf_calc_skip_steps(struct pf_rulequeue *);
-extern struct pool pf_src_tree_pl, pf_rule_pl;
+extern struct pool pf_src_tree_pl, pf_sn_item_pl, pf_rule_pl;
extern struct pool pf_state_pl, pf_state_key_pl, pf_state_item_pl,
pf_altq_pl, pf_pooladdr_pl, pf_rule_item_pl;
extern struct pool pf_state_scrub_pl;
@@ -1662,10 +1671,17 @@ extern int pf_state_insert(struct pfi_kif *,
struct pf_state_key *,
struct pf_state_key *,
struct pf_state *);
-extern int pf_insert_src_node(struct pf_src_node **,
- struct pf_rule *, struct pf_addr *,
- sa_family_t);
+int pf_insert_src_node(struct pf_src_node **,
+ struct pf_rule *, enum pf_sn_types,
+ sa_family_t, struct pf_addr *,
+ struct pf_addr *, int);
+void pf_remove_src_node(struct pf_src_node *);
+struct pf_src_node *pf_get_src_node(struct pf_state *,
+ enum pf_sn_types);
void pf_src_tree_remove_state(struct pf_state *);
+void pf_state_rm_src_node(struct pf_state *,
+ struct pf_src_node *);
+
extern struct pf_state *pf_find_state_byid(struct pf_state_cmp *);
extern struct pf_state *pf_find_state_all(struct pf_state_key_cmp *,
u_int, int *);
@@ -1870,12 +1886,12 @@ int pf_step_out_of_anchor(int *, struct pf_ruleset **,
int pf_get_transaddr(struct pf_rule *, struct pf_pdesc *,
struct pf_addr *, u_int16_t *, struct pf_addr *,
- u_int16_t *);
+ u_int16_t *, struct pf_src_node **);
int pf_map_addr(sa_family_t, struct pf_rule *,
struct pf_addr *, struct pf_addr *,
struct pf_addr *, struct pf_src_node **,
- struct pf_pool *);
+ struct pf_pool *, enum pf_sn_types);
int pf_state_key_setup(struct pf_pdesc *,
struct pf_state_key **, struct pf_state_key **,