Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_input.c
Show First 20 Lines • Show All 1,598 Lines • ▼ Show 20 Lines | #endif | ||||
/* | /* | ||||
* If a segment with the ACK-bit set arrives in the SYN-SENT state | * If a segment with the ACK-bit set arrives in the SYN-SENT state | ||||
* check SEQ.ACK first. | * check SEQ.ACK first. | ||||
*/ | */ | ||||
if ((tp->t_state == TCPS_SYN_SENT) && (thflags & TH_ACK) && | if ((tp->t_state == TCPS_SYN_SENT) && (thflags & TH_ACK) && | ||||
(SEQ_LEQ(th->th_ack, tp->iss) || SEQ_GT(th->th_ack, tp->snd_max))) { | (SEQ_LEQ(th->th_ack, tp->iss) || SEQ_GT(th->th_ack, tp->snd_max))) { | ||||
rstreason = BANDLIM_UNLIMITED; | rstreason = BANDLIM_UNLIMITED; | ||||
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT); | |||||
goto dropwithreset; | goto dropwithreset; | ||||
} | } | ||||
/* | /* | ||||
* Segment received on connection. | * Segment received on connection. | ||||
* Reset idle time and keep-alive timer. | * Reset idle time and keep-alive timer. | ||||
* XXX: This should be done after segment | * XXX: This should be done after segment | ||||
* validation to ignore broken/spoofed segs. | * validation to ignore broken/spoofed segs. | ||||
*/ | */ | ||||
tp->t_rcvtime = ticks; | tp->t_rcvtime = ticks; | ||||
if (thflags & TH_FIN) | |||||
tcp_log_end_status(tp, TCP_EI_STATUS_CLIENT_FIN); | |||||
/* | /* | ||||
* Scale up the window into a 32-bit value. | * Scale up the window into a 32-bit value. | ||||
* For the SYN_SENT state the scale is zero. | * For the SYN_SENT state the scale is zero. | ||||
*/ | */ | ||||
tiwin = th->th_win << tp->snd_scale; | tiwin = th->th_win << tp->snd_scale; | ||||
#ifdef STATS | #ifdef STATS | ||||
stats_voi_update_abs_ulong(tp->t_stats, VOI_TCP_FRWIN, tiwin); | stats_voi_update_abs_ulong(tp->t_stats, VOI_TCP_FRWIN, tiwin); | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 357 Lines • ▼ Show 20 Lines | #endif | ||||
* If the state is SYN_RECEIVED: | * If the state is SYN_RECEIVED: | ||||
* if seg contains an ACK, but not for our SYN/ACK, send a RST. | * if seg contains an ACK, but not for our SYN/ACK, send a RST. | ||||
*/ | */ | ||||
case TCPS_SYN_RECEIVED: | case TCPS_SYN_RECEIVED: | ||||
if ((thflags & TH_ACK) && | if ((thflags & TH_ACK) && | ||||
(SEQ_LEQ(th->th_ack, tp->snd_una) || | (SEQ_LEQ(th->th_ack, tp->snd_una) || | ||||
SEQ_GT(th->th_ack, tp->snd_max))) { | SEQ_GT(th->th_ack, tp->snd_max))) { | ||||
rstreason = BANDLIM_RST_OPENPORT; | rstreason = BANDLIM_RST_OPENPORT; | ||||
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT); | |||||
goto dropwithreset; | goto dropwithreset; | ||||
} | } | ||||
if (IS_FASTOPEN(tp->t_flags)) { | if (IS_FASTOPEN(tp->t_flags)) { | ||||
/* | /* | ||||
* When a TFO connection is in SYN_RECEIVED, the | * When a TFO connection is in SYN_RECEIVED, the | ||||
* only valid packets are the initial SYN, a | * only valid packets are the initial SYN, a | ||||
* retransmit/copy of the initial SYN (possibly with | * retransmit/copy of the initial SYN (possibly with | ||||
* a subset of the original data), a valid ACK, a | * a subset of the original data), a valid ACK, a | ||||
* FIN, or a RST. | * FIN, or a RST. | ||||
*/ | */ | ||||
if ((thflags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { | if ((thflags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { | ||||
rstreason = BANDLIM_RST_OPENPORT; | rstreason = BANDLIM_RST_OPENPORT; | ||||
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT); | |||||
goto dropwithreset; | goto dropwithreset; | ||||
} else if (thflags & TH_SYN) { | } else if (thflags & TH_SYN) { | ||||
/* non-initial SYN is ignored */ | /* non-initial SYN is ignored */ | ||||
if ((tcp_timer_active(tp, TT_DELACK) || | if ((tcp_timer_active(tp, TT_DELACK) || | ||||
tcp_timer_active(tp, TT_REXMT))) | tcp_timer_active(tp, TT_REXMT))) | ||||
goto drop; | goto drop; | ||||
} else if (!(thflags & (TH_ACK|TH_FIN|TH_RST))) { | } else if (!(thflags & (TH_ACK|TH_FIN|TH_RST))) { | ||||
goto drop; | goto drop; | ||||
Show All 15 Lines | #endif | ||||
* if SYN has been acked change to ESTABLISHED else SYN_RCVD state | * if SYN has been acked change to ESTABLISHED else SYN_RCVD state | ||||
* arrange for segment to be acked (eventually) | * arrange for segment to be acked (eventually) | ||||
* continue processing rest of data/controls, beginning with URG | * continue processing rest of data/controls, beginning with URG | ||||
*/ | */ | ||||
case TCPS_SYN_SENT: | case TCPS_SYN_SENT: | ||||
if ((thflags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) { | if ((thflags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) { | ||||
TCP_PROBE5(connect__refused, NULL, tp, | TCP_PROBE5(connect__refused, NULL, tp, | ||||
m, tp, th); | m, tp, th); | ||||
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT); | |||||
tp = tcp_drop(tp, ECONNREFUSED); | tp = tcp_drop(tp, ECONNREFUSED); | ||||
} | } | ||||
if (thflags & TH_RST) | if (thflags & TH_RST) | ||||
goto drop; | goto drop; | ||||
if (!(thflags & TH_SYN)) | if (!(thflags & TH_SYN)) | ||||
goto drop; | goto drop; | ||||
tp->irs = th->th_seq; | tp->irs = th->th_seq; | ||||
▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | if ((SEQ_GEQ(th->th_seq, tp->last_ack_sent) && | ||||
case TCPS_FIN_WAIT_2: | case TCPS_FIN_WAIT_2: | ||||
case TCPS_CLOSE_WAIT: | case TCPS_CLOSE_WAIT: | ||||
case TCPS_CLOSING: | case TCPS_CLOSING: | ||||
case TCPS_LAST_ACK: | case TCPS_LAST_ACK: | ||||
so->so_error = ECONNRESET; | so->so_error = ECONNRESET; | ||||
close: | close: | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
default: | default: | ||||
tcp_log_end_status(tp, TCP_EI_STATUS_CLIENT_RST); | |||||
tp = tcp_close(tp); | tp = tcp_close(tp); | ||||
} | } | ||||
} else { | } else { | ||||
TCPSTAT_INC(tcps_badrst); | TCPSTAT_INC(tcps_badrst); | ||||
/* Send challenge ACK. */ | /* Send challenge ACK. */ | ||||
tcp_respond(tp, mtod(m, void *), th, m, | tcp_respond(tp, mtod(m, void *), th, m, | ||||
tp->rcv_nxt, tp->snd_nxt, TH_ACK); | tp->rcv_nxt, tp->snd_nxt, TH_ACK); | ||||
tp->last_ack_sent = tp->rcv_nxt; | tp->last_ack_sent = tp->rcv_nxt; | ||||
m = NULL; | m = NULL; | ||||
} | } | ||||
} | } | ||||
goto drop; | goto drop; | ||||
} | } | ||||
/* | /* | ||||
* RFC5961 Section 4.2 | * RFC5961 Section 4.2 | ||||
* Send challenge ACK for any SYN in synchronized state. | * Send challenge ACK for any SYN in synchronized state. | ||||
*/ | */ | ||||
if ((thflags & TH_SYN) && tp->t_state != TCPS_SYN_SENT && | if ((thflags & TH_SYN) && tp->t_state != TCPS_SYN_SENT && | ||||
tp->t_state != TCPS_SYN_RECEIVED) { | tp->t_state != TCPS_SYN_RECEIVED) { | ||||
TCPSTAT_INC(tcps_badsyn); | TCPSTAT_INC(tcps_badsyn); | ||||
if (V_tcp_insecure_syn && | if (V_tcp_insecure_syn && | ||||
SEQ_GEQ(th->th_seq, tp->last_ack_sent) && | SEQ_GEQ(th->th_seq, tp->last_ack_sent) && | ||||
SEQ_LT(th->th_seq, tp->last_ack_sent + tp->rcv_wnd)) { | SEQ_LT(th->th_seq, tp->last_ack_sent + tp->rcv_wnd)) { | ||||
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT); | |||||
tp = tcp_drop(tp, ECONNRESET); | tp = tcp_drop(tp, ECONNRESET); | ||||
rstreason = BANDLIM_UNLIMITED; | rstreason = BANDLIM_UNLIMITED; | ||||
} else { | } else { | ||||
/* Send challenge ACK. */ | /* Send challenge ACK. */ | ||||
tcp_respond(tp, mtod(m, void *), th, m, tp->rcv_nxt, | tcp_respond(tp, mtod(m, void *), th, m, tp->rcv_nxt, | ||||
tp->snd_nxt, TH_ACK); | tp->snd_nxt, TH_ACK); | ||||
tp->last_ack_sent = tp->rcv_nxt; | tp->last_ack_sent = tp->rcv_nxt; | ||||
m = NULL; | m = NULL; | ||||
Show All 35 Lines | #endif | ||||
* In the SYN-RECEIVED state, validate that the packet belongs to | * In the SYN-RECEIVED state, validate that the packet belongs to | ||||
* this connection before trimming the data to fit the receive | * this connection before trimming the data to fit the receive | ||||
* window. Check the sequence number versus IRS since we know | * window. Check the sequence number versus IRS since we know | ||||
* the sequence numbers haven't wrapped. This is a partial fix | * the sequence numbers haven't wrapped. This is a partial fix | ||||
* for the "LAND" DoS attack. | * for the "LAND" DoS attack. | ||||
*/ | */ | ||||
if (tp->t_state == TCPS_SYN_RECEIVED && SEQ_LT(th->th_seq, tp->irs)) { | if (tp->t_state == TCPS_SYN_RECEIVED && SEQ_LT(th->th_seq, tp->irs)) { | ||||
rstreason = BANDLIM_RST_OPENPORT; | rstreason = BANDLIM_RST_OPENPORT; | ||||
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT); | |||||
goto dropwithreset; | goto dropwithreset; | ||||
} | } | ||||
todrop = tp->rcv_nxt - th->th_seq; | todrop = tp->rcv_nxt - th->th_seq; | ||||
if (todrop > 0) { | if (todrop > 0) { | ||||
if (thflags & TH_SYN) { | if (thflags & TH_SYN) { | ||||
thflags &= ~TH_SYN; | thflags &= ~TH_SYN; | ||||
th->th_seq++; | th->th_seq++; | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | #endif | ||||
if ((tp->t_flags & TF_CLOSED) && tlen) { | if ((tp->t_flags & TF_CLOSED) && tlen) { | ||||
if ((s = tcp_log_addrs(inc, th, NULL, NULL))) { | if ((s = tcp_log_addrs(inc, th, NULL, NULL))) { | ||||
log(LOG_DEBUG, "%s; %s: %s: Received %d bytes of data " | log(LOG_DEBUG, "%s; %s: %s: Received %d bytes of data " | ||||
"after socket was closed, " | "after socket was closed, " | ||||
"sending RST and removing tcpcb\n", | "sending RST and removing tcpcb\n", | ||||
s, __func__, tcpstates[tp->t_state], tlen); | s, __func__, tcpstates[tp->t_state], tlen); | ||||
free(s, M_TCPLOG); | free(s, M_TCPLOG); | ||||
} | } | ||||
tcp_log_end_status(tp, TCP_EI_STATUS_DATA_A_CLOSE); | |||||
/* tcp_close will kill the inp pre-log the Reset */ | |||||
tcp_log_end_status(tp, TCP_EI_STATUS_SERVER_RST); | |||||
tp = tcp_close(tp); | tp = tcp_close(tp); | ||||
TCPSTAT_INC(tcps_rcvafterclose); | TCPSTAT_INC(tcps_rcvafterclose); | ||||
rstreason = BANDLIM_UNLIMITED; | rstreason = BANDLIM_UNLIMITED; | ||||
goto dropwithreset; | goto dropwithreset; | ||||
} | } | ||||
/* | /* | ||||
* If segment ends after window, drop trailing data | * If segment ends after window, drop trailing data | ||||
▲ Show 20 Lines • Show All 975 Lines • ▼ Show 20 Lines | dropafterack: | ||||
* "LAND" DoS attack, and also prevents an ACK storm | * "LAND" DoS attack, and also prevents an ACK storm | ||||
* between two listening ports that have been sent forged | * between two listening ports that have been sent forged | ||||
* SYN segments, each with the source address of the other. | * SYN segments, each with the source address of the other. | ||||
*/ | */ | ||||
if (tp->t_state == TCPS_SYN_RECEIVED && (thflags & TH_ACK) && | if (tp->t_state == TCPS_SYN_RECEIVED && (thflags & TH_ACK) && | ||||
(SEQ_GT(tp->snd_una, th->th_ack) || | (SEQ_GT(tp->snd_una, th->th_ack) || | ||||
SEQ_GT(th->th_ack, tp->snd_max)) ) { | SEQ_GT(th->th_ack, tp->snd_max)) ) { | ||||
rstreason = BANDLIM_RST_OPENPORT; | rstreason = BANDLIM_RST_OPENPORT; | ||||
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT); | |||||
goto dropwithreset; | goto dropwithreset; | ||||
} | } | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
if (so->so_options & SO_DEBUG) | if (so->so_options & SO_DEBUG) | ||||
tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, | tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, | ||||
&tcp_savetcp, 0); | &tcp_savetcp, 0); | ||||
#endif | #endif | ||||
TCP_PROBE3(debug__input, tp, th, m); | TCP_PROBE3(debug__input, tp, th, m); | ||||
▲ Show 20 Lines • Show All 755 Lines • Show Last 20 Lines |