diff options
author | cmetz <cmetz@cvs.openbsd.org> | 1999-07-06 20:17:54 +0000 |
---|---|---|
committer | cmetz <cmetz@cvs.openbsd.org> | 1999-07-06 20:17:54 +0000 |
commit | b572bd87e759146844b72e7a327306a471ae69c7 (patch) | |
tree | 3e21a6f1fca265ba2767f46b76bfd8d2182243b9 /sys/netinet/tcp_input.c | |
parent | 1b325370253fe0a5d55ea7f66f9477a75800daaf (diff) |
Added support for TCP MD5 option (RFC 2385).
Diffstat (limited to 'sys/netinet/tcp_input.c')
-rw-r--r-- | sys/netinet/tcp_input.c | 166 |
1 files changed, 156 insertions, 10 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 4bc691e5928..9674066c544 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_input.c,v 1.39 1999/07/06 20:14:06 cmetz Exp $ */ +/* $OpenBSD: tcp_input.c,v 1.40 1999/07/06 20:17:52 cmetz Exp $ */ /* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */ /* @@ -758,9 +758,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) { @@ -1068,7 +1074,7 @@ findpcb: case PF_INET6: { struct sockaddr_in6 *sin6; - struct laddr6; + struct in6_addr laddr6; /* * This is probably the place to set the tp->pf @@ -1113,9 +1119,19 @@ findpcb: 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 */ + m->m_data -= iphlen + off; + m->m_len += iphlen + off; + if (tcp_dooptions(tp, optp, optlen, th, m, iphlen, + &ts_present, &ts_val, &ts_ecr)) + goto drop; + m->m_data += iphlen + off; + m->m_len -= iphlen + off; + } #ifdef TCP_SACK /* @@ -2137,17 +2153,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]; @@ -2216,12 +2237,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) |