Date: Sat, 3 Jun 2017 21:53:58 +0000 (UTC) From: Michael Tuexen <tuexen@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r319556 - head/sys/netinet Message-ID: <201706032153.v53LrwFP044028@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: tuexen Date: Sat Jun 3 21:53:58 2017 New Revision: 319556 URL: https://svnweb.freebsd.org/changeset/base/319556 Log: Fix the ICMP6 handling for TCP. The ICMP6 packets might not be contained in a single mbuf. So don't assume this. Keep the IPv4 and IPv6 code in sync and make explicit that the syncache code only need the TCP sequence number, not the complete TCP header. MFC after: 3 days Sponsored by: Netflix, Inc. Modified: head/sys/netinet/tcp_subr.c head/sys/netinet/tcp_syncache.c head/sys/netinet/tcp_syncache.h Modified: head/sys/netinet/tcp_subr.c ============================================================================== --- head/sys/netinet/tcp_subr.c Sat Jun 3 20:39:48 2017 (r319555) +++ head/sys/netinet/tcp_subr.c Sat Jun 3 21:53:58 2017 (r319556) @@ -1963,16 +1963,16 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip) if (inp != NULL && PRC_IS_REDIRECT(cmd)) { /* signal EHOSTDOWN, as it flushes the cached route */ inp = (*notify)(inp, EHOSTDOWN); - if (inp != NULL) - INP_WUNLOCK(inp); - } else if (inp != NULL) { + goto out; + } + icmp_tcp_seq = th->th_seq; + if (inp != NULL) { if (!(inp->inp_flags & INP_TIMEWAIT) && !(inp->inp_flags & INP_DROPPED) && !(inp->inp_socket == NULL)) { - icmp_tcp_seq = ntohl(th->th_seq); tp = intotcpcb(inp); - if (SEQ_GEQ(icmp_tcp_seq, tp->snd_una) && - SEQ_LT(icmp_tcp_seq, tp->snd_max)) { + if (SEQ_GEQ(ntohl(icmp_tcp_seq), tp->snd_una) && + SEQ_LT(ntohl(icmp_tcp_seq), tp->snd_max)) { if (cmd == PRC_MSGSIZE) { /* * MTU discovery: @@ -1980,7 +1980,7 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip) * in the route to the suggested new * value (if given) and then notify. */ - mtu = ntohs(icp->icmp_nextmtu); + mtu = ntohs(icp->icmp_nextmtu); /* * If no alternative MTU was * proposed, try the next smaller @@ -2011,16 +2011,17 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip) inetctlerrmap[cmd]); } } - if (inp != NULL) - INP_WUNLOCK(inp); } else { bzero(&inc, sizeof(inc)); inc.inc_fport = th->th_dport; inc.inc_lport = th->th_sport; inc.inc_faddr = faddr; inc.inc_laddr = ip->ip_src; - syncache_unreach(&inc, th); + syncache_unreach(&inc, icmp_tcp_seq); } +out: + if (inp != NULL) + INP_WUNLOCK(inp); INP_INFO_RUNLOCK(&V_tcbinfo); } #endif /* INET */ @@ -2030,7 +2031,6 @@ void tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d) { struct in6_addr *dst; - struct tcphdr *th; struct inpcb *(*notify)(struct inpcb *, int) = tcp_notify; struct ip6_hdr *ip6; struct mbuf *m; @@ -2040,11 +2040,14 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d) struct ip6ctlparam *ip6cp = NULL; const struct sockaddr_in6 *sa6_src = NULL; struct in_conninfo inc; + struct tcp_ports { + uint16_t th_sport; + uint16_t th_dport; + } t_ports; tcp_seq icmp_tcp_seq; unsigned int mtu; unsigned int off; - if (sa->sa_family != AF_INET6 || sa->sa_len != sizeof(struct sockaddr_in6)) return; @@ -2093,27 +2096,31 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d) /* Check if we can safely get the ports from the tcp hdr */ if (m == NULL || (m->m_pkthdr.len < - (int32_t) (off + offsetof(struct tcphdr, th_seq)))) { + (int32_t) (off + sizeof(struct tcp_ports)))) { return; } - - th = (struct tcphdr *) mtodo(ip6cp->ip6c_m, ip6cp->ip6c_off); + bzero(&t_ports, sizeof(struct tcp_ports)); + m_copydata(m, off, sizeof(struct tcp_ports), (caddr_t)&t_ports); INP_INFO_RLOCK(&V_tcbinfo); - inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_dst, th->th_dport, - &ip6->ip6_src, th->th_sport, INPLOOKUP_WLOCKPCB, NULL); + inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_dst, t_ports.th_dport, + &ip6->ip6_src, t_ports.th_sport, INPLOOKUP_WLOCKPCB, NULL); if (inp != NULL && PRC_IS_REDIRECT(cmd)) { /* signal EHOSTDOWN, as it flushes the cached route */ inp = (*notify)(inp, EHOSTDOWN); - if (inp != NULL) - INP_WUNLOCK(inp); - } else if (inp != NULL) { + goto out; + } + off += sizeof(struct tcp_ports); + if (m->m_pkthdr.len < (int32_t) (off + sizeof(tcp_seq))) { + goto out; + } + m_copydata(m, off, sizeof(tcp_seq), (caddr_t)&icmp_tcp_seq); + if (inp != NULL) { if (!(inp->inp_flags & INP_TIMEWAIT) && !(inp->inp_flags & INP_DROPPED) && !(inp->inp_socket == NULL)) { - icmp_tcp_seq = ntohl(th->th_seq); tp = intotcpcb(inp); - if (SEQ_GEQ(icmp_tcp_seq, tp->snd_una) && - SEQ_LT(icmp_tcp_seq, tp->snd_max)) { + if (SEQ_GEQ(ntohl(icmp_tcp_seq), tp->snd_una) && + SEQ_LT(ntohl(icmp_tcp_seq), tp->snd_max)) { if (cmd == PRC_MSGSIZE) { /* * MTU discovery: @@ -2130,22 +2137,20 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d) */ if (mtu < IPV6_MMTU) mtu = IPV6_MMTU - 8; - - bzero(&inc, sizeof(inc)); inc.inc_fibnum = M_GETFIB(m); inc.inc_flags |= INC_ISIPV6; inc.inc6_faddr = *dst; if (in6_setscope(&inc.inc6_faddr, m->m_pkthdr.rcvif, NULL)) - goto unlock_inp; - + goto out; /* * Only process the offered MTU if it * is smaller than the current one. */ if (mtu < tp->t_maxseg + - (sizeof (*th) + sizeof (*ip6))) { + sizeof (struct tcphdr) + + sizeof (struct ip6_hdr)) { tcp_hc_updatemtu(&inc, mtu); tcp_mtudisc(inp, mtu); ICMP6STAT_INC(icp6s_pmtuchg); @@ -2155,19 +2160,19 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d) inet6ctlerrmap[cmd]); } } -unlock_inp: - if (inp != NULL) - INP_WUNLOCK(inp); } else { bzero(&inc, sizeof(inc)); inc.inc_fibnum = M_GETFIB(m); inc.inc_flags |= INC_ISIPV6; - inc.inc_fport = th->th_dport; - inc.inc_lport = th->th_sport; + inc.inc_fport = t_ports.th_dport; + inc.inc_lport = t_ports.th_sport; inc.inc6_faddr = *dst; inc.inc6_laddr = ip6->ip6_src; - syncache_unreach(&inc, th); + syncache_unreach(&inc, icmp_tcp_seq); } +out: + if (inp != NULL) + INP_WUNLOCK(inp); INP_INFO_RUNLOCK(&V_tcbinfo); } #endif /* INET6 */ Modified: head/sys/netinet/tcp_syncache.c ============================================================================== --- head/sys/netinet/tcp_syncache.c Sat Jun 3 20:39:48 2017 (r319555) +++ head/sys/netinet/tcp_syncache.c Sat Jun 3 21:53:58 2017 (r319556) @@ -602,7 +602,7 @@ syncache_badack(struct in_conninfo *inc) } void -syncache_unreach(struct in_conninfo *inc, struct tcphdr *th) +syncache_unreach(struct in_conninfo *inc, tcp_seq th_seq) { struct syncache *sc; struct syncache_head *sch; @@ -613,7 +613,7 @@ syncache_unreach(struct in_conninfo *inc, struct tcphd goto done; /* If the sequence number != sc_iss, then it's a bogus ICMP msg */ - if (ntohl(th->th_seq) != sc->sc_iss) + if (ntohl(th_seq) != sc->sc_iss) goto done; /* Modified: head/sys/netinet/tcp_syncache.h ============================================================================== --- head/sys/netinet/tcp_syncache.h Sat Jun 3 20:39:48 2017 (r319555) +++ head/sys/netinet/tcp_syncache.h Sat Jun 3 21:53:58 2017 (r319556) @@ -38,7 +38,7 @@ void syncache_init(void); #ifdef VIMAGE void syncache_destroy(void); #endif -void syncache_unreach(struct in_conninfo *, struct tcphdr *); +void syncache_unreach(struct in_conninfo *, tcp_seq); int syncache_expand(struct in_conninfo *, struct tcpopt *, struct tcphdr *, struct socket **, struct mbuf *); int syncache_add(struct in_conninfo *, struct tcpopt *,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201706032153.v53LrwFP044028>