aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGleb Smirnoff <glebius@FreeBSD.org>2016-12-09 17:59:15 +0000
committerGleb Smirnoff <glebius@FreeBSD.org>2016-12-09 17:59:15 +0000
commit3cbee8caa140f9675d5f2653e829c8d3d5d92281 (patch)
tree81c986b90a725c3b36e8d426c4c5293f6770615d
parent169170209c38774c8755f21b2f40a1dd86945a71 (diff)
downloadsrc-3cbee8caa140f9675d5f2653e829c8d3d5d92281.tar.gz
src-3cbee8caa140f9675d5f2653e829c8d3d5d92281.zip
Use counter_ratecheck() in the ICMP rate limiting.
Together with: rrs, jtl
Notes
Notes: svn path=/head/; revision=309746
-rw-r--r--sys/netinet/icmp_var.h2
-rw-r--r--sys/netinet/ip_icmp.c81
-rw-r--r--sys/netpfil/pf/if_pfsync.c57
3 files changed, 81 insertions, 59 deletions
diff --git a/sys/netinet/icmp_var.h b/sys/netinet/icmp_var.h
index d3e72bc2823e..d76679f63da5 100644
--- a/sys/netinet/icmp_var.h
+++ b/sys/netinet/icmp_var.h
@@ -96,7 +96,7 @@ extern int badport_bandlim(int);
#define BANDLIM_RST_OPENPORT 4 /* No connection, listener */
#define BANDLIM_ICMP6_UNREACH 5
#define BANDLIM_SCTP_OOTB 6
-#define BANDLIM_MAX 6
+#define BANDLIM_MAX 7
#endif
#endif
diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c
index 137fecc614f1..ba399496ab58 100644
--- a/sys/netinet/ip_icmp.c
+++ b/sys/netinet/ip_icmp.c
@@ -973,44 +973,59 @@ ip_next_mtu(int mtu, int dir)
* the 'final' error, but it doesn't make sense to solve the printing
* delay with more complex code.
*/
+struct icmp_rate {
+ const char *descr;
+ struct counter_rate cr;
+};
+static VNET_DEFINE(struct icmp_rate, icmp_rates[BANDLIM_MAX]) = {
+ { "icmp unreach response" },
+ { "icmp ping response" },
+ { "icmp tstamp response" },
+ { "closed port RST response" },
+ { "open port RST response" },
+ { "icmp6 unreach response" },
+ { "sctp ootb response" }
+};
+#define V_icmp_rates VNET(icmp_rates)
+
+static void
+icmp_bandlimit_init(void)
+{
+
+ for (int i = 0; i < BANDLIM_MAX; i++) {
+ V_icmp_rates[i].cr.cr_rate = counter_u64_alloc(M_WAITOK);
+ V_icmp_rates[i].cr.cr_ticks = ticks;
+ }
+}
+VNET_SYSINIT(icmp_bandlimit, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY,
+ icmp_bandlimit_init, NULL);
+
+static void
+icmp_bandlimit_uninit(void)
+{
+
+ for (int i = 0; i < BANDLIM_MAX; i++)
+ counter_u64_free(V_icmp_rates[i].cr.cr_rate);
+}
+VNET_SYSUNINIT(icmp_bandlimit, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD,
+ icmp_bandlimit_uninit, NULL);
int
badport_bandlim(int which)
{
+ int64_t pps;
-#define N(a) (sizeof (a) / sizeof (a[0]))
- static struct rate {
- const char *type;
- struct timeval lasttime;
- int curpps;
- } rates[BANDLIM_MAX+1] = {
- { "icmp unreach response" },
- { "icmp ping response" },
- { "icmp tstamp response" },
- { "closed port RST response" },
- { "open port RST response" },
- { "icmp6 unreach response" },
- { "sctp ootb response" }
- };
+ if (V_icmplim == 0 || which == BANDLIM_UNLIMITED)
+ return (0);
- /*
- * Return ok status if feature disabled or argument out of range.
- */
- if (V_icmplim > 0 && (u_int) which < N(rates)) {
- struct rate *r = &rates[which];
- int opps = r->curpps;
+ KASSERT(which >= 0 && which < BANDLIM_MAX,
+ ("%s: which %d", __func__, which));
- if (!ppsratecheck(&r->lasttime, &r->curpps, V_icmplim))
- return -1; /* discard packet */
- /*
- * If we've dropped below the threshold after having
- * rate-limited traffic print the message. This preserves
- * the previous behaviour at the expense of added complexity.
- */
- if (V_icmplim_output && opps > V_icmplim)
- log(LOG_NOTICE, "Limiting %s from %d to %d packets/sec\n",
- r->type, opps, V_icmplim);
- }
- return 0; /* okay to send packet */
-#undef N
+ pps = counter_ratecheck(&V_icmp_rates[which].cr, V_icmplim);
+ if (pps == -1)
+ return (-1);
+ if (pps > 0 && V_icmplim_output)
+ log(LOG_NOTICE, "Limiting %s from %ld to %d packets/sec\n",
+ V_icmp_rates[which].descr, pps, V_icmplim);
+ return (0);
}
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
index 0d117d775beb..b68e0c1cefb5 100644
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -161,8 +161,8 @@ static struct pfsync_q pfsync_qs[] = {
{ pfsync_out_del, sizeof(struct pfsync_del_c), PFSYNC_ACT_DEL_C }
};
-static void pfsync_q_ins(struct pf_state *, int);
-static void pfsync_q_del(struct pf_state *);
+static void pfsync_q_ins(struct pf_state *, int, bool);
+static void pfsync_q_del(struct pf_state *, bool);
static void pfsync_update_state(struct pf_state *);
@@ -542,7 +542,7 @@ pfsync_state_import(struct pfsync_state *sp, u_int8_t flags)
if (!(flags & PFSYNC_SI_IOCTL)) {
st->state_flags &= ~PFSTATE_NOSYNC;
if (st->state_flags & PFSTATE_ACK) {
- pfsync_q_ins(st, PFSYNC_S_IACK);
+ pfsync_q_ins(st, PFSYNC_S_IACK, true);
pfsync_push(sc);
}
}
@@ -1668,7 +1668,7 @@ pfsync_insert_state(struct pf_state *st)
if (sc->sc_len == PFSYNC_MINPKT)
callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, V_pfsyncif);
- pfsync_q_ins(st, PFSYNC_S_INS);
+ pfsync_q_ins(st, PFSYNC_S_INS, true);
PFSYNC_UNLOCK(sc);
st->sync_updates = 0;
@@ -1789,7 +1789,7 @@ static void
pfsync_update_state(struct pf_state *st)
{
struct pfsync_softc *sc = V_pfsyncif;
- int sync = 0;
+ bool sync = false, ref = true;
PF_STATE_LOCK_ASSERT(st);
PFSYNC_LOCK(sc);
@@ -1798,7 +1798,7 @@ pfsync_update_state(struct pf_state *st)
pfsync_undefer_state(st, 0);
if (st->state_flags & PFSTATE_NOSYNC) {
if (st->sync_state != PFSYNC_S_NONE)
- pfsync_q_del(st);
+ pfsync_q_del(st, true);
PFSYNC_UNLOCK(sc);
return;
}
@@ -1815,14 +1815,17 @@ pfsync_update_state(struct pf_state *st)
if (st->key[PF_SK_WIRE]->proto == IPPROTO_TCP) {
st->sync_updates++;
if (st->sync_updates >= sc->sc_maxupdates)
- sync = 1;
+ sync = true;
}
break;
case PFSYNC_S_IACK:
- pfsync_q_del(st);
+ pfsync_q_del(st, false);
+ ref = false;
+ /* FALLTHROUGH */
+
case PFSYNC_S_NONE:
- pfsync_q_ins(st, PFSYNC_S_UPD_C);
+ pfsync_q_ins(st, PFSYNC_S_UPD_C, ref);
st->sync_updates = 0;
break;
@@ -1880,13 +1883,14 @@ static void
pfsync_update_state_req(struct pf_state *st)
{
struct pfsync_softc *sc = V_pfsyncif;
+ bool ref = true;
PF_STATE_LOCK_ASSERT(st);
PFSYNC_LOCK(sc);
if (st->state_flags & PFSTATE_NOSYNC) {
if (st->sync_state != PFSYNC_S_NONE)
- pfsync_q_del(st);
+ pfsync_q_del(st, true);
PFSYNC_UNLOCK(sc);
return;
}
@@ -1894,9 +1898,12 @@ pfsync_update_state_req(struct pf_state *st)
switch (st->sync_state) {
case PFSYNC_S_UPD_C:
case PFSYNC_S_IACK:
- pfsync_q_del(st);
+ pfsync_q_del(st, false);
+ ref = false;
+ /* FALLTHROUGH */
+
case PFSYNC_S_NONE:
- pfsync_q_ins(st, PFSYNC_S_UPD);
+ pfsync_q_ins(st, PFSYNC_S_UPD, true);
pfsync_push(sc);
break;
@@ -1917,13 +1924,14 @@ static void
pfsync_delete_state(struct pf_state *st)
{
struct pfsync_softc *sc = V_pfsyncif;
+ bool ref = true;
PFSYNC_LOCK(sc);
if (st->state_flags & PFSTATE_ACK)
pfsync_undefer_state(st, 1);
if (st->state_flags & PFSTATE_NOSYNC) {
if (st->sync_state != PFSYNC_S_NONE)
- pfsync_q_del(st);
+ pfsync_q_del(st, true);
PFSYNC_UNLOCK(sc);
return;
}
@@ -1931,30 +1939,27 @@ pfsync_delete_state(struct pf_state *st)
if (sc->sc_len == PFSYNC_MINPKT)
callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, V_pfsyncif);
- pf_ref_state(st);
-
switch (st->sync_state) {
case PFSYNC_S_INS:
/* We never got to tell the world so just forget about it. */
- pfsync_q_del(st);
+ pfsync_q_del(st, true);
break;
case PFSYNC_S_UPD_C:
case PFSYNC_S_UPD:
case PFSYNC_S_IACK:
- pfsync_q_del(st);
- /* FALLTHROUGH to putting it on the del list */
+ pfsync_q_del(st, false);
+ ref = false;
+ /* FALLTHROUGH */
case PFSYNC_S_NONE:
- pfsync_q_ins(st, PFSYNC_S_DEL);
+ pfsync_q_ins(st, PFSYNC_S_DEL, ref);
break;
default:
panic("%s: unexpected sync state %d", __func__, st->sync_state);
}
- pf_release_state(st);
-
PFSYNC_UNLOCK(sc);
}
@@ -1982,7 +1987,7 @@ pfsync_clear_states(u_int32_t creatorid, const char *ifname)
}
static void
-pfsync_q_ins(struct pf_state *st, int q)
+pfsync_q_ins(struct pf_state *st, int q, bool ref)
{
struct pfsync_softc *sc = V_pfsyncif;
size_t nlen = pfsync_qs[q].len;
@@ -2006,11 +2011,12 @@ pfsync_q_ins(struct pf_state *st, int q)
sc->sc_len += nlen;
TAILQ_INSERT_TAIL(&sc->sc_qs[q], st, sync_list);
st->sync_state = q;
- pf_ref_state(st);
+ if (ref)
+ pf_ref_state(st);
}
static void
-pfsync_q_del(struct pf_state *st)
+pfsync_q_del(struct pf_state *st, bool unref)
{
struct pfsync_softc *sc = V_pfsyncif;
int q = st->sync_state;
@@ -2022,7 +2028,8 @@ pfsync_q_del(struct pf_state *st)
sc->sc_len -= pfsync_qs[q].len;
TAILQ_REMOVE(&sc->sc_qs[q], st, sync_list);
st->sync_state = PFSYNC_S_NONE;
- pf_release_state(st);
+ if (unref)
+ pf_release_state(st);
if (TAILQ_EMPTY(&sc->sc_qs[q]))
sc->sc_len -= sizeof(struct pfsync_subheader);