TCPCT part 1g: Responder Cookie => Initiator
[linux-2.6.git] / net / ipv6 / tcp_ipv6.c
index f2ec382..fc0a4e5 100644 (file)
@@ -1162,7 +1162,9 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
  */
 static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 {
+       struct tcp_extend_values tmp_ext;
        struct tcp_options_received tmp_opt;
+       u8 *hash_location;
        struct request_sock *req;
        struct inet6_request_sock *treq;
        struct ipv6_pinfo *np = inet6_sk(sk);
@@ -1206,8 +1208,52 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        tcp_clear_options(&tmp_opt);
        tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
        tmp_opt.user_mss = tp->rx_opt.user_mss;
+       tcp_parse_options(skb, &tmp_opt, &hash_location, 0, dst);
+
+       if (tmp_opt.cookie_plus > 0 &&
+           tmp_opt.saw_tstamp &&
+           !tp->rx_opt.cookie_out_never &&
+           (sysctl_tcp_cookie_size > 0 ||
+            (tp->cookie_values != NULL &&
+             tp->cookie_values->cookie_desired > 0))) {
+               u8 *c;
+               u32 *d;
+               u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS];
+               int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE;
+
+               if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0)
+                       goto drop_and_free;
+
+               /* Secret recipe starts with IP addresses */
+               d = &ipv6_hdr(skb)->daddr.s6_addr32[0];
+               *mess++ ^= *d++;
+               *mess++ ^= *d++;
+               *mess++ ^= *d++;
+               *mess++ ^= *d++;
+               d = &ipv6_hdr(skb)->saddr.s6_addr32[0];
+               *mess++ ^= *d++;
+               *mess++ ^= *d++;
+               *mess++ ^= *d++;
+               *mess++ ^= *d++;
+
+               /* plus variable length Initiator Cookie */
+               c = (u8 *)mess;
+               while (l-- > 0)
+                       *c++ ^= *hash_location++;
 
-       tcp_parse_options(skb, &tmp_opt, 0, dst);
+#ifdef CONFIG_SYN_COOKIES
+               want_cookie = 0;        /* not our kind of cookie */
+#endif
+               tmp_ext.cookie_out_never = 0; /* false */
+               tmp_ext.cookie_plus = tmp_opt.cookie_plus;
+       } else if (!tp->rx_opt.cookie_in_always) {
+               /* redundant indications, but ensure initialization. */
+               tmp_ext.cookie_out_never = 1; /* true */
+               tmp_ext.cookie_plus = 0;
+       } else {
+               goto drop_and_free;
+       }
+       tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always;
 
        if (want_cookie && !tmp_opt.saw_tstamp)
                tcp_clear_options(&tmp_opt);
@@ -1244,7 +1290,9 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 
        security_inet_conn_request(sk, skb, req);
 
-       if (tcp_v6_send_synack(sk, req, NULL) || want_cookie)
+       if (tcp_v6_send_synack(sk, req,
+                              (struct request_values *)&tmp_ext) ||
+           want_cookie)
                goto drop_and_free;
 
        inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);