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