summaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
authorNiklas Hallqvist <niklas@cvs.openbsd.org>1999-07-22 17:14:19 +0000
committerNiklas Hallqvist <niklas@cvs.openbsd.org>1999-07-22 17:14:19 +0000
commit4e6f3beab6cded23491db88616a3edc498523dd4 (patch)
tree605e0123ef8abd8d70fe21fe504fe9ddd6a89d2b /sys/netinet
parent45a9f0be11f764f64438db00669abc064073b21c (diff)
Reintroduce rev 1.41 which brings us TCP signatures again, but this time
hopefully without random kernel data corruption.
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/tcp_input.c823
1 files changed, 545 insertions, 278 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 845c5135eec..48657232bbf 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_input.c,v 1.43 1999/07/18 16:33:08 deraadt Exp $ */
+/* $OpenBSD: tcp_input.c,v 1.44 1999/07/22 17:14:18 niklas Exp $ */
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
/*
@@ -48,6 +48,12 @@ You should have received a copy of the license with this software. If you
didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
*/
+/*
+ * XXX - At this point, the TUBA support is likely to be hopelessly broken.
+ * That's the bad news. The good news is that doing it again and doing it
+ * right shouldn't be hard now that the IPv4 dependencies are isolated.
+ */
+
#ifndef TUBA_INCLUDE
#include <sys/param.h>
#include <sys/systm.h>
@@ -88,17 +94,19 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
#include <netinet6/ipv6_var.h>
#include <netinet6/tcpipv6.h>
-struct tcpiphdr tcp_saveti;
-struct tcpipv6hdr tcp_saveti6;
-
/* for the packet header length in the mbuf */
#define M_PH_LEN(m) (((struct mbuf *)(m))->m_pkthdr.len)
#define M_V6_LEN(m) (M_PH_LEN(m) - sizeof(struct ipv6))
#define M_V4_LEN(m) (M_PH_LEN(m) - sizeof(struct ip))
#endif /* INET6 */
+#ifdef INET6
+char tcp_savebuf[sizeof(struct ipv6) + sizeof(struct tcphdr)];
+#else /* INET6 */
+char tcp_savebuf[sizeof(struct ip) + sizeof(struct tcphdr)];
+#endif /* INET6 */
+
int tcprexmtthresh = 3;
-struct tcpiphdr tcp_saveti;
int tcptv_keep_init = TCPTV_KEEP_INIT;
extern u_long sb_max;
@@ -305,9 +313,9 @@ tcp_input(struct mbuf *m, ...)
#else
tcp_input(m, va_alist)
register struct mbuf *m;
+ va_dcl
#endif
{
- register struct tcpiphdr *ti;
register struct inpcb *inp;
caddr_t optp = NULL;
int optlen = 0;
@@ -317,7 +325,6 @@ tcp_input(m, va_alist)
struct socket *so = NULL;
int todrop, acked, ourfinisacked, needoutput = 0;
short ostate = 0;
- struct in_addr laddr;
int dropsocket = 0;
int iss = 0;
u_long tiwin;
@@ -326,14 +333,19 @@ tcp_input(m, va_alist)
int iphlen;
va_list ap;
register struct tcphdr *th;
+ unsigned int pf;
#ifdef IPSEC
struct tdb *tdb = NULL;
#endif /* IPSEC */
+ union {
+ caddr_t p;
+#ifdef INET
+ struct ip *ip;
+#endif /* INET */
#ifdef INET6
- struct in6_addr laddr6;
- unsigned short is_ipv6; /* Type of incoming datagram. */
- struct ipv6 *ipv6 = NULL;
-#endif /* INET6 */
+ struct ipv6 *ipv6;
+#endif /* INET */
+ } nhu;
va_start(ap, m);
iphlen = va_arg(ap, int);
@@ -350,87 +362,113 @@ tcp_input(m, va_alist)
m->m_pkthdr.tdbi = NULL;
}
#endif /* IPSEC */
-#ifdef INET6
+
/*
- * Before we do ANYTHING, we have to figure out if it's TCP/IPv6 or
- * TCP/IPv4.
+ * Before we do ANYTHING, we have to figure out what network protocol
+ * is underneath the TCP header in this packet.
+ *
+ * For IPv4 and IPv6, options don't really do anything at this layer
+ * and therefore are stripped off.
*/
- is_ipv6 = mtod(m, struct ip *)->ip_v == 6;
+#if defined(INET) && defined(INET6)
+ switch (mtod(m, struct ip *)->ip_v) {
+#else /* defined(INET) && defined(INET6) */
+ switch (-1) {
+ case -1:
+#endif /* defined(INET) && defined(INET6) */
+#ifdef INET
+ case 4:
+ pf = PF_INET;
+
+#ifdef DIAGNOSTIC
+ if (iphlen < sizeof(struct ip)) {
+ m_freem(m);
+ return;
+ }
+#endif /* DIAGNOSTIC */
+
+ if (iphlen > sizeof(struct ip)) {
+ ip_stripoptions(m, (struct mbuf *)0);
+ iphlen = sizeof(struct ip);
+ }
+ break;
+#endif /* INET */
+#ifdef INET6
+ case 6:
+ pf = PF_INET6;
+
+#ifdef DIAGNOSTIC
+ if (iphlen < sizeof(struct ipv6)) {
+ m_freem(m);
+ return;
+ }
+#endif /* DIAGNOSTIC */
+
+ if (iphlen > sizeof(struct ipv6)) {
+ ipv6_stripoptions(m, iphlen);
+ iphlen = sizeof(struct ipv6);
+ }
+ break;
#endif /* INET6 */
+ default:
+ m_freem(m);
+ return;
+ }
/*
* Get IP and TCP header together in first mbuf.
* Note: IP leaves IP header in first mbuf.
*/
-#ifndef INET6
- ti = mtod(m, struct tcpiphdr *);
-#else /* INET6 */
- if (!is_ipv6)
-#endif /* INET6 */
- if (iphlen > sizeof (struct ip))
- ip_stripoptions(m, (struct mbuf *)0);
if (m->m_len < iphlen + sizeof(struct tcphdr)) {
if ((m = m_pullup2(m, iphlen + sizeof(struct tcphdr))) == 0) {
tcpstat.tcps_rcvshort++;
return;
}
-#ifndef INET6
- ti = mtod(m, struct tcpiphdr *);
-#endif /* INET6 */
}
tlen = m->m_pkthdr.len - iphlen;
-#ifdef INET6
/*
- * After that, do initial segment processing which is still very
- * dependent on what IP version you're using.
+ * Checksum extended TCP header and data.
*/
+#if defined(INET) && defined(INET6)
+ switch (pf) {
+#else /* defined(INET) && defined(INET6) */
+ switch (-1) {
+ case -1:
+#endif /* defined(INET) && defined(INET6) */
+#ifdef INET
+ case PF_INET:
+ {
+ struct ipovly *ipovly;
- if (is_ipv6) {
-#ifdef DIAGNOSTIC
- if (iphlen < sizeof(struct ipv6)) {
- m_freem(m);
- return;
- }
-#endif /* DIAGNOSTIC */
-
- /* strip off any options */
- if (iphlen > sizeof(struct ipv6)) {
- ipv6_stripoptions(m, iphlen);
- iphlen = sizeof(struct ipv6);
- }
+ ipovly = mtod(m, struct ipovly *);
- ti = NULL;
- ipv6 = mtod(m, struct ipv6 *);
+ len = sizeof (struct ip) + tlen;
+ bzero(ipovly->ih_x1, sizeof ipovly->ih_x1);
+ ipovly->ih_len = (u_int16_t)tlen;
+ HTONS(ipovly->ih_len);
- if (in6_cksum(m, IPPROTO_TCP, tlen, sizeof(struct ipv6))) {
- tcpstat.tcps_rcvbadsum++;
- goto drop;
- } /* endif in6_cksum */
- } else {
- ti = mtod(m, struct tcpiphdr *);
-#endif /* INET6 */
-
- /*
- * Checksum extended TCP header and data.
- */
-#ifndef INET6
- tlen = ((struct ip *)ti)->ip_len;
-#endif /* INET6 */
- len = sizeof (struct ip) + tlen;
- bzero(ti->ti_x1, sizeof ti->ti_x1);
- ti->ti_len = (u_int16_t)tlen;
- HTONS(ti->ti_len);
- if ((ti->ti_sum = in_cksum(m, len)) != 0) {
- tcpstat.tcps_rcvbadsum++;
- goto drop;
- }
+ if (in_cksum(m, len)) {
+ tcpstat.tcps_rcvbadsum++;
+ goto drop;
+ }
+ }
+ break;
+#endif /* INET */
#ifdef INET6
- }
+ case PF_INET6:
+ if (in6_cksum(m, IPPROTO_TCP, tlen, sizeof(struct ipv6))) {
+ tcpstat.tcps_rcvbadsum++;
+ goto drop;
+ } /* endif in6_cksum */
+ break;
#endif /* INET6 */
+ }
+
#endif /* TUBA_INCLUDE */
+ nhu.p = mtod(m, caddr_t);
th = (struct tcphdr *)(mtod(m, caddr_t) + iphlen);
/*
@@ -449,12 +487,6 @@ tcp_input(m, va_alist)
tcpstat.tcps_rcvshort++;
return;
}
-#ifdef INET6
- if (is_ipv6)
- ipv6 = mtod(m, struct ipv6 *);
- else
-#endif /* INET6 */
- ti = mtod(m, struct tcpiphdr *);
th = (struct tcphdr *)(mtod(m, caddr_t) + iphlen);
}
optlen = off - sizeof (struct tcphdr);
@@ -491,25 +523,51 @@ tcp_input(m, va_alist)
* Locate pcb for segment.
*/
findpcb:
+#if defined(INET) && defined(INET6)
+ switch (pf) {
+#else /* defined(INET) && defined(INET6) */
+ switch (-1) {
+ case -1:
+#endif /* defined(INET) && defined(INET6) */
+#ifdef INET
+ case PF_INET:
+ inp = in_pcbhashlookup(&tcbtable, nhu.ip->ip_src,
+ th->th_sport, nhu.ip->ip_dst, th->th_dport);
+ break;
+#endif /* INET */
#ifdef INET6
- if (is_ipv6) {
- inp = in6_pcbhashlookup(&tcbtable, &ipv6->ipv6_src, th->th_sport,
- &ipv6->ipv6_dst, th->th_dport);
- } else
+ case PF_INET6:
+ inp = in6_pcbhashlookup(&tcbtable, &nhu.ipv6->ipv6_src,
+ th->th_sport, &nhu.ipv6->ipv6_dst, th->th_dport);
+ break;
#endif /* INET6 */
- inp = in_pcbhashlookup(&tcbtable, ti->ti_src, ti->ti_sport,
- ti->ti_dst, ti->ti_dport);
+ }
+
if (inp == 0) {
++tcpstat.tcps_pcbhashmiss;
+#if defined(INET) && defined(INET6)
+ switch (pf) {
+#else /* defined(INET) && defined(INET6) */
+ switch (-1) {
+ case -1:
+#endif /* defined(INET) && defined(INET6) */
+#ifdef INET
+ case PF_INET:
+ inp = in_pcblookup(&tcbtable, &nhu.ip->ip_src,
+ th->th_sport, &nhu.ip->ip_dst, th->th_dport,
+ INPLOOKUP_WILDCARD);
+ break;
+#endif /* INET */
#ifdef INET6
- if (is_ipv6)
- inp = in_pcblookup(&tcbtable, &ipv6->ipv6_src,
- th->th_sport, &ipv6->ipv6_dst, th->th_dport,
- INPLOOKUP_WILDCARD | INPLOOKUP_IPV6);
- else
+ case PF_INET6:
+ inp = in_pcblookup(&tcbtable, &nhu.ipv6->ipv6_src,
+ th->th_sport, &nhu.ipv6->ipv6_dst,
+ th->th_dport,
+ INPLOOKUP_WILDCARD | INPLOOKUP_IPV6);
+ break;
#endif /* INET6 */
- inp = in_pcblookup(&tcbtable, &ti->ti_src, ti->ti_sport,
- &ti->ti_dst, ti->ti_dport, INPLOOKUP_WILDCARD);
+ }
+
/*
* If the state is CLOSED (i.e., TCB does not exist) then
* all data in the incoming segment is discarded.
@@ -538,12 +596,8 @@ findpcb:
if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) {
if (so->so_options & SO_DEBUG) {
ostate = tp->t_state;
-#ifdef INET6
- if (is_ipv6)
- tcp_saveti6 = *(mtod(m, struct tcpipv6hdr *));
- else
-#endif /* INET6 */
- tcp_saveti = *ti;
+ bcopy(mtod(m, caddr_t), tcp_savebuf,
+ iphlen + sizeof(struct tcphdr));
}
if (so->so_options & SO_ACCEPTCONN) {
struct socket *so1;
@@ -591,48 +645,57 @@ findpcb:
* to the new one.
*/
{
- int flags = inp->inp_flags;
- struct inpcb *oldinpcb = inp;
+ int flags = inp->inp_flags;
+ struct inpcb *oldinpcb = inp;
- inp = (struct inpcb *)so->so_pcb;
- inp->inp_flags |= (flags & (INP_IPV6 | INP_IPV6_UNDEC
- | INP_IPV6_MAPPED));
- if ((inp->inp_flags & INP_IPV6) &&
- !(inp->inp_flags & INP_IPV6_MAPPED)) {
- inp->inp_ipv6.ipv6_hoplimit =
- oldinpcb->inp_ipv6.ipv6_hoplimit;
- inp->inp_ipv6.ipv6_versfl =
- oldinpcb->inp_ipv6.ipv6_versfl;
- }
+ inp = (struct inpcb *)so->so_pcb;
+ inp->inp_flags |=
+ (flags & (INP_IPV6 | INP_IPV6_UNDEC
+ | INP_IPV6_MAPPED));
+ if ((inp->inp_flags & INP_IPV6) &&
+ !(inp->inp_flags &
+ INP_IPV6_MAPPED)) {
+ inp->inp_ipv6.ipv6_hoplimit =
+ oldinpcb->inp_ipv6.
+ ipv6_hoplimit;
+ inp->inp_ipv6.ipv6_versfl =
+ oldinpcb->inp_ipv6.ipv6_versfl;
+ }
}
#else /* INET6 */
inp = (struct inpcb *)so->so_pcb;
#endif /* INET6 */
inp->inp_lport = th->th_dport;
+#if defined(INET) && defined(INET6)
+ switch (pf) {
+#else /* defined(INET) && defined(INET6) */
+ switch (-1) {
+ case -1:
+#endif /* defined(INET) && defined(INET6) */
+#ifdef INET
+ case PF_INET:
#ifdef INET6
- if (is_ipv6) {
- inp->inp_laddr6 = ipv6->ipv6_dst;
- inp->inp_fflowinfo = htonl(0x0fffffff) &
- ipv6->ipv6_versfl;
-
- /*inp->inp_options = ipv6_srcroute();*/ /* soon. */
- /* still need to tweak outbound options
- processing to include this mbuf in
- the right place and put the correct
- NextHdr values in the right places.
- XXX rja */
- } else {
- if (inp->inp_flags & INP_IPV6) {/* v4 to v6 socket */
- CREATE_IPV6_MAPPED(inp->inp_laddr6,
- ti->ti_dst.s_addr);
- } else {
+ if (inp->inp_flags & INP_IPV6) {
+ /* v4 to v6 socket */
+ CREATE_IPV6_MAPPED(inp->inp_laddr6,
+ nhu.ip->ip_dst.s_addr);
+ } else
#endif /* INET6 */
- inp->inp_laddr = ti->ti_dst;
- inp->inp_options = ip_srcroute();
-#if INET6
- }
- }
+ {
+ inp->inp_laddr = nhu.ip->ip_dst;
+ inp->inp_options = ip_srcroute();
+ }
+ break;
+#endif /* INET */
+#ifdef INET6
+ case PF_INET6:
+ inp->inp_laddr6 = nhu.ipv6->ipv6_dst;
+ inp->inp_fflowinfo = htonl(0x0fffffff) &
+ nhu.ipv6->ipv6_versfl;
+ break;
#endif /* INET6 */
+ }
+
in_pcbrehash(inp);
tp = intotcpcb(inp);
tp->t_state = TCPS_LISTEN;
@@ -640,7 +703,8 @@ findpcb:
/* Compute proper scaling value from buffer space
*/
while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
- TCP_MAXWIN << tp->request_r_scale < so->so_rcv.sb_hiwat)
+ TCP_MAXWIN << tp->request_r_scale <
+ so->so_rcv.sb_hiwat)
tp->request_r_scale++;
}
}
@@ -652,12 +716,23 @@ findpcb:
(inp->inp_seclevel[SL_ESP_TRANS] >= IPSEC_LEVEL_REQUIRE &&
!(m->m_flags & M_CONF))) {
#ifdef notyet
+#if defined(INET) && defined(INET6)
+ switch (pf) {
+#else /* defined(INET) && defined(INET6) */
+ switch (-1) {
+ case -1:
+#endif /* defined(INET) && defined(INET6) */
+#ifdef INET
+ case PF_INET:
+ icmp_error(m, ICMP_BLAH, ICMP_BLAH, 0, 0);
+ break;
+#endif /* INET */
#ifdef INET6
- if (is_ipv6)
+ case PF_INET6:
ipv6_icmp_error(m, ICMPV6_BLAH, ICMPV6_BLAH, 0);
- else
+ break;
#endif /* INET6 */
- icmp_error(m, ICMP_BLAH, ICMP_BLAH, 0, 0);
+ }
#endif /* notyet */
tcpstat.tcps_rcvnosec++;
goto drop;
@@ -684,9 +759,15 @@ findpcb:
* Process options if not in LISTEN state,
* else do it below (after getting remote address).
*/
- if (optp && tp->t_state != TCPS_LISTEN)
- tcp_dooptions(tp, optp, optlen, th,
- &ts_present, &ts_val, &ts_ecr);
+ if (tp->t_state != TCPS_LISTEN)
+#ifdef TCP_SIGNATURE
+ if (optp || (tp->t_flags & TF_SIGNATURE))
+#else /* TCP_SIGNATURE */
+ if (optp)
+#endif /* TCP_SIGNATURE */
+ if (tcp_dooptions(tp, optp, optlen, th, m, iphlen,
+ &ts_present, &ts_val, &ts_ecr))
+ goto drop;
#ifdef TCP_SACK
if (!tp->sack_disable) {
@@ -812,12 +893,6 @@ findpcb:
}
/*
- * Drop TCP, IP headers and TCP options.
- */
- m->m_data += iphlen + off;
- m->m_len -= iphlen + off;
-
- /*
* Calculate amount of space in receive window,
* and then do TCP input processing.
* Receive window is amount of space in rcv queue,
@@ -849,10 +924,6 @@ findpcb:
*/
case TCPS_LISTEN: {
struct mbuf *am;
- register struct sockaddr_in *sin;
-#ifdef INET6
- register struct sockaddr_in6 *sin6;
-#endif /* INET6 */
if (tiflags & TH_RST)
goto drop;
@@ -861,17 +932,27 @@ findpcb:
if ((tiflags & TH_SYN) == 0)
goto drop;
if (th->th_dport == th->th_sport) {
+#if defined(INET) && defined(INET6)
+ switch (pf) {
+#else /* defined(INET) && defined(INET6) */
+ switch (-1) {
+ case -1:
+#endif /* defined(INET) && defined(INET6) */
+#ifdef INET
+ case PF_INET:
+ if (nhu.ip->ip_src.s_addr ==
+ nhu.ip->ip_dst.s_addr)
+ goto drop;
+ break;
+#endif /* INET */
#ifdef INET6
- if (is_ipv6) {
- if (IN6_ARE_ADDR_EQUAL(&ipv6->ipv6_src, &ipv6->ipv6_dst))
- goto drop;
- } else {
-#endif /* INET6 */
- if (ti->ti_dst.s_addr == ti->ti_src.s_addr)
- goto drop;
-#ifdef INET6
- }
+ case PF_INET6:
+ if (IN6_ARE_ADDR_EQUAL(&nhu.ipv6->ipv6_src,
+ &nhu.ipv6->ipv6_dst))
+ goto drop;
+ break;
#endif /* INET6 */
+ }
}
/*
@@ -881,118 +962,168 @@ findpcb:
*/
if (m->m_flags & (M_BCAST|M_MCAST))
goto drop;
+#if defined(INET) && defined(INET6)
+ switch (pf) {
+#else /* defined(INET) && defined(INET6) */
+ switch (-1) {
+ case -1:
+#endif /* defined(INET) && defined(INET6) */
+#ifdef INET
+ case PF_INET:
+ if (nhu.ip->ip_dst.s_addr == INADDR_BROADCAST)
+ goto drop;
+ if (IN_MULTICAST(nhu.ip->ip_dst.s_addr))
+ goto drop;
+ break;
+#endif /* INET */
#ifdef INET6
- if (is_ipv6) {
- /* XXX What about IPv6 Anycasting ?? :-( rja */
- if (IN6_IS_ADDR_MULTICAST(&ipv6->ipv6_dst))
+ case PF_INET6:
+ if (IN6_IS_ADDR_MULTICAST(&nhu.ipv6->ipv6_dst))
goto drop;
- } else
+ break;
#endif /* INET6 */
- if (IN_MULTICAST(ti->ti_dst.s_addr))
- goto drop;
+ }
+
am = m_get(M_DONTWAIT, MT_SONAME); /* XXX */
if (am == NULL)
goto drop;
+
+#if defined(INET) && defined(INET6)
+ switch (pf) {
+#else /* defined(INET) && defined(INET6) */
+ switch (-1) {
+ case -1:
+#endif /* defined(INET) && defined(INET6) */
+#ifdef INET
+ case PF_INET:
#ifdef INET6
- if (is_ipv6) {
- /*
- * This is probably the place to set the tp->pf value.
- * (Don't forget to do it in the v4 code as well!)
- *
- * Also, remember to blank out things like flowlabel, or
- * set flowlabel for accepted sockets in v6.
- *
- * FURTHERMORE, this is PROBABLY the place where the whole
- * business of key munging is set up for passive
- * connections.
- */
- am->m_len = sizeof(struct sockaddr_in6);
- sin6 = mtod(am, struct sockaddr_in6 *);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_len = sizeof(struct sockaddr_in6);
- sin6->sin6_addr = ipv6->ipv6_src;
- sin6->sin6_port = th->th_sport;
- sin6->sin6_flowinfo = htonl(0x0fffffff) &
- inp->inp_ipv6.ipv6_versfl;
- laddr6 = inp->inp_laddr6;
- if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6))
- inp->inp_laddr6 = ipv6->ipv6_dst;
- /* This is a good optimization. */
- if (in6_pcbconnect(inp, am)) {
- inp->inp_laddr6 = laddr6;
- (void) m_free(am);
- goto drop;
- } /* endif in6_pcbconnect() */
- tp->pf = PF_INET6;
- } else {
- /*
- * Letting v4 incoming datagrams to reach valid
- * PF_INET6 sockets causes some overhead here.
- */
- if (inp->inp_flags & INP_IPV6) {
- if (!(inp->inp_flags & (INP_IPV6_UNDEC|INP_IPV6_MAPPED))) {
- (void) m_free(am);
- goto drop;
- }
-
- am->m_len = sizeof(struct sockaddr_in6);
-
- sin6 = mtod(am, struct sockaddr_in6 *);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_len = sizeof(*sin6);
- CREATE_IPV6_MAPPED(sin6->sin6_addr, ti->ti_src.s_addr);
- sin6->sin6_port = th->th_sport;
- sin6->sin6_flowinfo = 0;
-
- laddr6 = inp->inp_laddr6;
- if (inp->inp_laddr.s_addr == INADDR_ANY)
- CREATE_IPV6_MAPPED(inp->inp_laddr6, ti->ti_dst.s_addr);
-
- /*
- * The pcb initially has the v6 default hoplimit
- * set. We're sending v4 packets so we need to set
- * the v4 ttl and tos.
- */
- inp->inp_ip.ip_ttl = ip_defttl;
- inp->inp_ip.ip_tos = 0;
-
- if (in6_pcbconnect(inp, am)) {
- inp->inp_laddr6 = laddr6;
- (void) m_freem(am);
- goto drop;
- }
- tp->pf = PF_INET;
- } else {
+ /*
+ * Letting v4 incoming datagrams to reach valid
+ * PF_INET6 sockets causes some overhead here.
+ */
+ if (inp->inp_flags & INP_IPV6) {
+ struct sockaddr_in6 *sin6;
+ struct in6_addr laddr6;
+
+ if (!(inp->inp_flags & (INP_IPV6_UNDEC |
+ INP_IPV6_MAPPED))) {
+ m_freem(am);
+ goto drop;
+ }
+
+ am->m_len = sizeof(struct sockaddr_in6);
+ sin6 = mtod(am, struct sockaddr_in6 *);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_len = sizeof(struct sockaddr_in6);
+ CREATE_IPV6_MAPPED(sin6->sin6_addr,
+ nhu.ip->ip_src.s_addr);
+ sin6->sin6_port = th->th_sport;
+ sin6->sin6_flowinfo = 0;
+
+ laddr6 = inp->inp_laddr6;
+ if (inp->inp_laddr.s_addr == INADDR_ANY)
+ break;
+ CREATE_IPV6_MAPPED(inp->inp_laddr6,
+ nhu.ip->ip_dst.s_addr);
+
+ /*
+ * The pcb initially has the v6 default hop
+ * limit set. We're sending v4 packets, so we
+ * need to set the v4 ttl and tos.
+ */
+ inp->inp_ip.ip_ttl = ip_defttl;
+ inp->inp_ip.ip_tos = 0;
+
+ if (in6_pcbconnect(inp, am)) {
+ inp->inp_laddr6 = laddr6;
+ m_freem(am);
+ goto drop;
+ }
+ } else /* (inp->inp_flags & INP_IPV6) */
#endif /* INET6 */
- am->m_len = sizeof (struct sockaddr_in);
- sin = mtod(am, struct sockaddr_in *);
- sin->sin_family = AF_INET;
- sin->sin_len = sizeof(*sin);
- sin->sin_addr = ti->ti_src;
- sin->sin_port = ti->ti_sport;
- bzero((caddr_t)sin->sin_zero, sizeof(sin->sin_zero));
- laddr = inp->inp_laddr;
- if (inp->inp_laddr.s_addr == INADDR_ANY)
- inp->inp_laddr = ti->ti_dst;
- if (in_pcbconnect(inp, am)) {
- inp->inp_laddr = laddr;
- (void) m_free(am);
- goto drop;
- }
- (void) m_free(am);
+ {
+ struct sockaddr_in *sin;
+ struct in_addr laddr;
+
+ am->m_len = sizeof(struct sockaddr_in);
+ sin = mtod(am, struct sockaddr_in *);
+ sin->sin_family = AF_INET;
+ sin->sin_len = sizeof(struct sockaddr_in);
+ sin->sin_addr = nhu.ip->ip_src;
+ sin->sin_port = th->th_sport;
+ bzero((caddr_t)sin->sin_zero,
+ sizeof(sin->sin_zero));
+ laddr = inp->inp_laddr;
+ if (inp->inp_laddr.s_addr == INADDR_ANY)
+ inp->inp_laddr = nhu.ip->ip_dst;
+ if (in_pcbconnect(inp, am)) {
+ inp->inp_laddr = laddr;
+ m_free(am);
+ goto drop;
+ }
+ } /* (inp->inp_flags & INP_IPV6) */
+ tp->pf = PF_INET;
+ break;
+#endif /* INET */
#ifdef INET6
- } /* if (inp->inp_flags & INP_IPV6) */
- } /* if (is_ipv6) */
+ case PF_INET6:
+ {
+ struct sockaddr_in6 *sin6;
+ struct in6_addr laddr6;
+
+ /*
+ * This is probably the place to set the tp->pf
+ * value. (Don't forget to do it in the v4 code
+ * as well!)
+ *
+ * Also, remember to blank out things like
+ * flowlabel, or set flowlabel for accepted
+ * sockets in v6.
+ */
+
+ am->m_len = sizeof(struct sockaddr_in6);
+ sin6 = mtod(am, struct sockaddr_in6 *);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_len = sizeof(struct sockaddr_in6);
+ sin6->sin6_addr = nhu.ipv6->ipv6_src;
+ sin6->sin6_port = th->th_sport;
+ sin6->sin6_flowinfo = htonl(0x0fffffff) &
+ inp->inp_ipv6.ipv6_versfl;
+ laddr6 = inp->inp_laddr6;
+
+ if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6))
+ inp->inp_laddr6 = nhu.ipv6->ipv6_dst;
+ /* This is a good optimization. */
+ if (in6_pcbconnect(inp, am)) {
+ inp->inp_laddr6 = laddr6;
+ m_free(am);
+ goto drop;
+ }
+ }
+
+ tp->pf = PF_INET6;
+ break;
#endif /* INET6 */
+ }
+
+ m_free(am);
tp->t_template = tcp_template(tp);
if (tp->t_template == 0) {
tp = tcp_drop(tp, ENOBUFS);
dropsocket = 0; /* socket is already gone */
goto drop;
}
- if (optp)
- tcp_dooptions(tp, optp, optlen, th,
- &ts_present, &ts_val, &ts_ecr);
+
+#ifdef TCP_SIGNATURE
+ if (optp || (tp->t_flags & TF_SIGNATURE)) {
+#else /* TCP_SIGNATURE */
+ if (optp) {
+#endif /* TCP_SIGNATURE */
+ if (tcp_dooptions(tp, optp, optlen, th, m, iphlen,
+ &ts_present, &ts_val, &ts_ecr))
+ goto drop;
+ }
+
#ifdef TCP_SACK
/*
* If peer did not send a SACK_PERMITTED option (i.e., if
@@ -1293,7 +1424,7 @@ trimthenstep6:
* Close the tcb.
*/
if (tiflags & TH_RST) {
- if (ti->ti_seq != tp->last_ack_sent)
+ if (th->th_seq != tp->last_ack_sent)
goto drop;
switch (tp->t_state) {
@@ -1824,6 +1955,12 @@ step6:
dodata: /* XXX */
/*
+ * Drop TCP, IP headers and TCP options.
+ */
+ m->m_data += iphlen + off;
+ m->m_len -= iphlen + off;
+
+ /*
* Process the segment text, merging it into the TCP sequencing queue,
* and arranging for acknowledgment of receipt if necessary.
* This process logically involves adjusting tp->rcv_wnd as data
@@ -1919,14 +2056,9 @@ dodata: /* XXX */
break;
}
}
- if (so->so_options & SO_DEBUG) {
-#ifdef INET6
- if (tp->pf == PF_INET6)
- tcp_trace(TA_INPUT, ostate, tp, (caddr_t) &tcp_saveti6, 0, tlen);
- else
-#endif /* INET6 */
- tcp_trace(TA_INPUT, ostate, tp, (caddr_t) &tcp_saveti, 0, tlen);
- }
+
+ if (so->so_options & SO_DEBUG)
+ tcp_trace(TA_INPUT, ostate, tp, tcp_savebuf, 0, tlen);
/*
* Return any desired output.
@@ -1967,26 +2099,36 @@ dropwithreset:
*/
if ((tiflags & TH_RST) || m->m_flags & (M_BCAST|M_MCAST))
goto drop;
+#if defined(INET) && defined(INET6)
+ switch (pf) {
+#else /* defined(INET) && defined(INET6) */
+ switch (-1) {
+ case -1:
+#endif /* defined(INET) && defined(INET6) */
+#ifdef INET
+ case PF_INET:
+ if (mtod(m, struct ip *)->ip_dst.s_addr == INADDR_BROADCAST)
+ goto drop;
+ if (IN_MULTICAST(mtod(m, struct ip *)->ip_dst.s_addr))
+ goto drop;
+ break;
+#endif /* INET */
#ifdef INET6
- if (is_ipv6) {
- /* For following calls to tcp_respond */
- ti = mtod(m, struct tcpiphdr *);
- if (IN6_IS_ADDR_MULTICAST(&ipv6->ipv6_dst))
- goto drop;
- } else {
+ case PF_INET6:
+ if (IN6_IS_ADDR_MULTICAST(&mtod(m, struct ipv6 *)->ipv6_dst))
+ goto drop;
+ break;
#endif /* INET6 */
- if (IN_MULTICAST(ti->ti_dst.s_addr))
- goto drop;
-#ifdef INET6
}
-#endif /* INET6 */
+
if (tiflags & TH_ACK)
- tcp_respond(tp, (caddr_t) ti, m, (tcp_seq)0, th->th_ack, TH_RST);
+ tcp_respond(tp, mtod(m, caddr_t), m, (tcp_seq)0, th->th_ack,
+ TH_RST);
else {
if (tiflags & TH_SYN)
tlen++;
- tcp_respond(tp, (caddr_t) ti, m, th->th_seq+tlen, (tcp_seq)0,
- TH_RST|TH_ACK);
+ tcp_respond(tp, mtod(m, caddr_t), m, th->th_seq+tlen,
+ (tcp_seq)0, TH_RST|TH_ACK);
}
/* destroy temporarily created socket */
if (dropsocket)
@@ -1997,14 +2139,8 @@ drop:
/*
* Drop space held by incoming segment and return.
*/
- if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) {
-#ifdef INET6
- if (tp->pf == PF_INET6)
- tcp_trace(TA_DROP, ostate, tp, (caddr_t) &tcp_saveti6, 0, tlen);
- else
-#endif /* INET6 */
- tcp_trace(TA_DROP, ostate, tp, (caddr_t) &tcp_saveti, 0, tlen);
- }
+ if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
+ tcp_trace(TA_DROP, ostate, tp, tcp_savebuf, 0, tlen);
m_freem(m);
/* destroy temporarily created socket */
@@ -2014,17 +2150,22 @@ drop:
#ifndef TUBA_INCLUDE
}
-void
-tcp_dooptions(tp, cp, cnt, th, ts_present, ts_val, ts_ecr)
+int
+tcp_dooptions(tp, cp, cnt, th, m, iphlen, ts_present, ts_val, ts_ecr)
struct tcpcb *tp;
u_char *cp;
int cnt;
struct tcphdr *th;
+ struct mbuf *m;
+ int iphlen;
int *ts_present;
u_int32_t *ts_val, *ts_ecr;
{
u_int16_t mss = 0;
int opt, optlen;
+#ifdef TCP_SIGNATURE
+ caddr_t sigp = NULL;
+#endif /* TCP_SIGNATURE */
for (; cnt > 0; cnt -= optlen, cp += optlen) {
opt = cp[0];
@@ -2093,11 +2234,137 @@ tcp_dooptions(tp, cp, cnt, th, ts_present, ts_val, ts_ecr)
continue;
break;
#endif
+#ifdef TCP_SIGNATURE
+ case TCPOPT_SIGNATURE:
+ if (optlen != TCPOLEN_SIGNATURE)
+ continue;
+
+ if (sigp && bcmp(sigp, cp + 2, 16))
+ return -1;
+
+ sigp = cp + 2;
+ break;
+#endif /* TCP_SIGNATURE */
}
}
+
+#ifdef TCP_SIGNATURE
+ if ((sigp ? TF_SIGNATURE : 0) ^ (tp->t_flags & TF_SIGNATURE)) {
+ tcpstat.tcps_rcvbadsig++;
+ return -1;
+ }
+
+ if (sigp) {
+ MD5_CTX ctx;
+ union sockaddr_union sa;
+ struct tdb *tdb;
+ char sig[16];
+
+ memset(&sa, 0, sizeof(union sockaddr_union));
+
+ switch (tp->pf) {
+ case 0:
+ case AF_INET:
+ sa.sa.sa_len = sizeof(struct sockaddr_in);
+ sa.sa.sa_family = AF_INET;
+ sa.sin.sin_addr = tp->t_inpcb->inp_laddr;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ sa.sa.sa_len = sizeof(struct sockaddr_in6);
+ sa.sa.sa_family = AF_INET6;
+ sa.sin6.sin6_addr = tp->t_inpcb->inp_laddr6;
+ break;
+#endif /* INET6 */
+ }
+
+ tdb = gettdb(0, &sa, IPPROTO_TCP);
+ if (tdb == NULL) {
+ printf("tdb miss\n");
+ tcpstat.tcps_rcvbadsig++;
+ return -1;
+ }
+
+ MD5Init(&ctx);
+
+ switch(tp->pf) {
+ case 0:
+#ifdef INET
+ case AF_INET:
+ {
+ struct ippseudo ippseudo;
+
+ ippseudo.ippseudo_src =
+ tp->t_inpcb->inp_faddr;
+ ippseudo.ippseudo_dst =
+ tp->t_inpcb->inp_laddr;
+ ippseudo.ippseudo_pad = 0;
+ ippseudo.ippseudo_p = IPPROTO_TCP;
+ ippseudo.ippseudo_len = htons(
+ m->m_pkthdr.len - iphlen);
+
+ MD5Update(&ctx, (char *)&ippseudo,
+ sizeof(struct ippseudo));
+ }
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ {
+ static int printed = 0;
+
+ if (!printed) {
+ printf("error: TCP MD5 support"
+ " for IPv6 not yet"
+ " implemented.\n");
+ printed = 1;
+ }
+ }
+ break
+#endif /* INET6 */
+ }
+
+ {
+ struct tcphdr tcphdr;
+
+ tcphdr.th_sport = th->th_sport;
+ tcphdr.th_dport = th->th_dport;
+ tcphdr.th_seq = htonl(th->th_seq);
+ tcphdr.th_ack = htonl(th->th_ack);
+ tcphdr.th_off = th->th_off;
+ tcphdr.th_x2 = th->th_x2;
+ tcphdr.th_flags = th->th_flags;
+ tcphdr.th_win = htons(th->th_win);
+ tcphdr.th_sum = 0;
+ tcphdr.th_urp = htons(th->th_urp);
+
+ MD5Update(&ctx, (char *)&tcphdr,
+ sizeof(struct tcphdr));
+ }
+
+ if (m_apply(m, iphlen + th->th_off * sizeof(uint32_t),
+ m->m_pkthdr.len - (iphlen + th->th_off *
+ sizeof(uint32_t)), tcp_signature_apply,
+ (caddr_t)&ctx))
+ return (-1);
+
+ MD5Update(&ctx, tdb->tdb_amxkey, tdb->tdb_amxkeylen);
+ MD5Final(sig, &ctx);
+
+ if (bcmp(sig, sigp, 16)) {
+ tcpstat.tcps_rcvbadsig++;
+ return (-1);
+ }
+
+ tcpstat.tcps_rcvgoodsig++;
+ }
+#endif /* TCP_SIGNATURE */
+
/* Update t_maxopd and t_maxseg after all options are processed */
if (th->th_flags & TH_SYN)
(void) tcp_mss(tp, mss); /* sets t_maxseg */
+
+ return (0);
}
#if defined(TCP_SACK) || defined(TCP_NEWRENO)