aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2011-01-18 10:08:30 -0500
committerPatrick McHardy <kaber@trash.net>2011-01-18 10:08:30 -0500
commit94b27cc36123069966616670c3653cd6873babe9 (patch)
treeb3a70cab28cbc021532d2a73cac6aae5e015d8ac /net
parentf615df76ed862b7d3927ec5f55b805ca19be29d9 (diff)
netfilter: allow NFQUEUE bypass if no listener is available
If an skb is to be NF_QUEUE'd, but no program has opened the queue, the packet is dropped. This adds a v2 target revision of xt_NFQUEUE that allows packets to continue through the ruleset instead. Because the actual queueing happens outside of the target context, the 'bypass' flag has to be communicated back to the netfilter core. Unfortunately the only choice to do this without adding a new function argument is to use the target function return value (i.e. the verdict). In the NF_QUEUE case, the upper 16bit already contain the queue number to use. The previous patch reduced NF_VERDICT_MASK to 0xff, i.e. we now have extra room for a new flag. If a hook issued a NF_QUEUE verdict, then the netfilter core will continue packet processing if the queueing hook returns -ESRCH (== "this queue does not exist") and the new NF_VERDICT_FLAG_QUEUE_BYPASS flag is set in the verdict value. Note: If the queue exists, but userspace does not consume packets fast enough, the skb will still be dropped. Signed-off-by: Florian Westphal <fwestphal@astaro.com> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/core.c3
-rw-r--r--net/netfilter/nf_queue.c7
-rw-r--r--net/netfilter/xt_NFQUEUE.c28
3 files changed, 34 insertions, 4 deletions
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 4d88e45b978e..1e00bf7d27c5 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -184,6 +184,9 @@ next_hook:
184 if (ret < 0) { 184 if (ret < 0) {
185 if (ret == -ECANCELED) 185 if (ret == -ECANCELED)
186 goto next_hook; 186 goto next_hook;
187 if (ret == -ESRCH &&
188 (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS))
189 goto next_hook;
187 kfree_skb(skb); 190 kfree_skb(skb);
188 } 191 }
189 ret = 0; 192 ret = 0;
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index ce1150d4a3f2..5ab22e2bbd7d 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -138,8 +138,10 @@ static int __nf_queue(struct sk_buff *skb,
138 rcu_read_lock(); 138 rcu_read_lock();
139 139
140 qh = rcu_dereference(queue_handler[pf]); 140 qh = rcu_dereference(queue_handler[pf]);
141 if (!qh) 141 if (!qh) {
142 status = -ESRCH;
142 goto err_unlock; 143 goto err_unlock;
144 }
143 145
144 afinfo = nf_get_afinfo(pf); 146 afinfo = nf_get_afinfo(pf);
145 if (!afinfo) 147 if (!afinfo)
@@ -303,6 +305,9 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
303 if (err < 0) { 305 if (err < 0) {
304 if (err == -ECANCELED) 306 if (err == -ECANCELED)
305 goto next_hook; 307 goto next_hook;
308 if (err == -ESRCH &&
309 (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS))
310 goto next_hook;
306 kfree_skb(skb); 311 kfree_skb(skb);
307 } 312 }
308 break; 313 break;
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c
index 39627706aac6..d4f4b5d66b20 100644
--- a/net/netfilter/xt_NFQUEUE.c
+++ b/net/netfilter/xt_NFQUEUE.c
@@ -83,9 +83,20 @@ nfqueue_tg_v1(struct sk_buff *skb, const struct xt_action_param *par)
83 return NF_QUEUE_NR(queue); 83 return NF_QUEUE_NR(queue);
84} 84}
85 85
86static int nfqueue_tg_v1_check(const struct xt_tgchk_param *par) 86static unsigned int
87nfqueue_tg_v2(struct sk_buff *skb, const struct xt_action_param *par)
87{ 88{
88 const struct xt_NFQ_info_v1 *info = par->targinfo; 89 const struct xt_NFQ_info_v2 *info = par->targinfo;
90 unsigned int ret = nfqueue_tg_v1(skb, par);
91
92 if (info->bypass)
93 ret |= NF_VERDICT_FLAG_QUEUE_BYPASS;
94 return ret;
95}
96
97static int nfqueue_tg_check(const struct xt_tgchk_param *par)
98{
99 const struct xt_NFQ_info_v2 *info = par->targinfo;
89 u32 maxid; 100 u32 maxid;
90 101
91 if (unlikely(!rnd_inited)) { 102 if (unlikely(!rnd_inited)) {
@@ -102,6 +113,8 @@ static int nfqueue_tg_v1_check(const struct xt_tgchk_param *par)
102 info->queues_total, maxid); 113 info->queues_total, maxid);
103 return -ERANGE; 114 return -ERANGE;
104 } 115 }
116 if (par->target->revision == 2 && info->bypass > 1)
117 return -EINVAL;
105 return 0; 118 return 0;
106} 119}
107 120
@@ -117,11 +130,20 @@ static struct xt_target nfqueue_tg_reg[] __read_mostly = {
117 .name = "NFQUEUE", 130 .name = "NFQUEUE",
118 .revision = 1, 131 .revision = 1,
119 .family = NFPROTO_UNSPEC, 132 .family = NFPROTO_UNSPEC,
120 .checkentry = nfqueue_tg_v1_check, 133 .checkentry = nfqueue_tg_check,
121 .target = nfqueue_tg_v1, 134 .target = nfqueue_tg_v1,
122 .targetsize = sizeof(struct xt_NFQ_info_v1), 135 .targetsize = sizeof(struct xt_NFQ_info_v1),
123 .me = THIS_MODULE, 136 .me = THIS_MODULE,
124 }, 137 },
138 {
139 .name = "NFQUEUE",
140 .revision = 2,
141 .family = NFPROTO_UNSPEC,
142 .checkentry = nfqueue_tg_check,
143 .target = nfqueue_tg_v2,
144 .targetsize = sizeof(struct xt_NFQ_info_v2),
145 .me = THIS_MODULE,
146 },
125}; 147};
126 148
127static int __init nfqueue_tg_init(void) 149static int __init nfqueue_tg_init(void)