ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[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                 (*pskb)->ip_summed = CHECKSUM_NONE;
73
74         switch (hooknum) {
75         case NF_IP_PRE_ROUTING:
76                 if (fwops->fw_acct_in)
77                         fwops->fw_acct_in(fwops, PF_INET,
78                                           (struct net_device *)in,
79                                           &redirpt, pskb);
80
81                 if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
82                         *pskb = ip_ct_gather_frags(*pskb);
83
84                         if (!*pskb)
85                                 return NF_STOLEN;
86                 }
87
88                 ret = fwops->fw_input(fwops, PF_INET, (struct net_device *)in,
89                                       &redirpt, pskb);
90                 break;
91
92         case NF_IP_FORWARD:
93                 /* Connection will only be set if it was
94                    demasqueraded: if so, skip forward chain. */
95                 if ((*pskb)->nfct)
96                         ret = FW_ACCEPT;
97                 else ret = fwops->fw_forward(fwops, PF_INET,
98                                              (struct net_device *)out,
99                                              &redirpt, pskb);
100                 break;
101
102         case NF_IP_POST_ROUTING:
103                 ret = fwops->fw_output(fwops, PF_INET,
104                                        (struct net_device *)out,
105                                        &redirpt, pskb);
106                 if (ret == FW_ACCEPT || ret == FW_SKIP) {
107                         if (fwops->fw_acct_out)
108                                 fwops->fw_acct_out(fwops, PF_INET,
109                                                    (struct net_device *)out,
110                                                    &redirpt,
111                                                    pskb);
112
113                         /* ip_conntrack_confirm return NF_DROP or NF_ACCEPT */
114                         if (ip_conntrack_confirm(*pskb) == NF_DROP)
115                                 ret = FW_BLOCK;
116                 }
117                 break;
118         }
119
120         switch (ret) {
121         case FW_REJECT: {
122                 /* Alexey says:
123                  *
124                  * Generally, routing is THE FIRST thing to make, when
125                  * packet enters IP stack. Before packet is routed you
126                  * cannot call any service routines from IP stack.  */
127                 struct iphdr *iph = (*pskb)->nh.iph;
128
129                 if ((*pskb)->dst != NULL
130                     || ip_route_input(*pskb, iph->daddr, iph->saddr, iph->tos,
131                                       (struct net_device *)in) == 0)
132                         icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH,
133                                   0);
134                 return NF_DROP;
135         }
136
137         case FW_ACCEPT:
138         case FW_SKIP:
139                 if (hooknum == NF_IP_PRE_ROUTING) {
140                         check_for_demasq(pskb);
141                         check_for_redirect(*pskb);
142                 } else if (hooknum == NF_IP_POST_ROUTING) {
143                         check_for_unredirect(*pskb);
144                         /* Handle ICMP errors from client here */
145                         if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
146                             && (*pskb)->nfct)
147                                 check_for_masq_error(pskb);
148                 }
149                 return NF_ACCEPT;
150
151         case FW_MASQUERADE:
152                 if (hooknum == NF_IP_FORWARD) {
153 #ifdef CONFIG_IP_VS
154                         /* check if it is for ip_vs */
155                         if (check_for_ip_vs_out(pskb, okfn) == NF_STOLEN)
156                                 return NF_STOLEN;
157 #endif
158                         return do_masquerade(pskb, out);
159                 }
160                 else return NF_ACCEPT;
161
162         case FW_REDIRECT:
163                 if (hooknum == NF_IP_PRE_ROUTING)
164                         return do_redirect(*pskb, in, redirpt);
165                 else return NF_ACCEPT;
166
167         default:
168                 /* FW_BLOCK */
169                 return NF_DROP;
170         }
171 }
172
173 static unsigned int fw_confirm(unsigned int hooknum,
174                                struct sk_buff **pskb,
175                                const struct net_device *in,
176                                const struct net_device *out,
177                                int (*okfn)(struct sk_buff *))
178 {
179         return ip_conntrack_confirm(*pskb);
180 }
181
182 extern int ip_fw_ctl(int optval, void *m, unsigned int len);
183
184 static int sock_fn(struct sock *sk, int optval, void *user, unsigned int len)
185 {
186         /* MAX of:
187            2.2: sizeof(struct ip_fwtest) (~14x4 + 3x4 = 17x4)
188            2.2: sizeof(struct ip_fwnew) (~1x4 + 15x4 + 3x4 + 3x4 = 22x4)
189            2.0: sizeof(struct ip_fw) (~25x4)
190
191            We can't include both 2.0 and 2.2 headers, they conflict.
192            Hence, 200 is a good number. --RR */
193         char tmp_fw[200];
194         if (!capable(CAP_NET_ADMIN))
195                 return -EPERM;
196
197         if (len > sizeof(tmp_fw) || len < 1)
198                 return -EINVAL;
199
200         if (copy_from_user(&tmp_fw, user, len))
201                 return -EFAULT;
202
203         return -ip_fw_ctl(optval, &tmp_fw, len);
204 }
205
206 static struct nf_hook_ops preroute_ops = {
207         .hook           = fw_in,
208         .owner          = THIS_MODULE,
209         .pf             = PF_INET,
210         .hooknum        = NF_IP_PRE_ROUTING,
211         .priority       = NF_IP_PRI_FILTER,
212 };
213
214 static struct nf_hook_ops postroute_ops = {
215         .hook           = fw_in,
216         .owner          = THIS_MODULE,
217         .pf             = PF_INET,
218         .hooknum        = NF_IP_POST_ROUTING,
219         .priority       = NF_IP_PRI_FILTER,
220 };
221
222 static struct nf_hook_ops forward_ops = {
223         .hook           = fw_in,
224         .owner          = THIS_MODULE,
225         .pf             = PF_INET,
226         .hooknum        = NF_IP_FORWARD,
227         .priority       = NF_IP_PRI_FILTER,
228 };
229
230 static struct nf_hook_ops local_in_ops = {
231         .hook           = fw_confirm,
232         .owner          = THIS_MODULE,
233         .pf             = PF_INET,
234         .hooknum        = NF_IP_LOCAL_IN,
235         .priority       = NF_IP_PRI_LAST - 1,
236 };
237
238 static struct nf_sockopt_ops sock_ops = {
239         .pf             = PF_INET,
240         .set_optmin     = 64,
241         .set_optmax     = 64 + 1024 + 1,
242         .set            = &sock_fn,
243 };
244
245 extern int ipfw_init_or_cleanup(int init);
246
247 static int init_or_cleanup(int init)
248 {
249         int ret = 0;
250
251         if (!init) goto cleanup;
252
253         ret = nf_register_sockopt(&sock_ops);
254
255         if (ret < 0)
256                 goto cleanup_nothing;
257
258         ret = ipfw_init_or_cleanup(1);
259         if (ret < 0)
260                 goto cleanup_sockopt;
261
262         ret = masq_init();
263         if (ret < 0)
264                 goto cleanup_ipfw;
265
266         nf_register_hook(&preroute_ops);
267         nf_register_hook(&postroute_ops);
268         nf_register_hook(&forward_ops);
269         nf_register_hook(&local_in_ops);
270
271         return ret;
272
273  cleanup:
274         nf_unregister_hook(&preroute_ops);
275         nf_unregister_hook(&postroute_ops);
276         nf_unregister_hook(&forward_ops);
277         nf_unregister_hook(&local_in_ops);
278
279         masq_cleanup();
280
281  cleanup_ipfw:
282         ipfw_init_or_cleanup(0);
283
284  cleanup_sockopt:
285         nf_unregister_sockopt(&sock_ops);
286
287  cleanup_nothing:
288         return ret;
289 }
290
291 static int __init init(void)
292 {
293         return init_or_cleanup(1);
294 }
295
296 static void __exit fini(void)
297 {
298         init_or_cleanup(0);
299 }
300
301 module_init(init);
302 module_exit(fini);