more changes on original files
[linux-2.4.git] / netfilter / iptable_mangle.c
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. */
24 struct ipt_standard
25 {
26         struct ipt_entry entry;
27         struct ipt_standard_target target;
28 };
29
30 struct ipt_error_target
31 {
32         struct ipt_entry_target target;
33         char errorname[IPT_FUNCTION_MAXNAMELEN];
34 };
35
36 struct 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 */
43 static 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
117 static 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. */
122 static unsigned int
123 ipt_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
132 static unsigned int
133 ipt_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 #ifdef CONFIG_IP_ROUTE_FWMARK
164                 || (*pskb)->nfmark != nfmark
165 #endif
166                 || (*pskb)->nh.iph->tos != tos))
167                 return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
168
169         return ret;
170 }
171
172 static struct nf_hook_ops ipt_ops[]
173 = { { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_PRE_ROUTING, 
174         NF_IP_PRI_MANGLE },
175     { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_LOCAL_IN,
176         NF_IP_PRI_MANGLE },
177     { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_FORWARD,
178         NF_IP_PRI_MANGLE },
179     { { NULL, NULL }, ipt_local_hook, PF_INET, NF_IP_LOCAL_OUT,
180         NF_IP_PRI_MANGLE },
181     { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_POST_ROUTING,
182         NF_IP_PRI_MANGLE }
183 };
184
185 static int __init init(void)
186 {
187         int ret;
188
189         /* Register table */
190         ret = ipt_register_table(&packet_mangler);
191         if (ret < 0)
192                 return ret;
193
194         /* Register hooks */
195         ret = nf_register_hook(&ipt_ops[0]);
196         if (ret < 0)
197                 goto cleanup_table;
198
199         ret = nf_register_hook(&ipt_ops[1]);
200         if (ret < 0)
201                 goto cleanup_hook0;
202
203         ret = nf_register_hook(&ipt_ops[2]);
204         if (ret < 0)
205                 goto cleanup_hook1;
206
207         ret = nf_register_hook(&ipt_ops[3]);
208         if (ret < 0)
209                 goto cleanup_hook2;
210
211         ret = nf_register_hook(&ipt_ops[4]);
212         if (ret < 0)
213                 goto cleanup_hook3;
214
215         return ret;
216
217  cleanup_hook3:
218         nf_unregister_hook(&ipt_ops[3]);
219  cleanup_hook2:
220         nf_unregister_hook(&ipt_ops[2]);
221  cleanup_hook1:
222         nf_unregister_hook(&ipt_ops[1]);
223  cleanup_hook0:
224         nf_unregister_hook(&ipt_ops[0]);
225  cleanup_table:
226         ipt_unregister_table(&packet_mangler);
227
228         return ret;
229 }
230
231 static void __exit fini(void)
232 {
233         unsigned int i;
234
235         for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++)
236                 nf_unregister_hook(&ipt_ops[i]);
237
238         ipt_unregister_table(&packet_mangler);
239 }
240
241 module_init(init);
242 module_exit(fini);
243 MODULE_LICENSE("GPL");