DragonFly submit List (threaded) for 2010-09
[
Date Prev][
Date Next]
[
Thread Prev][
Thread Next]
[
Date Index][
Thread Index]
[PATCH 2/2] Implement IPv6 support for TCP MD5 Signature Option (RFC 2385)
Import of FreeBSD commit r183001
Tested with a Cisco 2611XM running IOS 12.3(24), and Quagga 0.99.17
---
sys/netinet/tcp_output.c | 48 +++++++++++------------
sys/netinet/tcp_subr.c | 88 ++++++++++++++++++++++++++++++++++++--------
sys/netinet/tcp_syncache.c | 2 +-
sys/netinet/tcp_var.h | 2 +-
4 files changed, 97 insertions(+), 43 deletions(-)
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index dd8292b..8f0fe27 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -602,27 +602,26 @@ send:
tcp_sack_fill_report(tp, opt, &optlen);
#ifdef TCP_SIGNATURE
- if (!isipv6)
- if (tp->t_flags & TF_SIGNATURE) {
- int i;
- u_char *bp;
- /*
- * Initialize TCP-MD5 option (RFC2385)
- */
- bp = (u_char *)opt + optlen;
- *bp++ = TCPOLEN_SIGNATURE;
- sigoff = optlen + 2;
- for (i = 0; i < TCP_SIGLEN; i++)
- *bp++ = 0;
- optlen += TCPOLEN_SIGNATURE;
- /*
- * Terminate options list and maintain 32-bit alignment.
- */
- *bp++ = TCPOPT_NOP;
- *bp++ = TCPOPT_EOL;
- optlen += 2;
- }
+ if (tp->t_flags & TF_SIGNATURE) {
+ int i;
+ u_char *bp;
+ /*
+ * Initialize TCP-MD5 option (RFC2385)
+ */
+ bp = (u_char *)opt + optlen;
+ *bp++ = TCPOPT_SIGNATURE;
+ *bp++ = TCPOLEN_SIGNATURE;
+ sigoff = optlen + 2;
+ for (i = 0; i < TCP_SIGLEN; i++)
+ *bp++ = 0;
+ optlen += TCPOLEN_SIGNATURE;
+ /*
+ * Terminate options list and maintain 32-bit alignment.
+ */
+ *bp++ = TCPOPT_NOP;
+ *bp++ = TCPOPT_EOL;
+ optlen += 2;
+ }
#endif /* TCP_SIGNATURE */
KASSERT(optlen <= TCP_MAXOLEN, ("too many TCP options"));
hdrlen += optlen;
@@ -844,10 +843,9 @@ send:
}
#ifdef TCP_SIGNATURE
- if (!isipv6)
- if (tp->t_flags & TF_SIGNATURE)
- tcpsignature_compute(m, sizeof(struct ip), len, optlen,
- (u_char *)(th + 1) + sigoff, IPSEC_DIR_OUTBOUND);
+ if (tp->t_flags & TF_SIGNATURE)
+ tcpsignature_compute(m, len, optlen,
+ (u_char *)(th + 1) + sigoff, IPSEC_DIR_OUTBOUND);
#endif /* TCP_SIGNATURE */
/*
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index fafda1e..f64b97c 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1984,15 +1984,12 @@ tcp_xmit_bandwidth_limit(struct tcpcb *tp, tcp_seq ack_seq)
#ifdef TCP_SIGNATURE
/*
- * Compute TCP-MD5 hash of a TCPv4 segment. (RFC2385)
+ * Compute TCP-MD5 hash of a TCP segment. (RFC2385)
*
* We do this over ip, tcphdr, segment data, and the key in the SADB.
* When called from tcp_input(), we can be sure that th_sum has been
* zeroed out and verified already.
*
- * This function is for IPv4 use only. Calling this function with an
- * IPv6 packet in the mbuf chain will yield undefined results.
- *
* Return 0 if successful, otherwise return -1.
*
* XXX The key is retrieved from the system's PF_KEY SADB, by keying a
@@ -2004,7 +2001,6 @@ tcp_xmit_bandwidth_limit(struct tcpcb *tp, tcp_seq ack_seq)
int
tcpsignature_compute(
struct mbuf *m, /* mbuf chain */
- int off0, /* offset to TCP header */
int len, /* length of TCP data */
int optlen, /* length of TCP options */
u_char *buf, /* storage for MD5 digest */
@@ -2017,6 +2013,12 @@ tcpsignature_compute(
struct ipovly *ipovly;
struct secasvar *sav;
struct tcphdr *th;
+#ifdef INET6
+ struct ip6_hdr *ip6;
+ struct in6_addr in6;
+ uint32_t plen;
+ uint16_t nhdr;
+#endif /* INET6 */
u_short savecsum;
KASSERT(m != NULL, ("passed NULL mbuf. Game over."));
@@ -2025,21 +2027,36 @@ tcpsignature_compute(
* Extract the destination from the IP header in the mbuf.
*/
ip = mtod(m, struct ip *);
+#ifdef INET6
+ ip6 = NULL; /* Make the compiler happy. */
+#endif /* INET6 */
/*
* Look up an SADB entry which matches the address found in
* the segment.
*/
- sav = key_allocsa(AF_INET, (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
- IPPROTO_TCP, htonl(TCP_SIG_SPI));
+ switch (IP_VHL_V(ip->ip_vhl)) {
+ case IPVERSION:
+ sav = key_allocsa(AF_INET, (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
+ IPPROTO_TCP, htonl(TCP_SIG_SPI));
+ break;
+#ifdef INET6
+ case (IPV6_VERSION >> 4):
+ ip6 = mtod(m, struct ip6_hdr *);
+ sav = key_allocsa(AF_INET6, (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
+ IPPROTO_TCP, htonl(TCP_SIG_SPI));
+ break;
+#endif /* INET6 */
+ default:
+ return (EINVAL);
+ /* NOTREACHED */
+ break;
+ }
if (sav == NULL) {
kprintf("%s: SADB lookup failed\n", __func__);
return (EINVAL);
}
MD5Init(&ctx);
- ipovly = (struct ipovly *)ip;
- th = (struct tcphdr *)((u_char *)ip + off0);
- doff = off0 + sizeof(struct tcphdr) + optlen;
/*
* Step 1: Update MD5 hash with IP pseudo-header.
*
@@ -2049,12 +2066,51 @@ tcpsignature_compute(
* XXX One cannot depend on ipovly->ih_len here. When called from
* tcp_output(), the underlying ip_len member has not yet been set.
*/
- ippseudo.ippseudo_src = ipovly->ih_src;
- ippseudo.ippseudo_dst = ipovly->ih_dst;
- ippseudo.ippseudo_pad = 0;
- ippseudo.ippseudo_p = IPPROTO_TCP;
- ippseudo.ippseudo_len = htons(len + sizeof(struct tcphdr) + optlen);
- MD5Update(&ctx, (char *)&ippseudo, sizeof(struct ippseudo));
+ switch (IP_VHL_V(ip->ip_vhl)) {
+ case IPVERSION:
+ ipovly = (struct ipovly *)ip;
+ ippseudo.ippseudo_src = ipovly->ih_src;
+ ippseudo.ippseudo_dst = ipovly->ih_dst;
+ ippseudo.ippseudo_pad = 0;
+ ippseudo.ippseudo_p = IPPROTO_TCP;
+ ippseudo.ippseudo_len = htons(len + sizeof(struct tcphdr) + optlen);
+ MD5Update(&ctx, (char *)&ippseudo, sizeof(struct ippseudo));
+ th = (struct tcphdr *)((u_char *)ip + sizeof(struct ip));
+ doff = sizeof(struct ip) + sizeof(struct tcphdr) + optlen;
+ break;
+#ifdef INET6
+ /*
+ * RFC 2385, 2.0 Proposal
+ * For IPv6, the pseudo-header is as described in RFC 2460, namely the
+ * 128-bit source IPv6 address, 128-bit destination IPv6 address, zero-
+ * extended next header value (to form 32 bits), and 32-bit segment
+ * length.
+ * Note: Upper-Layer Packet Length comes before Next Header.
+ */
+ case (IPV6_VERSION >> 4):
+ in6 = ip6->ip6_src;
+ in6_clearscope(&in6);
+ MD5Update(&ctx, (char *)&in6, sizeof(struct in6_addr));
+ in6 = ip6->ip6_dst;
+ in6_clearscope(&in6);
+ MD5Update(&ctx, (char *)&in6, sizeof(struct in6_addr));
+ plen = htonl(len + sizeof(struct tcphdr) + optlen);
+ MD5Update(&ctx, (char *)&plen, sizeof(uint32_t));
+ nhdr = 0;
+ MD5Update(&ctx, (char *)&nhdr, sizeof(uint8_t));
+ MD5Update(&ctx, (char *)&nhdr, sizeof(uint8_t));
+ MD5Update(&ctx, (char *)&nhdr, sizeof(uint8_t));
+ nhdr = IPPROTO_TCP;
+ MD5Update(&ctx, (char *)&nhdr, sizeof(uint8_t));
+ th = (struct tcphdr *)((u_char *)ip6 + sizeof(struct ip6_hdr));
+ doff = sizeof(struct ip6_hdr) + sizeof(struct tcphdr) + optlen;
+ break;
+#endif /* INET6 */
+ default:
+ return (EINVAL);
+ /* NOTREACHED */
+ break;
+ }
/*
* Step 2: Update MD5 hash with TCP header, excluding options.
* The TCP checksum must be set to zero.
diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c
index ce53940..bc5fc02 100644
--- a/sys/netinet/tcp_syncache.c
+++ b/sys/netinet/tcp_syncache.c
@@ -1271,7 +1271,7 @@ syncache_respond(struct syncache *sc, struct mbuf *m)
*bp++ = TCPOLEN_SIGNATURE;
for (i = 0; i < TCP_SIGLEN; i++)
*bp++ = 0;
- tcpsignature_compute(m, sizeof(struct ip), 0, optlen,
+ tcpsignature_compute(m, 0, optlen,
optp + 2, IPSEC_DIR_OUTBOUND);
*bp++ = TCPOPT_NOP;
*bp++ = TCPOPT_EOL;
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 3549565..5b10d87 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -647,7 +647,7 @@ void syncache_destroy(struct tcpcb *tp);
#ifdef TCP_SIGNATURE
int tcpsignature_apply(void *fstate, void *data, unsigned int len);
-int tcpsignature_compute(struct mbuf *m, int off0, int len, int tcpoptlen,
+int tcpsignature_compute(struct mbuf *m, int len, int tcpoptlen,
u_char *buf, u_int direction);
#endif /* TCP_SIGNATURE */
--
1.6.6.2
--XsQoSWH+UP9D9v3l--
[
Date Prev][
Date Next]
[
Thread Prev][
Thread Next]
[
Date Index][
Thread Index]