patch-2.1.124 linux/net/ipv4/ip_masq_user.c

Next file: linux/net/ipv4/ip_masq_vdolive.c
Previous file: linux/net/ipv4/ip_masq_raudio.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.123/linux/net/ipv4/ip_masq_user.c linux/net/ipv4/ip_masq_user.c
@@ -0,0 +1,467 @@
+/*
+ *	IP_MASQ_USER user space control module
+ *
+ *
+ *	$Id: ip_masq_user.c,v 1.1 1998/08/29 23:51:08 davem Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <asm/system.h>
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/inet.h>
+#include <linux/init.h>
+#include <net/protocol.h>
+#include <net/icmp.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/checksum.h>
+#include <net/ip_masq.h>
+#include <net/ip_masq_mod.h>
+#include <linux/sysctl.h>
+#include <linux/ip_fw.h>
+
+#include <linux/ip_masq.h>
+
+/*
+ *	Debug level
+ */
+static int debug=0;
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(debug, "i");
+
+/*
+static int check_5uple (struct ip_masq_user *ums) {
+	return 0;
+}
+*/
+static void masq_user_k2u(const struct ip_masq *ms, struct ip_masq_user *ums)
+{
+	ums->protocol = ms->protocol;
+	ums->daddr = ms->daddr;
+	ums->dport = ms->dport;
+	ums->maddr = ms->maddr;
+	ums->mport = ms->mport;
+	ums->saddr = ms->saddr;
+	ums->sport = ms->sport;
+	ums->timeout = ms->timeout;
+}
+
+
+static int ip_masq_user_maddr(struct ip_masq_user *ums)
+{
+	struct device *dev;
+	struct rtable *rt;
+	int ret = -EINVAL;
+	u32 rt_daddr, rt_saddr;
+	u32 tos;
+
+	/*
+	 *	Did specify masq address.
+	 */
+	if (ums->maddr)
+		return 0;
+
+	/*
+	 *	Select address to use for routing query
+	 */
+
+	rt_daddr = ums->rt_daddr? ums->rt_daddr : ums->daddr;
+	rt_saddr = ums->rt_saddr? ums->rt_saddr : ums->saddr;
+
+
+	/*
+	 *	No address for routing, cannot continue
+	 */
+	if (rt_daddr == 0) {
+		IP_MASQ_DEBUG(1-debug, "cannot setup maddr with daddr=%lX, rt_addr=%lX\n",
+			     ntohl(ums->daddr), ntohl(ums->rt_daddr));
+		return -EINVAL;
+	}
+
+	/*
+	 *	Find out rt device 
+	 */
+
+	rt_saddr = 0; 
+	tos = RT_TOS(ums->ip_tos) | RTO_CONN;
+
+	if ((ret=ip_route_output(&rt, rt_daddr, rt_saddr, tos, 0 /* dev */))) {
+		IP_MASQ_DEBUG(0-debug, "could not setup maddr for routing daddr=%lX, saddr=%lX\n",
+			     ntohl(rt_daddr), ntohl(rt_saddr));
+		return ret;
+	}
+	dev = rt->u.dst.dev;
+	ums->maddr = ip_masq_select_addr(dev, rt->rt_gateway, RT_SCOPE_UNIVERSE);
+
+	IP_MASQ_DEBUG(1-debug, "did setup maddr=%lX\n", ntohl(ums->maddr));
+	ip_rt_put(rt);
+	return 0;
+}
+
+/*
+ *	Create new entry (from uspace)
+ */
+static int ip_masq_user_new(struct ip_masq_user *ums)
+{
+	struct ip_masq *ms = NULL;
+	unsigned mflags = 0;
+	int ret;
+
+	if (masq_proto_num (ums->protocol) == -1) {
+		return EPROTONOSUPPORT;
+	}
+
+	if (ums->dport == 0) {
+		ums->flags |= IP_MASQ_USER_F_LISTEN;
+	}
+
+	if (ums->flags | IP_MASQ_USER_F_LISTEN) {
+		if ((ums->saddr == 0) || (ums->sport == 0)) {
+			return EINVAL;
+		}
+		mflags |= (IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR);
+
+	}
+
+	if ((ret = ip_masq_user_maddr(ums)) < 0) {
+		return -ret;
+	}
+
+	mflags |= IP_MASQ_F_USER;
+	ms = ip_masq_new(ums->protocol, 
+			ums->maddr, ums->mport, 
+			ums->saddr, ums->sport,
+			ums->daddr, ums->dport,
+			mflags);
+	
+	if (ms == NULL) {
+		/*
+		 *	FIXME: ip_masq_new() should return errno
+		 */
+		return EBUSY;
+	}
+
+	/*
+	 *	Setup timeouts for this new entry
+	 */
+
+	if (ums->timeout) {
+		ms->timeout = ums->timeout;
+	} else if (ums->flags | IP_MASQ_USER_F_LISTEN) {
+		ip_masq_listen(ms);
+	}
+
+	masq_user_k2u(ms, ums);
+	ip_masq_put(ms);
+	return 0;
+}
+
+/* 
+ *	Delete existing entry
+ */
+static int ip_masq_user_del(struct ip_masq_user *ums)
+{
+	struct ip_masq *ms=NULL;
+
+	if (masq_proto_num (ums->protocol) == -1) {
+		return EPROTONOSUPPORT;
+	}
+	start_bh_atomic();
+	if (ums->mport && ums->maddr) {
+		ms = ip_masq_in_get(ums->protocol, 
+				ums->daddr, ums->dport, 
+				ums->maddr, ums->mport);
+		end_bh_atomic();
+	} else if (ums->sport && ums->saddr) {
+		ms = ip_masq_out_get(ums->protocol,
+				ums->saddr, ums->sport,
+				ums->daddr, ums->dport);
+		end_bh_atomic();
+	} else
+		return EINVAL;	
+	
+	if (ms == NULL) {
+		return ESRCH;
+	}
+
+	/*
+	 *	got (locked) entry, setup almost tiny timeout :) and  
+	 *	give away
+	 *
+	 *	FIXME: should use something better than S_CLOSE
+	 */
+	ms->timeout = IP_MASQ_S_CLOSE;
+
+	masq_user_k2u(ms, ums);
+	ip_masq_put(ms);
+	return 0;
+}
+
+static struct ip_masq * ip_masq_user_locked_get (struct ip_masq_user *ums, int *err)
+{
+	struct ip_masq *ms=NULL;
+	if (masq_proto_num (ums->protocol) == -1) {
+		*err = EPROTONOSUPPORT;
+	}
+
+	start_bh_atomic();
+	if (ums->mport && ums->maddr) {
+		ms = ip_masq_in_get(ums->protocol, 
+				ums->daddr, ums->dport, 
+				ums->maddr, ums->mport);
+		end_bh_atomic();
+	} else if (ums->sport && ums->saddr) {
+		ms = ip_masq_out_get(ums->protocol,
+				ums->saddr, ums->sport,
+				ums->daddr, ums->dport);
+		end_bh_atomic();
+	} else
+		*err = EINVAL;	
+	
+	if (ms == NULL) *err = ESRCH;
+	return ms;
+}
+
+/*
+ * 	Get existing entry (complete full tunnel info)
+ */
+static int ip_masq_user_get(struct ip_masq_user *ums)
+{
+	struct ip_masq *ms=NULL;
+	int err;
+
+	ms = ip_masq_user_locked_get(ums, &err);
+	if (ms == NULL)
+		return err;
+
+	masq_user_k2u(ms, ums);
+
+	ip_masq_put(ms);
+	return 0;
+}
+
+/* 
+ *	Set (some, valid) entry parameters
+ */
+static int ip_masq_user_set(struct ip_masq_user *ums)
+{
+	struct ip_masq *ms = NULL;
+	int err;
+
+	ms = ip_masq_user_locked_get(ums, &err);
+	if (ms == NULL)
+		return err;
+	
+	/*
+	 *	FIXME: must allow selecting what you want to set
+	 */
+	ms->timeout = ums->timeout;
+
+	masq_user_k2u(ms, ums);
+	
+	ip_masq_put(ms);
+	return 0;
+}
+
+
+/*
+ *	Entry point
+ *	ret value:
+ *		<0   err
+ *		==0  ok
+ *		>0   ok, copy to user
+ */
+static int ip_masq_user_ctl(int optname, struct ip_masq_ctl *mctl, int optlen)
+{
+	struct ip_masq_user *ums = &mctl->u.user;
+	int ret = EINVAL;
+	int arglen = optlen - IP_MASQ_CTL_BSIZE;
+	int cmd;
+
+	IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(len=%d/%d|%d/%d)\n",
+		arglen,
+		sizeof (*ums),
+		optlen,
+		sizeof (*mctl));
+
+	/*
+	 *	Yes, I'm a bad guy ...
+	 */
+	if (arglen != sizeof(*ums) && optlen != sizeof(*mctl)) 
+		return EINVAL;
+
+	MOD_INC_USE_COUNT;
+
+	/* 
+	 *	Don't trust the lusers - plenty of error checking! 
+	 */
+	cmd = mctl->m_cmd;
+	IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(cmd=%d)\n", cmd);
+
+	switch (mctl->m_cmd) {
+		case IP_MASQ_CMD_ADD:
+		case IP_MASQ_CMD_INSERT:
+			ret = ip_masq_user_new(ums);
+			break;
+		case IP_MASQ_CMD_DEL:
+			ret = ip_masq_user_del(ums);
+			break;
+		case IP_MASQ_CMD_SET:
+			ret = ip_masq_user_set(ums);
+			break;
+		case IP_MASQ_CMD_GET:
+			ret = ip_masq_user_get(ums);
+			break;
+	}
+
+	/*
+	 *	For all of the above, return masq tunnel info
+	 */
+
+	ret = -ret;
+
+	if (ret == 0) {
+		ret = sizeof (*ums) + IP_MASQ_CTL_BSIZE;
+		IP_MASQ_DEBUG(1-debug, "will return %d bytes to user\n", ret);
+	}
+
+	MOD_DEC_USE_COUNT;
+	return ret;
+}
+
+
+#ifdef CONFIG_PROC_FS
+static int ip_masq_user_info(char *buffer, char **start, off_t offset,
+			      int length, int proto)
+{
+	off_t pos=0, begin;
+	struct ip_masq *ms;
+	char temp[129];
+        int idx = 0;
+	int len=0;
+	int magic_control;
+
+	MOD_INC_USE_COUNT;
+
+	IP_MASQ_DEBUG(1-debug, "Entered user_info with proto=%d\n", proto);
+
+	if (offset < 128)
+	{
+		sprintf(temp,
+			"Prot SrcIP    SPrt DstIP    DPrt MAddr    MPrt State        Flgs Ref Ctl Expires (free=%d,%d,%d)",
+			atomic_read(ip_masq_free_ports), 
+			atomic_read(ip_masq_free_ports+1), 
+			atomic_read(ip_masq_free_ports+2));
+		len = sprintf(buffer, "%-127s\n", temp);
+	}
+	pos = 128;
+
+        for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++)
+	{
+	/*
+	 *	Lock is actually only need in next loop 
+	 *	we are called from uspace: must stop bh.
+	 */
+	read_lock_bh(&__ip_masq_lock);
+        for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link)
+	{
+		if (ms->protocol != proto) {
+			continue;
+		}
+
+		pos += 128;
+		if (pos <= offset) {
+			len = 0;
+			continue;
+		}
+
+		/*
+		 *	We have locked the tables, no need to del/add timers
+		 *	nor cli()  8)
+		 */
+		
+
+		magic_control = atomic_read(&ms->n_control);
+		if (!magic_control && ms->control) magic_control = -1;
+		sprintf(temp,"%-4s %08lX:%04X %08lX:%04X %08lX:%04X %-12s %3X %4d %3d %7lu",
+			masq_proto_name(ms->protocol),
+			ntohl(ms->saddr), ntohs(ms->sport),
+			ntohl(ms->daddr), ntohs(ms->dport),
+			ntohl(ms->maddr), ntohs(ms->mport),
+			ip_masq_state_name(ms->state),
+			ms->flags,
+			atomic_read(&ms->refcnt),
+			magic_control,
+			(ms->timer.expires-jiffies)/HZ);
+		len += sprintf(buffer+len, "%-127s\n", temp);
+
+		if(len >= length) {
+			read_unlock_bh(&__ip_masq_lock);
+			goto done;
+		}
+	}
+	read_unlock_bh(&__ip_masq_lock);
+	}
+
+done:
+
+	if (len) {
+		begin = len - (pos - offset);
+		*start = buffer + begin;
+		len -= begin;
+	}
+	if(len>length)
+		len = length;
+	MOD_DEC_USE_COUNT;
+	return len;
+}
+#else
+#define ip_masq_user_info	NULL
+#endif
+
+static struct ip_masq_hook ip_masq_user = {
+	ip_masq_user_ctl,
+	ip_masq_user_info
+};
+
+int ip_masq_user_init(void)
+{
+	if (ip_masq_user_hook != NULL) 
+		return -EEXIST;
+	ip_masq_user_hook = &ip_masq_user;
+	return 0;
+}
+
+int ip_masq_user_done(void)
+{
+	if (ip_masq_user_hook == NULL) 
+		return ENOENT;
+	ip_masq_user_hook = NULL;
+	return 0;
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+int init_module(void)
+{
+	if (ip_masq_user_init() != 0)
+		return -EIO;
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	if (ip_masq_user_done() != 0)
+		printk(KERN_INFO "ip_masq_user_done(): can't remove module");
+}
+
+#endif /* MODULE */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov