From 3d4ecc0736f992b1b16a70695efacb6addadf423 Mon Sep 17 00:00:00 2001 From: Markus Friedl Date: Wed, 14 Jan 2004 13:38:22 +0000 Subject: syncache+ipv6 support for TCP_SIGNATURE; with itojun; ok deraadt --- sys/netinet/tcp_input.c | 186 ++++++++++++++++++++++++++++++++++++++--------- sys/netinet/tcp_output.c | 40 +++++++--- sys/netinet/tcp_var.h | 3 +- 3 files changed, 183 insertions(+), 46 deletions(-) (limited to 'sys') diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 5818f01e91d..2c27ce418e8 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_input.c,v 1.143 2004/01/13 13:26:14 markus Exp $ */ +/* $OpenBSD: tcp_input.c,v 1.144 2004/01/14 13:38:21 markus Exp $ */ /* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */ /* @@ -2190,6 +2190,9 @@ tcp_dooptions(tp, cp, cnt, th, m, iphlen, oi) caddr_t sigp = NULL; #endif /* TCP_SIGNATURE */ +#ifdef TCP_SIGNATURE + if (cp) +#endif /* TCP_SIGNATURE */ for (; cnt > 0; cnt -= optlen, cp += optlen) { opt = cp[0]; if (opt == TCPOPT_EOL) @@ -2290,16 +2293,18 @@ tcp_dooptions(tp, cp, cnt, th, m, iphlen, oi) switch (tp->pf) { case 0: +#ifdef INET 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; + sa.sin.sin_addr = mtod(m, struct ip *)->ip_dst; break; +#endif #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; + sa.sin6.sin6_addr = mtod(m, struct ip6_hdr *)->ip6_dst; break; #endif /* INET6 */ } @@ -2321,9 +2326,9 @@ tcp_dooptions(tp, cp, cnt, th, m, iphlen, oi) struct ippseudo ippseudo; ippseudo.ippseudo_src = - tp->t_inpcb->inp_faddr; + mtod(m, struct ip *)->ip_src; ippseudo.ippseudo_dst = - tp->t_inpcb->inp_laddr; + mtod(m, struct ip *)->ip_dst; ippseudo.ippseudo_pad = 0; ippseudo.ippseudo_p = IPPROTO_TCP; ippseudo.ippseudo_len = htons( @@ -2337,14 +2342,21 @@ tcp_dooptions(tp, cp, cnt, th, m, iphlen, oi) #ifdef INET6 case AF_INET6: { - static int printed = 0; - - if (!printed) { - printf("error: TCP MD5 support" - " for IPv6 not yet" - " implemented.\n"); - printed = 1; - } + struct ip6_hdr_pseudo ip6pseudo; + + bzero(&ip6pseudo, sizeof(ip6pseudo)); + ip6pseudo.ip6ph_src = + mtod(m, struct ip6_hdr *)->ip6_src; + ip6pseudo.ip6ph_dst = + mtod(m, struct ip6_hdr *)->ip6_dst; + in6_clearscope(&ip6pseudo.ip6ph_src); + in6_clearscope(&ip6pseudo.ip6ph_dst); + ip6pseudo.ip6ph_nxt = IPPROTO_TCP; + ip6pseudo.ip6ph_len = htonl(m->m_pkthdr.len - + iphlen); + + MD5Update(&ctx, (char *)&ip6pseudo, + sizeof(ip6pseudo)); } break; #endif /* INET6 */ @@ -3764,6 +3776,10 @@ syn_cache_get(src, dst, th, hlen, tlen, so, m) #ifdef TCP_SACK if (sc->sc_flags & SCF_SACK_PERMIT) tp->t_flags |= TF_SACK_PERMIT; +#endif +#ifdef TCP_SIGNATURE + if (sc->sc_flags & SCF_SIGNATURE) + tp->t_flags |= TF_SIGNATURE; #endif tcp_rcvseqinit(tp); tp->t_state = TCPS_SYN_RECEIVED; @@ -3929,37 +3945,47 @@ syn_cache_add(src, dst, th, iphlen, so, m, optp, optlen, oi) if (win > TCP_MAXWIN) win = TCP_MAXWIN; - switch (src->sa_family) { -#ifdef INET - case AF_INET: - /* - * Remember the IP options, if any. - */ - ipopts = ip_srcroute(); - break; -#endif - default: - ipopts = NULL; - } - +#ifdef TCP_SIGNATURE + if (optp || (tp->t_flags & TF_SIGNATURE)) { +#else if (optp) { +#endif tb.t_inpcb = tp->t_inpcb; /* XXX */ tb.pf = tp->pf; #ifdef TCP_SACK tb.sack_disable = tcp_do_sack ? 0 : 1; #endif tb.t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0; +#ifdef TCP_SIGNATURE + if (tp->t_flags & TF_SIGNATURE) + tb.t_flags |= TF_SIGNATURE; +#endif + if (tcp_dooptions(&tb, optp, optlen, th, m, iphlen, oi)) return (0); - /* Update t_maxopd and t_maxseg after all options are processed */ - (void) tcp_mss(tp, oi->maxseg); /* sets t_maxseg */ - if (oi->maxseg) - tcp_mss_update(tp); - + if (optp) { + /* Update t_maxopd and t_maxseg after all options are processed */ + (void) tcp_mss(tp, oi->maxseg); /* sets t_maxseg */ + if (oi->maxseg) + tcp_mss_update(tp); + } } else tb.t_flags = 0; + switch (src->sa_family) { +#ifdef INET + case AF_INET: + /* + * Remember the IP options, if any. + */ + ipopts = ip_srcroute(); + break; +#endif + default: + ipopts = NULL; + } + /* * See if we already have an entry for this connection. * If we do, resend the SYN,ACK. We do not count this @@ -4044,6 +4070,10 @@ syn_cache_add(src, dst, th, iphlen, so, m, optp, optlen, oi) */ if (!tb.sack_disable && (tb.t_flags & TF_SACK_PERMIT)) sc->sc_flags |= SCF_SACK_PERMIT; +#endif +#ifdef TCP_SIGNATURE + if (tb.t_flags & TF_SIGNATURE) + sc->sc_flags |= SCF_SIGNATURE; #endif sc->sc_tp = tp; if (syn_cache_respond(sc, m) == 0) { @@ -4095,6 +4125,9 @@ syn_cache_respond(sc, m) optlen = 4 + (sc->sc_request_r_scale != 15 ? 4 : 0) + #ifdef TCP_SACK ((sc->sc_flags & SCF_SACK_PERMIT) ? 4 : 0) + +#endif +#ifdef TCP_SIGNATURE + ((sc->sc_flags & SCF_SIGNATURE) ? TCPOLEN_SIGNATURE + 2 : 0) + #endif ((sc->sc_flags & SCF_TIMESTAMP) ? TCPOLEN_TSTAMP_APPA : 0); @@ -4197,8 +4230,95 @@ syn_cache_respond(sc, m) } #ifdef TCP_SIGNATURE - /* XXX */ -#endif + if (sc->sc_flags & SCF_SIGNATURE) { + MD5_CTX ctx; + union sockaddr_union sa; + struct tdb *tdb; + + bzero(&sa, sizeof(union sockaddr_union)); + sa.sa.sa_len = sc->sc_dst.sa.sa_len; + sa.sa.sa_family = sc->sc_dst.sa.sa_family; + + switch (sc->sc_src.sa.sa_family) { + case 0: /*default to PF_INET*/ +#ifdef INET + case AF_INET: + sa.sin.sin_addr = mtod(m, struct ip *)->ip_dst; + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + sa.sin6.sin6_addr = mtod(m, struct ip6_hdr *)->ip6_dst; + break; +#endif /* INET6 */ + } + + tdb = gettdb(0, &sa, IPPROTO_TCP); + if (tdb == NULL) { + if (m) + m_freem(m); + return (EPERM); + } + + MD5Init(&ctx); + + switch (sc->sc_src.sa.sa_family) { + case 0: /*default to PF_INET*/ +#ifdef INET + case AF_INET: + { + struct ippseudo ippseudo; + + ippseudo.ippseudo_src = ip->ip_src; + ippseudo.ippseudo_dst = ip->ip_dst; + ippseudo.ippseudo_pad = 0; + ippseudo.ippseudo_p = IPPROTO_TCP; + ippseudo.ippseudo_len = htons(tlen - hlen); + + MD5Update(&ctx, (char *)&ippseudo, + sizeof(struct ippseudo)); + + } + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + { + struct ip6_hdr_pseudo ip6pseudo; + + bzero(&ip6pseudo, sizeof(ip6pseudo)); + ip6pseudo.ip6ph_src = ip6->ip6_src; + ip6pseudo.ip6ph_dst = ip6->ip6_dst; + in6_clearscope(&ip6pseudo.ip6ph_src); + in6_clearscope(&ip6pseudo.ip6ph_dst); + ip6pseudo.ip6ph_nxt = IPPROTO_TCP; + ip6pseudo.ip6ph_len = htonl(tlen - hlen); + + MD5Update(&ctx, (char *)&ip6pseudo, + sizeof(ip6pseudo)); + } + break; +#endif /* INET6 */ + } + + th->th_sum = 0; + MD5Update(&ctx, (char *)th, sizeof(struct tcphdr)); + MD5Update(&ctx, tdb->tdb_amxkey, tdb->tdb_amxkeylen); + + /* Send signature option */ + *(optp++) = TCPOPT_SIGNATURE; + *(optp++) = TCPOLEN_SIGNATURE; + + MD5Final(optp, &ctx); + optp += 16; + + /* Pad options list to the next 32 bit boundary and + * terminate it. + */ + *optp++ = TCPOPT_NOP; + *optp++ = TCPOPT_EOL; + } +#endif /* TCP_SIGNATURE */ /* Compute the packet's checksum. */ switch (sc->sc_src.sa.sa_family) { diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index 1c0b34a3902..2e912c25c5b 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_output.c,v 1.59 2003/12/10 07:22:43 itojun Exp $ */ +/* $OpenBSD: tcp_output.c,v 1.60 2004/01/14 13:38:21 markus Exp $ */ /* $NetBSD: tcp_output.c,v 1.16 1997/06/03 16:17:09 kml Exp $ */ /* @@ -100,6 +100,7 @@ #ifdef INET6 #include +#include #endif /* INET6 */ #ifdef TCP_SIGNATURE @@ -934,31 +935,46 @@ send: ippseudo.ippseudo_dst = ipovly->ih_dst; ippseudo.ippseudo_pad = 0; ippseudo.ippseudo_p = IPPROTO_TCP; - ippseudo.ippseudo_len = ipovly->ih_len + len + + ippseudo.ippseudo_len = ntohs(ipovly->ih_len) + len + optlen; + ippseudo.ippseudo_len = htons(ippseudo.ippseudo_len); MD5Update(&ctx, (char *)&ippseudo, sizeof(struct ippseudo)); - MD5Update(&ctx, mtod(m, caddr_t) + - sizeof(struct ip), - sizeof(struct tcphdr)); } 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; - } + struct ip6_hdr_pseudo ip6pseudo; + struct ip6_hdr *ip6; + + ip6 = mtod(m, struct ip6_hdr *); + bzero(&ip6pseudo, sizeof(ip6pseudo)); + ip6pseudo.ip6ph_src = ip6->ip6_src; + ip6pseudo.ip6ph_dst = ip6->ip6_dst; + in6_clearscope(&ip6pseudo.ip6ph_src); + in6_clearscope(&ip6pseudo.ip6ph_dst); + ip6pseudo.ip6ph_nxt = IPPROTO_TCP; + ip6pseudo.ip6ph_len = + htonl(sizeof(struct tcphdr) + len + optlen); + + MD5Update(&ctx, (char *)&ip6pseudo, + sizeof(ip6pseudo)); } break; #endif /* INET6 */ } + { + u_int16_t thsum = th->th_sum; + + /* RFC 2385 requires th_sum == 0 */ + th->th_sum = 0; + MD5Update(&ctx, (char *)th, sizeof(struct tcphdr)); + th->th_sum = thsum; + } + if (len && m_apply(m, hdrlen, len, tcp_signature_apply, (caddr_t)&ctx)) return (EINVAL); diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index 406adbc5604..22a448336eb 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_var.h,v 1.54 2004/01/13 13:26:14 markus Exp $ */ +/* $OpenBSD: tcp_var.h,v 1.55 2004/01/14 13:38:21 markus Exp $ */ /* $NetBSD: tcp_var.h,v 1.17 1996/02/13 23:44:24 christos Exp $ */ /* @@ -268,6 +268,7 @@ struct syn_cache { #define SCF_DEAD 0x0004 /* this entry to be released */ #define SCF_SACK_PERMIT 0x0008 /* permit sack */ #define SCF_ECN_PERMIT 0x0010 /* permit ecn */ +#define SCF_SIGNATURE 0x0020 /* enforce tcp signatures */ struct mbuf *sc_ipopts; /* IP options */ u_int16_t sc_peermaxseg; -- cgit v1.2.3