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 DON'T
8 /* (C) 1999-2001 Paul `Rusty' Russell
9 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
16 #include <linux/skbuff.h>
19 #include <linux/icmp.h>
20 #include <linux/udp.h>
21 #include <linux/netfilter_ipv4.h>
22 #include <linux/netdevice.h>
23 #include <linux/inetdevice.h>
24 #include <linux/proc_fs.h>
25 #include <linux/module.h>
26 #include <net/route.h>
29 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
30 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
32 #include <linux/netfilter_ipv4/ip_conntrack.h>
33 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
34 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
35 #include <linux/netfilter_ipv4/ip_nat.h>
36 #include <linux/netfilter_ipv4/ip_nat_core.h>
37 #include <linux/netfilter_ipv4/listhelp.h>
38 #include "ip_fw_compat.h"
43 #define DEBUGP(format, args...)
47 do_masquerade(struct sk_buff **pskb, const struct net_device *dev)
49 struct ip_nat_info *info;
50 enum ip_conntrack_info ctinfo;
51 struct ip_conntrack *ct;
54 /* Sorry, only ICMP, TCP and UDP. */
55 if ((*pskb)->nh.iph->protocol != IPPROTO_ICMP
56 && (*pskb)->nh.iph->protocol != IPPROTO_TCP
57 && (*pskb)->nh.iph->protocol != IPPROTO_UDP)
60 /* Feed it to connection tracking; in fact we're in NF_IP_FORWARD,
61 but connection tracking doesn't expect that */
62 ret = ip_conntrack_in(NF_IP_POST_ROUTING, pskb, dev, NULL, NULL);
63 if (ret != NF_ACCEPT) {
64 DEBUGP("ip_conntrack_in returned %u.\n", ret);
68 ct = ip_conntrack_get(*pskb, &ctinfo);
71 DEBUGP("ip_conntrack_in set to invalid conntrack.\n");
77 WRITE_LOCK(&ip_nat_lock);
78 /* Setup the masquerade, if not already */
79 if (!info->initialized) {
81 struct flowi fl = { .nl_u = { .ip4_u = { .daddr = (*pskb)->nh.iph->daddr } } };
83 struct ip_nat_multi_range range;
85 /* Pass 0 instead of saddr, since it's going to be changed
87 if (ip_route_output_key(&rt, &fl) != 0) {
88 DEBUGP("ipnat_rule_masquerade: Can't reroute.\n");
91 newsrc = inet_select_addr(rt->u.dst.dev, rt->rt_gateway,
94 range = ((struct ip_nat_multi_range)
96 {{IP_NAT_RANGE_MAP_IPS|IP_NAT_RANGE_PROTO_SPECIFIED,
98 { htons(61000) }, { htons(65095) } } } });
100 ret = ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
101 if (ret != NF_ACCEPT) {
102 WRITE_UNLOCK(&ip_nat_lock);
106 DEBUGP("Masquerading already done on this conn.\n");
107 WRITE_UNLOCK(&ip_nat_lock);
109 return do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb);
113 check_for_masq_error(struct sk_buff **pskb)
115 enum ip_conntrack_info ctinfo;
116 struct ip_conntrack *ct;
118 ct = ip_conntrack_get(*pskb, &ctinfo);
119 /* Wouldn't be here if not tracked already => masq'ed ICMP
120 ping or error related to masq'd connection */
122 if (ctinfo == IP_CT_RELATED) {
123 icmp_reply_translation(pskb, ct, NF_IP_PRE_ROUTING,
125 icmp_reply_translation(pskb, ct, NF_IP_POST_ROUTING,
131 check_for_demasq(struct sk_buff **pskb)
133 struct ip_conntrack_tuple tuple;
134 struct ip_conntrack_protocol *protocol;
135 struct ip_conntrack_tuple_hash *h;
136 enum ip_conntrack_info ctinfo;
137 struct ip_conntrack *ct;
140 protocol = ip_ct_find_proto((*pskb)->nh.iph->protocol);
142 /* We don't feed packets to conntrack system unless we know
143 they're part of an connection already established by an
144 explicit masq command. */
145 switch ((*pskb)->nh.iph->protocol) {
148 protocol->error(*pskb, &ctinfo, NF_IP_PRE_ROUTING);
149 ct = (struct ip_conntrack *)(*pskb)->nfct;
151 /* We only do SNAT in the compatibility layer.
152 So we can manipulate ICMP errors from
153 server here (== DNAT). Do SNAT icmp manips
154 in POST_ROUTING handling. */
155 if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
156 icmp_reply_translation(pskb, ct,
159 icmp_reply_translation(pskb, ct,
168 IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
170 if (!ip_ct_get_tuple((*pskb)->nh.iph, *pskb,
171 (*pskb)->nh.iph->ihl*4, &tuple, protocol)) {
173 printk("ip_fw_compat_masq: Can't get tuple\n");
182 h = ip_conntrack_find_get(&tuple, NULL);
184 /* MUST be found, and MUST be reply. */
185 if (h && DIRECTION(h) == 1) {
186 ret = ip_conntrack_in(NF_IP_PRE_ROUTING, pskb,
189 /* Put back the reference gained from find_get */
190 nf_conntrack_put(&h->ctrack->ct_general);
191 if (ret == NF_ACCEPT) {
192 struct ip_conntrack *ct;
193 ct = ip_conntrack_get(*pskb, &ctinfo);
196 struct ip_nat_info *info = &ct->nat.info;
198 do_bindings(ct, ctinfo, info,
203 printk("ip_fw_compat_masq: conntrack"
208 /* Put back the reference gained from find_get */
209 nf_conntrack_put(&h->ctrack->ct_general);
216 int ip_fw_masq_timeouts(void *user, int len)
218 printk("Sorry: masquerading timeouts set 5DAYS/2MINS/60SECS\n");
222 static const char *masq_proto_name(u_int16_t protonum)
225 case IPPROTO_TCP: return "TCP";
226 case IPPROTO_UDP: return "UDP";
227 case IPPROTO_ICMP: return "ICMP";
228 default: return "MORE-CAFFEINE-FOR-RUSTY";
233 print_masq(char *buffer, const struct ip_conntrack *conntrack)
237 /* This is for backwards compatibility, but ick!.
238 We should never export jiffies to userspace.
240 sprintf(temp,"%s %08X:%04X %08X:%04X %04X %08X %6d %6d %7lu",
241 masq_proto_name(conntrack->tuplehash[0].tuple.dst.protonum),
242 ntohl(conntrack->tuplehash[0].tuple.src.ip),
243 ntohs(conntrack->tuplehash[0].tuple.src.u.all),
244 ntohl(conntrack->tuplehash[0].tuple.dst.ip),
245 ntohs(conntrack->tuplehash[0].tuple.dst.u.all),
246 ntohs(conntrack->tuplehash[1].tuple.dst.u.all),
247 /* Sorry, no init_seq, delta or previous_delta (yet). */
249 conntrack->timeout.expires - jiffies);
251 return sprintf(buffer, "%-127s\n", temp);
254 /* Returns true when finished. */
256 masq_iterate(const struct ip_conntrack_tuple_hash *hash,
257 char *buffer, off_t offset, off_t *upto,
258 unsigned int *len, unsigned int maxlen)
262 IP_NF_ASSERT(hash->ctrack);
264 /* Only count originals */
268 if ((*upto)++ < offset)
271 newlen = print_masq(buffer + *len, hash->ctrack);
272 if (*len + newlen > maxlen)
279 /* Everything in the hash is masqueraded. */
281 masq_procinfo(char *buffer, char **start, off_t offset, int length)
287 /* Header: first record */
292 "Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires (free=0,0,0)");
293 len = sprintf(buffer, "%-127s\n", temp);
297 READ_LOCK(&ip_conntrack_lock);
298 /* Traverse hash; print originals then reply. */
299 for (i = 0; i < ip_conntrack_htable_size; i++) {
300 if (LIST_FIND(&ip_conntrack_hash[i], masq_iterate,
301 struct ip_conntrack_tuple_hash *,
302 buffer, offset, &upto, &len, length))
305 READ_UNLOCK(&ip_conntrack_lock);
307 /* `start' hack - see fs/proc/generic.c line ~165 */
308 *start = (char *)((unsigned int)upto - offset);
312 int __init masq_init(void)
315 struct proc_dir_entry *proc;
317 ret = ip_conntrack_init();
321 proc = proc_net_create("ip_masquerade",
324 proc->owner = THIS_MODULE;
327 ip_conntrack_cleanup();
331 ip_conntrack_cleanup();
337 void masq_cleanup(void)
340 ip_conntrack_cleanup();
341 proc_net_remove("ip_masquerade");