11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Filtering ARP tables module.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2002 David S. Miller (davem@redhat.com)
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
9e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt#include <linux/netfilter/x_tables.h>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netfilter_arp/arp_tables.h>
115a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("David S. Miller <davem@redhat.com>");
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("arptables filter table");
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   (1 << NF_ARP_FORWARD))
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2035aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardtstatic const struct xt_table packet_filter = {
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name		= "filter",
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.valid_hooks	= FILTER_VALID_HOOKS,
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.me		= THIS_MODULE,
24ee999d8b9573df1b547aacdc6d79f86eb79c25cdJan Engelhardt	.af		= NFPROTO_ARP,
252b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	.priority	= NF_IP_PRI_FILTER,
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The work comes in here from netfilter.c */
29737535c5cf3524e4bfaa91e22edefd52eccabbceJan Engelhardtstatic unsigned int
30795aa6ef6a1aba99050735eadd0c2341b789b53bPatrick McHardyarptable_filter_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
31737535c5cf3524e4bfaa91e22edefd52eccabbceJan Engelhardt		     const struct net_device *in, const struct net_device *out,
32737535c5cf3524e4bfaa91e22edefd52eccabbceJan Engelhardt		     int (*okfn)(struct sk_buff *))
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
342b21e051472fdb4680076278b2ccf63ebc1cc3bcJan Engelhardt	const struct net *net = dev_net((in != NULL) ? in : out);
353918fed5f31213067c1c345bd904e1ea369e6819Alexey Dobriyan
36795aa6ef6a1aba99050735eadd0c2341b789b53bPatrick McHardy	return arpt_do_table(skb, ops->hooknum, in, out,
37795aa6ef6a1aba99050735eadd0c2341b789b53bPatrick McHardy			     net->ipv4.arptable_filter);
383918fed5f31213067c1c345bd904e1ea369e6819Alexey Dobriyan}
393918fed5f31213067c1c345bd904e1ea369e6819Alexey Dobriyan
402b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardtstatic struct nf_hook_ops *arpfilter_ops __read_mostly;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
429ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyanstatic int __net_init arptable_filter_net_init(struct net *net)
439ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyan{
44e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt	struct arpt_replace *repl;
45e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt
46e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt	repl = arpt_alloc_initial_table(&packet_filter);
47e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt	if (repl == NULL)
48e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt		return -ENOMEM;
499ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyan	net->ipv4.arptable_filter =
50e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt		arpt_register_table(net, &packet_filter, repl);
51e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt	kfree(repl);
528c6ffba0eddc8c110dbf444f51354ce42069abfcRusty Russell	return PTR_ERR_OR_ZERO(net->ipv4.arptable_filter);
539ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyan}
549ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyan
559ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyanstatic void __net_exit arptable_filter_net_exit(struct net *net)
569ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyan{
579ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyan	arpt_unregister_table(net->ipv4.arptable_filter);
589ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyan}
599ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyan
609ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyanstatic struct pernet_operations arptable_filter_net_ops = {
619ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyan	.init = arptable_filter_net_init,
629ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyan	.exit = arptable_filter_net_exit,
639ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyan};
649ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyan
6565b4b4e81a5094d52cbe372b887b1779abe53f9bAndrew Mortonstatic int __init arptable_filter_init(void)
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
67964ddaa10de8f3aeed12bc2a30726514ff309e64Patrick McHardy	int ret;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
699ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyan	ret = register_pernet_subsys(&arptable_filter_net_ops);
709ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyan	if (ret < 0)
719ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyan		return ret;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
732b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	arpfilter_ops = xt_hook_link(&packet_filter, arptable_filter_hook);
742b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	if (IS_ERR(arpfilter_ops)) {
752b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ret = PTR_ERR(arpfilter_ops);
76964ddaa10de8f3aeed12bc2a30726514ff309e64Patrick McHardy		goto cleanup_table;
772b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	}
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
80964ddaa10de8f3aeed12bc2a30726514ff309e64Patrick McHardycleanup_table:
819ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyan	unregister_pernet_subsys(&arptable_filter_net_ops);
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8565b4b4e81a5094d52cbe372b887b1779abe53f9bAndrew Mortonstatic void __exit arptable_filter_fini(void)
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
872b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	xt_hook_unlink(&packet_filter, arpfilter_ops);
889ea0cb2601c4747dff758a9a7a5a4a433ad527f3Alexey Dobriyan	unregister_pernet_subsys(&arptable_filter_net_ops);
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9165b4b4e81a5094d52cbe372b887b1779abe53f9bAndrew Mortonmodule_init(arptable_filter_init);
9265b4b4e81a5094d52cbe372b887b1779abe53f9bAndrew Mortonmodule_exit(arptable_filter_fini);
93