patch-2.3.15 linux/net/ipv4/ip_masq_portfw.c
Next file: linux/net/ipv4/ip_masq_quake.c
Previous file: linux/net/ipv4/ip_masq_mod.c
Back to the patch index
Back to the overall index
- Lines: 509
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.3.14/linux/net/ipv4/ip_masq_portfw.c
- Orig date:
Tue Jun 29 09:22:08 1999
diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_masq_portfw.c linux/net/ipv4/ip_masq_portfw.c
@@ -1,508 +0,0 @@
-/*
- * IP_MASQ_PORTFW masquerading module
- *
- *
- * $Id: ip_masq_portfw.c,v 1.4 1999/06/29 12:35:53 davem Exp $
- *
- * Author: Steven Clarke <steven.clarke@monmouth.demon.co.uk>
- *
- * Fixes:
- * Juan Jose Ciarlante : created this new file from ip_masq.c and ip_fw.c
- * Juan Jose Ciarlante : modularized
- * Juan Jose Ciarlante : use GFP_KERNEL
- * Juan Jose Ciarlante : locking
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/list.h>
-#include <net/ip.h>
-#include <linux/ip_fw.h>
-#include <linux/ip_masq.h>
-#include <net/ip_masq.h>
-#include <net/ip_masq_mod.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-
-#define IP_PORTFW_PORT_MIN 1
-#define IP_PORTFW_PORT_MAX 60999
-
-struct ip_portfw {
- struct list_head list;
- __u32 laddr, raddr;
- __u16 lport, rport;
- atomic_t pref_cnt; /* pref "counter" down to 0 */
- int pref; /* user set pref */
-};
-
-static struct ip_masq_mod *mmod_self = NULL;
-/*
- * Debug level
- */
-#ifdef CONFIG_IP_MASQ_DEBUG
-static int debug=0;
-MODULE_PARM(debug, "i");
-#endif
-
-/*
- * Lock
- */
-static spinlock_t portfw_lock = SPIN_LOCK_UNLOCKED;
-
-static struct list_head portfw_list[2];
-static __inline__ int portfw_idx(int protocol)
-{
- return (protocol==IPPROTO_TCP);
-}
-
-/*
- *
- * Delete forwarding entry(s):
- * called from _DEL, u-space.
- * . "relaxed" match, except for lport
- *
- */
-
-static __inline__ int ip_portfw_del(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr)
-{
- int prot = portfw_idx(protocol);
- struct ip_portfw *n;
- struct list_head *entry;
- struct list_head *list = &portfw_list[prot];
- int nent;
-
- nent = atomic_read(&mmod_self->mmod_nent);
-
- write_lock_bh(&portfw_lock);
-
- for (entry=list->next;entry != list;entry = entry->next) {
- n = list_entry(entry, struct ip_portfw, list);
- if (n->lport == lport &&
- (!laddr || n->laddr == laddr) &&
- (!raddr || n->raddr == raddr) &&
- (!rport || n->rport == rport)) {
- list_del(entry);
- ip_masq_mod_dec_nent(mmod_self);
- kfree_s(n, sizeof(struct ip_portfw));
- MOD_DEC_USE_COUNT;
- }
- }
- write_unlock_bh(&portfw_lock);
-
- return nent==atomic_read(&mmod_self->mmod_nent)? ESRCH : 0;
-}
-
-/*
- * Flush tables
- * called from _FLUSH, u-space.
- */
-static __inline__ void ip_portfw_flush(void)
-{
- int prot;
- struct list_head *l;
- struct list_head *e;
- struct ip_portfw *n;
-
- write_lock_bh(&portfw_lock);
-
- for (prot = 0; prot < 2;prot++) {
- l = &portfw_list[prot];
- while((e=l->next) != l) {
- ip_masq_mod_dec_nent(mmod_self);
- n = list_entry (e, struct ip_portfw, list);
- list_del(e);
- kfree_s(n, sizeof (*n));
- MOD_DEC_USE_COUNT;
- }
- }
-
- write_unlock_bh(&portfw_lock);
-}
-
-/*
- * Lookup routine for lport,laddr match
- * must be called with locked tables
- */
-static __inline__ struct ip_portfw *ip_portfw_lookup(__u16 protocol, __u16 lport, __u32 laddr, __u32 *daddr_p, __u16 *dport_p)
-{
- int prot = portfw_idx(protocol);
-
- struct ip_portfw *n = NULL;
- struct list_head *l, *e;
-
- l = &portfw_list[prot];
-
- for (e=l->next;e!=l;e=e->next) {
- n = list_entry(e, struct ip_portfw, list);
- if (lport == n->lport && laddr == n->laddr) {
- /* Please be nice, don't pass only a NULL dport */
- if (daddr_p) {
- *daddr_p = n->raddr;
- *dport_p = n->rport;
- }
-
- goto out;
- }
- }
- n = NULL;
-out:
- return n;
-}
-
-/*
- * Edit routine for lport,[laddr], [raddr], [rport] match
- * By now, only called from u-space
- */
-static __inline__ int ip_portfw_edit(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr, int pref)
-{
- int prot = portfw_idx(protocol);
-
- struct ip_portfw *n = NULL;
- struct list_head *l, *e;
- int count = 0;
-
-
- read_lock_bh(&portfw_lock);
-
- l = &portfw_list[prot];
-
- for (e=l->next;e!=l;e=e->next) {
- n = list_entry(e, struct ip_portfw, list);
- if (lport == n->lport &&
- (!laddr || laddr == n->laddr) &&
- (!rport || rport == n->rport) &&
- (!raddr || raddr == n->raddr)) {
- n->pref = pref;
- atomic_set(&n->pref_cnt, pref);
- count++;
- }
- }
-
- read_unlock_bh(&portfw_lock);
-
- return count;
-}
-
-/*
- * Add/edit en entry
- * called from _ADD, u-space.
- * must return 0 or +errno
- */
-static __inline__ int ip_portfw_add(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr, int pref)
-{
- struct ip_portfw *npf;
- int prot = portfw_idx(protocol);
-
- if (pref <= 0)
- return EINVAL;
-
- if (ip_portfw_edit(protocol, lport, laddr, rport, raddr, pref)) {
- /*
- * Edit ok ...
- */
- return 0;
- }
-
- /* may block ... */
- npf = (struct ip_portfw*) kmalloc(sizeof(struct ip_portfw), GFP_KERNEL);
-
- if (!npf)
- return ENOMEM;
-
- MOD_INC_USE_COUNT;
- memset(npf, 0, sizeof(*npf));
-
- npf->laddr = laddr;
- npf->lport = lport;
- npf->rport = rport;
- npf->raddr = raddr;
- npf->pref = pref;
-
- atomic_set(&npf->pref_cnt, npf->pref);
- INIT_LIST_HEAD(&npf->list);
-
- write_lock_bh(&portfw_lock);
-
- /*
- * Add at head
- */
- list_add(&npf->list, &portfw_list[prot]);
-
- write_unlock_bh(&portfw_lock);
-
- ip_masq_mod_inc_nent(mmod_self);
- return 0;
-}
-
-
-
-static __inline__ int portfw_ctl(int optname, struct ip_masq_ctl *mctl, int optlen)
-{
- struct ip_portfw_user *mm = &mctl->u.portfw_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 (*mm),
- optlen,
- sizeof (*mctl));
-
- /*
- * Yes, I'm a bad guy ...
- */
- if (arglen != sizeof(*mm) && optlen != sizeof(*mctl))
- return EINVAL;
-
- /*
- * Don't trust the lusers - plenty of error checking!
- */
- cmd = mctl->m_cmd;
- IP_MASQ_DEBUG(1-debug, "ip_masq_portfw_ctl(cmd=%d)\n", cmd);
-
-
- switch (cmd) {
- case IP_MASQ_CMD_NONE:
- return 0;
- case IP_MASQ_CMD_FLUSH:
- break;
- default:
- if (htons(mm->lport) < IP_PORTFW_PORT_MIN || htons(mm->lport) > IP_PORTFW_PORT_MAX)
- return EINVAL;
-
- if (mm->protocol!=IPPROTO_TCP && mm->protocol!=IPPROTO_UDP)
- return EINVAL;
- }
-
- switch(cmd) {
- case IP_MASQ_CMD_ADD:
- ret = ip_portfw_add(mm->protocol,
- mm->lport, mm->laddr,
- mm->rport, mm->raddr,
- mm->pref);
- break;
-
- case IP_MASQ_CMD_DEL:
- ret = ip_portfw_del(mm->protocol,
- mm->lport, mm->laddr,
- mm->rport, mm->raddr);
- break;
- case IP_MASQ_CMD_FLUSH:
- ip_portfw_flush();
- ret = 0;
- break;
- }
-
-
- return ret;
-}
-
-
-
-
-#ifdef CONFIG_PROC_FS
-
-static int portfw_procinfo(char *buffer, char **start, off_t offset,
- int length, int unused)
-{
- off_t pos=0, begin;
- struct ip_portfw *pf;
- struct list_head *l, *e;
- char temp[65];
- int ind;
- int len=0;
-
-
- if (offset < 64)
- {
- sprintf(temp, "Prot LAddr LPort > RAddr RPort PrCnt Pref");
- len = sprintf(buffer, "%-63s\n", temp);
- }
- pos = 64;
-
- read_lock_bh(&portfw_lock);
-
- for(ind = 0; ind < 2; ind++)
- {
- l = &portfw_list[ind];
- for (e=l->next; e!=l; e=e->next)
- {
- pf = list_entry(e, struct ip_portfw, list);
- pos += 64;
- if (pos <= offset) {
- len = 0;
- continue;
- }
-
- sprintf(temp,"%s %08lX %5u > %08lX %5u %5d %5d",
- ind ? "TCP" : "UDP",
- ntohl(pf->laddr), ntohs(pf->lport),
- ntohl(pf->raddr), ntohs(pf->rport),
- atomic_read(&pf->pref_cnt), pf->pref);
- len += sprintf(buffer+len, "%-63s\n", temp);
-
- if (len >= length)
- goto done;
- }
- }
-done:
- read_unlock_bh(&portfw_lock);
-
- begin = len - (pos - offset);
- *start = buffer + begin;
- len -= begin;
- if(len>length)
- len = length;
- return len;
-}
-
-static struct proc_dir_entry portfw_proc_entry = {
-/* 0, 0, NULL", */
- 0, 6, "portfw", /* Just for compatibility, for now ... */
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- portfw_procinfo
-};
-
-#define proc_ent &portfw_proc_entry
-#else /* !CONFIG_PROC_FS */
-
-#define proc_ent NULL
-#endif
-
-static int portfw_in_rule(const struct sk_buff *skb, const struct iphdr *iph)
-{
- const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
-#ifdef CONFIG_IP_MASQ_DEBUG
- struct rtable *rt = (struct rtable *)skb->dst;
-#endif
- struct ip_portfw *pfw;
-
- IP_MASQ_DEBUG(2, "portfw_in_rule(): skb:= dev=%s (index=%d), rt_iif=%d, rt_flags=0x%x rt_dev___=%s daddr=%d.%d.%d.%d dport=%d\n",
- skb->dev->name, skb->dev->ifindex, rt->rt_iif, rt->rt_flags,
- rt->u.dst.dev->name,
- NIPQUAD(iph->daddr), ntohs(portp[1]));
-
- read_lock(&portfw_lock);
- pfw = ip_portfw_lookup(iph->protocol, portp[1], iph->daddr, NULL, NULL);
- read_unlock(&portfw_lock);
- return (pfw!=0);
-}
-
-static struct ip_masq * portfw_in_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
-{
- /*
- * If no entry exists in the masquerading table
- * and the port is involved
- * in port forwarding, create a new masq entry
- */
-
- __u32 raddr;
- __u16 rport;
- const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
- struct ip_masq *ms = NULL;
- struct ip_portfw *pf;
-
- /*
- * Lock for writing.
- */
- write_lock(&portfw_lock);
-
- if ((pf=ip_portfw_lookup(iph->protocol,
- portp[1], iph->daddr,
- &raddr, &rport))) {
- ms = ip_masq_new(iph->protocol,
- iph->daddr, portp[1],
- raddr, rport,
- iph->saddr, portp[0],
- 0);
- ip_masq_listen(ms);
-
- if (!ms || atomic_read(&mmod_self->mmod_nent) <= 1
- /* || ip_masq_nlocks(&portfw_lock) != 1 */ )
- /*
- * Maybe later...
- */
- goto out;
-
- /*
- * Entry created, lock==1.
- * if pref_cnt == 0, move
- * entry at _tail_.
- * This is a simple load balance scheduling
- */
-
- if (atomic_dec_and_test(&pf->pref_cnt)) {
-
- atomic_set(&pf->pref_cnt, pf->pref);
- list_del(&pf->list);
- list_add(&pf->list,
- portfw_list[portfw_idx(iph->protocol)].prev);
-
- }
- }
-out:
- write_unlock(&portfw_lock);
- return ms;
-}
-
-#define portfw_in_update NULL
-#define portfw_out_rule NULL
-#define portfw_out_create NULL
-#define portfw_out_update NULL
-
-static struct ip_masq_mod portfw_mod = {
- NULL, /* next */
- NULL, /* next_reg */
- "portfw", /* name */
- ATOMIC_INIT(0), /* nent */
- ATOMIC_INIT(0), /* refcnt */
- proc_ent,
- portfw_ctl,
- NULL, /* masq_mod_init */
- NULL, /* masq_mod_done */
- portfw_in_rule,
- portfw_in_update,
- portfw_in_create,
- portfw_out_rule,
- portfw_out_update,
- portfw_out_create,
-};
-
-
-
-__initfunc(int ip_portfw_init(void))
-{
- INIT_LIST_HEAD(&portfw_list[0]);
- INIT_LIST_HEAD(&portfw_list[1]);
- return register_ip_masq_mod ((mmod_self=&portfw_mod));
-}
-
-int ip_portfw_done(void)
-{
- return unregister_ip_masq_mod(&portfw_mod);
-}
-
-#ifdef MODULE
-EXPORT_NO_SYMBOLS;
-
-int init_module(void)
-{
- if (ip_portfw_init() != 0)
- return -EIO;
- return 0;
-}
-
-void cleanup_module(void)
-{
- if (ip_portfw_done() != 0)
- printk(KERN_INFO "ip_portfw_done(): can't remove module");
-}
-
-#endif /* MODULE */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)