ip6table_mangle.c 4.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*
 * IPv6 packet mangling table, a port of the IPv4 mangle table to IPv6
 *
 * Copyright (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
 * Copyright (C) 2000-2004 Netfilter Core Team <coreteam@netfilter.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/module.h>
#include <linux/netfilter_ipv6/ip6_tables.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
MODULE_DESCRIPTION("ip6tables mangle table");

#define MANGLE_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | \
			    (1 << NF_IP6_LOCAL_IN) | \
			    (1 << NF_IP6_FORWARD) | \
			    (1 << NF_IP6_LOCAL_OUT) | \
			    (1 << NF_IP6_POST_ROUTING))

static struct
{
	struct ip6t_replace repl;
	struct ip6t_standard entries[5];
	struct ip6t_error term;
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
} initial_table __initdata = {
	.repl = {
		.name = "mangle",
		.valid_hooks = MANGLE_VALID_HOOKS,
		.num_entries = 6,
		.size = sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error),
		.hook_entry = {
			[NF_IP6_PRE_ROUTING] 	= 0,
			[NF_IP6_LOCAL_IN]	= sizeof(struct ip6t_standard),
			[NF_IP6_FORWARD]	= sizeof(struct ip6t_standard) * 2,
			[NF_IP6_LOCAL_OUT] 	= sizeof(struct ip6t_standard) * 3,
			[NF_IP6_POST_ROUTING]	= sizeof(struct ip6t_standard) * 4,
		},
		.underflow = {
			[NF_IP6_PRE_ROUTING] 	= 0,
			[NF_IP6_LOCAL_IN]	= sizeof(struct ip6t_standard),
			[NF_IP6_FORWARD]	= sizeof(struct ip6t_standard) * 2,
			[NF_IP6_LOCAL_OUT] 	= sizeof(struct ip6t_standard) * 3,
			[NF_IP6_POST_ROUTING]	= sizeof(struct ip6t_standard) * 4,
		},
	},
	.entries = {
		IP6T_STANDARD_INIT(NF_ACCEPT),	/* PRE_ROUTING */
		IP6T_STANDARD_INIT(NF_ACCEPT),	/* LOCAL_IN */
		IP6T_STANDARD_INIT(NF_ACCEPT),	/* FORWARD */
		IP6T_STANDARD_INIT(NF_ACCEPT),	/* LOCAL_OUT */
		IP6T_STANDARD_INIT(NF_ACCEPT),	/* POST_ROUTING */
	},
	.term = IP6T_ERROR_INIT,		/* ERROR */
L
Linus Torvalds 已提交
58 59
};

60
static struct xt_table packet_mangler = {
L
Linus Torvalds 已提交
61 62 63 64
	.name		= "mangle",
	.valid_hooks	= MANGLE_VALID_HOOKS,
	.lock		= RW_LOCK_UNLOCKED,
	.me		= THIS_MODULE,
65
	.af		= AF_INET6,
L
Linus Torvalds 已提交
66 67 68 69 70
};

/* The work comes in here from netfilter.c. */
static unsigned int
ip6t_route_hook(unsigned int hook,
71
	 struct sk_buff *skb,
L
Linus Torvalds 已提交
72 73 74 75
	 const struct net_device *in,
	 const struct net_device *out,
	 int (*okfn)(struct sk_buff *))
{
76
	return ip6t_do_table(skb, hook, in, out, &packet_mangler);
L
Linus Torvalds 已提交
77 78 79 80
}

static unsigned int
ip6t_local_hook(unsigned int hook,
81
		   struct sk_buff *skb,
L
Linus Torvalds 已提交
82 83 84 85 86 87 88 89
		   const struct net_device *in,
		   const struct net_device *out,
		   int (*okfn)(struct sk_buff *))
{

	unsigned int ret;
	struct in6_addr saddr, daddr;
	u_int8_t hop_limit;
T
Thomas Graf 已提交
90
	u_int32_t flowlabel, mark;
L
Linus Torvalds 已提交
91 92 93

#if 0
	/* root is playing with raw sockets. */
94 95
	if (skb->len < sizeof(struct iphdr)
	    || ip_hdrlen(skb) < sizeof(struct iphdr)) {
L
Linus Torvalds 已提交
96 97 98 99 100 101
		if (net_ratelimit())
			printk("ip6t_hook: happy cracking.\n");
		return NF_ACCEPT;
	}
#endif

T
Thomas Graf 已提交
102
	/* save source/dest address, mark, hoplimit, flowlabel, priority,  */
103 104 105 106
	memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr));
	memcpy(&daddr, &ipv6_hdr(skb)->daddr, sizeof(daddr));
	mark = skb->mark;
	hop_limit = ipv6_hdr(skb)->hop_limit;
L
Linus Torvalds 已提交
107 108

	/* flowlabel and prio (includes version, which shouldn't change either */
109
	flowlabel = *((u_int32_t *)ipv6_hdr(skb));
L
Linus Torvalds 已提交
110

111
	ret = ip6t_do_table(skb, hook, in, out, &packet_mangler);
L
Linus Torvalds 已提交
112

113
	if (ret != NF_DROP && ret != NF_STOLEN
114 115 116 117 118
		&& (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr))
		    || memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr))
		    || skb->mark != mark
		    || ipv6_hdr(skb)->hop_limit != hop_limit))
		return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP;
L
Linus Torvalds 已提交
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160

	return ret;
}

static struct nf_hook_ops ip6t_ops[] = {
	{
		.hook		= ip6t_route_hook,
		.owner		= THIS_MODULE,
		.pf		= PF_INET6,
		.hooknum	= NF_IP6_PRE_ROUTING,
		.priority	= NF_IP6_PRI_MANGLE,
	},
	{
		.hook		= ip6t_local_hook,
		.owner		= THIS_MODULE,
		.pf		= PF_INET6,
		.hooknum	= NF_IP6_LOCAL_IN,
		.priority	= NF_IP6_PRI_MANGLE,
	},
	{
		.hook		= ip6t_route_hook,
		.owner		= THIS_MODULE,
		.pf		= PF_INET6,
		.hooknum	= NF_IP6_FORWARD,
		.priority	= NF_IP6_PRI_MANGLE,
	},
	{
		.hook		= ip6t_local_hook,
		.owner		= THIS_MODULE,
		.pf		= PF_INET6,
		.hooknum	= NF_IP6_LOCAL_OUT,
		.priority	= NF_IP6_PRI_MANGLE,
	},
	{
		.hook		= ip6t_route_hook,
		.owner		= THIS_MODULE,
		.pf		= PF_INET6,
		.hooknum	= NF_IP6_POST_ROUTING,
		.priority	= NF_IP6_PRI_MANGLE,
	},
};

161
static int __init ip6table_mangle_init(void)
L
Linus Torvalds 已提交
162 163 164 165 166 167 168 169 170
{
	int ret;

	/* Register table */
	ret = ip6t_register_table(&packet_mangler, &initial_table.repl);
	if (ret < 0)
		return ret;

	/* Register hooks */
171
	ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
L
Linus Torvalds 已提交
172 173 174 175 176 177 178 179 180 181
	if (ret < 0)
		goto cleanup_table;

	return ret;

 cleanup_table:
	ip6t_unregister_table(&packet_mangler);
	return ret;
}

182
static void __exit ip6table_mangle_fini(void)
L
Linus Torvalds 已提交
183
{
184
	nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
L
Linus Torvalds 已提交
185 186 187
	ip6t_unregister_table(&packet_mangler);
}

188 189
module_init(ip6table_mangle_init);
module_exit(ip6table_mangle_fini);