Linux-2.6.12-rc2
[safe/jmp/linux-2.6] / 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         .valid_hooks    = MANGLE_VALID_HOOKS,
128         .lock           = RW_LOCK_UNLOCKED,
129         .me             = THIS_MODULE,
130 };
131
132 /* The work comes in here from netfilter.c. */
133 static unsigned int
134 ip6t_route_hook(unsigned int hook,
135          struct sk_buff **pskb,
136          const struct net_device *in,
137          const struct net_device *out,
138          int (*okfn)(struct sk_buff *))
139 {
140         return ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL);
141 }
142
143 static unsigned int
144 ip6t_local_hook(unsigned int hook,
145                    struct sk_buff **pskb,
146                    const struct net_device *in,
147                    const struct net_device *out,
148                    int (*okfn)(struct sk_buff *))
149 {
150
151         unsigned long nfmark;
152         unsigned int ret;
153         struct in6_addr saddr, daddr;
154         u_int8_t hop_limit;
155         u_int32_t flowlabel;
156
157 #if 0
158         /* root is playing with raw sockets. */
159         if ((*pskb)->len < sizeof(struct iphdr)
160             || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
161                 if (net_ratelimit())
162                         printk("ip6t_hook: happy cracking.\n");
163                 return NF_ACCEPT;
164         }
165 #endif
166
167         /* save source/dest address, nfmark, hoplimit, flowlabel, priority,  */
168         memcpy(&saddr, &(*pskb)->nh.ipv6h->saddr, sizeof(saddr));
169         memcpy(&daddr, &(*pskb)->nh.ipv6h->daddr, sizeof(daddr));
170         nfmark = (*pskb)->nfmark;
171         hop_limit = (*pskb)->nh.ipv6h->hop_limit;
172
173         /* flowlabel and prio (includes version, which shouldn't change either */
174         flowlabel = *((u_int32_t *) (*pskb)->nh.ipv6h);
175
176         ret = ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL);
177
178         if (ret != NF_DROP && ret != NF_STOLEN 
179                 && (memcmp(&(*pskb)->nh.ipv6h->saddr, &saddr, sizeof(saddr))
180                     || memcmp(&(*pskb)->nh.ipv6h->daddr, &daddr, sizeof(daddr))
181                     || (*pskb)->nfmark != nfmark
182                     || (*pskb)->nh.ipv6h->hop_limit != hop_limit)) {
183
184                 /* something which could affect routing has changed */
185
186                 DEBUGP("ip6table_mangle: we'd need to re-route a packet\n");
187         }
188
189         return ret;
190 }
191
192 static struct nf_hook_ops ip6t_ops[] = {
193         {
194                 .hook           = ip6t_route_hook,
195                 .owner          = THIS_MODULE,
196                 .pf             = PF_INET6,
197                 .hooknum        = NF_IP6_PRE_ROUTING,
198                 .priority       = NF_IP6_PRI_MANGLE,
199         },
200         {
201                 .hook           = ip6t_local_hook,
202                 .owner          = THIS_MODULE,
203                 .pf             = PF_INET6,
204                 .hooknum        = NF_IP6_LOCAL_IN,
205                 .priority       = NF_IP6_PRI_MANGLE,
206         },
207         {
208                 .hook           = ip6t_route_hook,
209                 .owner          = THIS_MODULE,
210                 .pf             = PF_INET6,
211                 .hooknum        = NF_IP6_FORWARD,
212                 .priority       = NF_IP6_PRI_MANGLE,
213         },
214         {
215                 .hook           = ip6t_local_hook,
216                 .owner          = THIS_MODULE,
217                 .pf             = PF_INET6,
218                 .hooknum        = NF_IP6_LOCAL_OUT,
219                 .priority       = NF_IP6_PRI_MANGLE,
220         },
221         {
222                 .hook           = ip6t_route_hook,
223                 .owner          = THIS_MODULE,
224                 .pf             = PF_INET6,
225                 .hooknum        = NF_IP6_POST_ROUTING,
226                 .priority       = NF_IP6_PRI_MANGLE,
227         },
228 };
229
230 static int __init init(void)
231 {
232         int ret;
233
234         /* Register table */
235         ret = ip6t_register_table(&packet_mangler, &initial_table.repl);
236         if (ret < 0)
237                 return ret;
238
239         /* Register hooks */
240         ret = nf_register_hook(&ip6t_ops[0]);
241         if (ret < 0)
242                 goto cleanup_table;
243
244         ret = nf_register_hook(&ip6t_ops[1]);
245         if (ret < 0)
246                 goto cleanup_hook0;
247
248         ret = nf_register_hook(&ip6t_ops[2]);
249         if (ret < 0)
250                 goto cleanup_hook1;
251
252         ret = nf_register_hook(&ip6t_ops[3]);
253         if (ret < 0)
254                 goto cleanup_hook2;
255
256         ret = nf_register_hook(&ip6t_ops[4]);
257         if (ret < 0)
258                 goto cleanup_hook3;
259
260         return ret;
261
262  cleanup_hook3:
263         nf_unregister_hook(&ip6t_ops[3]);
264  cleanup_hook2:
265         nf_unregister_hook(&ip6t_ops[2]);
266  cleanup_hook1:
267         nf_unregister_hook(&ip6t_ops[1]);
268  cleanup_hook0:
269         nf_unregister_hook(&ip6t_ops[0]);
270  cleanup_table:
271         ip6t_unregister_table(&packet_mangler);
272
273         return ret;
274 }
275
276 static void __exit fini(void)
277 {
278         unsigned int i;
279
280         for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++)
281                 nf_unregister_hook(&ip6t_ops[i]);
282
283         ip6t_unregister_table(&packet_mangler);
284 }
285
286 module_init(init);
287 module_exit(fini);