summaryrefslogtreecommitdiff
path: root/sys/netinet/tcp_input.c
diff options
context:
space:
mode:
authorcmetz <cmetz@cvs.openbsd.org>1999-07-06 20:17:54 +0000
committercmetz <cmetz@cvs.openbsd.org>1999-07-06 20:17:54 +0000
commitb572bd87e759146844b72e7a327306a471ae69c7 (patch)
tree3e21a6f1fca265ba2767f46b76bfd8d2182243b9 /sys/netinet/tcp_input.c
parent1b325370253fe0a5d55ea7f66f9477a75800daaf (diff)
Added support for TCP MD5 option (RFC 2385).
Diffstat (limited to 'sys/netinet/tcp_input.c')
-rw-r--r--sys/netinet/tcp_input.c166
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)