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