if (!tcp_oow_rate_limited(twsk_net(tw), skb, mib_idx,
&tcptw->tw_last_oow_ack_time)) { /* Send ACK. Note, we do not put the bucket, *itwillbereleasedbycaller.
*/ return TCP_TW_ACK_OOW;
}
/* We are rate-limiting, so just release the tw sock and drop skb. */
inet_twsk_put(tw); return TCP_TW_SUCCESS;
}
if (!paws_reject &&
(TCP_SKB_CB(skb)->seq == rcv_nxt &&
(TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq || th->rst))) { /* In window segment, it may be only reset or bare ack. */
if (th->rst) { /* This is TIME_WAIT assassination, in two flavors. *Ohwell...nobodyhasasufficientsolutiontothis *protocolbugyet.
*/ if (!READ_ONCE(twsk_net(tw)->ipv4.sysctl_tcp_rfc1337)) {
kill:
inet_twsk_deschedule_put(tw); return TCP_TW_SUCCESS;
}
} else {
inet_twsk_reschedule(tw, TCP_TIMEWAIT_LEN);
}
if (tmp_opt.saw_tstamp) {
WRITE_ONCE(tcptw->tw_ts_recent,
tmp_opt.rcv_tsval);
WRITE_ONCE(tcptw->tw_ts_recent_stamp,
ktime_get_seconds());
}
if (paws_reject) {
*drop_reason = SKB_DROP_REASON_TCP_RFC7323_TW_PAWS;
__NET_INC_STATS(twsk_net(tw), LINUX_MIB_PAWS_TW_REJECTED);
}
if (!th->rst) { /* In this case we must reset the TIMEWAIT timer. * *IfitisACKlessSYNitmaybebotholdduplicate *andnewgoodSYNwithrandomsequencenumber<rcv_nxt. *Donotrescheduleinthelastcase.
*/ if (paws_reject || th->ack)
inet_twsk_reschedule(tw, TCP_TIMEWAIT_LEN);
/* Get the TIME_WAIT timeout firing. */ if (timeo < rto)
timeo = rto;
if (state == TCP_TIME_WAIT)
timeo = TCP_TIMEWAIT_LEN;
/* Linkage updates. *Notethataccesstotwafterthispointisillegal.
*/
inet_twsk_hashdance_schedule(tw, sk, net->ipv4.tcp_death_row.hashinfo, timeo);
} else { /* Sorry, if we're out of memory, just CLOSE this *socketup.We'vegotbiggerproblemsthan *non-gracefulsocketclosings.
*/
NET_INC_STATS(net, LINUX_MIB_TCPTIMEWAITOVERFLOW);
}
list_for_each_entry(net, net_exit_list, exit_list) { if (net->ipv4.tcp_death_row.hashinfo->pernet) { /* Even if tw_refcount == 1, we must clean up kernel reqsk */
inet_twsk_purge(net->ipv4.tcp_death_row.hashinfo);
} elseif (!purged_once) {
inet_twsk_purge(&tcp_hashinfo);
purged_once = true;
}
}
}
/* Warning : This function is called without sk_listener being locked. *Besuretoreadsocketfieldsonce,astheirvaluecouldchangeunderus.
*/ void tcp_openreq_init_rwin(struct request_sock *req, conststruct sock *sk_listener, conststruct dst_entry *dst)
{ struct inet_request_sock *ireq = inet_rsk(req); conststruct tcp_sock *tp = tcp_sk(sk_listener); int full_space = tcp_full_space(sk_listener);
u32 window_clamp;
__u8 rcv_wscale;
u32 rcv_wnd; int mss;
mss = tcp_mss_clamp(tp, dst_metric_advmss(dst));
window_clamp = READ_ONCE(tp->window_clamp); /* Set this up on the first call only */
req->rsk_window_clamp = window_clamp ? : dst_metric(dst, RTAX_WINDOW);
/* limit the window selection if the user enforce a smaller rx buffer */ if (sk_listener->sk_userlocks & SOCK_RCVBUF_LOCK &&
(req->rsk_window_clamp > full_space || req->rsk_window_clamp == 0))
req->rsk_window_clamp = full_space;
/* tcp_full_space because it is guaranteed to be the first packet */
tcp_select_initial_window(sk_listener, full_space,
mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0),
&req->rsk_rcv_wnd,
&req->rsk_window_clamp,
ireq->wscale_ok,
&rcv_wscale,
rcv_wnd);
ireq->rcv_wscale = rcv_wscale;
}
/* If no valid choice made yet, assign current system default ca. */ if (!ca_got_dst &&
(!icsk->icsk_ca_setsockopt ||
!bpf_try_module_get(icsk->icsk_ca_ops, icsk->icsk_ca_ops->owner)))
tcp_assign_congestion_control(sk);
if (tmp_opt.saw_tstamp) {
tmp_opt.ts_recent = req->ts_recent; if (tmp_opt.rcv_tsecr) { if (inet_rsk(req)->tstamp_ok && !fastopen)
tsecr_reject = !between(tmp_opt.rcv_tsecr,
tcp_rsk(req)->snt_tsval_first,
READ_ONCE(tcp_rsk(req)->snt_tsval_last));
tmp_opt.rcv_tsecr -= tcp_rsk(req)->ts_off;
} /* We do not store true stamp, but it is not required, *itcanbeestimated(approximately) *fromanotherdata.
*/
tmp_opt.ts_recent_stamp = ktime_get_seconds() - reqsk_timeout(req, TCP_RTO_MAX) / HZ;
paws_reject = tcp_paws_reject(&tmp_opt, th->rst);
}
}
/* RFC793 page 36: "If the connection is in any non-synchronized state ... *andtheincomingsegmentacknowledgessomethingnotyet *sent(thesegmentcarriesanunacceptableACK)... *aresetissent." * *InvalidACK:resetwillbesentbylisteningsocket. *NotethattheACKvaliditycheckforaFastOpensocketisdone *elsewhereandischeckeddirectlyagainstthechildsocketrather *thanreqbecauseuserdatamayhavebeensentout.
*/ if ((flg & TCP_FLAG_ACK) && !fastopen &&
(TCP_SKB_CB(skb)->ack_seq !=
tcp_rsk(req)->snt_isn + 1)) return sk;
/* RFC793: "first check sequence number". */
if (paws_reject || tsecr_reject ||
!tcp_in_window(TCP_SKB_CB(skb)->seq,
TCP_SKB_CB(skb)->end_seq,
tcp_rsk(req)->rcv_nxt,
tcp_rsk(req)->rcv_nxt +
tcp_synack_window(req))) { /* Out of window: send ACK and drop. */ if (!(flg & TCP_FLAG_RST) &&
!tcp_oow_rate_limited(sock_net(sk), skb,
LINUX_MIB_TCPACKSKIPPEDSYNRECV,
&tcp_rsk(req)->last_oow_ack_time))
req->rsk_ops->send_ack(sk, skb, req); if (paws_reject) {
SKB_DR_SET(*drop_reason, TCP_RFC7323_PAWS);
NET_INC_STATS(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
} elseif (tsecr_reject) {
SKB_DR_SET(*drop_reason, TCP_RFC7323_TSECR);
NET_INC_STATS(sock_net(sk), LINUX_MIB_TSECRREJECTED);
} else {
SKB_DR_SET(*drop_reason, TCP_OVERWINDOW);
} return NULL;
}
/* In sequence, PAWS is OK. */
if (TCP_SKB_CB(skb)->seq == tcp_rsk(req)->rcv_isn) { /* Truncate SYN, it is out of window starting
at tcp_rsk(req)->rcv_isn + 1. */
flg &= ~TCP_FLAG_SYN;
}
/* RFC793: "second check the RST bit" and *"fourth,checktheSYNbit"
*/ if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN)) {
TCP_INC_STATS(sock_net(sk), TCP_MIB_ATTEMPTFAILS); goto embryonic_reset;
}
/* ACK sequence verified above, just make sure ACK is *set.IfACKnotset,justsilentlydropthepacket. * *XXX(TFO)-ifweeverallow"dataafterSYN",the *followingcheckneedstoberemoved.
*/ if (!(flg & TCP_FLAG_ACK)) return NULL;
/* For Fast Open no more processing is needed (sk is the *childsocket).
*/ if (fastopen) return sk;
/* While TCP_DEFER_ACCEPT is active, drop bare ACK. */ if (req->num_timeout < READ_ONCE(inet_csk(sk)->icsk_accept_queue.rskq_defer_accept) &&
TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) {
inet_rsk(req)->acked = 1;
__NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPDEFERACCEPTDROP); return NULL;
}
/* OK, ACK is valid, create big socket and *feedthissegmenttoit.Itwillrepeatall *thetests.THISSEGMENTMUSTMOVESOCKETTO *ESTABLISHEDSTATE.Ifitwillbedroppedafter *socketiscreated,waitfortroubles.
*/
child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL,
req, &own_req); if (!child) goto listen_overflow;
if (own_req && tmp_opt.saw_tstamp &&
!after(TCP_SKB_CB(skb)->seq, tcp_rsk(req)->rcv_nxt))
tcp_sk(child)->rx_opt.ts_recent = tmp_opt.rcv_tsval;
listen_overflow:
SKB_DR_SET(*drop_reason, TCP_LISTEN_OVERFLOW); if (sk != req->rsk_listener)
__NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMIGRATEREQFAILURE);
if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_abort_on_overflow)) {
inet_rsk(req)->acked = 1; return NULL;
}
embryonic_reset: if (!(flg & TCP_FLAG_RST)) { /* Received a bad SYN pkt - for TFO We try not to reset *thelocalconnectionunlessit'sreallynecessaryto *avoidbecomingvulnerabletooutsideattackaimingat *resettinglegitlocalconnections.
*/
req->rsk_ops->send_reset(sk, skb, SK_RST_REASON_INVALID_SYN);
} elseif (fastopen) { /* received a valid RST pkt */
reqsk_fastopen_remove(sk, req, true);
tcp_reset(sk, skb);
} if (!fastopen) { bool unlinked = inet_csk_reqsk_queue_drop(sk, req);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.