Import 2.3.99pre4-2
[davej-history.git] / net / ipv4 / netfilter / ip_fw_compat_masq.c
blob96bdc9d8d675b17945a554d79c2d06c3fa98b0bf
1 /* Masquerading compatibility layer.
3 Note that there are no restrictions on other programs binding to
4 ports 61000:65095 (in 2.0 and 2.2 they get EADDRINUSE). Just DONT
5 DO IT.
6 */
7 #include <linux/skbuff.h>
8 #include <linux/in.h>
9 #include <linux/ip.h>
10 #include <linux/icmp.h>
11 #include <linux/udp.h>
12 #include <linux/netfilter_ipv4.h>
13 #include <linux/netdevice.h>
14 #include <linux/inetdevice.h>
15 #include <linux/proc_fs.h>
16 #include <linux/version.h>
17 #include <net/route.h>
19 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
20 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
22 #include <linux/netfilter_ipv4/ip_conntrack.h>
23 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
24 #include <linux/netfilter_ipv4/ip_nat.h>
25 #include <linux/netfilter_ipv4/ip_nat_core.h>
26 #include <linux/netfilter_ipv4/listhelp.h>
28 #if 0
29 #define DEBUGP printk
30 #else
31 #define DEBUGP(format, args...)
32 #endif
34 unsigned int
35 do_masquerade(struct sk_buff **pskb, const struct net_device *dev)
37 struct iphdr *iph = (*pskb)->nh.iph;
38 struct ip_nat_info *info;
39 enum ip_conntrack_info ctinfo;
40 struct ip_conntrack *ct;
41 unsigned int ret;
43 /* Sorry, only ICMP, TCP and UDP. */
44 if (iph->protocol != IPPROTO_ICMP
45 && iph->protocol != IPPROTO_TCP
46 && iph->protocol != IPPROTO_UDP)
47 return NF_DROP;
49 /* Feed it to connection tracking; in fact we're in NF_IP_FORWARD,
50 but connection tracking doesn't expect that */
51 ret = ip_conntrack_in(NF_IP_POST_ROUTING, pskb, dev, NULL, NULL);
52 if (ret != NF_ACCEPT) {
53 DEBUGP("ip_conntrack_in returned %u.\n", ret);
54 return ret;
57 ct = ip_conntrack_get(*pskb, &ctinfo);
59 if (!ct) {
60 DEBUGP("ip_conntrack_in set to invalid conntrack.\n");
61 return NF_DROP;
64 info = &ct->nat.info;
66 WRITE_LOCK(&ip_nat_lock);
67 /* Setup the masquerade, if not already */
68 if (!info->initialized) {
69 u_int32_t newsrc;
70 struct rtable *rt;
71 struct ip_nat_multi_range range;
73 /* Pass 0 instead of saddr, since it's going to be changed
74 anyway. */
75 if (ip_route_output(&rt, iph->daddr, 0, 0, 0) != 0) {
76 DEBUGP("ipnat_rule_masquerade: Can't reroute.\n");
77 return NF_DROP;
79 newsrc = inet_select_addr(rt->u.dst.dev, rt->rt_gateway,
80 RT_SCOPE_UNIVERSE);
81 ip_rt_put(rt);
82 range = ((struct ip_nat_multi_range)
83 { 1,
84 {{IP_NAT_RANGE_MAP_IPS|IP_NAT_RANGE_PROTO_SPECIFIED,
85 newsrc, newsrc,
86 { htons(61000) }, { htons(65095) } } } });
88 ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
89 place_in_hashes(ct, info);
90 info->initialized = 1;
91 } else
92 DEBUGP("Masquerading already done on this conn.\n");
93 WRITE_UNLOCK(&ip_nat_lock);
95 return do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb);
98 unsigned int
99 check_for_demasq(struct sk_buff **pskb)
101 struct ip_conntrack_tuple tuple;
102 struct iphdr *iph = (*pskb)->nh.iph;
103 struct ip_conntrack_protocol *protocol;
104 struct ip_conntrack_tuple_hash *h;
105 enum ip_conntrack_info ctinfo;
106 int ret;
108 protocol = find_proto(iph->protocol);
110 /* We don't feed packets to conntrack system unless we know
111 they're part of an connection already established by an
112 explicit masq command. */
113 switch (iph->protocol) {
114 case IPPROTO_ICMP:
115 /* ICMP errors. */
116 if (icmp_error_track(*pskb)) {
117 /* If it is valid, tranlsate it */
118 if ((*pskb)->nfct) {
119 struct ip_conntrack *ct
120 = (struct ip_conntrack *)
121 (*pskb)->nfct->master;
122 enum ip_conntrack_dir dir;
124 if ((*pskb)->nfct-ct->infos >= IP_CT_IS_REPLY)
125 dir = IP_CT_DIR_REPLY;
126 else
127 dir = IP_CT_DIR_ORIGINAL;
129 icmp_reply_translation(*pskb,
131 NF_IP_PRE_ROUTING,
132 dir);
134 return NF_ACCEPT;
136 /* Fall thru... */
137 case IPPROTO_TCP:
138 case IPPROTO_UDP:
139 if (!get_tuple(iph, (*pskb)->len, &tuple, protocol)) {
140 printk("ip_fw_compat_masq: Couldn't get tuple\n");
141 return NF_ACCEPT;
143 break;
145 default:
146 /* Not ours... */
147 return NF_ACCEPT;
149 h = ip_conntrack_find_get(&tuple, NULL);
151 /* MUST be found, and MUST be reply. */
152 if (h && DIRECTION(h) == 1) {
153 ret = ip_conntrack_in(NF_IP_PRE_ROUTING, pskb,
154 NULL, NULL, NULL);
156 /* Put back the reference gained from find_get */
157 nf_conntrack_put(&h->ctrack->infos[0]);
158 if (ret == NF_ACCEPT) {
159 struct ip_conntrack *ct;
160 ct = ip_conntrack_get(*pskb, &ctinfo);
162 if (ct) {
163 struct ip_nat_info *info = &ct->nat.info;
165 do_bindings(ct, ctinfo, info,
166 NF_IP_PRE_ROUTING,
167 pskb);
168 } else
169 printk("ip_fw_compat_masq: conntrack"
170 " didn't like\n");
172 } else {
173 if (h)
174 /* Put back the reference gained from find_get */
175 nf_conntrack_put(&h->ctrack->infos[0]);
176 ret = NF_ACCEPT;
179 return ret;
182 int ip_fw_masq_timeouts(void *user, int len)
184 printk("Sorry: masquerading timeouts set 5DAYS/2MINS/60SECS\n");
185 return 0;
188 static const char *masq_proto_name(u_int16_t protonum)
190 switch (protonum) {
191 case IPPROTO_TCP: return "TCP";
192 case IPPROTO_UDP: return "UDP";
193 case IPPROTO_ICMP: return "ICMP";
194 default: return "MORE-CAFFIENE-FOR-RUSTY";
198 static unsigned int
199 print_masq(char *buffer, const struct ip_conntrack *conntrack)
201 char temp[129];
203 /* This is for backwards compatibility, but ick!.
204 We should never export jiffies to userspace.
206 sprintf(temp,"%s %08X:%04X %08X:%04X %04X %08X %6d %6d %7lu",
207 masq_proto_name(conntrack->tuplehash[0].tuple.dst.protonum),
208 ntohl(conntrack->tuplehash[0].tuple.src.ip),
209 ntohs(conntrack->tuplehash[0].tuple.src.u.all),
210 ntohl(conntrack->tuplehash[0].tuple.dst.ip),
211 ntohs(conntrack->tuplehash[0].tuple.dst.u.all),
212 ntohs(conntrack->tuplehash[1].tuple.dst.u.all),
213 /* Sorry, no init_seq, delta or previous_delta (yet). */
214 0, 0, 0,
215 conntrack->timeout.expires - jiffies);
217 return sprintf(buffer, "%-127s\n", temp);
220 /* Returns true when finished. */
221 static int
222 masq_iterate(const struct ip_conntrack_tuple_hash *hash,
223 char *buffer, off_t offset, off_t *upto,
224 unsigned int *len, unsigned int maxlen)
226 unsigned int newlen;
228 IP_NF_ASSERT(hash->ctrack);
230 /* Only count originals */
231 if (DIRECTION(hash))
232 return 0;
234 if ((*upto)++ < offset)
235 return 0;
237 newlen = print_masq(buffer + *len, hash->ctrack);
238 if (*len + newlen > maxlen)
239 return 1;
240 else *len += newlen;
242 return 0;
245 /* Everything in the hash is masqueraded. */
246 static int
247 masq_procinfo(char *buffer, char **start, off_t offset, int length)
249 unsigned int i;
250 int len = 0;
251 off_t upto = 0;
253 READ_LOCK(&ip_conntrack_lock);
254 /* Traverse hash; print originals then reply. */
255 for (i = 0; i < ip_conntrack_htable_size; i++) {
256 if (LIST_FIND(&ip_conntrack_hash[i], masq_iterate,
257 struct ip_conntrack_tuple_hash *,
258 buffer, offset, &upto, &len, length))
259 break;
261 READ_UNLOCK(&ip_conntrack_lock);
263 /* `start' hack - see fs/proc/generic.c line ~165 */
264 *start = (char *)((unsigned int)upto - offset);
265 return len;
268 int __init masq_init(void)
270 int ret;
272 ret = ip_conntrack_init();
273 if (ret == 0) {
274 ret = ip_nat_init();
275 if (ret == 0)
276 proc_net_create("ip_masquerade", 0, masq_procinfo);
277 else
278 ip_conntrack_cleanup();
281 return ret;
284 void masq_cleanup(void)
286 ip_nat_cleanup();
287 ip_conntrack_cleanup();
288 proc_net_remove("ip_masquerade");