Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/netinet Fix TCP signature code:
details: https://anonhg.NetBSD.org/src/rev/f941d437ed68
branches: trunk
changeset: 350012:f941d437ed68
user: christos <christos%NetBSD.org@localhost>
date: Mon Jan 02 01:18:42 2017 +0000
description:
Fix TCP signature code:
1. pack options more tightly instead of being generous with no/op
2. put TCP_SIGNATURE option before SACK
3. fix computation of options length, by deferring it
XXX: Really we should move the options setting code in one place instead
of having two copies one for input and one for output.
XXX: tcp_optlen/tcp_hdrsiz need to be fixed; they were wrong before too.
diffstat:
sys/netinet/tcp.h | 6 +-
sys/netinet/tcp_input.c | 142 +++++++++++++++++++++++-----------------
sys/netinet/tcp_output.c | 162 ++++++++++++++++++++++++++++------------------
sys/netinet/tcp_subr.c | 6 +-
4 files changed, 188 insertions(+), 128 deletions(-)
diffs (truncated from 510 to 300 lines):
diff -r 11481494647f -r f941d437ed68 sys/netinet/tcp.h
--- a/sys/netinet/tcp.h Mon Jan 02 01:02:19 2017 +0000
+++ b/sys/netinet/tcp.h Mon Jan 02 01:18:42 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tcp.h,v 1.31 2015/02/14 12:57:53 he Exp $ */
+/* $NetBSD: tcp.h,v 1.32 2017/01/02 01:18:42 christos Exp $ */
/*
* Copyright (c) 1982, 1986, 1993
@@ -75,7 +75,11 @@
} __packed;
#define TCPOPT_EOL 0
+#define TCPOLEN_EOL 1
+#define TCPOPT_PAD 0
+#define TCPOLEN_PAD 1
#define TCPOPT_NOP 1
+#define TCPOLEN_NOP 1
#define TCPOPT_MAXSEG 2
#define TCPOLEN_MAXSEG 4
#define TCPOPT_WINDOW 3
diff -r 11481494647f -r f941d437ed68 sys/netinet/tcp_input.c
--- a/sys/netinet/tcp_input.c Mon Jan 02 01:02:19 2017 +0000
+++ b/sys/netinet/tcp_input.c Mon Jan 02 01:18:42 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tcp_input.c,v 1.351 2016/12/31 22:46:46 christos Exp $ */
+/* $NetBSD: tcp_input.c,v 1.352 2017/01/02 01:18:42 christos Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -148,7 +148,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tcp_input.c,v 1.351 2016/12/31 22:46:46 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tcp_input.c,v 1.352 2017/01/02 01:18:42 christos Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -4534,6 +4534,10 @@
struct tcphdr *th;
u_int hlen;
struct socket *so;
+#ifdef TCP_SIGNATURE
+ struct secasvar *sav = NULL;
+ u_int8_t *sigp = NULL;
+#endif
ro = &sc->sc_route;
switch (sc->sc_src.sa.sa_family) {
@@ -4551,15 +4555,8 @@
return (EAFNOSUPPORT);
}
- /* Compute the size of the TCP options. */
- optlen = 4 + (sc->sc_request_r_scale != 15 ? 4 : 0) +
- ((sc->sc_flags & SCF_SACK_PERMIT) ? (TCPOLEN_SACK_PERMITTED + 2) : 0) +
-#ifdef TCP_SIGNATURE
- ((sc->sc_flags & SCF_SIGNATURE) ? TCPOLEN_SIGLEN : 0) +
-#endif
- ((sc->sc_flags & SCF_TIMESTAMP) ? TCPOLEN_TSTAMP_APPA : 0);
-
- tlen = hlen + sizeof(struct tcphdr) + optlen;
+ /* worst case scanario, since we don't know the option size yet */
+ tlen = hlen + sizeof(struct tcphdr) + MAX_TCPOPTLEN;
/*
* Create the IP+TCP header from scratch.
@@ -4568,8 +4565,9 @@
m_freem(m);
#ifdef DIAGNOSTIC
if (max_linkhdr + tlen > MCLBYTES)
- return (ENOBUFS);
-#endif
+ return ENOBUFS;
+#endif
+
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m && (max_linkhdr + tlen) > MHLEN) {
MCLGET(m, M_DONTWAIT);
@@ -4579,12 +4577,11 @@
}
}
if (m == NULL)
- return (ENOBUFS);
+ return ENOBUFS;
MCLAIM(m, &tcp_tx_mowner);
/* Fixup the mbuf. */
m->m_data += max_linkhdr;
- m->m_len = m->m_pkthdr.len = tlen;
if (sc->sc_tp) {
tp = sc->sc_tp;
if (tp->t_inpcb)
@@ -4625,50 +4622,102 @@
break;
#endif
default:
- th = NULL;
+ return ENOBUFS;
}
th->th_seq = htonl(sc->sc_iss);
th->th_ack = htonl(sc->sc_irs + 1);
- th->th_off = (sizeof(struct tcphdr) + optlen) >> 2;
th->th_flags = TH_SYN|TH_ACK;
th->th_win = htons(sc->sc_win);
- /* th_sum already 0 */
- /* th_urp already 0 */
+ /* th_x2, th_sum, th_urp already 0 from memset */
/* Tack on the TCP options. */
optp = (u_int8_t *)(th + 1);
+ optlen = 0;
*optp++ = TCPOPT_MAXSEG;
- *optp++ = 4;
+ *optp++ = TCPOLEN_MAXSEG;
*optp++ = (sc->sc_ourmaxseg >> 8) & 0xff;
*optp++ = sc->sc_ourmaxseg & 0xff;
+ optlen += TCPOLEN_MAXSEG;
if (sc->sc_request_r_scale != 15) {
*((u_int32_t *)optp) = htonl(TCPOPT_NOP << 24 |
TCPOPT_WINDOW << 16 | TCPOLEN_WINDOW << 8 |
sc->sc_request_r_scale);
- optp += 4;
+ optp += TCPOLEN_WINDOW + TCPOLEN_NOP;
+ optlen += TCPOLEN_WINDOW + TCPOLEN_NOP;
+ }
+
+ if (sc->sc_flags & SCF_SACK_PERMIT) {
+ /* Let the peer know that we will SACK. */
+ *optp++ = TCPOPT_SACK_PERMITTED;
+ *optp++ = TCPOLEN_SACK_PERMITTED;
+ optlen += TCPOLEN_SACK_PERMITTED;
}
if (sc->sc_flags & SCF_TIMESTAMP) {
+ while (!optlen || optlen % 4 != 2) {
+ optlen += TCPOLEN_NOP;
+ *optp++ = TCPOPT_NOP;
+ }
+ *optp++ = TCPOPT_TIMESTAMP;
+ *optp++ = TCPOLEN_TIMESTAMP;
u_int32_t *lp = (u_int32_t *)(optp);
/* Form timestamp option as shown in appendix A of RFC 1323. */
- *lp++ = htonl(TCPOPT_TSTAMP_HDR);
*lp++ = htonl(SYN_CACHE_TIMESTAMP(sc));
*lp = htonl(sc->sc_timestamp);
- optp += TCPOLEN_TSTAMP_APPA;
+ optp += TCPOLEN_TIMESTAMP - 2;
+ optlen += TCPOLEN_TIMESTAMP;
+ }
+
+#ifdef TCP_SIGNATURE
+ if (sc->sc_flags & SCF_SIGNATURE) {
+
+ sav = tcp_signature_getsav(m, th);
+
+ if (sav == NULL) {
+ if (m)
+ m_freem(m);
+ return (EPERM);
+ }
+
+ *optp++ = TCPOPT_SIGNATURE;
+ *optp++ = TCPOLEN_SIGNATURE;
+ sigp = optp;
+ memset(optp, 0, TCP_SIGLEN);
+ optp += TCP_SIGLEN;
+ optlen += TCPOLEN_SIGNATURE;
+
}
-
- if (sc->sc_flags & SCF_SACK_PERMIT) {
- u_int8_t *p = optp;
-
- /* Let the peer know that we will SACK. */
- p[0] = TCPOPT_SACK_PERMITTED;
- p[1] = 2;
- p[2] = TCPOPT_NOP;
- p[3] = TCPOPT_NOP;
- optp += 4;
+#endif
+ /* Terminate and pad TCP options to a 4 byte boundary. */
+ if (optlen % 4) {
+ optlen += TCPOLEN_EOL;
+ *optp++ = TCPOPT_EOL;
}
+ /*
+ * According to RFC 793 (STD0007):
+ * "The content of the header beyond the End-of-Option option
+ * must be header padding (i.e., zero)."
+ * and later: "The padding is composed of zeros."
+ */
+ while (optlen % 4) {
+ optlen += TCPOLEN_PAD;
+ *optp++ = TCPOPT_PAD;
+ }
+
+ /* compute the actual values now that we've added the options */
+ tlen = hlen + sizeof(struct tcphdr) + optlen;
+ m->m_len = m->m_pkthdr.len = tlen;
+ th->th_off = (sizeof(struct tcphdr) + optlen) >> 2;
+
+#ifdef TCP_SIGNATURE
+ if (sav) {
+ (void)tcp_signature(m, th, hlen, sav, sigp);
+ key_sa_recordxfer(sav, m);
+ KEY_FREESAV(&sav);
+ }
+#endif
/*
* Send ECN SYN-ACK setup packet.
@@ -4719,33 +4768,6 @@
TCP_STATINC(TCP_STAT_ECN_ECT);
}
-#ifdef TCP_SIGNATURE
- if (sc->sc_flags & SCF_SIGNATURE) {
- struct secasvar *sav;
- u_int8_t *sigp;
-
- sav = tcp_signature_getsav(m, th);
-
- if (sav == NULL) {
- if (m)
- m_freem(m);
- return (EPERM);
- }
-
- *optp++ = TCPOPT_SIGNATURE;
- *optp++ = TCPOLEN_SIGNATURE;
- sigp = optp;
- memset(optp, 0, TCP_SIGLEN);
- optp += TCP_SIGLEN;
- *optp++ = TCPOPT_NOP;
- *optp++ = TCPOPT_EOL;
-
- (void)tcp_signature(m, th, hlen, sav, sigp);
-
- key_sa_recordxfer(sav, m);
- KEY_FREESAV(&sav);
- }
-#endif
/* Compute the packet's checksum. */
switch (sc->sc_src.sa.sa_family) {
diff -r 11481494647f -r f941d437ed68 sys/netinet/tcp_output.c
--- a/sys/netinet/tcp_output.c Mon Jan 02 01:02:19 2017 +0000
+++ b/sys/netinet/tcp_output.c Mon Jan 02 01:18:42 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tcp_output.c,v 1.187 2016/12/08 05:16:33 ozaki-r Exp $ */
+/* $NetBSD: tcp_output.c,v 1.188 2017/01/02 01:18:42 christos Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -135,7 +135,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tcp_output.c,v 1.187 2016/12/08 05:16:33 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tcp_output.c,v 1.188 2017/01/02 01:18:42 christos Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -566,8 +566,8 @@
struct ip6_hdr *ip6;
#endif
struct tcphdr *th;
- u_char opt[MAX_TCPOPTLEN];
-#define OPT_FITS(more) ((optlen + (more)) < sizeof(opt))
+ u_char opt[MAX_TCPOPTLEN], *optp;
+#define OPT_FITS(more) ((optlen + (more)) <= sizeof(opt))
unsigned optlen, hdrlen, packetlen;
unsigned int sack_numblks;
int idle, sendalot, txsegsize, rxsegsize;
@@ -1116,6 +1116,7 @@
* max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MCLBYTES
*/
optlen = 0;
+ optp = opt;
switch (af) {
#ifdef INET
case AF_INET:
@@ -1157,31 +1158,28 @@
in6_pcbrtentry_unref(synrt, tp->t_in6pcb);
#endif
if ((tp->t_flags & TF_NOOPT) == 0 && OPT_FITS(4)) {
- opt[0] = TCPOPT_MAXSEG;
- opt[1] = 4;
- opt[2] = (tp->t_ourmss >> 8) & 0xff;
- opt[3] = tp->t_ourmss & 0xff;
- optlen = 4;
+ *optp++ = TCPOPT_MAXSEG;
+ *optp++ = TCPOLEN_MAXSEG;
+ *optp++ = (tp->t_ourmss >> 8) & 0xff;
+ *optp++ = tp->t_ourmss & 0xff;
+ optlen += TCPOLEN_MAXSEG;
Home |
Main Index |
Thread Index |
Old Index