diff options
author | dwmalone <dwmalone@FreeBSD.org> | 2004-07-17 19:44:13 +0000 |
---|---|---|
committer | dwmalone <dwmalone@FreeBSD.org> | 2004-07-17 19:44:13 +0000 |
commit | 71eccf2cf55ca05d858bd43ea8dcf26e64a94c66 (patch) | |
tree | e3253b105d7c3ba69e7b3d55d4fcea1bbdd49f7c /sys/netinet/tcp_syncache.c | |
parent | 4c16bbdae3c2b668d0d9672affa2e8749490f8ae (diff) | |
download | FreeBSD-src-71eccf2cf55ca05d858bd43ea8dcf26e64a94c66.zip FreeBSD-src-71eccf2cf55ca05d858bd43ea8dcf26e64a94c66.tar.gz |
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 <orly@cnri.dit.ie>
Approved by: ume, silby
MFC after: 1 month
Diffstat (limited to 'sys/netinet/tcp_syncache.c')
-rw-r--r-- | sys/netinet/tcp_syncache.c | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c index dbbfbb1..9947d53 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 { |