ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / net / ipv6 / netfilter / ip6table_mangle.c
1 /*
2  * IPv6 packet mangling table, a port of the IPv4 mangle table to IPv6
3  *
4  * Copyright (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
5  * Copyright (C) 2000-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  * Extended to all five netfilter hooks by Brad Chapman & Harald Welte
12  */
13 #include <linux/module.h>
14 #include <linux/netfilter_ipv6/ip6_tables.h>
15
16 MODULE_LICENSE("GPL");
17 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
18 MODULE_DESCRIPTION("ip6tables mangle table");
19
20 #define MANGLE_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | \
21                             (1 << NF_IP6_LOCAL_IN) | \
22                             (1 << NF_IP6_FORWARD) | \
23                             (1 << NF_IP6_LOCAL_OUT) | \
24                             (1 << NF_IP6_POST_ROUTING))
25
26 #if 0
27 #define DEBUGP(x, args...)      printk(KERN_DEBUG x, ## args)
28 #else
29 #define DEBUGP(x, args...)
30 #endif
31
32 /* Standard entry. */
33 struct ip6t_standard
34 {
35         struct ip6t_entry entry;
36         struct ip6t_standard_target target;
37 };
38
39 struct ip6t_error_target
40 {
41         struct ip6t_entry_target target;
42         char errorname[IP6T_FUNCTION_MAXNAMELEN];
43 };
44
45 struct ip6t_error
46 {
47         struct ip6t_entry entry;
48         struct ip6t_error_target target;
49 };
50
51 static struct
52 {
53         struct ip6t_replace repl;
54         struct ip6t_standard entries[5];
55         struct ip6t_error term;
56 } initial_table __initdata
57 = { { "mangle", MANGLE_VALID_HOOKS, 6,
58       sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error),
59       { [NF_IP6_PRE_ROUTING]    = 0,
60         [NF_IP6_LOCAL_IN]       = sizeof(struct ip6t_standard),
61         [NF_IP6_FORWARD]        = sizeof(struct ip6t_standard) * 2,
62         [NF_IP6_LOCAL_OUT]      = sizeof(struct ip6t_standard) * 3,
63         [NF_IP6_POST_ROUTING]   = sizeof(struct ip6t_standard) * 4},
64       { [NF_IP6_PRE_ROUTING]    = 0,
65         [NF_IP6_LOCAL_IN]       = sizeof(struct ip6t_standard),
66         [NF_IP6_FORWARD]        = sizeof(struct ip6t_standard) * 2,
67         [NF_IP6_LOCAL_OUT]      = sizeof(struct ip6t_standard) * 3,
68         [NF_IP6_POST_ROUTING]   = sizeof(struct ip6t_standard) * 4},
69       0, NULL, { } },
70     {
71             /* PRE_ROUTING */
72             { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
73                 0,
74                 sizeof(struct ip6t_entry),
75                 sizeof(struct ip6t_standard),
76                 0, { 0, 0 }, { } },
77               { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
78                 -NF_ACCEPT - 1 } },
79             /* LOCAL_IN */
80             { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
81                 0,
82                 sizeof(struct ip6t_entry),
83                 sizeof(struct ip6t_standard),
84                 0, { 0, 0 }, { } },
85               { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
86                 -NF_ACCEPT - 1 } },
87             /* FORWARD */
88             { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
89                 0,
90                 sizeof(struct ip6t_entry),
91                 sizeof(struct ip6t_standard),
92                 0, { 0, 0 }, { } },
93               { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
94                 -NF_ACCEPT - 1 } },
95             /* LOCAL_OUT */
96             { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
97                 0,
98                 sizeof(struct ip6t_entry),
99                 sizeof(struct ip6t_standard),
100                 0, { 0, 0 }, { } },
101               { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
102                 -NF_ACCEPT - 1 } },
103             /* POST_ROUTING */
104             { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
105                 0,
106                 sizeof(struct ip6t_entry),
107                 sizeof(struct ip6t_standard),
108                 0, { 0, 0 }, { } },
109               { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
110                 -NF_ACCEPT - 1 } }
111     },
112     /* ERROR */
113     { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
114         0,
115         sizeof(struct ip6t_entry),
116         sizeof(struct ip6t_error),
117         0, { 0, 0 }, { } },
118       { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
119           { } },
120         "ERROR"
121       }
122     }
123 };
124
125 static struct ip6t_table packet_mangler = {
126         .name           = "mangle",
127         .table          = &initial_table.repl,
128         .valid_hooks    = MANGLE_VALID_HOOKS,
129         .lock           = RW_LOCK_UNLOCKED,
130         .me             = THIS_MODULE,
131 };
132
133 /* The work comes in here from netfilter.c. */
134 static unsigned int
135 ip6t_route_hook(unsigned int hook,
136          struct sk_buff **pskb,
137          const struct net_device *in,
138          const struct net_device *out,
139          int (*okfn)(struct sk_buff *))
140 {
141         return ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL);
142 }
143
144 static unsigned int
145 ip6t_local_hook(unsigned int hook,
146                    struct sk_buff **pskb,
147                    const struct net_device *in,
148                    const struct net_device *out,
149                    int (*okfn)(struct sk_buff *))
150 {
151
152         unsigned long nfmark;
153         unsigned int ret;
154         struct in6_addr saddr, daddr;
155         u_int8_t hop_limit;
156         u_int32_t flowlabel;
157
158 #if 0
159         /* root is playing with raw sockets. */
160         if ((*pskb)->len < sizeof(struct iphdr)
161             || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
162                 if (net_ratelimit())
163                         printk("ip6t_hook: happy cracking.\n");
164                 return NF_ACCEPT;
165         }
166 #endif
167
168         /* FIXME: Push down to extensions --RR */
169         if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0)
170                 return NF_DROP;
171
172         /* save source/dest address, nfmark, hoplimit, flowlabel, priority,  */
173         memcpy(&saddr, &(*pskb)->nh.ipv6h->saddr, sizeof(saddr));
174         memcpy(&daddr, &(*pskb)->nh.ipv6h->daddr, sizeof(daddr));
175         nfmark = (*pskb)->nfmark;
176         hop_limit = (*pskb)->nh.ipv6h->hop_limit;
177
178         /* flowlabel and prio (includes version, which shouldn't change either */
179         flowlabel = *((u_int32_t *) (*pskb)->nh.ipv6h);
180
181         ret = ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL);
182
183         if (ret != NF_DROP && ret != NF_STOLEN 
184                 && (memcmp(&(*pskb)->nh.ipv6h->saddr, &saddr, sizeof(saddr))
185                     || memcmp(&(*pskb)->nh.ipv6h->daddr, &daddr, sizeof(daddr))
186                     || (*pskb)->nfmark != nfmark
187                     || (*pskb)->nh.ipv6h->hop_limit != hop_limit)) {
188
189                 /* something which could affect routing has changed */
190
191                 DEBUGP("ip6table_mangle: we'd need to re-route a packet\n");
192         }
193
194         return ret;
195 }
196
197 static struct nf_hook_ops ip6t_ops[] = {
198         {
199                 .hook           = ip6t_route_hook,
200                 .owner          = THIS_MODULE,
201                 .pf             = PF_INET6,
202                 .hooknum        = NF_IP6_PRE_ROUTING,
203                 .priority       = NF_IP6_PRI_MANGLE,
204         },
205         {
206                 .hook           = ip6t_local_hook,
207                 .owner          = THIS_MODULE,
208                 .pf             = PF_INET6,
209                 .hooknum        = NF_IP6_LOCAL_IN,
210                 .priority       = NF_IP6_PRI_MANGLE,
211         },
212         {
213                 .hook           = ip6t_route_hook,
214                 .owner          = THIS_MODULE,
215                 .pf             = PF_INET6,
216                 .hooknum        = NF_IP6_FORWARD,
217                 .priority       = NF_IP6_PRI_MANGLE,
218         },
219         {
220                 .hook           = ip6t_local_hook,
221                 .owner          = THIS_MODULE,
222                 .pf             = PF_INET6,
223                 .hooknum        = NF_IP6_LOCAL_OUT,
224                 .priority       = NF_IP6_PRI_MANGLE,
225         },
226         {
227                 .hook           = ip6t_route_hook,
228                 .owner          = THIS_MODULE,
229                 .pf             = PF_INET6,
230                 .hooknum        = NF_IP6_POST_ROUTING,
231                 .priority       = NF_IP6_PRI_MANGLE,
232         },
233 };
234
235 static int __init init(void)
236 {
237         int ret;
238
239         /* Register table */
240         ret = ip6t_register_table(&packet_mangler);
241         if (ret < 0)
242                 return ret;
243
244         /* Register hooks */
245         ret = nf_register_hook(&ip6t_ops[0]);
246         if (ret < 0)
247                 goto cleanup_table;
248
249         ret = nf_register_hook(&ip6t_ops[1]);
250         if (ret < 0)
251                 goto cleanup_hook0;
252
253         ret = nf_register_hook(&ip6t_ops[2]);
254         if (ret < 0)
255                 goto cleanup_hook1;
256
257         ret = nf_register_hook(&ip6t_ops[3]);
258         if (ret < 0)
259                 goto cleanup_hook2;
260
261         ret = nf_register_hook(&ip6t_ops[4]);
262         if (ret < 0)
263                 goto cleanup_hook3;
264
265         return ret;
266
267  cleanup_hook3:
268         nf_unregister_hook(&ip6t_ops[3]);
269  cleanup_hook2:
270         nf_unregister_hook(&ip6t_ops[2]);
271  cleanup_hook1:
272         nf_unregister_hook(&ip6t_ops[1]);
273  cleanup_hook0:
274         nf_unregister_hook(&ip6t_ops[0]);
275  cleanup_table:
276         ip6t_unregister_table(&packet_mangler);
277
278         return ret;
279 }
280
281 static void __exit fini(void)
282 {
283         unsigned int i;
284
285         for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++)
286                 nf_unregister_hook(&ip6t_ops[i]);
287
288         ip6t_unregister_table(&packet_mangler);
289 }
290
291 module_init(init);
292 module_exit(fini);