[NETNS][IPV6] ip6_fib - make it per network namespace
[pandora-kernel.git] / net / ipv6 / tcp_ipv6.c
index 12750f2..fd773ac 100644 (file)
@@ -455,8 +455,7 @@ out:
 }
 
 
-static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
-                             struct dst_entry *dst)
+static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req)
 {
        struct inet6_request_sock *treq = inet6_rsk(req);
        struct ipv6_pinfo *np = inet6_sk(sk);
@@ -464,6 +463,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
        struct ipv6_txoptions *opt = NULL;
        struct in6_addr * final_p = NULL, final;
        struct flowi fl;
+       struct dst_entry *dst;
        int err = -1;
 
        memset(&fl, 0, sizeof(fl));
@@ -476,24 +476,22 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
        fl.fl_ip_sport = inet_sk(sk)->sport;
        security_req_classify_flow(req, &fl);
 
-       if (dst == NULL) {
-               opt = np->opt;
-               if (opt && opt->srcrt) {
-                       struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
-                       ipv6_addr_copy(&final, &fl.fl6_dst);
-                       ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
-                       final_p = &final;
-               }
-
-               err = ip6_dst_lookup(sk, &dst, &fl);
-               if (err)
-                       goto done;
-               if (final_p)
-                       ipv6_addr_copy(&fl.fl6_dst, final_p);
-               if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
-                       goto done;
+       opt = np->opt;
+       if (opt && opt->srcrt) {
+               struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
+               ipv6_addr_copy(&final, &fl.fl6_dst);
+               ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
+               final_p = &final;
        }
 
+       err = ip6_dst_lookup(sk, &dst, &fl);
+       if (err)
+               goto done;
+       if (final_p)
+               ipv6_addr_copy(&fl.fl6_dst, final_p);
+       if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+               goto done;
+
        skb = tcp_make_synack(sk, dst, req);
        if (skb) {
                struct tcphdr *th = tcp_hdr(skb);
@@ -514,6 +512,20 @@ done:
        return err;
 }
 
+static inline void syn_flood_warning(struct sk_buff *skb)
+{
+#ifdef CONFIG_SYN_COOKIES
+       if (sysctl_tcp_syncookies)
+               printk(KERN_INFO
+                      "TCPv6: Possible SYN flooding on port %d. "
+                      "Sending cookies.\n", ntohs(tcp_hdr(skb)->dest));
+       else
+#endif
+               printk(KERN_INFO
+                      "TCPv6: Possible SYN flooding on port %d. "
+                      "Dropping request.\n", ntohs(tcp_hdr(skb)->dest));
+}
+
 static void tcp_v6_reqsk_destructor(struct request_sock *req)
 {
        if (inet6_rsk(req)->pktopts)
@@ -917,7 +929,7 @@ done_opts:
 }
 #endif
 
-static struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
+struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
        .family         =       AF_INET6,
        .obj_size       =       sizeof(struct tcp6_request_sock),
        .rtx_syn_ack    =       tcp_v6_send_synack,
@@ -1215,9 +1227,9 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
                return NULL;
        }
 
-#if 0 /*def CONFIG_SYN_COOKIES*/
+#ifdef CONFIG_SYN_COOKIES
        if (!th->rst && !th->syn && th->ack)
-               sk = cookie_v6_check(sk, skb, &(IPCB(skb)->opt));
+               sk = cookie_v6_check(sk, skb);
 #endif
        return sk;
 }
@@ -1233,6 +1245,11 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        struct tcp_sock *tp = tcp_sk(sk);
        struct request_sock *req = NULL;
        __u32 isn = TCP_SKB_CB(skb)->when;
+#ifdef CONFIG_SYN_COOKIES
+       int want_cookie = 0;
+#else
+#define want_cookie 0
+#endif
 
        if (skb->protocol == htons(ETH_P_IP))
                return tcp_v4_conn_request(sk, skb);
@@ -1240,12 +1257,14 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        if (!ipv6_unicast_destination(skb))
                goto drop;
 
-       /*
-        *      There are no SYN attacks on IPv6, yet...
-        */
        if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
                if (net_ratelimit())
-                       printk(KERN_INFO "TCPv6: dropping request, synflood is possible\n");
+                       syn_flood_warning(skb);
+#ifdef CONFIG_SYN_COOKIES
+               if (sysctl_tcp_syncookies)
+                       want_cookie = 1;
+               else
+#endif
                goto drop;
        }
 
@@ -1266,39 +1285,51 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 
        tcp_parse_options(skb, &tmp_opt, 0);
 
+       if (want_cookie) {
+               tcp_clear_options(&tmp_opt);
+               tmp_opt.saw_tstamp = 0;
+       }
+
        tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
        tcp_openreq_init(req, &tmp_opt, skb);
 
        treq = inet6_rsk(req);
        ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr);
        ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr);
-       TCP_ECN_create_request(req, tcp_hdr(skb));
        treq->pktopts = NULL;
-       if (ipv6_opt_accepted(sk, skb) ||
-           np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
-           np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
-               atomic_inc(&skb->users);
-               treq->pktopts = skb;
-       }
-       treq->iif = sk->sk_bound_dev_if;
+       if (!want_cookie)
+               TCP_ECN_create_request(req, tcp_hdr(skb));
+
+       if (want_cookie) {
+               isn = cookie_v6_init_sequence(sk, skb, &req->mss);
+       } else if (!isn) {
+               if (ipv6_opt_accepted(sk, skb) ||
+                   np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
+                   np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
+                       atomic_inc(&skb->users);
+                       treq->pktopts = skb;
+               }
+               treq->iif = sk->sk_bound_dev_if;
 
-       /* So that link locals have meaning */
-       if (!sk->sk_bound_dev_if &&
-           ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
-               treq->iif = inet6_iif(skb);
+               /* So that link locals have meaning */
+               if (!sk->sk_bound_dev_if &&
+                   ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
+                       treq->iif = inet6_iif(skb);
 
-       if (isn == 0)
                isn = tcp_v6_init_sequence(skb);
+       }
 
        tcp_rsk(req)->snt_isn = isn;
 
        security_inet_conn_request(sk, skb, req);
 
-       if (tcp_v6_send_synack(sk, req, NULL))
+       if (tcp_v6_send_synack(sk, req))
                goto drop;
 
-       inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
-       return 0;
+       if (!want_cookie) {
+               inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
+               return 0;
+       }
 
 drop:
        if (req)