Project

General

Profile

Bug #1820 » 0002-Implement-IPv6-support-for-TCP-MD5-Signature-Option-.patch

david, 09/03/2010 07:19 PM

View differences:

sys/netinet/tcp_output.c
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++ = 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;
}
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;
......
}
#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 */
/*
sys/netinet/tcp_subr.c
#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
......
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 */
......
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."));
......
* 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.
*
......
* 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.
sys/netinet/tcp_syncache.c
*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;
sys/netinet/tcp_var.h
#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 */
(2-2/2)