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