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#include <linux/module.h>
12#include <linux/netfilter_ipv6/ip6_tables.h>
13
14MODULE_LICENSE("GPL");
15MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
16MODULE_DESCRIPTION("ip6tables mangle table");
17
18#define MANGLE_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | \
19			    (1 << NF_IP6_LOCAL_IN) | \
20			    (1 << NF_IP6_FORWARD) | \
21			    (1 << NF_IP6_LOCAL_OUT) | \
22			    (1 << NF_IP6_POST_ROUTING))
23
24#define DEBUGP(x, args...)
25
26static struct
27{
28	struct ip6t_replace repl;
29	struct ip6t_standard entries[5];
30	struct ip6t_error term;
31} initial_table __initdata = {
32	.repl = {
33		.name = "mangle",
34		.valid_hooks = MANGLE_VALID_HOOKS,
35		.num_entries = 6,
36		.size = sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error),
37		.hook_entry = {
38			[NF_IP6_PRE_ROUTING] 	= 0,
39			[NF_IP6_LOCAL_IN]	= sizeof(struct ip6t_standard),
40			[NF_IP6_FORWARD]	= sizeof(struct ip6t_standard) * 2,
41			[NF_IP6_LOCAL_OUT] 	= sizeof(struct ip6t_standard) * 3,
42			[NF_IP6_POST_ROUTING]	= sizeof(struct ip6t_standard) * 4,
43		},
44		.underflow = {
45			[NF_IP6_PRE_ROUTING] 	= 0,
46			[NF_IP6_LOCAL_IN]	= sizeof(struct ip6t_standard),
47			[NF_IP6_FORWARD]	= sizeof(struct ip6t_standard) * 2,
48			[NF_IP6_LOCAL_OUT] 	= sizeof(struct ip6t_standard) * 3,
49			[NF_IP6_POST_ROUTING]	= sizeof(struct ip6t_standard) * 4,
50		},
51	},
52	.entries = {
53		IP6T_STANDARD_INIT(NF_ACCEPT),	/* PRE_ROUTING */
54		IP6T_STANDARD_INIT(NF_ACCEPT),	/* LOCAL_IN */
55		IP6T_STANDARD_INIT(NF_ACCEPT),	/* FORWARD */
56		IP6T_STANDARD_INIT(NF_ACCEPT),	/* LOCAL_OUT */
57		IP6T_STANDARD_INIT(NF_ACCEPT),	/* POST_ROUTING */
58	},
59	.term = IP6T_ERROR_INIT,		/* ERROR */
60};
61
62static struct xt_table packet_mangler = {
63	.name		= "mangle",
64	.valid_hooks	= MANGLE_VALID_HOOKS,
65	.lock		= RW_LOCK_UNLOCKED,
66	.me		= THIS_MODULE,
67	.af		= AF_INET6,
68};
69
70/* The work comes in here from netfilter.c. */
71static unsigned int
72ip6t_route_hook(unsigned int hook,
73	 struct sk_buff **pskb,
74	 const struct net_device *in,
75	 const struct net_device *out,
76	 int (*okfn)(struct sk_buff *))
77{
78	return ip6t_do_table(pskb, hook, in, out, &packet_mangler);
79}
80
81static unsigned int
82ip6t_local_hook(unsigned int hook,
83		   struct sk_buff **pskb,
84		   const struct net_device *in,
85		   const struct net_device *out,
86		   int (*okfn)(struct sk_buff *))
87{
88
89	unsigned int ret;
90	struct in6_addr saddr, daddr;
91	u_int8_t hop_limit;
92	u_int32_t flowlabel, mark;
93
94
95	/* save source/dest address, mark, hoplimit, flowlabel, priority,  */
96	memcpy(&saddr, &ipv6_hdr(*pskb)->saddr, sizeof(saddr));
97	memcpy(&daddr, &ipv6_hdr(*pskb)->daddr, sizeof(daddr));
98	mark = (*pskb)->mark;
99	hop_limit = ipv6_hdr(*pskb)->hop_limit;
100
101	/* flowlabel and prio (includes version, which shouldn't change either */
102	flowlabel = *((u_int32_t *)ipv6_hdr(*pskb));
103
104	ret = ip6t_do_table(pskb, hook, in, out, &packet_mangler);
105
106	if (ret != NF_DROP && ret != NF_STOLEN
107		&& (memcmp(&ipv6_hdr(*pskb)->saddr, &saddr, sizeof(saddr))
108		    || memcmp(&ipv6_hdr(*pskb)->daddr, &daddr, sizeof(daddr))
109		    || (*pskb)->mark != mark
110		    || ipv6_hdr(*pskb)->hop_limit != hop_limit))
111		return ip6_route_me_harder(*pskb) == 0 ? ret : NF_DROP;
112
113	return ret;
114}
115
116static struct nf_hook_ops ip6t_ops[] = {
117	{
118		.hook		= ip6t_route_hook,
119		.owner		= THIS_MODULE,
120		.pf		= PF_INET6,
121		.hooknum	= NF_IP6_PRE_ROUTING,
122		.priority	= NF_IP6_PRI_MANGLE,
123	},
124	{
125		.hook		= ip6t_local_hook,
126		.owner		= THIS_MODULE,
127		.pf		= PF_INET6,
128		.hooknum	= NF_IP6_LOCAL_IN,
129		.priority	= NF_IP6_PRI_MANGLE,
130	},
131	{
132		.hook		= ip6t_route_hook,
133		.owner		= THIS_MODULE,
134		.pf		= PF_INET6,
135		.hooknum	= NF_IP6_FORWARD,
136		.priority	= NF_IP6_PRI_MANGLE,
137	},
138	{
139		.hook		= ip6t_local_hook,
140		.owner		= THIS_MODULE,
141		.pf		= PF_INET6,
142		.hooknum	= NF_IP6_LOCAL_OUT,
143		.priority	= NF_IP6_PRI_MANGLE,
144	},
145	{
146		.hook		= ip6t_route_hook,
147		.owner		= THIS_MODULE,
148		.pf		= PF_INET6,
149		.hooknum	= NF_IP6_POST_ROUTING,
150		.priority	= NF_IP6_PRI_MANGLE,
151	},
152};
153
154static int __init ip6table_mangle_init(void)
155{
156	int ret;
157
158	/* Register table */
159	ret = ip6t_register_table(&packet_mangler, &initial_table.repl);
160	if (ret < 0)
161		return ret;
162
163	/* Register hooks */
164	ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
165	if (ret < 0)
166		goto cleanup_table;
167
168	return ret;
169
170 cleanup_table:
171	ip6t_unregister_table(&packet_mangler);
172	return ret;
173}
174
175static void __exit ip6table_mangle_fini(void)
176{
177	nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
178	ip6t_unregister_table(&packet_mangler);
179}
180
181module_init(ip6table_mangle_init);
182module_exit(ip6table_mangle_fini);
183