netfilter: nf_tables: build-in filter chain type
[linux-2.6-block.git] / net / netfilter / nft_chain_filter.c
CommitLineData
02c7b25e
PNA
1#include <linux/init.h>
2#include <linux/kernel.h>
3#include <linux/netdevice.h>
4#include <net/net_namespace.h>
5#include <net/netfilter/nf_tables.h>
6#include <linux/netfilter_ipv4.h>
7#include <linux/netfilter_ipv6.h>
8#include <linux/netfilter_bridge.h>
9#include <linux/netfilter_arp.h>
10#include <net/netfilter/nf_tables_ipv4.h>
11#include <net/netfilter/nf_tables_ipv6.h>
12
13#ifdef CONFIG_NF_TABLES_IPV4
14static unsigned int nft_do_chain_ipv4(void *priv,
15 struct sk_buff *skb,
16 const struct nf_hook_state *state)
17{
18 struct nft_pktinfo pkt;
19
20 nft_set_pktinfo(&pkt, skb, state);
21 nft_set_pktinfo_ipv4(&pkt, skb);
22
23 return nft_do_chain(&pkt, priv);
24}
25
26static const struct nft_chain_type nft_chain_filter_ipv4 = {
27 .name = "filter",
28 .type = NFT_CHAIN_T_DEFAULT,
29 .family = NFPROTO_IPV4,
30 .hook_mask = (1 << NF_INET_LOCAL_IN) |
31 (1 << NF_INET_LOCAL_OUT) |
32 (1 << NF_INET_FORWARD) |
33 (1 << NF_INET_PRE_ROUTING) |
34 (1 << NF_INET_POST_ROUTING),
35 .hooks = {
36 [NF_INET_LOCAL_IN] = nft_do_chain_ipv4,
37 [NF_INET_LOCAL_OUT] = nft_do_chain_ipv4,
38 [NF_INET_FORWARD] = nft_do_chain_ipv4,
39 [NF_INET_PRE_ROUTING] = nft_do_chain_ipv4,
40 [NF_INET_POST_ROUTING] = nft_do_chain_ipv4,
41 },
42};
43
44static void nft_chain_filter_ipv4_init(void)
45{
46 nft_register_chain_type(&nft_chain_filter_ipv4);
47}
48static void nft_chain_filter_ipv4_fini(void)
49{
50 nft_unregister_chain_type(&nft_chain_filter_ipv4);
51}
52
53#else
54static inline void nft_chain_filter_ipv4_init(void) {}
55static inline void nft_chain_filter_ipv4_fini(void) {}
56#endif /* CONFIG_NF_TABLES_IPV4 */
57
58#ifdef CONFIG_NF_TABLES_ARP
59static unsigned int nft_do_chain_arp(void *priv, struct sk_buff *skb,
60 const struct nf_hook_state *state)
61{
62 struct nft_pktinfo pkt;
63
64 nft_set_pktinfo(&pkt, skb, state);
65 nft_set_pktinfo_unspec(&pkt, skb);
66
67 return nft_do_chain(&pkt, priv);
68}
69
70static const struct nft_chain_type nft_chain_filter_arp = {
71 .name = "filter",
72 .type = NFT_CHAIN_T_DEFAULT,
73 .family = NFPROTO_ARP,
74 .owner = THIS_MODULE,
75 .hook_mask = (1 << NF_ARP_IN) |
76 (1 << NF_ARP_OUT),
77 .hooks = {
78 [NF_ARP_IN] = nft_do_chain_arp,
79 [NF_ARP_OUT] = nft_do_chain_arp,
80 },
81};
82
83static void nft_chain_filter_arp_init(void)
84{
85 nft_register_chain_type(&nft_chain_filter_arp);
86}
87
88static void nft_chain_filter_arp_fini(void)
89{
90 nft_unregister_chain_type(&nft_chain_filter_arp);
91}
92#else
93static inline void nft_chain_filter_arp_init(void) {}
94static inline void nft_chain_filter_arp_fini(void) {}
95#endif /* CONFIG_NF_TABLES_ARP */
96
97#ifdef CONFIG_NF_TABLES_IPV6
98static unsigned int nft_do_chain_ipv6(void *priv,
99 struct sk_buff *skb,
100 const struct nf_hook_state *state)
101{
102 struct nft_pktinfo pkt;
103
104 nft_set_pktinfo(&pkt, skb, state);
105 nft_set_pktinfo_ipv6(&pkt, skb);
106
107 return nft_do_chain(&pkt, priv);
108}
109
110static const struct nft_chain_type nft_chain_filter_ipv6 = {
111 .name = "filter",
112 .type = NFT_CHAIN_T_DEFAULT,
113 .family = NFPROTO_IPV6,
114 .hook_mask = (1 << NF_INET_LOCAL_IN) |
115 (1 << NF_INET_LOCAL_OUT) |
116 (1 << NF_INET_FORWARD) |
117 (1 << NF_INET_PRE_ROUTING) |
118 (1 << NF_INET_POST_ROUTING),
119 .hooks = {
120 [NF_INET_LOCAL_IN] = nft_do_chain_ipv6,
121 [NF_INET_LOCAL_OUT] = nft_do_chain_ipv6,
122 [NF_INET_FORWARD] = nft_do_chain_ipv6,
123 [NF_INET_PRE_ROUTING] = nft_do_chain_ipv6,
124 [NF_INET_POST_ROUTING] = nft_do_chain_ipv6,
125 },
126};
127
128static void nft_chain_filter_ipv6_init(void)
129{
130 nft_register_chain_type(&nft_chain_filter_ipv6);
131}
132
133static void nft_chain_filter_ipv6_fini(void)
134{
135 nft_unregister_chain_type(&nft_chain_filter_ipv6);
136}
137#else
138static inline void nft_chain_filter_ipv6_init(void) {}
139static inline void nft_chain_filter_ipv6_fini(void) {}
140#endif /* CONFIG_NF_TABLES_IPV6 */
141
142#ifdef CONFIG_NF_TABLES_INET
143static unsigned int nft_do_chain_inet(void *priv, struct sk_buff *skb,
144 const struct nf_hook_state *state)
145{
146 struct nft_pktinfo pkt;
147
148 nft_set_pktinfo(&pkt, skb, state);
149
150 switch (state->pf) {
151 case NFPROTO_IPV4:
152 nft_set_pktinfo_ipv4(&pkt, skb);
153 break;
154 case NFPROTO_IPV6:
155 nft_set_pktinfo_ipv6(&pkt, skb);
156 break;
157 default:
158 break;
159 }
160
161 return nft_do_chain(&pkt, priv);
162}
163
164static const struct nft_chain_type nft_chain_filter_inet = {
165 .name = "filter",
166 .type = NFT_CHAIN_T_DEFAULT,
167 .family = NFPROTO_INET,
168 .hook_mask = (1 << NF_INET_LOCAL_IN) |
169 (1 << NF_INET_LOCAL_OUT) |
170 (1 << NF_INET_FORWARD) |
171 (1 << NF_INET_PRE_ROUTING) |
172 (1 << NF_INET_POST_ROUTING),
173 .hooks = {
174 [NF_INET_LOCAL_IN] = nft_do_chain_inet,
175 [NF_INET_LOCAL_OUT] = nft_do_chain_inet,
176 [NF_INET_FORWARD] = nft_do_chain_inet,
177 [NF_INET_PRE_ROUTING] = nft_do_chain_inet,
178 [NF_INET_POST_ROUTING] = nft_do_chain_inet,
179 },
180};
181
182static void nft_chain_filter_inet_init(void)
183{
184 nft_register_chain_type(&nft_chain_filter_inet);
185}
186
187static void nft_chain_filter_inet_fini(void)
188{
189 nft_unregister_chain_type(&nft_chain_filter_inet);
190}
191#else
192static inline void nft_chain_filter_inet_init(void) {}
193static inline void nft_chain_filter_inet_fini(void) {}
194#endif /* CONFIG_NF_TABLES_IPV6 */
195
196#ifdef CONFIG_NF_TABLES_BRIDGE
197static unsigned int
198nft_do_chain_bridge(void *priv,
199 struct sk_buff *skb,
200 const struct nf_hook_state *state)
201{
202 struct nft_pktinfo pkt;
203
204 nft_set_pktinfo(&pkt, skb, state);
205
206 switch (eth_hdr(skb)->h_proto) {
207 case htons(ETH_P_IP):
208 nft_set_pktinfo_ipv4_validate(&pkt, skb);
209 break;
210 case htons(ETH_P_IPV6):
211 nft_set_pktinfo_ipv6_validate(&pkt, skb);
212 break;
213 default:
214 nft_set_pktinfo_unspec(&pkt, skb);
215 break;
216 }
217
218 return nft_do_chain(&pkt, priv);
219}
220
221static const struct nft_chain_type nft_chain_filter_bridge = {
222 .name = "filter",
223 .type = NFT_CHAIN_T_DEFAULT,
224 .family = NFPROTO_BRIDGE,
225 .hook_mask = (1 << NF_BR_PRE_ROUTING) |
226 (1 << NF_BR_LOCAL_IN) |
227 (1 << NF_BR_FORWARD) |
228 (1 << NF_BR_LOCAL_OUT) |
229 (1 << NF_BR_POST_ROUTING),
230 .hooks = {
231 [NF_BR_PRE_ROUTING] = nft_do_chain_bridge,
232 [NF_BR_LOCAL_IN] = nft_do_chain_bridge,
233 [NF_BR_FORWARD] = nft_do_chain_bridge,
234 [NF_BR_LOCAL_OUT] = nft_do_chain_bridge,
235 [NF_BR_POST_ROUTING] = nft_do_chain_bridge,
236 },
237};
238
239static void nft_chain_filter_bridge_init(void)
240{
241 nft_register_chain_type(&nft_chain_filter_bridge);
242}
243
244static void nft_chain_filter_bridge_fini(void)
245{
246 nft_unregister_chain_type(&nft_chain_filter_bridge);
247}
248#else
249static inline void nft_chain_filter_bridge_init(void) {}
250static inline void nft_chain_filter_bridge_fini(void) {}
251#endif /* CONFIG_NF_TABLES_BRIDGE */
252
253#ifdef CONFIG_NF_TABLES_NETDEV
254static unsigned int nft_do_chain_netdev(void *priv, struct sk_buff *skb,
255 const struct nf_hook_state *state)
256{
257 struct nft_pktinfo pkt;
258
259 nft_set_pktinfo(&pkt, skb, state);
260
261 switch (skb->protocol) {
262 case htons(ETH_P_IP):
263 nft_set_pktinfo_ipv4_validate(&pkt, skb);
264 break;
265 case htons(ETH_P_IPV6):
266 nft_set_pktinfo_ipv6_validate(&pkt, skb);
267 break;
268 default:
269 nft_set_pktinfo_unspec(&pkt, skb);
270 break;
271 }
272
273 return nft_do_chain(&pkt, priv);
274}
275
276static const struct nft_chain_type nft_chain_filter_netdev = {
277 .name = "filter",
278 .type = NFT_CHAIN_T_DEFAULT,
279 .family = NFPROTO_NETDEV,
280 .hook_mask = (1 << NF_NETDEV_INGRESS),
281 .hooks = {
282 [NF_NETDEV_INGRESS] = nft_do_chain_netdev,
283 },
284};
285
286static void nft_netdev_event(unsigned long event, struct net_device *dev,
287 struct nft_ctx *ctx)
288{
289 struct nft_base_chain *basechain = nft_base_chain(ctx->chain);
290
291 switch (event) {
292 case NETDEV_UNREGISTER:
293 if (strcmp(basechain->dev_name, dev->name) != 0)
294 return;
295
296 __nft_release_basechain(ctx);
297 break;
298 case NETDEV_CHANGENAME:
299 if (dev->ifindex != basechain->ops.dev->ifindex)
300 return;
301
302 strncpy(basechain->dev_name, dev->name, IFNAMSIZ);
303 break;
304 }
305}
306
307static int nf_tables_netdev_event(struct notifier_block *this,
308 unsigned long event, void *ptr)
309{
310 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
311 struct nft_table *table;
312 struct nft_chain *chain, *nr;
313 struct nft_ctx ctx = {
314 .net = dev_net(dev),
315 };
316
317 if (event != NETDEV_UNREGISTER &&
318 event != NETDEV_CHANGENAME)
319 return NOTIFY_DONE;
320
321 nfnl_lock(NFNL_SUBSYS_NFTABLES);
322 list_for_each_entry(table, &ctx.net->nft.tables, list) {
323 if (table->family != NFPROTO_NETDEV)
324 continue;
325
326 ctx.family = table->family;
327 ctx.table = table;
328 list_for_each_entry_safe(chain, nr, &table->chains, list) {
329 if (!nft_is_base_chain(chain))
330 continue;
331
332 ctx.chain = chain;
333 nft_netdev_event(event, dev, &ctx);
334 }
335 }
336 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
337
338 return NOTIFY_DONE;
339}
340
341static struct notifier_block nf_tables_netdev_notifier = {
342 .notifier_call = nf_tables_netdev_event,
343};
344
345static int nft_chain_filter_netdev_init(void)
346{
347 int err;
348
349 nft_register_chain_type(&nft_chain_filter_netdev);
350
351 err = register_netdevice_notifier(&nf_tables_netdev_notifier);
352 if (err)
353 goto err_register_netdevice_notifier;
354
355 return 0;
356
357err_register_netdevice_notifier:
358 nft_unregister_chain_type(&nft_chain_filter_netdev);
359
360 return err;
361}
362
363static void nft_chain_filter_netdev_fini(void)
364{
365 nft_unregister_chain_type(&nft_chain_filter_netdev);
366 unregister_netdevice_notifier(&nf_tables_netdev_notifier);
367}
368#else
369static inline int nft_chain_filter_netdev_init(void) { return 0; }
370static inline void nft_chain_filter_netdev_fini(void) {}
371#endif /* CONFIG_NF_TABLES_NETDEV */
372
373int __init nft_chain_filter_init(void)
374{
375 int err;
376
377 err = nft_chain_filter_netdev_init();
378 if (err < 0)
379 return err;
380
381 nft_chain_filter_ipv4_init();
382 nft_chain_filter_ipv6_init();
383 nft_chain_filter_arp_init();
384 nft_chain_filter_inet_init();
385 nft_chain_filter_bridge_init();
386
387 return 0;
388}
389
390void __exit nft_chain_filter_fini(void)
391{
392 nft_chain_filter_bridge_fini();
393 nft_chain_filter_inet_fini();
394 nft_chain_filter_arp_fini();
395 nft_chain_filter_ipv6_fini();
396 nft_chain_filter_ipv4_fini();
397 nft_chain_filter_netdev_fini();
398}