Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_syncache.c
Show First 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | |||||
#ifdef INET6 | #ifdef INET6 | ||||
#include <netinet/ip6.h> | #include <netinet/ip6.h> | ||||
#include <netinet/icmp6.h> | #include <netinet/icmp6.h> | ||||
#include <netinet6/nd6.h> | #include <netinet6/nd6.h> | ||||
#include <netinet6/ip6_var.h> | #include <netinet6/ip6_var.h> | ||||
#include <netinet6/in6_pcb.h> | #include <netinet6/in6_pcb.h> | ||||
#endif | #endif | ||||
#include <netinet/tcp.h> | #include <netinet/tcp.h> | ||||
#ifdef TCP_RFC7413 | |||||
#include <netinet/tcp_fastopen.h> | #include <netinet/tcp_fastopen.h> | ||||
#endif | |||||
#include <netinet/tcp_fsm.h> | #include <netinet/tcp_fsm.h> | ||||
#include <netinet/tcp_seq.h> | #include <netinet/tcp_seq.h> | ||||
#include <netinet/tcp_timer.h> | #include <netinet/tcp_timer.h> | ||||
#include <netinet/tcp_var.h> | #include <netinet/tcp_var.h> | ||||
#include <netinet/tcp_syncache.h> | #include <netinet/tcp_syncache.h> | ||||
#ifdef INET6 | #ifdef INET6 | ||||
#include <netinet6/tcp6_var.h> | #include <netinet6/tcp6_var.h> | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 1,074 Lines • ▼ Show 20 Lines | failed: | ||||
if (sc != NULL && sc != &scs) | if (sc != NULL && sc != &scs) | ||||
syncache_free(sc); | syncache_free(sc); | ||||
if (s != NULL) | if (s != NULL) | ||||
free(s, M_TCPLOG); | free(s, M_TCPLOG); | ||||
*lsop = NULL; | *lsop = NULL; | ||||
return (0); | return (0); | ||||
} | } | ||||
#ifdef TCP_RFC7413 | |||||
static void | static void | ||||
syncache_tfo_expand(struct syncache *sc, struct socket **lsop, struct mbuf *m, | syncache_tfo_expand(struct syncache *sc, struct socket **lsop, struct mbuf *m, | ||||
uint64_t response_cookie) | uint64_t response_cookie) | ||||
{ | { | ||||
struct inpcb *inp; | struct inpcb *inp; | ||||
struct tcpcb *tp; | struct tcpcb *tp; | ||||
unsigned int *pending_counter; | unsigned int *pending_counter; | ||||
Show All 15 Lines | if (*lsop == NULL) { | ||||
tp->t_flags |= TF_FASTOPEN; | tp->t_flags |= TF_FASTOPEN; | ||||
tp->t_tfo_cookie.server = response_cookie; | tp->t_tfo_cookie.server = response_cookie; | ||||
tp->snd_max = tp->iss; | tp->snd_max = tp->iss; | ||||
tp->snd_nxt = tp->iss; | tp->snd_nxt = tp->iss; | ||||
tp->t_tfo_pending = pending_counter; | tp->t_tfo_pending = pending_counter; | ||||
TCPSTAT_INC(tcps_sc_completed); | TCPSTAT_INC(tcps_sc_completed); | ||||
} | } | ||||
} | } | ||||
#endif /* TCP_RFC7413 */ | |||||
/* | /* | ||||
* Given a LISTEN socket and an inbound SYN request, add | * Given a LISTEN socket and an inbound SYN request, add | ||||
* this to the syn cache, and send back a segment: | * this to the syn cache, and send back a segment: | ||||
* <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK> | * <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK> | ||||
* to the source. | * to the source. | ||||
* | * | ||||
* IMPORTANT NOTE: We do _NOT_ ACK data that might accompany the SYN. | * IMPORTANT NOTE: We do _NOT_ ACK data that might accompany the SYN. | ||||
Show All 26 Lines | |||||
#ifdef INET6 | #ifdef INET6 | ||||
int autoflowlabel = 0; | int autoflowlabel = 0; | ||||
#endif | #endif | ||||
#ifdef MAC | #ifdef MAC | ||||
struct label *maclabel; | struct label *maclabel; | ||||
#endif | #endif | ||||
struct syncache scs; | struct syncache scs; | ||||
struct ucred *cred; | struct ucred *cred; | ||||
#ifdef TCP_RFC7413 | |||||
uint64_t tfo_response_cookie; | uint64_t tfo_response_cookie; | ||||
unsigned int *tfo_pending = NULL; | unsigned int *tfo_pending = NULL; | ||||
int tfo_cookie_valid = 0; | int tfo_cookie_valid = 0; | ||||
int tfo_response_cookie_valid = 0; | int tfo_response_cookie_valid = 0; | ||||
#endif | |||||
INP_WLOCK_ASSERT(inp); /* listen socket */ | INP_WLOCK_ASSERT(inp); /* listen socket */ | ||||
KASSERT((th->th_flags & (TH_RST|TH_ACK|TH_SYN)) == TH_SYN, | KASSERT((th->th_flags & (TH_RST|TH_ACK|TH_SYN)) == TH_SYN, | ||||
("%s: unexpected tcp flags", __func__)); | ("%s: unexpected tcp flags", __func__)); | ||||
/* | /* | ||||
* Combine all so/tp operations very early to drop the INP lock as | * Combine all so/tp operations very early to drop the INP lock as | ||||
* soon as possible. | * soon as possible. | ||||
*/ | */ | ||||
so = *lsop; | so = *lsop; | ||||
KASSERT(SOLISTENING(so), ("%s: %p not listening", __func__, so)); | KASSERT(SOLISTENING(so), ("%s: %p not listening", __func__, so)); | ||||
tp = sototcpcb(so); | tp = sototcpcb(so); | ||||
cred = crhold(so->so_cred); | cred = crhold(so->so_cred); | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if ((inc->inc_flags & INC_ISIPV6) && | if ((inc->inc_flags & INC_ISIPV6) && | ||||
(inp->inp_flags & IN6P_AUTOFLOWLABEL)) | (inp->inp_flags & IN6P_AUTOFLOWLABEL)) | ||||
autoflowlabel = 1; | autoflowlabel = 1; | ||||
#endif | #endif | ||||
ip_ttl = inp->inp_ip_ttl; | ip_ttl = inp->inp_ip_ttl; | ||||
ip_tos = inp->inp_ip_tos; | ip_tos = inp->inp_ip_tos; | ||||
win = so->sol_sbrcv_hiwat; | win = so->sol_sbrcv_hiwat; | ||||
ltflags = (tp->t_flags & (TF_NOOPT | TF_SIGNATURE)); | ltflags = (tp->t_flags & (TF_NOOPT | TF_SIGNATURE)); | ||||
#ifdef TCP_RFC7413 | |||||
if (V_tcp_fastopen_server_enable && IS_FASTOPEN(tp->t_flags) && | if (V_tcp_fastopen_server_enable && IS_FASTOPEN(tp->t_flags) && | ||||
(tp->t_tfo_pending != NULL) && | (tp->t_tfo_pending != NULL) && | ||||
(to->to_flags & TOF_FASTOPEN)) { | (to->to_flags & TOF_FASTOPEN)) { | ||||
/* | /* | ||||
* Limit the number of pending TFO connections to | * Limit the number of pending TFO connections to | ||||
* approximately half of the queue limit. This prevents TFO | * approximately half of the queue limit. This prevents TFO | ||||
* SYN floods from starving the service by filling the | * SYN floods from starving the service by filling the | ||||
* listen queue with bogus TFO connections. | * listen queue with bogus TFO connections. | ||||
Show All 10 Lines | if (V_tcp_fastopen_server_enable && IS_FASTOPEN(tp->t_flags) && | ||||
} | } | ||||
/* | /* | ||||
* Remember the TFO pending counter as it will have to be | * Remember the TFO pending counter as it will have to be | ||||
* decremented below if we don't make it to syncache_tfo_expand(). | * decremented below if we don't make it to syncache_tfo_expand(). | ||||
*/ | */ | ||||
tfo_pending = tp->t_tfo_pending; | tfo_pending = tp->t_tfo_pending; | ||||
} | } | ||||
#endif | |||||
/* By the time we drop the lock these should no longer be used. */ | /* By the time we drop the lock these should no longer be used. */ | ||||
so = NULL; | so = NULL; | ||||
tp = NULL; | tp = NULL; | ||||
#ifdef MAC | #ifdef MAC | ||||
if (mac_syncache_init(&maclabel) != 0) { | if (mac_syncache_init(&maclabel) != 0) { | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
goto done; | goto done; | ||||
} else | } else | ||||
mac_syncache_create(maclabel, inp); | mac_syncache_create(maclabel, inp); | ||||
#endif | #endif | ||||
#ifdef TCP_RFC7413 | |||||
if (!tfo_cookie_valid) | if (!tfo_cookie_valid) | ||||
#endif | |||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
/* | /* | ||||
* Remember the IP options, if any. | * Remember the IP options, if any. | ||||
*/ | */ | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if (!(inc->inc_flags & INC_ISIPV6)) | if (!(inc->inc_flags & INC_ISIPV6)) | ||||
#endif | #endif | ||||
Show All 29 Lines | #endif /* TCP_SIGNATURE */ | ||||
* XXX: We do not check the sequence number to see if this is a | * XXX: We do not check the sequence number to see if this is a | ||||
* real retransmit or a new connection attempt. The question is | * real retransmit or a new connection attempt. The question is | ||||
* how to handle such a case; either ignore it as spoofed, or | * how to handle such a case; either ignore it as spoofed, or | ||||
* drop the current entry and create a new one? | * drop the current entry and create a new one? | ||||
*/ | */ | ||||
sc = syncache_lookup(inc, &sch); /* returns locked entry */ | sc = syncache_lookup(inc, &sch); /* returns locked entry */ | ||||
SCH_LOCK_ASSERT(sch); | SCH_LOCK_ASSERT(sch); | ||||
if (sc != NULL) { | if (sc != NULL) { | ||||
#ifdef TCP_RFC7413 | |||||
if (tfo_cookie_valid) | if (tfo_cookie_valid) | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
#endif | |||||
TCPSTAT_INC(tcps_sc_dupsyn); | TCPSTAT_INC(tcps_sc_dupsyn); | ||||
if (ipopts) { | if (ipopts) { | ||||
/* | /* | ||||
* If we were remembering a previous source route, | * If we were remembering a previous source route, | ||||
* forget it and use the new one we've been given. | * forget it and use the new one we've been given. | ||||
*/ | */ | ||||
if (sc->sc_ipopts) | if (sc->sc_ipopts) | ||||
(void) m_free(sc->sc_ipopts); | (void) m_free(sc->sc_ipopts); | ||||
Show All 26 Lines | if (syncache_respond(sc, sch, 1, m) == 0) { | ||||
syncache_timeout(sc, sch, 1); | syncache_timeout(sc, sch, 1); | ||||
TCPSTAT_INC(tcps_sndacks); | TCPSTAT_INC(tcps_sndacks); | ||||
TCPSTAT_INC(tcps_sndtotal); | TCPSTAT_INC(tcps_sndtotal); | ||||
} | } | ||||
SCH_UNLOCK(sch); | SCH_UNLOCK(sch); | ||||
goto done; | goto done; | ||||
} | } | ||||
#ifdef TCP_RFC7413 | |||||
if (tfo_cookie_valid) { | if (tfo_cookie_valid) { | ||||
bzero(&scs, sizeof(scs)); | bzero(&scs, sizeof(scs)); | ||||
sc = &scs; | sc = &scs; | ||||
goto skip_alloc; | goto skip_alloc; | ||||
} | } | ||||
#endif | |||||
sc = uma_zalloc(V_tcp_syncache.zone, M_NOWAIT | M_ZERO); | sc = uma_zalloc(V_tcp_syncache.zone, M_NOWAIT | M_ZERO); | ||||
if (sc == NULL) { | if (sc == NULL) { | ||||
/* | /* | ||||
* The zone allocator couldn't provide more entries. | * The zone allocator couldn't provide more entries. | ||||
* Treat this as if the cache was full; drop the oldest | * Treat this as if the cache was full; drop the oldest | ||||
* entry and insert the new one. | * entry and insert the new one. | ||||
*/ | */ | ||||
Show All 11 Lines | if (sc == NULL) { | ||||
SCH_UNLOCK(sch); | SCH_UNLOCK(sch); | ||||
if (ipopts) | if (ipopts) | ||||
(void) m_free(ipopts); | (void) m_free(ipopts); | ||||
goto done; | goto done; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
#ifdef TCP_RFC7413 | |||||
skip_alloc: | skip_alloc: | ||||
if (!tfo_cookie_valid && tfo_response_cookie_valid) | if (!tfo_cookie_valid && tfo_response_cookie_valid) | ||||
sc->sc_tfo_cookie = &tfo_response_cookie; | sc->sc_tfo_cookie = &tfo_response_cookie; | ||||
#endif | |||||
/* | /* | ||||
* Fill in the syncache values. | * Fill in the syncache values. | ||||
*/ | */ | ||||
#ifdef MAC | #ifdef MAC | ||||
sc->sc_label = maclabel; | sc->sc_label = maclabel; | ||||
#endif | #endif | ||||
sc->sc_cred = cred; | sc->sc_cred = cred; | ||||
▲ Show 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | if (V_tcp_syncookies) | ||||
sc->sc_flowlabel = sc->sc_iss; | sc->sc_flowlabel = sc->sc_iss; | ||||
else | else | ||||
sc->sc_flowlabel = ip6_randomflowlabel(); | sc->sc_flowlabel = ip6_randomflowlabel(); | ||||
sc->sc_flowlabel = htonl(sc->sc_flowlabel) & IPV6_FLOWLABEL_MASK; | sc->sc_flowlabel = htonl(sc->sc_flowlabel) & IPV6_FLOWLABEL_MASK; | ||||
} | } | ||||
#endif | #endif | ||||
SCH_UNLOCK(sch); | SCH_UNLOCK(sch); | ||||
#ifdef TCP_RFC7413 | |||||
if (tfo_cookie_valid) { | if (tfo_cookie_valid) { | ||||
syncache_tfo_expand(sc, lsop, m, tfo_response_cookie); | syncache_tfo_expand(sc, lsop, m, tfo_response_cookie); | ||||
/* INP_WUNLOCK(inp) will be performed by the caller */ | /* INP_WUNLOCK(inp) will be performed by the caller */ | ||||
rv = 1; | rv = 1; | ||||
goto tfo_expanded; | goto tfo_expanded; | ||||
} | } | ||||
#endif | |||||
/* | /* | ||||
* Do a standard 3-way handshake. | * Do a standard 3-way handshake. | ||||
*/ | */ | ||||
if (syncache_respond(sc, sch, 0, m) == 0) { | if (syncache_respond(sc, sch, 0, m) == 0) { | ||||
if (V_tcp_syncookies && V_tcp_syncookiesonly && sc != &scs) | if (V_tcp_syncookies && V_tcp_syncookiesonly && sc != &scs) | ||||
syncache_free(sc); | syncache_free(sc); | ||||
else if (sc != &scs) | else if (sc != &scs) | ||||
syncache_insert(sc, sch); /* locks and unlocks sch */ | syncache_insert(sc, sch); /* locks and unlocks sch */ | ||||
TCPSTAT_INC(tcps_sndacks); | TCPSTAT_INC(tcps_sndacks); | ||||
TCPSTAT_INC(tcps_sndtotal); | TCPSTAT_INC(tcps_sndtotal); | ||||
} else { | } else { | ||||
if (sc != &scs) | if (sc != &scs) | ||||
syncache_free(sc); | syncache_free(sc); | ||||
TCPSTAT_INC(tcps_sc_dropped); | TCPSTAT_INC(tcps_sc_dropped); | ||||
} | } | ||||
done: | done: | ||||
if (m) { | if (m) { | ||||
*lsop = NULL; | *lsop = NULL; | ||||
m_freem(m); | m_freem(m); | ||||
} | } | ||||
#ifdef TCP_RFC7413 | |||||
/* | /* | ||||
* If tfo_pending is not NULL here, then a TFO SYN that did not | * If tfo_pending is not NULL here, then a TFO SYN that did not | ||||
* result in a new socket was processed and the associated pending | * result in a new socket was processed and the associated pending | ||||
* counter has not yet been decremented. All such TFO processing paths | * counter has not yet been decremented. All such TFO processing paths | ||||
* transit this point. | * transit this point. | ||||
*/ | */ | ||||
if (tfo_pending != NULL) | if (tfo_pending != NULL) | ||||
tcp_fastopen_decrement_counter(tfo_pending); | tcp_fastopen_decrement_counter(tfo_pending); | ||||
tfo_expanded: | tfo_expanded: | ||||
#endif | |||||
if (cred != NULL) | if (cred != NULL) | ||||
crfree(cred); | crfree(cred); | ||||
#ifdef MAC | #ifdef MAC | ||||
if (sc == &scs) | if (sc == &scs) | ||||
mac_syncache_destroy(&maclabel); | mac_syncache_destroy(&maclabel); | ||||
#endif | #endif | ||||
return (rv); | return (rv); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | if (sc->sc_flags & SCF_TIMESTAMP) { | ||||
to.to_flags |= TOF_TS; | to.to_flags |= TOF_TS; | ||||
} | } | ||||
if (sc->sc_flags & SCF_SACK) | if (sc->sc_flags & SCF_SACK) | ||||
to.to_flags |= TOF_SACKPERM; | to.to_flags |= TOF_SACKPERM; | ||||
#if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE) | #if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE) | ||||
if (sc->sc_flags & SCF_SIGNATURE) | if (sc->sc_flags & SCF_SIGNATURE) | ||||
to.to_flags |= TOF_SIGNATURE; | to.to_flags |= TOF_SIGNATURE; | ||||
#endif | #endif | ||||
#ifdef TCP_RFC7413 | |||||
if (sc->sc_tfo_cookie) { | if (sc->sc_tfo_cookie) { | ||||
to.to_flags |= TOF_FASTOPEN; | to.to_flags |= TOF_FASTOPEN; | ||||
to.to_tfo_len = TCP_FASTOPEN_COOKIE_LEN; | to.to_tfo_len = TCP_FASTOPEN_COOKIE_LEN; | ||||
to.to_tfo_cookie = sc->sc_tfo_cookie; | to.to_tfo_cookie = sc->sc_tfo_cookie; | ||||
/* don't send cookie again when retransmitting response */ | /* don't send cookie again when retransmitting response */ | ||||
sc->sc_tfo_cookie = NULL; | sc->sc_tfo_cookie = NULL; | ||||
} | } | ||||
#endif | |||||
optlen = tcp_addoptions(&to, (u_char *)(th + 1)); | optlen = tcp_addoptions(&to, (u_char *)(th + 1)); | ||||
/* Adjust headers by option size. */ | /* Adjust headers by option size. */ | ||||
th->th_off = (sizeof(struct tcphdr) + optlen) >> 2; | th->th_off = (sizeof(struct tcphdr) + optlen) >> 2; | ||||
m->m_len += optlen; | m->m_len += optlen; | ||||
m->m_pkthdr.len += optlen; | m->m_pkthdr.len += optlen; | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if (sc->sc_inc.inc_flags & INC_ISIPV6) | if (sc->sc_inc.inc_flags & INC_ISIPV6) | ||||
▲ Show 20 Lines • Show All 500 Lines • Show Last 20 Lines |