diff options
Diffstat (limited to 'sys/netinet/tcp_input.c')
-rw-r--r-- | sys/netinet/tcp_input.c | 127 |
1 files changed, 94 insertions, 33 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 3fda6e903738..b64a71837ab4 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -202,6 +202,11 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, insecure_rst, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(tcp_insecure_rst), 0, "Follow RFC793 instead of RFC5961 criteria for accepting RST packets"); +VNET_DEFINE(int, tcp_insecure_ack) = 0; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, insecure_ack, CTLFLAG_VNET | CTLFLAG_RW, + &VNET_NAME(tcp_insecure_ack), 0, + "Follow RFC793 criteria for validating SEG.ACK"); + VNET_DEFINE(int, tcp_recvspace) = 1024*64; #define V_tcp_recvspace VNET(tcp_recvspace) SYSCTL_INT(_net_inet_tcp, TCPCTL_RECVSPACE, recvspace, CTLFLAG_VNET | CTLFLAG_RW, @@ -833,6 +838,7 @@ tcp_input_with_port(struct mbuf **mp, int *offp, int proto, uint16_t port) ((thflags & (TH_ACK|TH_SYN)) == TH_SYN ? INPLOOKUP_RLOCKPCB : INPLOOKUP_WLOCKPCB); findpcb: + tp = NULL; #ifdef INET6 if (isipv6 && fwd_tag != NULL) { struct sockaddr_in6 *next_hop6; @@ -915,23 +921,6 @@ findpcb: log(LOG_INFO, "%s; %s: Connection attempt " "to closed port\n", s, __func__); } - /* - * When blackholing do not respond with a RST but - * completely ignore the segment and drop it. - */ - if (((V_blackhole == 1 && (thflags & TH_SYN)) || - V_blackhole == 2) && (V_blackhole_local || ( -#ifdef INET6 - isipv6 ? !in6_localaddr(&ip6->ip6_src) : -#endif -#ifdef INET - !in_localip(ip->ip_src) -#else - true -#endif - ))) - goto dropunlock; - rstreason = BANDLIM_RST_CLOSEDPORT; goto dropwithreset; } @@ -1410,15 +1399,27 @@ tfo_socket_result: return (IPPROTO_DONE); dropwithreset: + /* + * When blackholing do not respond with a RST but + * completely ignore the segment and drop it. + */ + if (((rstreason == BANDLIM_RST_OPENPORT && V_blackhole == 3) || + (rstreason == BANDLIM_RST_CLOSEDPORT && + ((V_blackhole == 1 && (thflags & TH_SYN)) || V_blackhole > 1))) && + (V_blackhole_local || ( +#ifdef INET6 + isipv6 ? !in6_localaddr(&ip6->ip6_src) : +#endif +#ifdef INET + !in_localip(ip->ip_src) +#else + true +#endif + ))) + goto dropunlock; TCP_PROBE5(receive, NULL, tp, m, tp, th); - - if (inp != NULL) { - tcp_dropwithreset(m, th, tp, tlen, rstreason); - INP_UNLOCK(inp); - } else - tcp_dropwithreset(m, th, NULL, tlen, rstreason); + tcp_dropwithreset(m, th, tp, tlen, rstreason); m = NULL; /* mbuf chain got consumed. */ - goto drop; dropunlock: if (m != NULL) @@ -1615,7 +1616,14 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th, tcp_dooptions(&to, (u_char *)(th + 1), (th->th_off << 2) - sizeof(struct tcphdr), (thflags & TH_SYN) ? TO_SYN : 0); - + if (tp->t_flags2 & TF2_PROC_SACK_PROHIBIT) { + /* + * We don't look at sack's from the + * peer because the MSS is too small which + * can subject us to an attack. + */ + to.to_flags &= ~TOF_SACK; + } #if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE) if ((tp->t_flags & TF_SIGNATURE) != 0 && (to.to_flags & TOF_SIGNATURE) == 0) { @@ -2200,10 +2208,7 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th, } } else { TCPSTAT_INC(tcps_badrst); - /* Send challenge ACK. */ - tcp_respond(tp, mtod(m, void *), th, m, - tp->rcv_nxt, tp->snd_nxt, TH_ACK); - tp->last_ack_sent = tp->rcv_nxt; + tcp_send_challenge_ack(tp, th, m); m = NULL; } } @@ -2225,10 +2230,7 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th, rstreason = BANDLIM_UNLIMITED; } else { tcp_ecn_input_syn_sent(tp, thflags, iptos); - /* Send challenge ACK. */ - tcp_respond(tp, mtod(m, void *), th, m, tp->rcv_nxt, - tp->snd_nxt, TH_ACK); - tp->last_ack_sent = tp->rcv_nxt; + tcp_send_challenge_ack(tp, th, m); m = NULL; } goto drop; @@ -2435,6 +2437,42 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th, /* * Ack processing. */ + if (SEQ_GEQ(tp->snd_una, tp->iss + (TCP_MAXWIN << tp->snd_scale))) { + /* Checking SEG.ACK against ISS is definitely redundant. */ + tp->t_flags2 |= TF2_NO_ISS_CHECK; + } + if (!V_tcp_insecure_ack) { + tcp_seq seq_min; + bool ghost_ack_check; + + if (tp->t_flags2 & TF2_NO_ISS_CHECK) { + /* Check for too old ACKs (RFC 5961, Section 5.2). */ + seq_min = tp->snd_una - tp->max_sndwnd; + ghost_ack_check = false; + } else { + if (SEQ_GT(tp->iss + 1, tp->snd_una - tp->max_sndwnd)) { + /* Checking for ghost ACKs is stricter. */ + seq_min = tp->iss + 1; + ghost_ack_check = true; + } else { + /* + * Checking for too old ACKs (RFC 5961, + * Section 5.2) is stricter. + */ + seq_min = tp->snd_una - tp->max_sndwnd; + ghost_ack_check = false; + } + } + if (SEQ_LT(th->th_ack, seq_min)) { + if (ghost_ack_check) + TCPSTAT_INC(tcps_rcvghostack); + else + TCPSTAT_INC(tcps_rcvacktooold); + tcp_send_challenge_ack(tp, th, m); + m = NULL; + goto drop; + } + } switch (tp->t_state) { /* * In SYN_RECEIVED state, the ack ACKs our SYN, so enter @@ -3883,6 +3921,17 @@ tcp_mss_update(struct tcpcb *tp, int offer, int mtuoffer, mss = max(mss, 64); tp->t_maxseg = mss; + if (tp->t_maxseg < V_tcp_mssdflt) { + /* + * The MSS is so small we should not process incoming + * SACK's since we are subject to attack in such a + * case. + */ + tp->t_flags2 |= TF2_PROC_SACK_PROHIBIT; + } else { + tp->t_flags2 &= ~TF2_PROC_SACK_PROHIBIT; + } + } void @@ -3934,6 +3983,16 @@ tcp_mss(struct tcpcb *tp, int offer) * XXXGL: shouldn't we reserve space for IP/IPv6 options? */ tp->t_maxseg = max(mss, 64); + if (tp->t_maxseg < V_tcp_mssdflt) { + /* + * The MSS is so small we should not process incoming + * SACK's since we are subject to attack in such a + * case. + */ + tp->t_flags2 |= TF2_PROC_SACK_PROHIBIT; + } else { + tp->t_flags2 &= ~TF2_PROC_SACK_PROHIBIT; + } SOCKBUF_LOCK(&so->so_rcv); if ((so->so_rcv.sb_hiwat == V_tcp_recvspace) && metrics.rmx_recvpipe) @@ -3955,6 +4014,8 @@ tcp_mss(struct tcpcb *tp, int offer) tp->t_tsomax = cap.tsomax; tp->t_tsomaxsegcount = cap.tsomaxsegcount; tp->t_tsomaxsegsize = cap.tsomaxsegsize; + if (cap.ipsec_tso) + tp->t_flags2 |= TF2_IPSEC_TSO; } } |