1 /* Masquerade. Simple mapping which alters range to a local IP address
2 (depending on route). */
4 /* (C) 1999-2001 Paul `Rusty' Russell
5 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
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.
12 #include <linux/config.h>
13 #include <linux/types.h>
15 #include <linux/timer.h>
16 #include <linux/module.h>
17 #include <linux/netfilter.h>
18 #include <net/protocol.h>
19 #include <net/checksum.h>
20 #include <linux/netfilter_ipv4.h>
21 #include <linux/netfilter_ipv4/ip_nat_rule.h>
22 #include <linux/netfilter_ipv4/ip_tables.h>
24 MODULE_LICENSE("GPL");
25 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
26 MODULE_DESCRIPTION("iptables MASQUERADE target module");
31 #define DEBUGP(format, args...)
34 /* Lock protects masq region inside conntrack */
35 static DECLARE_RWLOCK(masq_lock);
37 /* FIXME: Multiple targets. --RR */
39 masquerade_check(const char *tablename,
40 const struct ipt_entry *e,
42 unsigned int targinfosize,
43 unsigned int hook_mask)
45 const struct ip_nat_multi_range *mr = targinfo;
47 if (strcmp(tablename, "nat") != 0) {
48 DEBUGP("masquerade_check: bad table `%s'.\n", tablename);
51 if (targinfosize != IPT_ALIGN(sizeof(*mr))) {
52 DEBUGP("masquerade_check: size %u != %u.\n",
53 targinfosize, sizeof(*mr));
56 if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) {
57 DEBUGP("masquerade_check: bad hooks %x.\n", hook_mask);
60 if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
61 DEBUGP("masquerade_check: bad MAP_IPS.\n");
64 if (mr->rangesize != 1) {
65 DEBUGP("masquerade_check: bad rangesize %u.\n", mr->rangesize);
72 masquerade_target(struct sk_buff **pskb,
73 const struct net_device *in,
74 const struct net_device *out,
79 struct ip_conntrack *ct;
80 enum ip_conntrack_info ctinfo;
81 const struct ip_nat_multi_range *mr;
82 struct ip_nat_multi_range newrange;
86 IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
88 /* FIXME: For the moment, don't do local packets, breaks
89 testsuite for 2.3.49 --RR */
93 ct = ip_conntrack_get(*pskb, &ctinfo);
94 IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW
95 || ctinfo == IP_CT_RELATED));
100 struct flowi fl = { .nl_u = { .ip4_u =
101 { .daddr = (*pskb)->nh.iph->daddr,
102 .tos = (RT_TOS((*pskb)->nh.iph->tos) |
104 #ifdef CONFIG_IP_ROUTE_FWMARK
105 .fwmark = (*pskb)->nfmark
108 if (ip_route_output_key(&rt, &fl) != 0) {
109 /* Funky routing can do this. */
112 " No route: Rusty's brain broke!\n");
115 if (rt->u.dst.dev != out) {
118 " Route sent us somewhere else.\n");
125 DEBUGP("newsrc = %u.%u.%u.%u\n", NIPQUAD(newsrc));
128 WRITE_LOCK(&masq_lock);
129 ct->nat.masq_index = out->ifindex;
130 WRITE_UNLOCK(&masq_lock);
132 /* Transfer from original range. */
133 newrange = ((struct ip_nat_multi_range)
134 { 1, { { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS,
136 mr->range[0].min, mr->range[0].max } } });
138 /* Hand modified range to generic setup. */
139 return ip_nat_setup_info(ct, &newrange, hooknum);
143 device_cmp(const struct ip_conntrack *i, void *_ina)
146 struct in_ifaddr *ina = _ina;
148 READ_LOCK(&masq_lock);
149 /* If it's masquerading out this interface with a different address,
150 or we don't know the new address of this interface. */
151 if (i->nat.masq_index == ina->ifa_dev->dev->ifindex
152 && i->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip != ina->ifa_address)
154 READ_UNLOCK(&masq_lock);
159 static int masq_inet_event(struct notifier_block *this,
163 /* For some configurations, interfaces often come back with
164 * the same address. If not, clean up old conntrack
166 if (event == NETDEV_UP)
167 ip_ct_selective_cleanup(device_cmp, ptr);
172 static struct notifier_block masq_inet_notifier = {
173 .notifier_call = masq_inet_event,
176 static struct ipt_target masquerade = {
177 .name = "MASQUERADE",
178 .target = masquerade_target,
179 .checkentry = masquerade_check,
183 static int __init init(void)
187 ret = ipt_register_target(&masquerade);
190 /* Register IP address change reports */
191 register_inetaddr_notifier(&masq_inet_notifier);
196 static void __exit fini(void)
198 ipt_unregister_target(&masquerade);
199 unregister_inetaddr_notifier(&masq_inet_notifier);