patch-2.3.99-pre2 linux/net/ipv4/netfilter/ip_fw_compat_masq.c
Next file: linux/net/ipv4/netfilter/ip_fw_compat_redir.c
Previous file: linux/net/ipv4/netfilter/ip_fw_compat.c
Back to the patch index
Back to the overall index
- Lines: 289
- Date:
Fri Mar 17 10:56:20 2000
- Orig file:
v2.3.99-pre1/linux/net/ipv4/netfilter/ip_fw_compat_masq.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.3.99-pre1/linux/net/ipv4/netfilter/ip_fw_compat_masq.c linux/net/ipv4/netfilter/ip_fw_compat_masq.c
@@ -0,0 +1,288 @@
+/* Masquerading compatibility layer.
+
+ Note that there are no restrictions on other programs binding to
+ ports 61000:65095 (in 2.0 and 2.2 they get EADDRINUSE). Just DONT
+ DO IT.
+ */
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/icmp.h>
+#include <linux/udp.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/version.h>
+#include <net/route.h>
+
+#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
+#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
+
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_core.h>
+#include <linux/netfilter_ipv4/listhelp.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+unsigned int
+do_masquerade(struct sk_buff **pskb, const struct net_device *dev)
+{
+ struct iphdr *iph = (*pskb)->nh.iph;
+ struct ip_nat_info *info;
+ enum ip_conntrack_info ctinfo;
+ struct ip_conntrack *ct;
+ unsigned int ret;
+
+ /* Sorry, only ICMP, TCP and UDP. */
+ if (iph->protocol != IPPROTO_ICMP
+ && iph->protocol != IPPROTO_TCP
+ && iph->protocol != IPPROTO_UDP)
+ return NF_DROP;
+
+ /* Feed it to connection tracking; in fact we're in NF_IP_FORWARD,
+ but connection tracking doesn't expect that */
+ ret = ip_conntrack_in(NF_IP_POST_ROUTING, pskb, dev, NULL, NULL);
+ if (ret != NF_ACCEPT) {
+ DEBUGP("ip_conntrack_in returned %u.\n", ret);
+ return ret;
+ }
+
+ ct = ip_conntrack_get(*pskb, &ctinfo);
+
+ if (!ct) {
+ DEBUGP("ip_conntrack_in set to invalid conntrack.\n");
+ return NF_DROP;
+ }
+
+ info = &ct->nat.info;
+
+ WRITE_LOCK(&ip_nat_lock);
+ /* Setup the masquerade, if not already */
+ if (!info->initialized) {
+ u_int32_t newsrc;
+ struct rtable *rt;
+ struct ip_nat_multi_range range;
+
+ /* Pass 0 instead of saddr, since it's going to be changed
+ anyway. */
+ if (ip_route_output(&rt, iph->daddr, 0, 0, 0) != 0) {
+ DEBUGP("ipnat_rule_masquerade: Can't reroute.\n");
+ return NF_DROP;
+ }
+ newsrc = inet_select_addr(rt->u.dst.dev, rt->rt_gateway,
+ RT_SCOPE_UNIVERSE);
+ ip_rt_put(rt);
+ range = ((struct ip_nat_multi_range)
+ { 1,
+ {{IP_NAT_RANGE_MAP_IPS|IP_NAT_RANGE_PROTO_SPECIFIED,
+ newsrc, newsrc,
+ { htons(61000) }, { htons(65095) } } } });
+
+ ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
+ place_in_hashes(ct, info);
+ info->initialized = 1;
+ } else
+ DEBUGP("Masquerading already done on this conn.\n");
+ WRITE_UNLOCK(&ip_nat_lock);
+
+ return do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb);
+}
+
+unsigned int
+check_for_demasq(struct sk_buff **pskb)
+{
+ struct ip_conntrack_tuple tuple;
+ struct iphdr *iph = (*pskb)->nh.iph;
+ struct ip_conntrack_protocol *protocol;
+ struct ip_conntrack_tuple_hash *h;
+ enum ip_conntrack_info ctinfo;
+ int ret;
+
+ protocol = find_proto(iph->protocol);
+
+ /* We don't feed packets to conntrack system unless we know
+ they're part of an connection already established by an
+ explicit masq command. */
+ switch (iph->protocol) {
+ case IPPROTO_ICMP:
+ /* ICMP errors. */
+ if (icmp_error_track(*pskb)) {
+ /* If it is valid, tranlsate it */
+ if ((*pskb)->nfct) {
+ struct ip_conntrack *ct
+ = (struct ip_conntrack *)
+ (*pskb)->nfct->master;
+ enum ip_conntrack_dir dir;
+
+ if ((*pskb)->nfct-ct->infos >= IP_CT_IS_REPLY)
+ dir = IP_CT_DIR_REPLY;
+ else
+ dir = IP_CT_DIR_ORIGINAL;
+
+ icmp_reply_translation(*pskb,
+ ct,
+ NF_IP_PRE_ROUTING,
+ dir);
+ }
+ return NF_ACCEPT;
+ }
+ /* Fall thru... */
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ if (!get_tuple(iph, (*pskb)->len, &tuple, protocol)) {
+ printk("ip_fw_compat_masq: Couldn't get tuple\n");
+ return NF_ACCEPT;
+ }
+ break;
+
+ default:
+ /* Not ours... */
+ return NF_ACCEPT;
+ }
+ h = ip_conntrack_find_get(&tuple, NULL);
+
+ /* MUST be found, and MUST be reply. */
+ if (h && DIRECTION(h) == 1) {
+ ret = ip_conntrack_in(NF_IP_PRE_ROUTING, pskb,
+ NULL, NULL, NULL);
+
+ /* Put back the reference gained from find_get */
+ nf_conntrack_put(&h->ctrack->infos[0]);
+ if (ret == NF_ACCEPT) {
+ struct ip_conntrack *ct;
+ ct = ip_conntrack_get(*pskb, &ctinfo);
+
+ if (ct) {
+ struct ip_nat_info *info = &ct->nat.info;
+
+ do_bindings(ct, ctinfo, info,
+ NF_IP_PRE_ROUTING,
+ pskb);
+ } else
+ printk("ip_fw_compat_masq: conntrack"
+ " didn't like\n");
+ }
+ } else {
+ if (h)
+ /* Put back the reference gained from find_get */
+ nf_conntrack_put(&h->ctrack->infos[0]);
+ ret = NF_ACCEPT;
+ }
+
+ return ret;
+}
+
+int ip_fw_masq_timeouts(void *user, int len)
+{
+ printk("Sorry: masquerading timeouts set 5DAYS/2MINS/60SECS\n");
+ return 0;
+}
+
+static const char *masq_proto_name(u_int16_t protonum)
+{
+ switch (protonum) {
+ case IPPROTO_TCP: return "TCP";
+ case IPPROTO_UDP: return "UDP";
+ case IPPROTO_ICMP: return "ICMP";
+ default: return "MORE-CAFFIENE-FOR-RUSTY";
+ }
+}
+
+static unsigned int
+print_masq(char *buffer, const struct ip_conntrack *conntrack)
+{
+ char temp[129];
+
+ /* This is for backwards compatibility, but ick!.
+ We should never export jiffies to userspace.
+ */
+ sprintf(temp,"%s %08X:%04X %08X:%04X %04X %08X %6d %6d %7lu",
+ masq_proto_name(conntrack->tuplehash[0].tuple.dst.protonum),
+ ntohl(conntrack->tuplehash[0].tuple.src.ip),
+ ntohs(conntrack->tuplehash[0].tuple.src.u.all),
+ ntohl(conntrack->tuplehash[0].tuple.dst.ip),
+ ntohs(conntrack->tuplehash[0].tuple.dst.u.all),
+ ntohs(conntrack->tuplehash[1].tuple.dst.u.all),
+ /* Sorry, no init_seq, delta or previous_delta (yet). */
+ 0, 0, 0,
+ conntrack->timeout.expires - jiffies);
+
+ return sprintf(buffer, "%-127s\n", temp);
+}
+
+/* Returns true when finished. */
+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)
+{
+ unsigned int newlen;
+
+ IP_NF_ASSERT(hash->ctrack);
+
+ /* Only count originals */
+ if (DIRECTION(hash))
+ return 0;
+
+ if ((*upto)++ < offset)
+ return 0;
+
+ newlen = print_masq(buffer + *len, hash->ctrack);
+ if (*len + newlen > maxlen)
+ return 1;
+ else *len += newlen;
+
+ return 0;
+}
+
+/* Everything in the hash is masqueraded. */
+static int
+masq_procinfo(char *buffer, char **start, off_t offset, int length)
+{
+ unsigned int i;
+ int len = 0;
+ off_t upto = 0;
+
+ READ_LOCK(&ip_conntrack_lock);
+ /* Traverse hash; print originals then reply. */
+ for (i = 0; i < ip_conntrack_htable_size; i++) {
+ if (LIST_FIND(&ip_conntrack_hash[i], masq_iterate,
+ struct ip_conntrack_tuple_hash *,
+ buffer, offset, &upto, &len, length))
+ break;
+ }
+ READ_UNLOCK(&ip_conntrack_lock);
+
+ /* `start' hack - see fs/proc/generic.c line ~165 */
+ *start = (char *)((unsigned int)upto - offset);
+ return len;
+}
+
+int __init masq_init(void)
+{
+ int ret;
+
+ ret = ip_conntrack_init();
+ if (ret == 0) {
+ ret = ip_nat_init();
+ if (ret == 0)
+ proc_net_create("ip_masquerade", 0, masq_procinfo);
+ else
+ ip_conntrack_cleanup();
+ }
+
+ return ret;
+}
+
+void masq_cleanup(void)
+{
+ ip_nat_cleanup();
+ ip_conntrack_cleanup();
+ proc_net_remove("ip_masquerade");
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)