From owner-svn-src-all@freebsd.org Thu Oct 18 19:21:20 2018 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id B8411EFF958; Thu, 18 Oct 2018 19:21:19 +0000 (UTC) (envelope-from tuexen@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 6E15879A19; Thu, 18 Oct 2018 19:21:19 +0000 (UTC) (envelope-from tuexen@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 6923F24259; Thu, 18 Oct 2018 19:21:19 +0000 (UTC) (envelope-from tuexen@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w9IJLJ0V065705; Thu, 18 Oct 2018 19:21:19 GMT (envelope-from tuexen@FreeBSD.org) Received: (from tuexen@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w9IJLIEu065703; Thu, 18 Oct 2018 19:21:18 GMT (envelope-from tuexen@FreeBSD.org) Message-Id: <201810181921.w9IJLIEu065703@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: tuexen set sender to tuexen@FreeBSD.org using -f From: Michael Tuexen Date: Thu, 18 Oct 2018 19:21:18 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r339430 - head/sys/netinet X-SVN-Group: head X-SVN-Commit-Author: tuexen X-SVN-Commit-Paths: head/sys/netinet X-SVN-Commit-Revision: 339430 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Oct 2018 19:21:20 -0000 Author: tuexen Date: Thu Oct 18 19:21:18 2018 New Revision: 339430 URL: https://svnweb.freebsd.org/changeset/base/339430 Log: The handling of RST segments in the SYN-RCVD state exists in the code paths. Both are not consistent and the one on the syn cache code does not conform to the relevant specifications (Page 69 of RFC 793 and Section 4.2 of RFC 5961). This patch fixes this: * The sequence numbers checks are fixed as specified on page Page 69 RFC 793. * The sysctl variable net.inet.tcp.insecure_rst is now honoured and the behaviour as specified in Section 4.2 of RFC 5961. Approved by: re (gjb@) Reviewed by: bz@, glebius@, rrs@, Differential Revision: https://reviews.freebsd.org/D17595 Sponsored by: Netflix, Inc. Modified: head/sys/netinet/tcp_input.c head/sys/netinet/tcp_syncache.c head/sys/netinet/tcp_syncache.h Modified: head/sys/netinet/tcp_input.c ============================================================================== --- head/sys/netinet/tcp_input.c Thu Oct 18 19:19:45 2018 (r339429) +++ head/sys/netinet/tcp_input.c Thu Oct 18 19:21:18 2018 (r339430) @@ -1165,7 +1165,7 @@ tfo_socket_result: * causes. */ if (thflags & TH_RST) { - syncache_chkrst(&inc, th); + syncache_chkrst(&inc, th, m); goto dropunlock; } /* Modified: head/sys/netinet/tcp_syncache.c ============================================================================== --- head/sys/netinet/tcp_syncache.c Thu Oct 18 19:19:45 2018 (r339429) +++ head/sys/netinet/tcp_syncache.c Thu Oct 18 19:21:18 2018 (r339430) @@ -131,7 +131,7 @@ static void syncache_drop(struct syncache *, struct s static void syncache_free(struct syncache *); static void syncache_insert(struct syncache *, struct syncache_head *); static int syncache_respond(struct syncache *, struct syncache_head *, - const struct mbuf *); + const struct mbuf *, int); static struct socket *syncache_socket(struct syncache *, struct socket *, struct mbuf *m); static void syncache_timeout(struct syncache *sc, struct syncache_head *sch, @@ -489,7 +489,7 @@ syncache_timer(void *xsch) free(s, M_TCPLOG); } - syncache_respond(sc, sch, NULL); + syncache_respond(sc, sch, NULL, TH_SYN|TH_ACK); TCPSTAT_INC(tcps_sc_retransmitted); syncache_timeout(sc, sch, 0); } @@ -537,9 +537,10 @@ syncache_lookup(struct in_conninfo *inc, struct syncac * This function is called when we get a RST for a * non-existent connection, so that we can see if the * connection is in the syn cache. If it is, zap it. + * If required send a challenge ACK. */ void -syncache_chkrst(struct in_conninfo *inc, struct tcphdr *th) +syncache_chkrst(struct in_conninfo *inc, struct tcphdr *th, struct mbuf *m) { struct syncache *sc; struct syncache_head *sch; @@ -590,19 +591,36 @@ syncache_chkrst(struct in_conninfo *inc, struct tcphdr * send a reset with the sequence number at the rightmost edge * of our receive window, and we have to handle this case. */ - if (SEQ_GEQ(th->th_seq, sc->sc_irs) && - SEQ_LEQ(th->th_seq, sc->sc_irs + sc->sc_wnd)) { - syncache_drop(sc, sch); - if ((s = tcp_log_addrs(inc, th, NULL, NULL))) - log(LOG_DEBUG, "%s; %s: Our SYN|ACK was rejected, " - "connection attempt aborted by remote endpoint\n", - s, __func__); - TCPSTAT_INC(tcps_sc_reset); + if ((SEQ_GEQ(th->th_seq, sc->sc_irs + 1) && + SEQ_LT(th->th_seq, sc->sc_irs + 1 + sc->sc_wnd)) || + (sc->sc_wnd == 0 && th->th_seq == sc->sc_irs + 1)) { + if (V_tcp_insecure_rst || + th->th_seq == sc->sc_irs + 1) { + syncache_drop(sc, sch); + if ((s = tcp_log_addrs(inc, th, NULL, NULL))) + log(LOG_DEBUG, + "%s; %s: Our SYN|ACK was rejected, " + "connection attempt aborted by remote " + "endpoint\n", + s, __func__); + TCPSTAT_INC(tcps_sc_reset); + } else { + TCPSTAT_INC(tcps_badrst); + /* Send challenge ACK. */ + if ((s = tcp_log_addrs(inc, th, NULL, NULL))) + log(LOG_DEBUG, "%s; %s: RST with invalid " + " SEQ %u != NXT %u (+WND %u), " + "sending challenge ACK\n", + s, __func__, + th->th_seq, sc->sc_irs + 1, sc->sc_wnd); + syncache_respond(sc, sch, m, TH_ACK); + } } else { if ((s = tcp_log_addrs(inc, th, NULL, NULL))) log(LOG_DEBUG, "%s; %s: RST with invalid SEQ %u != " - "IRS %u (+WND %u), segment ignored\n", - s, __func__, th->th_seq, sc->sc_irs, sc->sc_wnd); + "NXT %u (+WND %u), segment ignored\n", + s, __func__, + th->th_seq, sc->sc_irs + 1, sc->sc_wnd); TCPSTAT_INC(tcps_badrst); } @@ -1413,7 +1431,7 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *t s, __func__); free(s, M_TCPLOG); } - if (syncache_respond(sc, sch, m) == 0) { + if (syncache_respond(sc, sch, m, TH_SYN|TH_ACK) == 0) { sc->sc_rxmits = 0; syncache_timeout(sc, sch, 1); TCPSTAT_INC(tcps_sndacks); @@ -1577,7 +1595,7 @@ skip_alloc: /* * Do a standard 3-way handshake. */ - if (syncache_respond(sc, sch, m) == 0) { + if (syncache_respond(sc, sch, m, TH_SYN|TH_ACK) == 0) { if (V_tcp_syncookies && V_tcp_syncookiesonly && sc != &scs) syncache_free(sc); else if (sc != &scs) @@ -1618,12 +1636,12 @@ tfo_expanded: } /* - * Send SYN|ACK to the peer. Either in response to the peer's SYN, + * Send SYN|ACK or ACK to the peer. Either in response to a peer's segment, * i.e. m0 != NULL, or upon 3WHS ACK timeout, i.e. m0 == NULL. */ static int syncache_respond(struct syncache *sc, struct syncache_head *sch, - const struct mbuf *m0) + const struct mbuf *m0, int flags) { struct ip *ip = NULL; struct mbuf *m; @@ -1709,15 +1727,18 @@ syncache_respond(struct syncache *sc, struct syncache_ th->th_sport = sc->sc_inc.inc_lport; th->th_dport = sc->sc_inc.inc_fport; - th->th_seq = htonl(sc->sc_iss); + if (flags & TH_SYN) + th->th_seq = htonl(sc->sc_iss); + else + th->th_seq = htonl(sc->sc_iss + 1); th->th_ack = htonl(sc->sc_irs + 1); th->th_off = sizeof(struct tcphdr) >> 2; th->th_x2 = 0; - th->th_flags = TH_SYN|TH_ACK; + th->th_flags = flags; th->th_win = htons(sc->sc_wnd); th->th_urp = 0; - if (sc->sc_flags & SCF_ECN) { + if ((flags & TH_SYN) && (sc->sc_flags & SCF_ECN)) { th->th_flags |= TH_ECE; TCPSTAT_INC(tcps_ecn_shs); } @@ -1726,29 +1747,31 @@ syncache_respond(struct syncache *sc, struct syncache_ if ((sc->sc_flags & SCF_NOOPT) == 0) { to.to_flags = 0; - to.to_mss = mssopt; - to.to_flags = TOF_MSS; - if (sc->sc_flags & SCF_WINSCALE) { - to.to_wscale = sc->sc_requested_r_scale; - to.to_flags |= TOF_SCALE; + if (flags & TH_SYN) { + to.to_mss = mssopt; + to.to_flags = TOF_MSS; + if (sc->sc_flags & SCF_WINSCALE) { + to.to_wscale = sc->sc_requested_r_scale; + to.to_flags |= TOF_SCALE; + } + if (sc->sc_flags & SCF_SACK) + to.to_flags |= TOF_SACKPERM; +#if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE) + if (sc->sc_flags & SCF_SIGNATURE) + to.to_flags |= TOF_SIGNATURE; +#endif + if (sc->sc_tfo_cookie) { + to.to_flags |= TOF_FASTOPEN; + to.to_tfo_len = TCP_FASTOPEN_COOKIE_LEN; + to.to_tfo_cookie = sc->sc_tfo_cookie; + /* don't send cookie again when retransmitting response */ + sc->sc_tfo_cookie = NULL; + } } if (sc->sc_flags & SCF_TIMESTAMP) { to.to_tsval = sc->sc_tsoff + tcp_ts_getticks(); to.to_tsecr = sc->sc_tsreflect; to.to_flags |= TOF_TS; - } - if (sc->sc_flags & SCF_SACK) - to.to_flags |= TOF_SACKPERM; -#if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE) - if (sc->sc_flags & SCF_SIGNATURE) - to.to_flags |= TOF_SIGNATURE; -#endif - if (sc->sc_tfo_cookie) { - to.to_flags |= TOF_FASTOPEN; - to.to_tfo_len = TCP_FASTOPEN_COOKIE_LEN; - to.to_tfo_cookie = sc->sc_tfo_cookie; - /* don't send cookie again when retransmitting response */ - sc->sc_tfo_cookie = NULL; } optlen = tcp_addoptions(&to, (u_char *)(th + 1)); Modified: head/sys/netinet/tcp_syncache.h ============================================================================== --- head/sys/netinet/tcp_syncache.h Thu Oct 18 19:19:45 2018 (r339429) +++ head/sys/netinet/tcp_syncache.h Thu Oct 18 19:21:18 2018 (r339430) @@ -46,7 +46,7 @@ int syncache_expand(struct in_conninfo *, struct tcpo int syncache_add(struct in_conninfo *, struct tcpopt *, struct tcphdr *, struct inpcb *, struct socket **, struct mbuf *, void *, void *); -void syncache_chkrst(struct in_conninfo *, struct tcphdr *); +void syncache_chkrst(struct in_conninfo *, struct tcphdr *, struct mbuf *); void syncache_badack(struct in_conninfo *); int syncache_pcblist(struct sysctl_req *req, int max_pcbs, int *pcbs_exported);