1/* Masquerading compatibility layer.
2
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 <linux/module.h>
18#include <net/route.h>
19
20#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
21#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
22
23#include <linux/netfilter_ipv4/ip_conntrack.h>
24#include <linux/netfilter_ipv4/ip_conntrack_core.h>
25#include <linux/netfilter_ipv4/ip_nat.h>
26#include <linux/netfilter_ipv4/ip_nat_core.h>
27#include <linux/netfilter_ipv4/listhelp.h>
28
29#define DEBUGP(format, args...)
30
31unsigned int
32do_masquerade(struct sk_buff **pskb, const struct net_device *dev)
33{
34	struct iphdr *iph = (*pskb)->nh.iph;
35	struct ip_nat_info *info;
36	enum ip_conntrack_info ctinfo;
37	struct ip_conntrack *ct;
38	unsigned int ret;
39
40	/* Sorry, only ICMP, TCP and UDP. */
41	if (iph->protocol != IPPROTO_ICMP
42	    && iph->protocol != IPPROTO_TCP
43	    && iph->protocol != IPPROTO_UDP)
44		return NF_DROP;
45
46	/* Feed it to connection tracking; in fact we're in NF_IP_FORWARD,
47           but connection tracking doesn't expect that */
48	ret = ip_conntrack_in(NF_IP_POST_ROUTING, pskb, dev, NULL, NULL);
49	if (ret != NF_ACCEPT) {
50		DEBUGP("ip_conntrack_in returned %u.\n", ret);
51		return ret;
52	}
53
54	ct = ip_conntrack_get(*pskb, &ctinfo);
55
56	if (!ct) {
57		DEBUGP("ip_conntrack_in set to invalid conntrack.\n");
58		return NF_DROP;
59	}
60
61	info = &ct->nat.info;
62
63	WRITE_LOCK(&ip_nat_lock);
64	/* Setup the masquerade, if not already */
65	if (!info->initialized) {
66		u_int32_t newsrc;
67		struct rtable *rt;
68		struct ip_nat_multi_range range;
69
70		/* Pass 0 instead of saddr, since it's going to be changed
71		   anyway. */
72		if (ip_route_output(&rt, iph->daddr, 0, 0, 0) != 0) {
73			DEBUGP("ipnat_rule_masquerade: Can't reroute.\n");
74			return NF_DROP;
75		}
76		newsrc = inet_select_addr(rt->u.dst.dev, rt->rt_gateway,
77					  RT_SCOPE_UNIVERSE);
78		ip_rt_put(rt);
79		range = ((struct ip_nat_multi_range)
80			 { 1,
81			   {{IP_NAT_RANGE_MAP_IPS|IP_NAT_RANGE_PROTO_SPECIFIED,
82			     newsrc, newsrc,
83			     { htons(61000) }, { htons(65095) } } } });
84
85		ret = ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
86		if (ret != NF_ACCEPT) {
87			WRITE_UNLOCK(&ip_nat_lock);
88			return ret;
89		}
90
91		place_in_hashes(ct, info);
92		info->initialized = 1;
93	} else
94		DEBUGP("Masquerading already done on this conn.\n");
95	WRITE_UNLOCK(&ip_nat_lock);
96
97	return do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb);
98}
99
100void
101check_for_masq_error(struct sk_buff *skb)
102{
103	enum ip_conntrack_info ctinfo;
104	struct ip_conntrack *ct;
105
106	ct = ip_conntrack_get(skb, &ctinfo);
107	/* Wouldn't be here if not tracked already => masq'ed ICMP
108           ping or error related to masq'd connection */
109	IP_NF_ASSERT(ct);
110	if (ctinfo == IP_CT_RELATED) {
111		icmp_reply_translation(skb, ct, NF_IP_PRE_ROUTING,
112				       CTINFO2DIR(ctinfo));
113		icmp_reply_translation(skb, ct, NF_IP_POST_ROUTING,
114				       CTINFO2DIR(ctinfo));
115	}
116}
117
118unsigned int
119check_for_demasq(struct sk_buff **pskb)
120{
121	struct ip_conntrack_tuple tuple;
122	struct iphdr *iph = (*pskb)->nh.iph;
123	struct ip_conntrack_protocol *protocol;
124	struct ip_conntrack_tuple_hash *h;
125	enum ip_conntrack_info ctinfo;
126	struct ip_conntrack *ct;
127	int ret;
128
129	protocol = ip_ct_find_proto(iph->protocol);
130
131	/* We don't feed packets to conntrack system unless we know
132           they're part of an connection already established by an
133           explicit masq command. */
134	switch (iph->protocol) {
135	case IPPROTO_ICMP:
136		/* ICMP errors. */
137		ct = icmp_error_track(*pskb, &ctinfo, NF_IP_PRE_ROUTING);
138		if (ct) {
139			/* We only do SNAT in the compatibility layer.
140			   So we can manipulate ICMP errors from
141			   server here (== DNAT).  Do SNAT icmp manips
142			   in POST_ROUTING handling. */
143			if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
144				icmp_reply_translation(*pskb, ct,
145						       NF_IP_PRE_ROUTING,
146						       CTINFO2DIR(ctinfo));
147				icmp_reply_translation(*pskb, ct,
148						       NF_IP_POST_ROUTING,
149						       CTINFO2DIR(ctinfo));
150			}
151			return NF_ACCEPT;
152		}
153		/* Fall thru... */
154	case IPPROTO_TCP:
155	case IPPROTO_UDP:
156		IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
157
158		if (!get_tuple(iph, (*pskb)->len, &tuple, protocol)) {
159			if (net_ratelimit())
160				printk("ip_fw_compat_masq: Can't get tuple\n");
161			return NF_ACCEPT;
162		}
163		break;
164
165	default:
166		/* Not ours... */
167		return NF_ACCEPT;
168	}
169	h = ip_conntrack_find_get(&tuple, NULL);
170
171	/* MUST be found, and MUST be reply. */
172	if (h && DIRECTION(h) == 1) {
173		ret = ip_conntrack_in(NF_IP_PRE_ROUTING, pskb,
174				      NULL, NULL, NULL);
175
176		/* Put back the reference gained from find_get */
177		nf_conntrack_put(&h->ctrack->infos[0]);
178		if (ret == NF_ACCEPT) {
179			struct ip_conntrack *ct;
180			ct = ip_conntrack_get(*pskb, &ctinfo);
181
182			if (ct) {
183				struct ip_nat_info *info = &ct->nat.info;
184
185				do_bindings(ct, ctinfo, info,
186					    NF_IP_PRE_ROUTING,
187					    pskb);
188			} else
189				if (net_ratelimit())
190					printk("ip_fw_compat_masq: conntrack"
191					       " didn't like\n");
192		}
193	} else {
194		if (h)
195			/* Put back the reference gained from find_get */
196			nf_conntrack_put(&h->ctrack->infos[0]);
197		ret = NF_ACCEPT;
198	}
199
200	return ret;
201}
202
203int ip_fw_masq_timeouts(void *user, int len)
204{
205	printk("Sorry: masquerading timeouts set 5DAYS/2MINS/60SECS\n");
206	return 0;
207}
208
209static const char *masq_proto_name(u_int16_t protonum)
210{
211	switch (protonum) {
212	case IPPROTO_TCP: return "TCP";
213	case IPPROTO_UDP: return "UDP";
214	case IPPROTO_ICMP: return "ICMP";
215	default: return "MORE-CAFFIENE-FOR-RUSTY";
216	}
217}
218
219static unsigned int
220print_masq(char *buffer, const struct ip_conntrack *conntrack)
221{
222	char temp[129];
223
224	/* This is for backwards compatibility, but ick!.
225	   We should never export jiffies to userspace.
226	*/
227	sprintf(temp,"%s %08X:%04X %08X:%04X %04X %08X %6d %6d %7lu",
228		masq_proto_name(conntrack->tuplehash[0].tuple.dst.protonum),
229		ntohl(conntrack->tuplehash[0].tuple.src.ip),
230		ntohs(conntrack->tuplehash[0].tuple.src.u.all),
231		ntohl(conntrack->tuplehash[0].tuple.dst.ip),
232		ntohs(conntrack->tuplehash[0].tuple.dst.u.all),
233		ntohs(conntrack->tuplehash[1].tuple.dst.u.all),
234		/* Sorry, no init_seq, delta or previous_delta (yet). */
235		0, 0, 0,
236		conntrack->timeout.expires - jiffies);
237
238	return sprintf(buffer, "%-127s\n", temp);
239}
240
241/* Returns true when finished. */
242static int
243masq_iterate(const struct ip_conntrack_tuple_hash *hash,
244	     char *buffer, off_t offset, off_t *upto,
245	     unsigned int *len, unsigned int maxlen)
246{
247	unsigned int newlen;
248
249	IP_NF_ASSERT(hash->ctrack);
250
251	/* Only count originals */
252	if (DIRECTION(hash))
253		return 0;
254
255	if ((*upto)++ < offset)
256		return 0;
257
258	newlen = print_masq(buffer + *len, hash->ctrack);
259	if (*len + newlen > maxlen)
260		return 1;
261	else *len += newlen;
262
263	return 0;
264}
265
266/* Everything in the hash is masqueraded. */
267static int
268masq_procinfo(char *buffer, char **start, off_t offset, int length)
269{
270	unsigned int i;
271	int len = 0;
272	off_t upto = 1;
273
274	/* Header: first record */
275	if (offset == 0) {
276		char temp[128];
277
278		sprintf(temp,
279			"Prc FromIP   FPrt ToIP     TPrt Masq Init-seq  Delta PDelta Expires (free=0,0,0)");
280		len = sprintf(buffer, "%-127s\n", temp);
281		offset = 1;
282	}
283
284	READ_LOCK(&ip_conntrack_lock);
285	/* Traverse hash; print originals then reply. */
286	for (i = 0; i < ip_conntrack_htable_size; i++) {
287		if (LIST_FIND(&ip_conntrack_hash[i], masq_iterate,
288			      struct ip_conntrack_tuple_hash *,
289			      buffer, offset, &upto, &len, length))
290			break;
291	}
292	READ_UNLOCK(&ip_conntrack_lock);
293
294	/* `start' hack - see fs/proc/generic.c line ~165 */
295	*start = (char *)((unsigned int)upto - offset);
296	return len;
297}
298
299int __init masq_init(void)
300{
301	int ret;
302	struct proc_dir_entry *proc;
303
304	ret = ip_conntrack_init();
305	if (ret == 0) {
306		ret = ip_nat_init();
307		if (ret == 0) {
308			proc = proc_net_create("ip_masquerade",
309					       0, masq_procinfo);
310			if (proc)
311				proc->owner = THIS_MODULE;
312			else {
313				ip_nat_cleanup();
314				ip_conntrack_cleanup();
315				ret = -ENOMEM;
316			}
317		} else
318			ip_conntrack_cleanup();
319	}
320
321	return ret;
322}
323
324void masq_cleanup(void)
325{
326	ip_nat_cleanup();
327	ip_conntrack_cleanup();
328	proc_net_remove("ip_masquerade");
329}
330