1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Filtering ARP tables module. |
4 | * |
5 | * Copyright (C) 2002 David S. Miller (davem@redhat.com) |
6 | * |
7 | */ |
8 | |
9 | #include <linux/module.h> |
10 | #include <linux/netfilter/x_tables.h> |
11 | #include <linux/netfilter_arp/arp_tables.h> |
12 | #include <linux/slab.h> |
13 | |
14 | MODULE_LICENSE("GPL" ); |
15 | MODULE_AUTHOR("David S. Miller <davem@redhat.com>" ); |
16 | MODULE_DESCRIPTION("arptables filter table" ); |
17 | |
18 | #define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \ |
19 | (1 << NF_ARP_FORWARD)) |
20 | |
21 | static const struct xt_table packet_filter = { |
22 | .name = "filter" , |
23 | .valid_hooks = FILTER_VALID_HOOKS, |
24 | .me = THIS_MODULE, |
25 | .af = NFPROTO_ARP, |
26 | .priority = NF_IP_PRI_FILTER, |
27 | }; |
28 | |
29 | static struct nf_hook_ops *arpfilter_ops __read_mostly; |
30 | |
31 | static int arptable_filter_table_init(struct net *net) |
32 | { |
33 | struct arpt_replace *repl; |
34 | int err; |
35 | |
36 | repl = arpt_alloc_initial_table(&packet_filter); |
37 | if (repl == NULL) |
38 | return -ENOMEM; |
39 | err = arpt_register_table(net, table: &packet_filter, repl, ops: arpfilter_ops); |
40 | kfree(objp: repl); |
41 | return err; |
42 | } |
43 | |
44 | static void __net_exit arptable_filter_net_pre_exit(struct net *net) |
45 | { |
46 | arpt_unregister_table_pre_exit(net, name: "filter" ); |
47 | } |
48 | |
49 | static void __net_exit arptable_filter_net_exit(struct net *net) |
50 | { |
51 | arpt_unregister_table(net, name: "filter" ); |
52 | } |
53 | |
54 | static struct pernet_operations arptable_filter_net_ops = { |
55 | .exit = arptable_filter_net_exit, |
56 | .pre_exit = arptable_filter_net_pre_exit, |
57 | }; |
58 | |
59 | static int __init arptable_filter_init(void) |
60 | { |
61 | int ret = xt_register_template(t: &packet_filter, |
62 | table_init: arptable_filter_table_init); |
63 | |
64 | if (ret < 0) |
65 | return ret; |
66 | |
67 | arpfilter_ops = xt_hook_ops_alloc(&packet_filter, arpt_do_table); |
68 | if (IS_ERR(ptr: arpfilter_ops)) { |
69 | xt_unregister_template(t: &packet_filter); |
70 | return PTR_ERR(ptr: arpfilter_ops); |
71 | } |
72 | |
73 | ret = register_pernet_subsys(&arptable_filter_net_ops); |
74 | if (ret < 0) { |
75 | xt_unregister_template(t: &packet_filter); |
76 | kfree(objp: arpfilter_ops); |
77 | return ret; |
78 | } |
79 | |
80 | return ret; |
81 | } |
82 | |
83 | static void __exit arptable_filter_fini(void) |
84 | { |
85 | unregister_pernet_subsys(&arptable_filter_net_ops); |
86 | xt_unregister_template(t: &packet_filter); |
87 | kfree(objp: arpfilter_ops); |
88 | } |
89 | |
90 | module_init(arptable_filter_init); |
91 | module_exit(arptable_filter_fini); |
92 | |