netfilter: SYNPROXY: Return NF_STOLEN instead of NF_DROP during handshaking
authorGao Feng <fgao@ikuai8.com>
Thu, 20 Apr 2017 06:01:45 +0000 (14:01 +0800)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 26 Apr 2017 07:30:22 +0000 (09:30 +0200)
Current SYNPROXY codes return NF_DROP during normal TCP handshaking,
it is not friendly to caller. Because the nf_hook_slow would treat
the NF_DROP as an error, and return -EPERM.
As a result, it may cause the top caller think it meets one error.

For example, the following codes are from cfv_rx_poll()
err = netif_receive_skb(skb);
if (unlikely(err)) {
++cfv->ndev->stats.rx_dropped;
} else {
++cfv->ndev->stats.rx_packets;
cfv->ndev->stats.rx_bytes += skb_len;
}
When SYNPROXY returns NF_DROP, then netif_receive_skb returns -EPERM.
As a result, the cfv driver would treat it as an error, and increase
the rx_dropped counter.

So use NF_STOLEN instead of NF_DROP now because there is no error
happened indeed, and free the skb directly.

Signed-off-by: Gao Feng <fgao@ikuai8.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/ipv4/netfilter/ipt_SYNPROXY.c
net/ipv6/netfilter/ip6t_SYNPROXY.c

index c308ee0ee0bcf7b5e96aa80df69ac6066bc0ee60..af2b69b6895f5ae8e326b27e05efa01cc1405e1b 100644 (file)
@@ -293,12 +293,16 @@ synproxy_tg4(struct sk_buff *skb, const struct xt_action_param *par)
                                          XT_SYNPROXY_OPT_ECN);
 
                synproxy_send_client_synack(net, skb, th, &opts);
-               return NF_DROP;
-
+               consume_skb(skb);
+               return NF_STOLEN;
        } else if (th->ack && !(th->fin || th->rst || th->syn)) {
                /* ACK from client */
-               synproxy_recv_client_ack(net, skb, th, &opts, ntohl(th->seq));
-               return NF_DROP;
+               if (synproxy_recv_client_ack(net, skb, th, &opts, ntohl(th->seq))) {
+                       consume_skb(skb);
+                       return NF_STOLEN;
+               } else {
+                       return NF_DROP;
+               }
        }
 
        return XT_CONTINUE;
@@ -367,10 +371,13 @@ static unsigned int ipv4_synproxy_hook(void *priv,
                         * number match the one of first SYN.
                         */
                        if (synproxy_recv_client_ack(net, skb, th, &opts,
-                                                    ntohl(th->seq) + 1))
+                                                    ntohl(th->seq) + 1)) {
                                this_cpu_inc(snet->stats->cookie_retrans);
-
-                       return NF_DROP;
+                               consume_skb(skb);
+                               return NF_STOLEN;
+                       } else {
+                               return NF_DROP;
+                       }
                }
 
                synproxy->isn = ntohl(th->ack_seq);
index 1252537f215ff5e670acb6bab3d7b756a6a1d980..d3c4daa708b9014378f5cdec4b0cc811f9999d92 100644 (file)
@@ -307,12 +307,17 @@ synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par)
                                          XT_SYNPROXY_OPT_ECN);
 
                synproxy_send_client_synack(net, skb, th, &opts);
-               return NF_DROP;
+               consume_skb(skb);
+               return NF_STOLEN;
 
        } else if (th->ack && !(th->fin || th->rst || th->syn)) {
                /* ACK from client */
-               synproxy_recv_client_ack(net, skb, th, &opts, ntohl(th->seq));
-               return NF_DROP;
+               if (synproxy_recv_client_ack(net, skb, th, &opts, ntohl(th->seq))) {
+                       consume_skb(skb);
+                       return NF_STOLEN;
+               } else {
+                       return NF_DROP;
+               }
        }
 
        return XT_CONTINUE;
@@ -388,10 +393,13 @@ static unsigned int ipv6_synproxy_hook(void *priv,
                         * number match the one of first SYN.
                         */
                        if (synproxy_recv_client_ack(net, skb, th, &opts,
-                                                    ntohl(th->seq) + 1))
+                                                    ntohl(th->seq) + 1)) {
                                this_cpu_inc(snet->stats->cookie_retrans);
-
-                       return NF_DROP;
+                               consume_skb(skb);
+                               return NF_STOLEN;
+                       } else {
+                               return NF_DROP;
+                       }
                }
 
                synproxy->isn = ntohl(th->ack_seq);