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
- Lines: 468
- Date:
Sun Oct 4 10:21:45 1998
- Orig file:
v2.1.123/linux/net/ipv4/ip_masq_user.c
- Orig date:
Wed Dec 31 16:00:00 1969
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