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
7 #include <linux/skbuff.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>
31 #define DEBUGP(format, args...)
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
;
43 /* Sorry, only ICMP, TCP and UDP. */
44 if (iph
->protocol
!= IPPROTO_ICMP
45 && iph
->protocol
!= IPPROTO_TCP
46 && iph
->protocol
!= IPPROTO_UDP
)
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
);
57 ct
= ip_conntrack_get(*pskb
, &ctinfo
);
60 DEBUGP("ip_conntrack_in set to invalid conntrack.\n");
66 WRITE_LOCK(&ip_nat_lock
);
67 /* Setup the masquerade, if not already */
68 if (!info
->initialized
) {
71 struct ip_nat_multi_range range
;
73 /* Pass 0 instead of saddr, since it's going to be changed
75 if (ip_route_output(&rt
, iph
->daddr
, 0, 0, 0) != 0) {
76 DEBUGP("ipnat_rule_masquerade: Can't reroute.\n");
79 newsrc
= inet_select_addr(rt
->u
.dst
.dev
, rt
->rt_gateway
,
82 range
= ((struct ip_nat_multi_range
)
84 {{IP_NAT_RANGE_MAP_IPS
|IP_NAT_RANGE_PROTO_SPECIFIED
,
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;
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
);
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
;
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
) {
116 if (icmp_error_track(*pskb
)) {
117 /* If it is valid, tranlsate it */
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
;
127 dir
= IP_CT_DIR_ORIGINAL
;
129 icmp_reply_translation(*pskb
,
139 if (!get_tuple(iph
, (*pskb
)->len
, &tuple
, protocol
)) {
140 printk("ip_fw_compat_masq: Couldn't get tuple\n");
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
,
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
);
163 struct ip_nat_info
*info
= &ct
->nat
.info
;
165 do_bindings(ct
, ctinfo
, info
,
169 printk("ip_fw_compat_masq: conntrack"
174 /* Put back the reference gained from find_get */
175 nf_conntrack_put(&h
->ctrack
->infos
[0]);
182 int ip_fw_masq_timeouts(void *user
, int len
)
184 printk("Sorry: masquerading timeouts set 5DAYS/2MINS/60SECS\n");
188 static const char *masq_proto_name(u_int16_t 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";
199 print_masq(char *buffer
, const struct ip_conntrack
*conntrack
)
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). */
215 conntrack
->timeout
.expires
- jiffies
);
217 return sprintf(buffer
, "%-127s\n", temp
);
220 /* Returns true when finished. */
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
)
228 IP_NF_ASSERT(hash
->ctrack
);
230 /* Only count originals */
234 if ((*upto
)++ < offset
)
237 newlen
= print_masq(buffer
+ *len
, hash
->ctrack
);
238 if (*len
+ newlen
> maxlen
)
245 /* Everything in the hash is masqueraded. */
247 masq_procinfo(char *buffer
, char **start
, off_t offset
, int length
)
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
))
261 READ_UNLOCK(&ip_conntrack_lock
);
263 /* `start' hack - see fs/proc/generic.c line ~165 */
264 *start
= (char *)((unsigned int)upto
- offset
);
268 int __init
masq_init(void)
272 ret
= ip_conntrack_init();
276 proc_net_create("ip_masquerade", 0, masq_procinfo
);
278 ip_conntrack_cleanup();
284 void masq_cleanup(void)
287 ip_conntrack_cleanup();
288 proc_net_remove("ip_masquerade");