d80850727555717b6884937dd4b69de917fff371
[linux-2.6.git] / net / ipv6 / netfilter / ip6table_security.c
1 /*
2  * "security" table for IPv6
3  *
4  * This is for use by Mandatory Access Control (MAC) security models,
5  * which need to be able to manage security policy in separate context
6  * to DAC.
7  *
8  * Based on iptable_mangle.c
9  *
10  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
11  * Copyright (C) 2000-2004 Netfilter Core Team <coreteam <at> netfilter.org>
12  * Copyright (C) 2008 Red Hat, Inc., James Morris <jmorris <at> redhat.com>
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License version 2 as
16  * published by the Free Software Foundation.
17  */
18 #include <linux/module.h>
19 #include <linux/netfilter_ipv6/ip6_tables.h>
20
21 MODULE_LICENSE("GPL");
22 MODULE_AUTHOR("James Morris <jmorris <at> redhat.com>");
23 MODULE_DESCRIPTION("ip6tables security table, for MAC rules");
24
25 #define SECURITY_VALID_HOOKS    (1 << NF_INET_LOCAL_IN) | \
26                                 (1 << NF_INET_FORWARD) | \
27                                 (1 << NF_INET_LOCAL_OUT)
28
29 static struct
30 {
31         struct ip6t_replace repl;
32         struct ip6t_standard entries[3];
33         struct ip6t_error term;
34 } initial_table __net_initdata = {
35         .repl = {
36                 .name = "security",
37                 .valid_hooks = SECURITY_VALID_HOOKS,
38                 .num_entries = 4,
39                 .size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error),
40                 .hook_entry = {
41                         [NF_INET_LOCAL_IN]      = 0,
42                         [NF_INET_FORWARD]       = sizeof(struct ip6t_standard),
43                         [NF_INET_LOCAL_OUT]     = sizeof(struct ip6t_standard) * 2,
44                 },
45                 .underflow = {
46                         [NF_INET_LOCAL_IN]      = 0,
47                         [NF_INET_FORWARD]       = sizeof(struct ip6t_standard),
48                         [NF_INET_LOCAL_OUT]     = sizeof(struct ip6t_standard) * 2,
49                 },
50         },
51         .entries = {
52                 IP6T_STANDARD_INIT(NF_ACCEPT),  /* LOCAL_IN */
53                 IP6T_STANDARD_INIT(NF_ACCEPT),  /* FORWARD */
54                 IP6T_STANDARD_INIT(NF_ACCEPT),  /* LOCAL_OUT */
55         },
56         .term = IP6T_ERROR_INIT,                /* ERROR */
57 };
58
59 static struct xt_table security_table = {
60         .name           = "security",
61         .valid_hooks    = SECURITY_VALID_HOOKS,
62         .me             = THIS_MODULE,
63         .af             = AF_INET6,
64 };
65
66 static unsigned int
67 ip6t_local_in_hook(unsigned int hook,
68                    struct sk_buff *skb,
69                    const struct net_device *in,
70                    const struct net_device *out,
71                    int (*okfn)(struct sk_buff *))
72 {
73         return ip6t_do_table(skb, hook, in, out,
74                              dev_net(in)->ipv6.ip6table_security);
75 }
76
77 static unsigned int
78 ip6t_forward_hook(unsigned int hook,
79                   struct sk_buff *skb,
80                   const struct net_device *in,
81                   const struct net_device *out,
82                   int (*okfn)(struct sk_buff *))
83 {
84         return ip6t_do_table(skb, hook, in, out,
85                              dev_net(in)->ipv6.ip6table_security);
86 }
87
88 static unsigned int
89 ip6t_local_out_hook(unsigned int hook,
90                     struct sk_buff *skb,
91                     const struct net_device *in,
92                     const struct net_device *out,
93                     int (*okfn)(struct sk_buff *))
94 {
95         /* TBD: handle short packets via raw socket */
96         return ip6t_do_table(skb, hook, in, out,
97                              dev_net(out)->ipv6.ip6table_security);
98 }
99
100 static struct nf_hook_ops ip6t_ops[] __read_mostly = {
101         {
102                 .hook           = ip6t_local_in_hook,
103                 .owner          = THIS_MODULE,
104                 .pf             = NFPROTO_IPV6,
105                 .hooknum        = NF_INET_LOCAL_IN,
106                 .priority       = NF_IP6_PRI_SECURITY,
107         },
108         {
109                 .hook           = ip6t_forward_hook,
110                 .owner          = THIS_MODULE,
111                 .pf             = NFPROTO_IPV6,
112                 .hooknum        = NF_INET_FORWARD,
113                 .priority       = NF_IP6_PRI_SECURITY,
114         },
115         {
116                 .hook           = ip6t_local_out_hook,
117                 .owner          = THIS_MODULE,
118                 .pf             = NFPROTO_IPV6,
119                 .hooknum        = NF_INET_LOCAL_OUT,
120                 .priority       = NF_IP6_PRI_SECURITY,
121         },
122 };
123
124 static int __net_init ip6table_security_net_init(struct net *net)
125 {
126         net->ipv6.ip6table_security =
127                 ip6t_register_table(net, &security_table, &initial_table.repl);
128
129         if (IS_ERR(net->ipv6.ip6table_security))
130                 return PTR_ERR(net->ipv6.ip6table_security);
131
132         return 0;
133 }
134
135 static void __net_exit ip6table_security_net_exit(struct net *net)
136 {
137         ip6t_unregister_table(net->ipv6.ip6table_security);
138 }
139
140 static struct pernet_operations ip6table_security_net_ops = {
141         .init = ip6table_security_net_init,
142         .exit = ip6table_security_net_exit,
143 };
144
145 static int __init ip6table_security_init(void)
146 {
147         int ret;
148
149         ret = register_pernet_subsys(&ip6table_security_net_ops);
150         if (ret < 0)
151                 return ret;
152
153         ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
154         if (ret < 0)
155                 goto cleanup_table;
156
157         return ret;
158
159 cleanup_table:
160         unregister_pernet_subsys(&ip6table_security_net_ops);
161         return ret;
162 }
163
164 static void __exit ip6table_security_fini(void)
165 {
166         nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
167         unregister_pernet_subsys(&ip6table_security_net_ops);
168 }
169
170 module_init(ip6table_security_init);
171 module_exit(ip6table_security_fini);