patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / net / ipv4 / netfilter / ip_fw_compat.c
1 /* Compatibility framework for ipchains and ipfwadm support; designed
2    to look as much like the 2.2 infrastructure as possible. */
3
4 /* (C) 1999-2001 Paul `Rusty' Russell
5  * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11
12 struct notifier_block;
13
14 #include <linux/netfilter_ipv4.h>
15 #include <linux/ip.h>
16 #include <net/icmp.h>
17 #include <linux/if.h>
18 #include <linux/inetdevice.h>
19 #include <linux/netdevice.h>
20 #include <linux/module.h>
21 #include <asm/uaccess.h>
22 #include <net/ip.h>
23 #include <net/route.h>
24 #include <linux/netfilter_ipv4/compat_firewall.h>
25 #include <linux/netfilter_ipv4/ip_conntrack.h>
26 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
27 #include "ip_fw_compat.h"
28
29 static struct firewall_ops *fwops;
30
31 #ifdef CONFIG_IP_VS
32 /* From ip_vs_core.c */
33 extern unsigned int
34 check_for_ip_vs_out(struct sk_buff **skb_p, int (*okfn)(struct sk_buff *));
35 #endif
36
37 /* They call these; we do what they want. */
38 int register_firewall(int pf, struct firewall_ops *fw)
39 {
40         if (pf != PF_INET) {
41                 printk("Attempt to register non-IP firewall module.\n");
42                 return -EINVAL;
43         }
44         if (fwops) {
45                 printk("Attempt to register multiple firewall modules.\n");
46                 return -EBUSY;
47         }
48
49         fwops = fw;
50         return 0;
51 }
52
53 int unregister_firewall(int pf, struct firewall_ops *fw)
54 {
55         fwops = NULL;
56         return 0;
57 }
58
59 static unsigned int
60 fw_in(unsigned int hooknum,
61       struct sk_buff **pskb,
62       const struct net_device *in,
63       const struct net_device *out,
64       int (*okfn)(struct sk_buff *))
65 {
66         int ret = FW_BLOCK;
67         u_int16_t redirpt;
68
69         /* Assume worse case: any hook could change packet */
70         (*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED;
71         if ((*pskb)->ip_summed == CHECKSUM_HW)
72                 if (skb_checksum_help(pskb, (out == NULL)))
73                         return NF_DROP;
74
75         switch (hooknum) {
76         case NF_IP_PRE_ROUTING:
77                 if (fwops->fw_acct_in)
78                         fwops->fw_acct_in(fwops, PF_INET,
79                                           (struct net_device *)in,
80                                           &redirpt, pskb);
81
82                 if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
83                         *pskb = ip_ct_gather_frags(*pskb);
84
85                         if (!*pskb)
86                                 return NF_STOLEN;
87                 }
88
89                 ret = fwops->fw_input(fwops, PF_INET, (struct net_device *)in,
90                                       &redirpt, pskb);
91                 break;
92
93         case NF_IP_FORWARD:
94                 /* Connection will only be set if it was
95                    demasqueraded: if so, skip forward chain. */
96                 if ((*pskb)->nfct)
97                         ret = FW_ACCEPT;
98                 else ret = fwops->fw_forward(fwops, PF_INET,
99                                              (struct net_device *)out,
100                                              &redirpt, pskb);
101                 break;
102
103         case NF_IP_POST_ROUTING:
104                 ret = fwops->fw_output(fwops, PF_INET,
105                                        (struct net_device *)out,
106                                        &redirpt, pskb);
107                 if (ret == FW_ACCEPT || ret == FW_SKIP) {
108                         if (fwops->fw_acct_out)
109                                 fwops->fw_acct_out(fwops, PF_INET,
110                                                    (struct net_device *)out,
111                                                    &redirpt,
112                                                    pskb);
113
114                         /* ip_conntrack_confirm return NF_DROP or NF_ACCEPT */
115                         if (ip_conntrack_confirm(*pskb) == NF_DROP)
116                                 ret = FW_BLOCK;
117                 }
118                 break;
119         }
120
121         switch (ret) {
122         case FW_REJECT: {
123                 /* Alexey says:
124                  *
125                  * Generally, routing is THE FIRST thing to make, when
126                  * packet enters IP stack. Before packet is routed you
127                  * cannot call any service routines from IP stack.  */
128                 struct iphdr *iph = (*pskb)->nh.iph;
129
130                 if ((*pskb)->dst != NULL
131                     || ip_route_input(*pskb, iph->daddr, iph->saddr, iph->tos,
132                                       (struct net_device *)in) == 0)
133                         icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH,
134                                   0);
135                 return NF_DROP;
136         }
137
138         case FW_ACCEPT:
139         case FW_SKIP:
140                 if (hooknum == NF_IP_PRE_ROUTING) {
141                         check_for_demasq(pskb);
142                         check_for_redirect(*pskb);
143                 } else if (hooknum == NF_IP_POST_ROUTING) {
144                         check_for_unredirect(*pskb);
145                         /* Handle ICMP errors from client here */
146                         if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
147                             && (*pskb)->nfct)
148                                 check_for_masq_error(pskb);
149                 }
150                 return NF_ACCEPT;
151
152         case FW_MASQUERADE:
153                 if (hooknum == NF_IP_FORWARD) {
154 #ifdef CONFIG_IP_VS
155                         /* check if it is for ip_vs */
156                         if (check_for_ip_vs_out(pskb, okfn) == NF_STOLEN)
157                                 return NF_STOLEN;
158 #endif
159                         return do_masquerade(pskb, out);
160                 }
161                 else return NF_ACCEPT;
162
163         case FW_REDIRECT:
164                 if (hooknum == NF_IP_PRE_ROUTING)
165                         return do_redirect(*pskb, in, redirpt);
166                 else return NF_ACCEPT;
167
168         default:
169                 /* FW_BLOCK */
170                 return NF_DROP;
171         }
172 }
173
174 static unsigned int fw_confirm(unsigned int hooknum,
175                                struct sk_buff **pskb,
176                                const struct net_device *in,
177                                const struct net_device *out,
178                                int (*okfn)(struct sk_buff *))
179 {
180         return ip_conntrack_confirm(*pskb);
181 }
182
183 extern int ip_fw_ctl(int optval, void *m, unsigned int len);
184
185 static int sock_fn(struct sock *sk, int optval, void __user *user, unsigned int len)
186 {
187         /* MAX of:
188            2.2: sizeof(struct ip_fwtest) (~14x4 + 3x4 = 17x4)
189            2.2: sizeof(struct ip_fwnew) (~1x4 + 15x4 + 3x4 + 3x4 = 22x4)
190            2.0: sizeof(struct ip_fw) (~25x4)
191
192            We can't include both 2.0 and 2.2 headers, they conflict.
193            Hence, 200 is a good number. --RR */
194         char tmp_fw[200];
195         if (!capable(CAP_NET_ADMIN))
196                 return -EPERM;
197
198         if (len > sizeof(tmp_fw) || len < 1)
199                 return -EINVAL;
200
201         if (copy_from_user(&tmp_fw, user, len))
202                 return -EFAULT;
203
204         return -ip_fw_ctl(optval, &tmp_fw, len);
205 }
206
207 static struct nf_hook_ops preroute_ops = {
208         .hook           = fw_in,
209         .owner          = THIS_MODULE,
210         .pf             = PF_INET,
211         .hooknum        = NF_IP_PRE_ROUTING,
212         .priority       = NF_IP_PRI_FILTER,
213 };
214
215 static struct nf_hook_ops postroute_ops = {
216         .hook           = fw_in,
217         .owner          = THIS_MODULE,
218         .pf             = PF_INET,
219         .hooknum        = NF_IP_POST_ROUTING,
220         .priority       = NF_IP_PRI_FILTER,
221 };
222
223 static struct nf_hook_ops forward_ops = {
224         .hook           = fw_in,
225         .owner          = THIS_MODULE,
226         .pf             = PF_INET,
227         .hooknum        = NF_IP_FORWARD,
228         .priority       = NF_IP_PRI_FILTER,
229 };
230
231 static struct nf_hook_ops local_in_ops = {
232         .hook           = fw_confirm,
233         .owner          = THIS_MODULE,
234         .pf             = PF_INET,
235         .hooknum        = NF_IP_LOCAL_IN,
236         .priority       = NF_IP_PRI_LAST - 1,
237 };
238
239 static struct nf_sockopt_ops sock_ops = {
240         .pf             = PF_INET,
241         .set_optmin     = 64,
242         .set_optmax     = 64 + 1024 + 1,
243         .set            = &sock_fn,
244 };
245
246 extern int ipfw_init_or_cleanup(int init);
247
248 static int init_or_cleanup(int init)
249 {
250         int ret = 0;
251
252         if (!init) goto cleanup;
253
254         ret = nf_register_sockopt(&sock_ops);
255
256         if (ret < 0)
257                 goto cleanup_nothing;
258
259         ret = ipfw_init_or_cleanup(1);
260         if (ret < 0)
261                 goto cleanup_sockopt;
262
263         ret = masq_init();
264         if (ret < 0)
265                 goto cleanup_ipfw;
266
267         nf_register_hook(&preroute_ops);
268         nf_register_hook(&postroute_ops);
269         nf_register_hook(&forward_ops);
270         nf_register_hook(&local_in_ops);
271
272         return ret;
273
274  cleanup:
275         nf_unregister_hook(&preroute_ops);
276         nf_unregister_hook(&postroute_ops);
277         nf_unregister_hook(&forward_ops);
278         nf_unregister_hook(&local_in_ops);
279
280         masq_cleanup();
281
282  cleanup_ipfw:
283         ipfw_init_or_cleanup(0);
284
285  cleanup_sockopt:
286         nf_unregister_sockopt(&sock_ops);
287
288  cleanup_nothing:
289         return ret;
290 }
291
292 static int __init init(void)
293 {
294         return init_or_cleanup(1);
295 }
296
297 static void __exit fini(void)
298 {
299         init_or_cleanup(0);
300 }
301
302 module_init(init);
303 module_exit(fini);