From 969860f3edecccbc04bec207ad3f83989cae112a Mon Sep 17 00:00:00 2001 From: David Malone Date: Sat, 17 Jul 2004 19:44:13 +0000 Subject: [PATCH] The tcp syncache code was leaving the IPv6 flowlabel uninitialised for the SYN|ACK packet and then letting in6_pcbconnect set the flowlabel later. Arange for the syncache/syncookie code to set and recall the flow label so that the flowlabel used for the SYN|ACK is consistent. This is done by using some of the cookie (when tcp cookies are enabeled) and by stashing the flowlabel in syncache. Tested and Discovered by: Orla McGann Approved by: ume, silby MFC after: 1 month --- sys/netinet/tcp_syncache.c | 37 +++++++++++++++++++++++++++++++------ sys/netinet/tcp_var.h | 1 + 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c index dbbfbb1d4d44..9947d534807f 100644 --- a/sys/netinet/tcp_syncache.c +++ b/sys/netinet/tcp_syncache.c @@ -38,6 +38,7 @@ #include "opt_inet6.h" #include "opt_ipsec.h" #include "opt_mac.h" +#include "opt_random_ip_id.h" #include "opt_tcpdebug.h" #include "opt_tcp_sack.h" @@ -120,7 +121,7 @@ static int syncache_respond(struct syncache *, struct mbuf *); static struct socket *syncache_socket(struct syncache *, struct socket *, struct mbuf *m); static void syncache_timer(void *); -static u_int32_t syncookie_generate(struct syncache *); +static u_int32_t syncookie_generate(struct syncache *, u_int32_t *); static struct syncache *syncookie_lookup(struct in_conninfo *, struct tcphdr *, struct socket *); @@ -640,6 +641,9 @@ syncache_socket(sc, lso, m) inp->in6p_laddr = laddr6; goto abort; } + /* Override flowlabel from in6_pcbconnect. */ + inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; + inp->in6p_flowinfo |= sc->sc_flowlabel; } else #endif { @@ -829,6 +833,7 @@ syncache_add(inc, to, th, sop, m) struct syncache_head *sch; struct mbuf *ipopts = NULL; struct rmxp_tao tao; + u_int32_t flowtmp; int i, win; INP_INFO_WLOCK_ASSERT(&tcbinfo); @@ -938,10 +943,25 @@ syncache_add(inc, to, th, sop, m) sc->sc_irs = th->th_seq; sc->sc_flags = 0; sc->sc_peer_mss = to->to_flags & TOF_MSS ? to->to_mss : 0; - if (tcp_syncookies) - sc->sc_iss = syncookie_generate(sc); - else + sc->sc_flowlabel = 0; + if (tcp_syncookies) { + sc->sc_iss = syncookie_generate(sc, &flowtmp); + if (inc->inc_isipv6 && + (sc->sc_tp->t_inpcb->in6p_flags & IN6P_AUTOFLOWLABEL)) { + sc->sc_flowlabel = flowtmp & IPV6_FLOWLABEL_MASK; + } + } else { sc->sc_iss = arc4random(); + if (inc->inc_isipv6 && + (sc->sc_tp->t_inpcb->in6p_flags & IN6P_AUTOFLOWLABEL)) { + sc->sc_flowlabel = +#ifdef RANDOM_IP_ID + (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK); +#else + (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK); +#endif + } + } /* Initial receive window: clip sbspace to [0 .. TCP_MAXWIN] */ win = sbspace(&so->so_rcv); @@ -1153,7 +1173,8 @@ syncache_respond(sc, m) ip6->ip6_dst = sc->sc_inc.inc6_faddr; ip6->ip6_plen = htons(tlen - hlen); /* ip6_hlim is set after checksum */ - /* ip6_flow = ??? */ + ip6->ip6_flow &= ~IPV6_FLOWLABEL_MASK; + ip6->ip6_flow |= sc->sc_flowlabel; th = (struct tcphdr *)(ip6 + 1); } else @@ -1344,7 +1365,7 @@ CTASSERT(sizeof(struct md5_add) == 28); */ static u_int32_t -syncookie_generate(struct syncache *sc) +syncookie_generate(struct syncache *sc, u_int32_t *flowid) { u_int32_t md5_buffer[4]; u_int32_t data; @@ -1386,6 +1407,7 @@ syncookie_generate(struct syncache *sc) MD5Add(add); MD5Final((u_char *)&md5_buffer, &syn_ctx); data ^= (md5_buffer[0] & ~SYNCOOKIE_WNDMASK); + *flowid = md5_buffer[1]; return (data); } @@ -1444,11 +1466,14 @@ syncookie_lookup(inc, th, so) sc->sc_ipopts = NULL; sc->sc_inc.inc_fport = inc->inc_fport; sc->sc_inc.inc_lport = inc->inc_lport; + sc->sc_tp = sototcpcb(so); #ifdef INET6 sc->sc_inc.inc_isipv6 = inc->inc_isipv6; if (inc->inc_isipv6) { sc->sc_inc.inc6_faddr = inc->inc6_faddr; sc->sc_inc.inc6_laddr = inc->inc6_laddr; + if (sc->sc_tp->t_inpcb->in6p_flags & IN6P_AUTOFLOWLABEL) + sc->sc_flowlabel = md5_buffer[1] & IPV6_FLOWLABEL_MASK; } else #endif { diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index 5eabf38fcb8a..c8a612d66176 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -254,6 +254,7 @@ struct syncache { struct mbuf *sc_ipopts; /* source route */ struct in_conninfo sc_inc; /* addresses */ u_int32_t sc_tsrecent; + u_int32_t sc_flowlabel; /* IPv6 flowlabel */ tcp_cc sc_cc_send; /* holds CC or CCnew */ tcp_cc sc_cc_recv; tcp_seq sc_irs; /* seq from peer */