Use counter_ratecheck() in the ICMP rate limiting.
Together with: rrs, jtl
This commit is contained in:
parent
169170209c
commit
3cbee8caa1
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=309746
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user