diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /net/ipv4/netfilter/ipt_MASQUERADE.c |
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'net/ipv4/netfilter/ipt_MASQUERADE.c')
-rw-r--r-- | net/ipv4/netfilter/ipt_MASQUERADE.c | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c new file mode 100644 index 00000000000..57e9f6cf1c3 --- /dev/null +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c | |||
@@ -0,0 +1,207 @@ | |||
1 | /* Masquerade. Simple mapping which alters range to a local IP address | ||
2 | (depending on route). */ | ||
3 | |||
4 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
5 | * (C) 2002-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 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/types.h> | ||
14 | #include <linux/ip.h> | ||
15 | #include <linux/timer.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/netfilter.h> | ||
18 | #include <net/protocol.h> | ||
19 | #include <net/ip.h> | ||
20 | #include <net/checksum.h> | ||
21 | #include <linux/netfilter_ipv4.h> | ||
22 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
23 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
24 | |||
25 | MODULE_LICENSE("GPL"); | ||
26 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | ||
27 | MODULE_DESCRIPTION("iptables MASQUERADE target module"); | ||
28 | |||
29 | #if 0 | ||
30 | #define DEBUGP printk | ||
31 | #else | ||
32 | #define DEBUGP(format, args...) | ||
33 | #endif | ||
34 | |||
35 | /* Lock protects masq region inside conntrack */ | ||
36 | static DECLARE_RWLOCK(masq_lock); | ||
37 | |||
38 | /* FIXME: Multiple targets. --RR */ | ||
39 | static int | ||
40 | masquerade_check(const char *tablename, | ||
41 | const struct ipt_entry *e, | ||
42 | void *targinfo, | ||
43 | unsigned int targinfosize, | ||
44 | unsigned int hook_mask) | ||
45 | { | ||
46 | const struct ip_nat_multi_range_compat *mr = targinfo; | ||
47 | |||
48 | if (strcmp(tablename, "nat") != 0) { | ||
49 | DEBUGP("masquerade_check: bad table `%s'.\n", tablename); | ||
50 | return 0; | ||
51 | } | ||
52 | if (targinfosize != IPT_ALIGN(sizeof(*mr))) { | ||
53 | DEBUGP("masquerade_check: size %u != %u.\n", | ||
54 | targinfosize, sizeof(*mr)); | ||
55 | return 0; | ||
56 | } | ||
57 | if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) { | ||
58 | DEBUGP("masquerade_check: bad hooks %x.\n", hook_mask); | ||
59 | return 0; | ||
60 | } | ||
61 | if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) { | ||
62 | DEBUGP("masquerade_check: bad MAP_IPS.\n"); | ||
63 | return 0; | ||
64 | } | ||
65 | if (mr->rangesize != 1) { | ||
66 | DEBUGP("masquerade_check: bad rangesize %u.\n", mr->rangesize); | ||
67 | return 0; | ||
68 | } | ||
69 | return 1; | ||
70 | } | ||
71 | |||
72 | static unsigned int | ||
73 | masquerade_target(struct sk_buff **pskb, | ||
74 | const struct net_device *in, | ||
75 | const struct net_device *out, | ||
76 | unsigned int hooknum, | ||
77 | const void *targinfo, | ||
78 | void *userinfo) | ||
79 | { | ||
80 | struct ip_conntrack *ct; | ||
81 | enum ip_conntrack_info ctinfo; | ||
82 | const struct ip_nat_multi_range_compat *mr; | ||
83 | struct ip_nat_range newrange; | ||
84 | struct rtable *rt; | ||
85 | u_int32_t newsrc; | ||
86 | |||
87 | IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); | ||
88 | |||
89 | /* FIXME: For the moment, don't do local packets, breaks | ||
90 | testsuite for 2.3.49 --RR */ | ||
91 | if ((*pskb)->sk) | ||
92 | return NF_ACCEPT; | ||
93 | |||
94 | ct = ip_conntrack_get(*pskb, &ctinfo); | ||
95 | IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED | ||
96 | || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); | ||
97 | |||
98 | mr = targinfo; | ||
99 | rt = (struct rtable *)(*pskb)->dst; | ||
100 | newsrc = inet_select_addr(out, rt->rt_gateway, RT_SCOPE_UNIVERSE); | ||
101 | if (!newsrc) { | ||
102 | printk("MASQUERADE: %s ate my IP address\n", out->name); | ||
103 | return NF_DROP; | ||
104 | } | ||
105 | |||
106 | WRITE_LOCK(&masq_lock); | ||
107 | ct->nat.masq_index = out->ifindex; | ||
108 | WRITE_UNLOCK(&masq_lock); | ||
109 | |||
110 | /* Transfer from original range. */ | ||
111 | newrange = ((struct ip_nat_range) | ||
112 | { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS, | ||
113 | newsrc, newsrc, | ||
114 | mr->range[0].min, mr->range[0].max }); | ||
115 | |||
116 | /* Hand modified range to generic setup. */ | ||
117 | return ip_nat_setup_info(ct, &newrange, hooknum); | ||
118 | } | ||
119 | |||
120 | static inline int | ||
121 | device_cmp(struct ip_conntrack *i, void *ifindex) | ||
122 | { | ||
123 | int ret; | ||
124 | |||
125 | READ_LOCK(&masq_lock); | ||
126 | ret = (i->nat.masq_index == (int)(long)ifindex); | ||
127 | READ_UNLOCK(&masq_lock); | ||
128 | |||
129 | return ret; | ||
130 | } | ||
131 | |||
132 | static int masq_device_event(struct notifier_block *this, | ||
133 | unsigned long event, | ||
134 | void *ptr) | ||
135 | { | ||
136 | struct net_device *dev = ptr; | ||
137 | |||
138 | if (event == NETDEV_DOWN) { | ||
139 | /* Device was downed. Search entire table for | ||
140 | conntracks which were associated with that device, | ||
141 | and forget them. */ | ||
142 | IP_NF_ASSERT(dev->ifindex != 0); | ||
143 | |||
144 | ip_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex); | ||
145 | } | ||
146 | |||
147 | return NOTIFY_DONE; | ||
148 | } | ||
149 | |||
150 | static int masq_inet_event(struct notifier_block *this, | ||
151 | unsigned long event, | ||
152 | void *ptr) | ||
153 | { | ||
154 | struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev; | ||
155 | |||
156 | if (event == NETDEV_DOWN) { | ||
157 | /* IP address was deleted. Search entire table for | ||
158 | conntracks which were associated with that device, | ||
159 | and forget them. */ | ||
160 | IP_NF_ASSERT(dev->ifindex != 0); | ||
161 | |||
162 | ip_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex); | ||
163 | } | ||
164 | |||
165 | return NOTIFY_DONE; | ||
166 | } | ||
167 | |||
168 | static struct notifier_block masq_dev_notifier = { | ||
169 | .notifier_call = masq_device_event, | ||
170 | }; | ||
171 | |||
172 | static struct notifier_block masq_inet_notifier = { | ||
173 | .notifier_call = masq_inet_event, | ||
174 | }; | ||
175 | |||
176 | static struct ipt_target masquerade = { | ||
177 | .name = "MASQUERADE", | ||
178 | .target = masquerade_target, | ||
179 | .checkentry = masquerade_check, | ||
180 | .me = THIS_MODULE, | ||
181 | }; | ||
182 | |||
183 | static int __init init(void) | ||
184 | { | ||
185 | int ret; | ||
186 | |||
187 | ret = ipt_register_target(&masquerade); | ||
188 | |||
189 | if (ret == 0) { | ||
190 | /* Register for device down reports */ | ||
191 | register_netdevice_notifier(&masq_dev_notifier); | ||
192 | /* Register IP address change reports */ | ||
193 | register_inetaddr_notifier(&masq_inet_notifier); | ||
194 | } | ||
195 | |||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | static void __exit fini(void) | ||
200 | { | ||
201 | ipt_unregister_target(&masquerade); | ||
202 | unregister_netdevice_notifier(&masq_dev_notifier); | ||
203 | unregister_inetaddr_notifier(&masq_inet_notifier); | ||
204 | } | ||
205 | |||
206 | module_init(init); | ||
207 | module_exit(fini); | ||