Merge master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa
[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         .af             = AF_INET6,
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         /* save source/dest address, nfmark, hoplimit, flowlabel, priority,  */
169         memcpy(&saddr, &(*pskb)->nh.ipv6h->saddr, sizeof(saddr));
170         memcpy(&daddr, &(*pskb)->nh.ipv6h->daddr, sizeof(daddr));
171         nfmark = (*pskb)->nfmark;
172         hop_limit = (*pskb)->nh.ipv6h->hop_limit;
173
174         /* flowlabel and prio (includes version, which shouldn't change either */
175         flowlabel = *((u_int32_t *) (*pskb)->nh.ipv6h);
176
177         ret = ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL);
178
179         if (ret != NF_DROP && ret != NF_STOLEN 
180                 && (memcmp(&(*pskb)->nh.ipv6h->saddr, &saddr, sizeof(saddr))
181                     || memcmp(&(*pskb)->nh.ipv6h->daddr, &daddr, sizeof(daddr))
182                     || (*pskb)->nfmark != nfmark
183                     || (*pskb)->nh.ipv6h->hop_limit != hop_limit)) {
184
185                 /* something which could affect routing has changed */
186
187                 DEBUGP("ip6table_mangle: we'd need to re-route a packet\n");
188         }
189
190         return ret;
191 }
192
193 static struct nf_hook_ops ip6t_ops[] = {
194         {
195                 .hook           = ip6t_route_hook,
196                 .owner          = THIS_MODULE,
197                 .pf             = PF_INET6,
198                 .hooknum        = NF_IP6_PRE_ROUTING,
199                 .priority       = NF_IP6_PRI_MANGLE,
200         },
201         {
202                 .hook           = ip6t_local_hook,
203                 .owner          = THIS_MODULE,
204                 .pf             = PF_INET6,
205                 .hooknum        = NF_IP6_LOCAL_IN,
206                 .priority       = NF_IP6_PRI_MANGLE,
207         },
208         {
209                 .hook           = ip6t_route_hook,
210                 .owner          = THIS_MODULE,
211                 .pf             = PF_INET6,
212                 .hooknum        = NF_IP6_FORWARD,
213                 .priority       = NF_IP6_PRI_MANGLE,
214         },
215         {
216                 .hook           = ip6t_local_hook,
217                 .owner          = THIS_MODULE,
218                 .pf             = PF_INET6,
219                 .hooknum        = NF_IP6_LOCAL_OUT,
220                 .priority       = NF_IP6_PRI_MANGLE,
221         },
222         {
223                 .hook           = ip6t_route_hook,
224                 .owner          = THIS_MODULE,
225                 .pf             = PF_INET6,
226                 .hooknum        = NF_IP6_POST_ROUTING,
227                 .priority       = NF_IP6_PRI_MANGLE,
228         },
229 };
230
231 static int __init ip6table_mangle_init(void)
232 {
233         int ret;
234
235         /* Register table */
236         ret = ip6t_register_table(&packet_mangler, &initial_table.repl);
237         if (ret < 0)
238                 return ret;
239
240         /* Register hooks */
241         ret = nf_register_hook(&ip6t_ops[0]);
242         if (ret < 0)
243                 goto cleanup_table;
244
245         ret = nf_register_hook(&ip6t_ops[1]);
246         if (ret < 0)
247                 goto cleanup_hook0;
248
249         ret = nf_register_hook(&ip6t_ops[2]);
250         if (ret < 0)
251                 goto cleanup_hook1;
252
253         ret = nf_register_hook(&ip6t_ops[3]);
254         if (ret < 0)
255                 goto cleanup_hook2;
256
257         ret = nf_register_hook(&ip6t_ops[4]);
258         if (ret < 0)
259                 goto cleanup_hook3;
260
261         return ret;
262
263  cleanup_hook3:
264         nf_unregister_hook(&ip6t_ops[3]);
265  cleanup_hook2:
266         nf_unregister_hook(&ip6t_ops[2]);
267  cleanup_hook1:
268         nf_unregister_hook(&ip6t_ops[1]);
269  cleanup_hook0:
270         nf_unregister_hook(&ip6t_ops[0]);
271  cleanup_table:
272         ip6t_unregister_table(&packet_mangler);
273
274         return ret;
275 }
276
277 static void __exit ip6table_mangle_fini(void)
278 {
279         unsigned int i;
280
281         for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++)
282                 nf_unregister_hook(&ip6t_ops[i]);
283
284         ip6t_unregister_table(&packet_mangler);
285 }
286
287 module_init(ip6table_mangle_init);
288 module_exit(ip6table_mangle_fini);