summaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorHenning Brauer <henning@cvs.openbsd.org>2017-11-13 11:30:12 +0000
committerHenning Brauer <henning@cvs.openbsd.org>2017-11-13 11:30:12 +0000
commitda34c0e0269decb017a680092e02d33530b4e0a5 (patch)
tree44842a7d58c38dfae36b72fab509fe77f624b088 /sys/net
parent564d693f1d76ac81f1703fee00bbbdc93fbda60b (diff)
add a generic packet rate matching filter. allows things like
pass in proto icmp max-pkt-rate 100/10 all packets matching the rule in the direction the state was created are taken into consideration (typically: requests, but not replies). Just like with the other max-*, the rule stops matching if the maximum is reached, so in typical scenarios the default block rule would kick in then. with input from Holger Mikolon ok mikeb
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/pf.c18
-rw-r--r--sys/net/pf_ioctl.c5
-rw-r--r--sys/net/pfvar.h22
3 files changed, 31 insertions, 14 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c
index cf8cdc08674..3382ee63e7c 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.1044 2017/11/13 01:24:09 dlg Exp $ */
+/* $OpenBSD: pf.c,v 1.1045 2017/11/13 11:30:11 henning Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -161,8 +161,6 @@ struct pool pf_src_tree_pl, pf_rule_pl, pf_queue_pl;
struct pool pf_state_pl, pf_state_key_pl, pf_state_item_pl;
struct pool pf_rule_item_pl, pf_sn_item_pl;
-void pf_init_threshold(struct pf_threshold *, u_int32_t,
- u_int32_t);
void pf_add_threshold(struct pf_threshold *);
int pf_check_threshold(struct pf_threshold *);
int pf_check_tcp_cksum(struct mbuf *, int, int,
@@ -274,6 +272,13 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
s = pf_find_state(i, k, d, m); \
if (s == NULL || (s)->timeout == PFTM_PURGE) \
return (PF_DROP); \
+ if ((s)->rule.ptr->pktrate.limit && d == (s)->direction) { \
+ pf_add_threshold(&(s)->rule.ptr->pktrate); \
+ if (pf_check_threshold(&(s)->rule.ptr->pktrate)) { \
+ s = NULL; \
+ return (PF_DROP); \
+ } \
+ } \
if (d == PF_OUT && \
(((s)->rule.ptr->rt == PF_ROUTETO && \
(s)->rule.ptr->direction == PF_OUT) || \
@@ -3596,6 +3601,13 @@ pf_match_rule(struct pf_test_ctx *ctx, struct pf_ruleset *ruleset)
ctx->pd->m->m_pkthdr.pf.prio),
TAILQ_NEXT(r, entries));
+ /* must be last! */
+ if (r->pktrate.limit) {
+ pf_add_threshold(&r->pktrate);
+ PF_TEST_ATTRIB((pf_check_threshold(&r->pktrate)),
+ TAILQ_NEXT(r, entries));
+ }
+
/* FALLTHROUGH */
if (r->tag)
ctx->tag = r->tag;
diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c
index 99aebe1087c..e392d5364e7 100644
--- a/sys/net/pf_ioctl.c
+++ b/sys/net/pf_ioctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_ioctl.c,v 1.324 2017/10/31 22:05:12 sashan Exp $ */
+/* $OpenBSD: pf_ioctl.c,v 1.325 2017/11/13 11:30:11 henning Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -1317,6 +1317,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
pr->rule.rcv_kif = NULL;
pr->rule.anchor = NULL;
pr->rule.overload_tbl = NULL;
+ pr->rule.pktrate.limit /= PF_THRESHOLD_MULT;
bzero(&pr->rule.gcle, sizeof(pr->rule.gcle));
pr->rule.ruleset = NULL;
if (pf_anchor_copyout(ruleset, rule, pr)) {
@@ -2737,6 +2738,8 @@ pf_rule_copyin(struct pf_rule *from, struct pf_rule *to,
to->max_src_conn = from->max_src_conn;
to->max_src_conn_rate.limit = from->max_src_conn_rate.limit;
to->max_src_conn_rate.seconds = from->max_src_conn_rate.seconds;
+ pf_init_threshold(&to->pktrate, from->pktrate.limit,
+ from->pktrate.seconds);
if (to->qname[0] != 0) {
if ((to->qid = pf_qname2qid(to->qname, 0)) == 0)
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 11ac9cf0ce3..c68814bc989 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfvar.h,v 1.466 2017/09/05 22:15:32 sashan Exp $ */
+/* $OpenBSD: pfvar.h,v 1.467 2017/11/13 11:30:11 henning Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -317,6 +317,15 @@ struct pf_rule_addr {
u_int16_t weight;
};
+struct pf_threshold {
+ u_int32_t limit;
+#define PF_THRESHOLD_MULT 1000
+#define PF_THRESHOLD_MAX 0xffffffff / PF_THRESHOLD_MULT
+ u_int32_t seconds;
+ u_int32_t count;
+ u_int32_t last;
+};
+
struct pf_poolhashkey {
union {
u_int8_t key8[16];
@@ -496,6 +505,7 @@ struct pf_rule {
struct pf_pool nat;
struct pf_pool rdr;
struct pf_pool route;
+ struct pf_threshold pktrate;
u_int64_t evaluations;
u_int64_t packets[2];
@@ -610,15 +620,6 @@ struct pf_rule {
#define PFSTATE_ADAPT_END 12000 /* default adaptive timeout end */
-struct pf_threshold {
- u_int32_t limit;
-#define PF_THRESHOLD_MULT 1000
-#define PF_THRESHOLD_MAX 0xffffffff / PF_THRESHOLD_MULT
- u_int32_t seconds;
- u_int32_t count;
- u_int32_t last;
-};
-
struct pf_rule_item {
SLIST_ENTRY(pf_rule_item) entry;
struct pf_rule *r;
@@ -1749,6 +1750,7 @@ int pf_translate(struct pf_pdesc *, struct pf_addr *, u_int16_t,
int pf_translate_af(struct pf_pdesc *);
void pf_route(struct pf_pdesc *, struct pf_rule *, struct pf_state *);
void pf_route6(struct pf_pdesc *, struct pf_rule *, struct pf_state *);
+void pf_init_threshold(struct pf_threshold *, u_int32_t, u_int32_t);
void pfr_initialize(void);
int pfr_match_addr(struct pfr_ktable *, struct pf_addr *, sa_family_t);