1 /* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
9 #include <linux/types.h>
10 #include <linux/module.h>
11 #include <linux/atomic.h>
12 #include <linux/inetdevice.h>
14 #include <linux/timer.h>
15 #include <linux/netfilter.h>
16 #include <net/protocol.h>
18 #include <net/checksum.h>
19 #include <net/route.h>
20 #include <linux/netfilter_ipv4.h>
21 #include <linux/netfilter/x_tables.h>
22 #include <net/netfilter/nf_nat.h>
23 #include <net/netfilter/ipv4/nf_nat_masquerade.h>
26 nf_nat_masquerade_ipv4(struct sk_buff
*skb
, unsigned int hooknum
,
27 const struct nf_nat_range
*range
,
28 const struct net_device
*out
)
31 struct nf_conn_nat
*nat
;
32 enum ip_conntrack_info ctinfo
;
33 struct nf_nat_range newrange
;
34 const struct rtable
*rt
;
37 NF_CT_ASSERT(hooknum
== NF_INET_POST_ROUTING
);
39 ct
= nf_ct_get(skb
, &ctinfo
);
41 NF_CT_ASSERT(ct
&& (ctinfo
== IP_CT_NEW
|| ctinfo
== IP_CT_RELATED
||
42 ctinfo
== IP_CT_RELATED_REPLY
));
44 /* Source address is 0.0.0.0 - locally generated packet that is
45 * probably not supposed to be masqueraded.
47 if (ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
.src
.u3
.ip
== 0)
51 nh
= rt_nexthop(rt
, ip_hdr(skb
)->daddr
);
52 newsrc
= inet_select_addr(out
, nh
, RT_SCOPE_UNIVERSE
);
54 pr_info("%s ate my IP address\n", out
->name
);
58 nat
= nf_ct_nat_ext_add(ct
);
60 nat
->masq_index
= out
->ifindex
;
62 /* Transfer from original range. */
63 memset(&newrange
.min_addr
, 0, sizeof(newrange
.min_addr
));
64 memset(&newrange
.max_addr
, 0, sizeof(newrange
.max_addr
));
65 newrange
.flags
= range
->flags
| NF_NAT_RANGE_MAP_IPS
;
66 newrange
.min_addr
.ip
= newsrc
;
67 newrange
.max_addr
.ip
= newsrc
;
68 newrange
.min_proto
= range
->min_proto
;
69 newrange
.max_proto
= range
->max_proto
;
71 /* Hand modified range to generic setup. */
72 return nf_nat_setup_info(ct
, &newrange
, NF_NAT_MANIP_SRC
);
74 EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4
);
76 static int device_cmp(struct nf_conn
*i
, void *ifindex
)
78 const struct nf_conn_nat
*nat
= nfct_nat(i
);
82 if (nf_ct_l3num(i
) != NFPROTO_IPV4
)
84 return nat
->masq_index
== (int)(long)ifindex
;
87 static int masq_device_event(struct notifier_block
*this,
91 const struct net_device
*dev
= netdev_notifier_info_to_dev(ptr
);
92 struct net
*net
= dev_net(dev
);
94 if (event
== NETDEV_DOWN
) {
95 /* Device was downed. Search entire table for
96 * conntracks which were associated with that device,
99 NF_CT_ASSERT(dev
->ifindex
!= 0);
101 nf_ct_iterate_cleanup_net(net
, device_cmp
,
102 (void *)(long)dev
->ifindex
, 0, 0);
108 static int masq_inet_event(struct notifier_block
*this,
112 struct in_device
*idev
= ((struct in_ifaddr
*)ptr
)->ifa_dev
;
113 struct netdev_notifier_info info
;
115 /* The masq_dev_notifier will catch the case of the device going
116 * down. So if the inetdev is dead and being destroyed we have
117 * no work to do. Otherwise this is an individual address removal
118 * and we have to perform the flush.
123 netdev_notifier_info_init(&info
, idev
->dev
);
124 return masq_device_event(this, event
, &info
);
127 static struct notifier_block masq_dev_notifier
= {
128 .notifier_call
= masq_device_event
,
131 static struct notifier_block masq_inet_notifier
= {
132 .notifier_call
= masq_inet_event
,
135 static atomic_t masquerade_notifier_refcount
= ATOMIC_INIT(0);
137 void nf_nat_masquerade_ipv4_register_notifier(void)
139 /* check if the notifier was already set */
140 if (atomic_inc_return(&masquerade_notifier_refcount
) > 1)
143 /* Register for device down reports */
144 register_netdevice_notifier(&masq_dev_notifier
);
145 /* Register IP address change reports */
146 register_inetaddr_notifier(&masq_inet_notifier
);
148 EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4_register_notifier
);
150 void nf_nat_masquerade_ipv4_unregister_notifier(void)
152 /* check if the notifier still has clients */
153 if (atomic_dec_return(&masquerade_notifier_refcount
) > 0)
156 unregister_netdevice_notifier(&masq_dev_notifier
);
157 unregister_inetaddr_notifier(&masq_inet_notifier
);
159 EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4_unregister_notifier
);
161 MODULE_LICENSE("GPL");
162 MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");