1/*
2 * This is the 1999 rewrite of IP Firewalling, aiming for kernel 2.3.x.
3 *
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 *
6 * Extended to all five netfilter hooks by Brad Chapman & Harald Welte
7 */
8#include <linux/config.h>
9#include <linux/module.h>
10#include <linux/netfilter_ipv4/ip_tables.h>
11#include <linux/netdevice.h>
12#include <linux/skbuff.h>
13#include <net/sock.h>
14#include <net/route.h>
15#include <linux/ip.h>
16
17#define MANGLE_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | \
18			    (1 << NF_IP_LOCAL_IN) | \
19			    (1 << NF_IP_FORWARD) | \
20			    (1 << NF_IP_LOCAL_OUT) | \
21			    (1 << NF_IP_POST_ROUTING))
22
23/* Standard entry. */
24struct ipt_standard
25{
26	struct ipt_entry entry;
27	struct ipt_standard_target target;
28};
29
30struct ipt_error_target
31{
32	struct ipt_entry_target target;
33	char errorname[IPT_FUNCTION_MAXNAMELEN];
34};
35
36struct ipt_error
37{
38	struct ipt_entry entry;
39	struct ipt_error_target target;
40};
41
42/* Ouch - five different hooks? Maybe this should be a config option..... -- BC */
43static struct
44{
45	struct ipt_replace repl;
46	struct ipt_standard entries[5];
47	struct ipt_error term;
48} initial_table __initdata
49= { { "mangle", MANGLE_VALID_HOOKS, 6,
50      sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error),
51      { [NF_IP_PRE_ROUTING] 	0,
52	[NF_IP_LOCAL_IN] 	sizeof(struct ipt_standard),
53	[NF_IP_FORWARD] 	sizeof(struct ipt_standard) * 2,
54	[NF_IP_LOCAL_OUT] 	sizeof(struct ipt_standard) * 3,
55	[NF_IP_POST_ROUTING] 	sizeof(struct ipt_standard) * 4 },
56      { [NF_IP_PRE_ROUTING] 	0,
57	[NF_IP_LOCAL_IN] 	sizeof(struct ipt_standard),
58	[NF_IP_FORWARD] 	sizeof(struct ipt_standard) * 2,
59	[NF_IP_LOCAL_OUT] 	sizeof(struct ipt_standard) * 3,
60	[NF_IP_POST_ROUTING]	sizeof(struct ipt_standard) * 4 },
61      0, NULL, { } },
62    {
63	    /* PRE_ROUTING */
64	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
65		0,
66		sizeof(struct ipt_entry),
67		sizeof(struct ipt_standard),
68		0, { 0, 0 }, { } },
69	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
70		-NF_ACCEPT - 1 } },
71	    /* LOCAL_IN */
72 	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
73		0,
74		sizeof(struct ipt_entry),
75		sizeof(struct ipt_standard),
76		0, { 0, 0 }, { } },
77	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
78		-NF_ACCEPT - 1 } },
79	    /* FORWARD */
80 	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
81		0,
82		sizeof(struct ipt_entry),
83		sizeof(struct ipt_standard),
84		0, { 0, 0 }, { } },
85	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
86		-NF_ACCEPT - 1 } },
87	    /* LOCAL_OUT */
88	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
89		0,
90		sizeof(struct ipt_entry),
91		sizeof(struct ipt_standard),
92		0, { 0, 0 }, { } },
93	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
94		-NF_ACCEPT - 1 } },
95	    /* POST_ROUTING */
96	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
97		0,
98		sizeof(struct ipt_entry),
99		sizeof(struct ipt_standard),
100		0, { 0, 0 }, { } },
101	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
102		-NF_ACCEPT - 1 } },
103    },
104    /* ERROR */
105    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
106	0,
107	sizeof(struct ipt_entry),
108	sizeof(struct ipt_error),
109	0, { 0, 0 }, { } },
110      { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
111	  { } },
112	"ERROR"
113      }
114    }
115};
116
117static struct ipt_table packet_mangler
118= { { NULL, NULL }, "mangle", &initial_table.repl,
119    MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
120
121/* The work comes in here from netfilter.c. */
122static unsigned int
123ipt_route_hook(unsigned int hook,
124	 struct sk_buff **pskb,
125	 const struct net_device *in,
126	 const struct net_device *out,
127	 int (*okfn)(struct sk_buff *))
128{
129	return ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL);
130}
131
132static unsigned int
133ipt_local_hook(unsigned int hook,
134		   struct sk_buff **pskb,
135		   const struct net_device *in,
136		   const struct net_device *out,
137		   int (*okfn)(struct sk_buff *))
138{
139	unsigned int ret;
140	u_int8_t tos;
141	u_int32_t saddr, daddr;
142	unsigned long nfmark;
143
144	/* root is playing with raw sockets. */
145	if ((*pskb)->len < sizeof(struct iphdr)
146	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
147		if (net_ratelimit())
148			printk("ipt_hook: happy cracking.\n");
149		return NF_ACCEPT;
150	}
151
152	/* Save things which could affect route */
153	nfmark = (*pskb)->nfmark;
154	saddr = (*pskb)->nh.iph->saddr;
155	daddr = (*pskb)->nh.iph->daddr;
156	tos = (*pskb)->nh.iph->tos;
157
158	ret = ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL);
159	/* Reroute for ANY change. */
160	if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE
161	    && ((*pskb)->nh.iph->saddr != saddr
162		|| (*pskb)->nh.iph->daddr != daddr
163		|| (*pskb)->nfmark != nfmark
164		|| (*pskb)->nh.iph->tos != tos))
165		return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
166
167	return ret;
168}
169
170static struct nf_hook_ops ipt_ops[]
171= { { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_PRE_ROUTING,
172	NF_IP_PRI_MANGLE },
173    { { NULL, NULL }, ipt_local_hook, PF_INET, NF_IP_LOCAL_IN,
174	NF_IP_PRI_MANGLE },
175    { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_FORWARD,
176	NF_IP_PRI_MANGLE },
177    { { NULL, NULL }, ipt_local_hook, PF_INET, NF_IP_LOCAL_OUT,
178	NF_IP_PRI_MANGLE },
179    { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_POST_ROUTING,
180	NF_IP_PRI_MANGLE }
181};
182
183static int __init init(void)
184{
185	int ret;
186
187	/* Register table */
188	ret = ipt_register_table(&packet_mangler);
189	if (ret < 0)
190		return ret;
191
192	/* Register hooks */
193	ret = nf_register_hook(&ipt_ops[0]);
194	if (ret < 0)
195		goto cleanup_table;
196
197	ret = nf_register_hook(&ipt_ops[1]);
198	if (ret < 0)
199		goto cleanup_hook0;
200
201	ret = nf_register_hook(&ipt_ops[2]);
202	if (ret < 0)
203		goto cleanup_hook1;
204
205	ret = nf_register_hook(&ipt_ops[3]);
206	if (ret < 0)
207		goto cleanup_hook2;
208
209	ret = nf_register_hook(&ipt_ops[4]);
210	if (ret < 0)
211		goto cleanup_hook3;
212
213	return ret;
214
215 cleanup_hook3:
216        nf_unregister_hook(&ipt_ops[3]);
217 cleanup_hook2:
218        nf_unregister_hook(&ipt_ops[2]);
219 cleanup_hook1:
220	nf_unregister_hook(&ipt_ops[1]);
221 cleanup_hook0:
222	nf_unregister_hook(&ipt_ops[0]);
223 cleanup_table:
224	ipt_unregister_table(&packet_mangler);
225
226	return ret;
227}
228
229static void __exit fini(void)
230{
231	unsigned int i;
232
233	for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++)
234		nf_unregister_hook(&ipt_ops[i]);
235
236	ipt_unregister_table(&packet_mangler);
237}
238
239module_init(init);
240module_exit(fini);
241MODULE_LICENSE("GPL");
242