Patchwork [RFC,3/4] netfilter: Add support for failopen in nf_queue()

login
register
mail settings
Submitter Krishna Kumar
Date May 7, 2012, 6:04 a.m.
Message ID <20120507060411.19528.45006.sendpatchset@localhost.localdomain>
Download mbox | patch
Permalink /patch/157225/
State Superseded
Headers show

Comments

Krishna Kumar - May 7, 2012, 6:04 a.m.
Pass FAILOPEN flags, add support for fail-open, add support for
GSO skb. If __nf_queue() returns >0 to indicate fail-open, we
call okfn() immediately and return 0 to caller.

Signed-off-by: Krishna Kumar <krkumar2@in.ibm.com>
---
 net/netfilter/core.c         |    4 ++
 net/netfilter/nf_internals.h |    3 +-
 net/netfilter/nf_queue.c     |   47 ++++++++++++++++++++++++---------
 3 files changed, 40 insertions(+), 14 deletions(-)


--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff -ruNp org/net/netfilter/core.c new/net/netfilter/core.c
--- org/net/netfilter/core.c	2012-05-07 09:20:53.828751916 +0530
+++ new/net/netfilter/core.c	2012-05-07 09:20:53.868813999 +0530
@@ -192,7 +192,9 @@  next_hook:
 			ret = -EPERM;
 	} else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
 		int err = nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
-						verdict >> NF_VERDICT_QBITS);
+				   verdict >> NF_VERDICT_QBITS,
+				   verdict & NF_VERDICT_FLAG_FAIL_OPEN);
+
 		if (err < 0) {
 			if (err == -ECANCELED)
 				goto next_hook;
diff -ruNp org/net/netfilter/nf_internals.h new/net/netfilter/nf_internals.h
--- org/net/netfilter/nf_internals.h	2012-05-07 09:20:53.827751461 +0530
+++ new/net/netfilter/nf_internals.h	2012-05-07 09:20:53.867814083 +0530
@@ -29,7 +29,8 @@  extern int nf_queue(struct sk_buff *skb,
 		    struct net_device *indev,
 		    struct net_device *outdev,
 		    int (*okfn)(struct sk_buff *),
-		    unsigned int queuenum);
+		    unsigned int queuenum,
+		    int flags);
 extern int __init netfilter_queue_init(void);
 
 /* nf_log.c */
diff -ruNp org/net/netfilter/nf_queue.c new/net/netfilter/nf_queue.c
--- org/net/netfilter/nf_queue.c	2012-05-07 10:15:51.882590018 +0530
+++ new/net/netfilter/nf_queue.c	2012-05-07 09:20:53.866762950 +0530
@@ -123,7 +123,8 @@  static int __nf_queue(struct sk_buff *sk
 		      struct net_device *indev,
 		      struct net_device *outdev,
 		      int (*okfn)(struct sk_buff *),
-		      unsigned int queuenum)
+		      unsigned int queuenum,
+		      int flags)
 {
 	int status = -ENOENT;
 	struct nf_queue_entry *entry = NULL;
@@ -185,11 +186,11 @@  static int __nf_queue(struct sk_buff *sk
 #endif
 	skb_dst_force(skb);
 	afinfo->saveroute(skb, entry);
-	status = qh->outfn(entry, queuenum, 0);
+	status = qh->outfn(entry, queuenum, flags);
 
 	rcu_read_unlock();
 
-	if (status < 0) {
+	if (status) {
 		nf_queue_entry_release_refs(entry);
 		goto err;
 	}
@@ -230,15 +231,25 @@  int nf_queue(struct sk_buff *skb,
 	     struct net_device *indev,
 	     struct net_device *outdev,
 	     int (*okfn)(struct sk_buff *),
-	     unsigned int queuenum)
+	     unsigned int queuenum,
+	     int flags)
 {
 	struct sk_buff *segs;
 	int err = -EINVAL;
 	unsigned int queued;
 
-	if (!skb_is_gso(skb))
-		return __nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
-				  queuenum);
+	if (!skb_is_gso(skb)) {
+		err = __nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
+				  queuenum, flags);
+		if (err > 0) {
+			/* Queue failed due to queue-full and handler
+			 * returned >0 indicating fail-open - temporarily
+			 * accept packets.
+			 */
+			err = okfn(skb);
+		}
+		return err;
+	}
 
 	switch (pf) {
 	case NFPROTO_IPV4:
@@ -266,16 +277,28 @@  int nf_queue(struct sk_buff *skb,
 		if (err == 0) {
 			nf_bridge_adjust_segmented_data(segs);
 			err = __nf_queue(segs, elem, pf, hook, indev,
-					   outdev, okfn, queuenum);
+					 outdev, okfn, queuenum, flags);
 		}
-		if (err == 0)
+
+		if (err == 0) {
 			queued++;
-		else
+		} else if (err > 0) {
+			/* Queue failed due to queue-full and handler
+			 * returned >0 indicating fail-open - accept
+			 * this and remaining segments.
+			 */
+			okfn(segs);
+		} else {
+			/* Queue failed due to queue-full and handler
+			 * returned <0 - free this and remaining skb
+			 * segments.
+			 */
 			kfree_skb(segs);
+		}
 		segs = nskb;
 	} while (segs);
 
-	if (queued) {
+	if (queued || err > 0) {
 		kfree_skb(skb);
 		return 0;
 	}
@@ -325,7 +348,7 @@  void nf_reinject(struct nf_queue_entry *
 	case NF_QUEUE:
 		err = __nf_queue(skb, elem, entry->pf, entry->hook,
 				 entry->indev, entry->outdev, entry->okfn,
-				 verdict >> NF_VERDICT_QBITS);
+				 verdict >> NF_VERDICT_QBITS, 0);
 		if (err < 0) {
 			if (err == -ECANCELED)
 				goto next_hook;