Skip to content

Commit 7b57f25

Browse files
committed
tcp: improve sending of SYN-cookies
Ensure that when the sysctl-variable net.inet.tcp.syncookies_only is non zero, SYN-cookies are sent and no SYN-cache entry is added to the SYN-cache. In particular, this behavior should not depend on the value of the sysctl-variable net.inet.tcp.syncookies, which controls whether SYN cookies are used in combination with the SYN-cache to deal with bucket overflows. Also ensure that tcps_sc_completed does not include TCP connections established via a SYN-cookie. While there, make V_tcp_syncookies and V_tcp_syncookiesonly bool instead of int, since they are used as boolean variables. Reviewed by: rscheff, cc, Peter Lei, Nick Banks MFC after: 1 week Sponsored by: Netflix, Inc. Differential Revision: https://reviews.freebsd.org/D52225
1 parent 06527b2 commit 7b57f25

File tree

1 file changed

+48
-41
lines changed

1 file changed

+48
-41
lines changed

sys/netinet/tcp_syncache.c

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,15 @@
102102

103103
#include <security/mac/mac_framework.h>
104104

105-
VNET_DEFINE_STATIC(int, tcp_syncookies) = 1;
105+
VNET_DEFINE_STATIC(bool, tcp_syncookies) = true;
106106
#define V_tcp_syncookies VNET(tcp_syncookies)
107-
SYSCTL_INT(_net_inet_tcp, OID_AUTO, syncookies, CTLFLAG_VNET | CTLFLAG_RW,
107+
SYSCTL_BOOL(_net_inet_tcp, OID_AUTO, syncookies, CTLFLAG_VNET | CTLFLAG_RW,
108108
&VNET_NAME(tcp_syncookies), 0,
109109
"Use TCP SYN cookies if the syncache overflows");
110110

111-
VNET_DEFINE_STATIC(int, tcp_syncookiesonly) = 0;
111+
VNET_DEFINE_STATIC(bool, tcp_syncookiesonly) = false;
112112
#define V_tcp_syncookiesonly VNET(tcp_syncookiesonly)
113-
SYSCTL_INT(_net_inet_tcp, OID_AUTO, syncookies_only, CTLFLAG_VNET | CTLFLAG_RW,
113+
SYSCTL_BOOL(_net_inet_tcp, OID_AUTO, syncookies_only, CTLFLAG_VNET | CTLFLAG_RW,
114114
&VNET_NAME(tcp_syncookiesonly), 0,
115115
"Use only TCP SYN cookies");
116116

@@ -553,9 +553,8 @@ syncache_timer(void *xsch)
553553
static inline bool
554554
syncache_cookiesonly(void)
555555
{
556-
557-
return (V_tcp_syncookies && (V_tcp_syncache.paused ||
558-
V_tcp_syncookiesonly));
556+
return ((V_tcp_syncookies && V_tcp_syncache.paused) ||
557+
V_tcp_syncookiesonly);
559558
}
560559

561560
/*
@@ -1083,40 +1082,48 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
10831082
#endif
10841083

10851084
if (sc == NULL) {
1086-
/*
1087-
* There is no syncache entry, so see if this ACK is
1088-
* a returning syncookie. To do this, first:
1089-
* A. Check if syncookies are used in case of syncache
1090-
* overflows
1091-
* B. See if this socket has had a syncache entry dropped in
1092-
* the recent past. We don't want to accept a bogus
1093-
* syncookie if we've never received a SYN or accept it
1094-
* twice.
1095-
* C. check that the syncookie is valid. If it is, then
1096-
* cobble up a fake syncache entry, and return.
1097-
*/
1098-
if (locked && !V_tcp_syncookies) {
1099-
SCH_UNLOCK(sch);
1100-
TCPSTAT_INC(tcps_sc_spurcookie);
1101-
if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
1102-
log(LOG_DEBUG, "%s; %s: Spurious ACK, "
1103-
"segment rejected (syncookies disabled)\n",
1104-
s, __func__);
1105-
goto failed;
1106-
}
1107-
if (locked && !V_tcp_syncookiesonly &&
1108-
sch->sch_last_overflow < time_uptime - SYNCOOKIE_LIFETIME) {
1085+
if (locked) {
1086+
/*
1087+
* The syncache is currently in use (neither disabled,
1088+
* nor paused), but no entry was found.
1089+
*/
1090+
if (!V_tcp_syncookies) {
1091+
/*
1092+
* Since no syncookies are used in case of
1093+
* a bucket overflow, don't even check for
1094+
* a valid syncookie.
1095+
*/
1096+
SCH_UNLOCK(sch);
1097+
TCPSTAT_INC(tcps_sc_spurcookie);
1098+
if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
1099+
log(LOG_DEBUG, "%s; %s: Spurious ACK, "
1100+
"segment rejected "
1101+
"(syncookies disabled)\n",
1102+
s, __func__);
1103+
goto failed;
1104+
}
1105+
if (sch->sch_last_overflow <
1106+
time_uptime - SYNCOOKIE_LIFETIME) {
1107+
/*
1108+
* Since the bucket did not overflow recently,
1109+
* don't even check for a valid syncookie.
1110+
*/
1111+
SCH_UNLOCK(sch);
1112+
TCPSTAT_INC(tcps_sc_spurcookie);
1113+
if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
1114+
log(LOG_DEBUG, "%s; %s: Spurious ACK, "
1115+
"segment rejected "
1116+
"(no syncache entry)\n",
1117+
s, __func__);
1118+
goto failed;
1119+
}
11091120
SCH_UNLOCK(sch);
1110-
TCPSTAT_INC(tcps_sc_spurcookie);
1111-
if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
1112-
log(LOG_DEBUG, "%s; %s: Spurious ACK, "
1113-
"segment rejected (no syncache entry)\n",
1114-
s, __func__);
1115-
goto failed;
11161121
}
1117-
if (locked)
1118-
SCH_UNLOCK(sch);
11191122
bzero(&scs, sizeof(scs));
1123+
/*
1124+
* Now check, if the syncookie is valid. If it is, create an on
1125+
* stack syncache entry.
1126+
*/
11201127
if (syncookie_expand(inc, sch, &scs, th, to, *lsop, port)) {
11211128
sc = &scs;
11221129
TCPSTAT_INC(tcps_sc_recvcookie);
@@ -1291,7 +1298,7 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
12911298
if (__predict_false(*lsop == NULL)) {
12921299
TCPSTAT_INC(tcps_sc_aborted);
12931300
TCPSTATES_DEC(TCPS_SYN_RECEIVED);
1294-
} else
1301+
} else if (sc != &scs)
12951302
TCPSTAT_INC(tcps_sc_completed);
12961303

12971304
if (sc != &scs)
@@ -1718,13 +1725,13 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
17181725
if (V_tcp_do_ecn && (tp->t_flags2 & TF2_CANNOT_DO_ECN) == 0)
17191726
sc->sc_flags |= tcp_ecn_syncache_add(tcp_get_flags(th), iptos);
17201727

1721-
if (V_tcp_syncookies)
1728+
if (V_tcp_syncookies || V_tcp_syncookiesonly)
17221729
sc->sc_iss = syncookie_generate(sch, sc);
17231730
else
17241731
sc->sc_iss = arc4random();
17251732
#ifdef INET6
17261733
if (autoflowlabel) {
1727-
if (V_tcp_syncookies)
1734+
if (V_tcp_syncookies || V_tcp_syncookiesonly)
17281735
sc->sc_flowlabel = sc->sc_iss;
17291736
else
17301737
sc->sc_flowlabel = ip6_randomflowlabel();

0 commit comments

Comments
 (0)