In the tcp_input() path:

- Filter out multicast destinations explicitly for every incoming packet,
  not just SYNs.  Previously, non-SYN multicast destination would be
  filtered out as a side effect of PCB lookup.  Remove now redundant
  similar checks in the dropwithreset case and in syn_cache_add().
- Defer the TCP checksum until we know that we want to process the
  packet (i.e. have a non-CLOSED connection or a listen socket).
This commit is contained in:
thorpej 2000-02-12 17:19:34 +00:00
parent b939c73fb4
commit 312cb38ccb
1 changed files with 92 additions and 67 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: tcp_input.c,v 1.102 2000/01/31 14:18:56 itojun Exp $ */ /* $NetBSD: tcp_input.c,v 1.103 2000/02/12 17:19:34 thorpej Exp $ */
/* /*
%%% portions-copyright-nrl-95 %%% portions-copyright-nrl-95
@ -226,6 +226,17 @@ do { \
TCP_SET_DELACK(tp); \ TCP_SET_DELACK(tp); \
} while (0) } while (0)
/*
* Convert TCP protocol fields to host order for easier processing.
*/
#define TCP_FIELDS_TO_HOST(th) \
do { \
NTOHL((th)->th_seq); \
NTOHL((th)->th_ack); \
NTOHS((th)->th_win); \
NTOHS((th)->th_urp); \
} while (0)
int int
tcp_reass(tp, th, m, tlen) tcp_reass(tp, th, m, tlen)
register struct tcpcb *tp; register struct tcpcb *tp;
@ -584,6 +595,26 @@ tcp_input(m, va_alist)
opti.ts_present = 0; opti.ts_present = 0;
opti.maxseg = 0; opti.maxseg = 0;
/*
* RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN.
*
* TCP is, by definition, unicast, so we reject all
* multicast outright.
*
* Note, there are additional src/dst address checks in
* the AF-specific code below.
*/
if (m->m_flags & (M_BCAST|M_MCAST)) {
/* XXX stat */
goto drop;
}
#ifdef INET6
if (m->m_flags & M_ANYCAST6) {
/* XXX stat */
goto drop;
}
#endif
/* /*
* Get IP and TCP header together in first mbuf. * Get IP and TCP header together in first mbuf.
* Note: IP leaves IP header in first mbuf. * Note: IP leaves IP header in first mbuf.
@ -621,27 +652,17 @@ tcp_input(m, va_alist)
#endif #endif
/* /*
* Checksum extended TCP header and data. * Make sure destination address is not multicast.
* Source address checked in ip_input().
*/ */
if (IN_MULTICAST(ip->ip_dst.s_addr)) {
/* XXX stat */
goto drop;
}
/* We do the checksum after PCB lookup... */
len = ip->ip_len; len = ip->ip_len;
tlen = len - toff; tlen = len - toff;
#ifndef PULLDOWN_TEST
{
struct ipovly *ipov;
ipov = (struct ipovly *)ip;
bzero(ipov->ih_x1, sizeof ipov->ih_x1);
ipov->ih_len = htons(tlen);
}
if (in_cksum(m, len) != 0) {
tcpstat.tcps_rcvbadsum++;
goto drop;
}
#else
if (in4_cksum(m, IPPROTO_TCP, toff, tlen) != 0) {
tcpstat.tcps_rcvbadsum++;
goto drop;
}
#endif
break; break;
#ifdef INET6 #ifdef INET6
case 6: case 6:
@ -676,14 +697,17 @@ tcp_input(m, va_alist)
} }
/* /*
* Checksum extended TCP header and data. * Make sure destination address is not multicast.
* Source address checked in ip6_input().
*/ */
len = m->m_pkthdr.len; if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
tlen = len - toff; /* XXX stat */
if (in6_cksum(m, IPPROTO_TCP, toff, tlen)) {
tcpstat.tcps_rcvbadsum++;
goto drop; goto drop;
} }
/* We do the checksum after PCB lookup... */
len = m->m_pkthdr.len;
tlen = len - toff;
break; break;
#endif #endif
default: default:
@ -761,14 +785,6 @@ tcp_input(m, va_alist)
} }
tiflags = th->th_flags; tiflags = th->th_flags;
/*
* Convert TCP protocol specific fields to host format.
*/
NTOHL(th->th_seq);
NTOHL(th->th_ack);
NTOHS(th->th_win);
NTOHS(th->th_urp);
/* /*
* Locate pcb for segment. * Locate pcb for segment.
*/ */
@ -839,6 +855,7 @@ findpcb:
dst, ntohs(th->th_dport), dst, ntohs(th->th_dport),
src, ntohs(th->th_sport)); src, ntohs(th->th_sport));
} }
TCP_FIELDS_TO_HOST(th);
goto dropwithreset; goto dropwithreset;
} }
#ifdef IPSEC #ifdef IPSEC
@ -877,6 +894,7 @@ findpcb:
} }
if (in6p == NULL) { if (in6p == NULL) {
++tcpstat.tcps_noport; ++tcpstat.tcps_noport;
TCP_FIELDS_TO_HOST(th);
goto dropwithreset; goto dropwithreset;
} }
#ifdef IPSEC #ifdef IPSEC
@ -909,11 +927,49 @@ findpcb:
} }
#endif #endif
if (tp == 0) { if (tp == 0) {
TCP_FIELDS_TO_HOST(th);
goto dropwithreset; goto dropwithreset;
} }
if (tp->t_state == TCPS_CLOSED) if (tp->t_state == TCPS_CLOSED)
goto drop; goto drop;
/*
* Checksum extended TCP header and data.
*/
switch (af) {
case AF_INET:
#ifndef PULLDOWN_TEST
{
struct ipovly *ipov;
ipov = (struct ipovly *)ip;
bzero(ipov->ih_x1, sizeof ipov->ih_x1);
ipov->ih_len = htons(tlen + off);
if (in_cksum(m, len) != 0) {
tcpstat.tcps_rcvbadsum++;
goto drop;
}
}
#else
if (in4_cksum(m, IPPROTO_TCP, toff, tlen + off) != 0) {
tcpstat.tcps_rcvbadsum++;
goto drop;
}
#endif
break;
#ifdef INET6
case AF_INET6:
if (in6_cksum(m, IPPROTO_TCP, toff, tlen + off) != 0) {
tcpstat.tcps_rcvbadsum++;
goto drop;
}
break;
#endif
}
TCP_FIELDS_TO_HOST(th);
/* Unscale the window into a 32-bit value. */ /* Unscale the window into a 32-bit value. */
if ((tiflags & TH_SYN) == 0) if ((tiflags & TH_SYN) == 0)
tiwin = th->th_win << tp->snd_scale; tiwin = th->th_win << tp->snd_scale;
@ -2063,16 +2119,8 @@ dropwithreset:
* Make ACK acceptable to originator of segment. * Make ACK acceptable to originator of segment.
* Don't bother to respond if destination was broadcast/multicast. * Don't bother to respond if destination was broadcast/multicast.
*/ */
if ((tiflags & TH_RST) || m->m_flags & (M_BCAST|M_MCAST)) if (tiflags & TH_RST)
goto drop; goto drop;
if (ip && IN_MULTICAST(ip->ip_dst.s_addr))
goto drop;
#ifdef INET6
if (m->m_flags & M_ANYCAST6)
goto drop;
else if (ip6 && IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst))
goto drop;
#endif
{ {
/* /*
* need to recover version # field, which was overwritten on * need to recover version # field, which was overwritten on
@ -3144,32 +3192,9 @@ syn_cache_add(src, dst, th, hlen, so, m, optp, optlen, oi)
/* /*
* RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN
* in_broadcast() should never return true on a received *
* packet with M_BCAST not set. * Note this check is performed in tcp_input() very early on.
*/ */
if (m->m_flags & (M_BCAST|M_MCAST))
return 0;
#ifdef INET6
if (m->m_flags & M_ANYCAST6)
return 0;
#endif
switch (src->sa_family) {
case AF_INET:
if (IN_MULTICAST(((struct sockaddr_in *)src)->sin_addr.s_addr)
|| IN_MULTICAST(((struct sockaddr_in *)dst)->sin_addr.s_addr))
return 0;
break;
#ifdef INET6
case AF_INET6:
if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)src)->sin6_addr)
|| IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)dst)->sin6_addr))
return 0;
break;
#endif
default:
return 0;
}
/* /*
* Initialize some local state. * Initialize some local state.