Syncoockies can be used in combination with the syncache. If the cache

overflows, syncookies are used.
This patch restricts the usage of syncookies in this case: accept
syncookies only if there was an overflow of the syncache recently.
This mitigates a problem reported in PR217637, where is syncookie was
accepted without any recent drops.
Thanks to glebius@ for suggesting an improvement.

PR:			217637
Reviewed by:		gnn, glebius
MFC after:		1 week
Sponsored by:		Netflix, Inc.
Differential Revision:	https://reviews.freebsd.org/D10272
This commit is contained in:
Michael Tuexen 2017-04-20 19:19:33 +00:00
parent 933870f0d1
commit 190d9abce7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=317208
2 changed files with 22 additions and 5 deletions

View File

@ -260,6 +260,7 @@ syncache_init(void)
&V_tcp_syncache.hashbase[i].sch_mtx, 0);
V_tcp_syncache.hashbase[i].sch_length = 0;
V_tcp_syncache.hashbase[i].sch_sc = &V_tcp_syncache;
V_tcp_syncache.hashbase[i].sch_last_overflow = INT64_MIN;
}
/* Create the syncache entry zone. */
@ -335,6 +336,7 @@ syncache_insert(struct syncache *sc, struct syncache_head *sch)
KASSERT(!TAILQ_EMPTY(&sch->sch_bucket),
("sch->sch_length incorrect"));
sc2 = TAILQ_LAST(&sch->sch_bucket, sch_head);
sch->sch_last_overflow = time_uptime;
syncache_drop(sc2, sch);
TCPSTAT_INC(tcps_sc_bucketoverflow);
}
@ -974,10 +976,13 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
/*
* There is no syncache entry, so see if this ACK is
* a returning syncookie. To do this, first:
* A. See if this socket has had a syncache entry dropped in
* the past. We don't want to accept a bogus syncookie
* if we've never received a SYN.
* B. check that the syncookie is valid. If it is, then
* A. Check if syncookies are used in case of syncache
* overflows
* B. See if this socket has had a syncache entry dropped in
* the recent past. We don't want to accept a bogus
* syncookie if we've never received a SYN or accept it
* twice.
* C. check that the syncookie is valid. If it is, then
* cobble up a fake syncache entry, and return.
*/
if (!V_tcp_syncookies) {
@ -988,6 +993,15 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
s, __func__);
goto failed;
}
if (!V_tcp_syncookiesonly &&
sch->sch_last_overflow < time_uptime - SYNCOOKIE_LIFETIME) {
SCH_UNLOCK(sch);
if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
log(LOG_DEBUG, "%s; %s: Spurious ACK, "
"segment rejected (no syncache entry)\n",
s, __func__);
goto failed;
}
bzero(&scs, sizeof(scs));
sc = syncookie_lookup(inc, sch, &scs, th, to, *lsop);
SCH_UNLOCK(sch);
@ -1411,8 +1425,10 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
* entry and insert the new one.
*/
TCPSTAT_INC(tcps_sc_zonefail);
if ((sc = TAILQ_LAST(&sch->sch_bucket, sch_head)) != NULL)
if ((sc = TAILQ_LAST(&sch->sch_bucket, sch_head)) != NULL) {
sch->sch_last_overflow = time_uptime;
syncache_drop(sc, sch);
}
sc = uma_zalloc(V_tcp_syncache.zone, M_NOWAIT | M_ZERO);
if (sc == NULL) {
if (V_tcp_syncookies) {

View File

@ -99,6 +99,7 @@ struct syncache_head {
int sch_nextc;
u_int sch_length;
struct tcp_syncache *sch_sc;
time_t sch_last_overflow;
};
#define SYNCOOKIE_SECRET_SIZE 16