pre-2.3.4..
[davej-history.git] / net / ipv4 / ip_masq_portfw.c
blobad26674013d897e445913d2ab78740a40ec2f382
1 /*
2 * IP_MASQ_PORTFW masquerading module
5 * $Id: ip_masq_portfw.c,v 1.3 1998/12/08 05:42:12 davem Exp $
7 * Author: Steven Clarke <steven.clarke@monmouth.demon.co.uk>
9 * Fixes:
10 * Juan Jose Ciarlante : created this new file from ip_masq.c and ip_fw.c
11 * Juan Jose Ciarlante : modularized
12 * Juan Jose Ciarlante : use GFP_KERNEL
13 * Juan Jose Ciarlante : locking
17 #include <linux/config.h>
18 #include <linux/module.h>
19 #include <linux/types.h>
20 #include <linux/kernel.h>
21 #include <linux/errno.h>
22 #include <linux/list.h>
23 #include <net/ip.h>
24 #include <linux/ip_fw.h>
25 #include <linux/ip_masq.h>
26 #include <net/ip_masq.h>
27 #include <net/ip_masq_mod.h>
28 #include <linux/proc_fs.h>
29 #include <linux/init.h>
31 #define IP_PORTFW_PORT_MIN 1
32 #define IP_PORTFW_PORT_MAX 60999
34 struct ip_portfw {
35 struct list_head list;
36 __u32 laddr, raddr;
37 __u16 lport, rport;
38 atomic_t pref_cnt; /* pref "counter" down to 0 */
39 int pref; /* user set pref */
42 static struct ip_masq_mod *mmod_self = NULL;
44 * Debug level
46 #ifdef CONFIG_IP_MASQ_DEBUG
47 static int debug=0;
48 MODULE_PARM(debug, "i");
49 #endif
52 * Lock
54 #ifdef __SMP__
55 static spinlock_t portfw_lock = SPIN_LOCK_UNLOCKED;
56 #endif
58 static struct list_head portfw_list[2];
59 static __inline__ int portfw_idx(int protocol)
61 return (protocol==IPPROTO_TCP);
66 * Delete forwarding entry(s):
67 * called from _DEL, u-space.
68 * . "relaxed" match, except for lport
72 static __inline__ int ip_portfw_del(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr)
74 int prot = portfw_idx(protocol);
75 struct ip_portfw *n;
76 struct list_head *entry;
77 struct list_head *list = &portfw_list[prot];
78 int nent;
80 nent = atomic_read(&mmod_self->mmod_nent);
82 write_lock_bh(&portfw_lock);
84 for (entry=list->next;entry != list;entry = entry->next) {
85 n = list_entry(entry, struct ip_portfw, list);
86 if (n->lport == lport &&
87 (!laddr || n->laddr == laddr) &&
88 (!raddr || n->raddr == raddr) &&
89 (!rport || n->rport == rport)) {
90 list_del(entry);
91 ip_masq_mod_dec_nent(mmod_self);
92 kfree_s(n, sizeof(struct ip_portfw));
93 MOD_DEC_USE_COUNT;
96 write_unlock_bh(&portfw_lock);
98 return nent==atomic_read(&mmod_self->mmod_nent)? ESRCH : 0;
102 * Flush tables
103 * called from _FLUSH, u-space.
105 static __inline__ void ip_portfw_flush(void)
107 int prot;
108 struct list_head *l;
109 struct list_head *e;
110 struct ip_portfw *n;
112 write_lock_bh(&portfw_lock);
114 for (prot = 0; prot < 2;prot++) {
115 l = &portfw_list[prot];
116 while((e=l->next) != l) {
117 ip_masq_mod_dec_nent(mmod_self);
118 n = list_entry (e, struct ip_portfw, list);
119 list_del(e);
120 kfree_s(n, sizeof (*n));
121 MOD_DEC_USE_COUNT;
125 write_unlock_bh(&portfw_lock);
129 * Lookup routine for lport,laddr match
130 * must be called with locked tables
132 static __inline__ struct ip_portfw *ip_portfw_lookup(__u16 protocol, __u16 lport, __u32 laddr, __u32 *daddr_p, __u16 *dport_p)
134 int prot = portfw_idx(protocol);
136 struct ip_portfw *n = NULL;
137 struct list_head *l, *e;
139 l = &portfw_list[prot];
141 for (e=l->next;e!=l;e=e->next) {
142 n = list_entry(e, struct ip_portfw, list);
143 if (lport == n->lport && laddr == n->laddr) {
144 /* Please be nice, don't pass only a NULL dport */
145 if (daddr_p) {
146 *daddr_p = n->raddr;
147 *dport_p = n->rport;
150 goto out;
153 n = NULL;
154 out:
155 return n;
159 * Edit routine for lport,[laddr], [raddr], [rport] match
160 * By now, only called from u-space
162 static __inline__ int ip_portfw_edit(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr, int pref)
164 int prot = portfw_idx(protocol);
166 struct ip_portfw *n = NULL;
167 struct list_head *l, *e;
168 int count = 0;
171 read_lock_bh(&portfw_lock);
173 l = &portfw_list[prot];
175 for (e=l->next;e!=l;e=e->next) {
176 n = list_entry(e, struct ip_portfw, list);
177 if (lport == n->lport &&
178 (!laddr || laddr == n->laddr) &&
179 (!rport || rport == n->rport) &&
180 (!raddr || raddr == n->raddr)) {
181 n->pref = pref;
182 atomic_set(&n->pref_cnt, pref);
183 count++;
187 read_unlock_bh(&portfw_lock);
189 return count;
193 * Add/edit en entry
194 * called from _ADD, u-space.
195 * must return 0 or +errno
197 static __inline__ int ip_portfw_add(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr, int pref)
199 struct ip_portfw *npf;
200 int prot = portfw_idx(protocol);
202 if (pref <= 0)
203 return EINVAL;
205 if (ip_portfw_edit(protocol, lport, laddr, rport, raddr, pref)) {
207 * Edit ok ...
209 return 0;
212 /* may block ... */
213 npf = (struct ip_portfw*) kmalloc(sizeof(struct ip_portfw), GFP_KERNEL);
215 if (!npf)
216 return ENOMEM;
218 MOD_INC_USE_COUNT;
219 memset(npf, 0, sizeof(*npf));
221 npf->laddr = laddr;
222 npf->lport = lport;
223 npf->rport = rport;
224 npf->raddr = raddr;
225 npf->pref = pref;
227 atomic_set(&npf->pref_cnt, npf->pref);
228 INIT_LIST_HEAD(&npf->list);
230 write_lock_bh(&portfw_lock);
233 * Add at head
235 list_add(&npf->list, &portfw_list[prot]);
237 write_unlock_bh(&portfw_lock);
239 ip_masq_mod_inc_nent(mmod_self);
240 return 0;
245 static __inline__ int portfw_ctl(int optname, struct ip_masq_ctl *mctl, int optlen)
247 struct ip_portfw_user *mm = &mctl->u.portfw_user;
248 int ret = EINVAL;
249 int arglen = optlen - IP_MASQ_CTL_BSIZE;
250 int cmd;
253 IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(len=%d/%d|%d/%d)\n",
254 arglen,
255 sizeof (*mm),
256 optlen,
257 sizeof (*mctl));
260 * Yes, I'm a bad guy ...
262 if (arglen != sizeof(*mm) && optlen != sizeof(*mctl))
263 return EINVAL;
266 * Don't trust the lusers - plenty of error checking!
268 cmd = mctl->m_cmd;
269 IP_MASQ_DEBUG(1-debug, "ip_masq_portfw_ctl(cmd=%d)\n", cmd);
272 switch (cmd) {
273 case IP_MASQ_CMD_NONE:
274 return 0;
275 case IP_MASQ_CMD_FLUSH:
276 break;
277 default:
278 if (htons(mm->lport) < IP_PORTFW_PORT_MIN || htons(mm->lport) > IP_PORTFW_PORT_MAX)
279 return EINVAL;
281 if (mm->protocol!=IPPROTO_TCP && mm->protocol!=IPPROTO_UDP)
282 return EINVAL;
285 switch(cmd) {
286 case IP_MASQ_CMD_ADD:
287 ret = ip_portfw_add(mm->protocol,
288 mm->lport, mm->laddr,
289 mm->rport, mm->raddr,
290 mm->pref);
291 break;
293 case IP_MASQ_CMD_DEL:
294 ret = ip_portfw_del(mm->protocol,
295 mm->lport, mm->laddr,
296 mm->rport, mm->raddr);
297 break;
298 case IP_MASQ_CMD_FLUSH:
299 ip_portfw_flush();
300 ret = 0;
301 break;
305 return ret;
311 #ifdef CONFIG_PROC_FS
313 static int portfw_procinfo(char *buffer, char **start, off_t offset,
314 int length, int unused)
316 off_t pos=0, begin;
317 struct ip_portfw *pf;
318 struct list_head *l, *e;
319 char temp[65];
320 int ind;
321 int len=0;
324 if (offset < 64)
326 sprintf(temp, "Prot LAddr LPort > RAddr RPort PrCnt Pref");
327 len = sprintf(buffer, "%-63s\n", temp);
329 pos = 64;
331 read_lock_bh(&portfw_lock);
333 for(ind = 0; ind < 2; ind++)
335 l = &portfw_list[ind];
336 for (e=l->next; e!=l; e=e->next)
338 pf = list_entry(e, struct ip_portfw, list);
339 pos += 64;
340 if (pos <= offset) {
341 len = 0;
342 continue;
345 sprintf(temp,"%s %08lX %5u > %08lX %5u %5d %5d",
346 ind ? "TCP" : "UDP",
347 ntohl(pf->laddr), ntohs(pf->lport),
348 ntohl(pf->raddr), ntohs(pf->rport),
349 atomic_read(&pf->pref_cnt), pf->pref);
350 len += sprintf(buffer+len, "%-63s\n", temp);
352 if (len >= length)
353 goto done;
356 done:
357 read_unlock_bh(&portfw_lock);
359 begin = len - (pos - offset);
360 *start = buffer + begin;
361 len -= begin;
362 if(len>length)
363 len = length;
364 return len;
367 static struct proc_dir_entry portfw_proc_entry = {
368 /* 0, 0, NULL", */
369 0, 6, "portfw", /* Just for compatibility, for now ... */
370 S_IFREG | S_IRUGO, 1, 0, 0,
371 0, &proc_net_inode_operations,
372 portfw_procinfo
375 #define proc_ent &portfw_proc_entry
376 #else /* !CONFIG_PROC_FS */
378 #define proc_ent NULL
379 #endif
381 static int portfw_in_rule(const struct sk_buff *skb, const struct iphdr *iph)
383 const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
384 #ifdef CONFIG_IP_MASQ_DEBUG
385 struct rtable *rt = (struct rtable *)skb->dst;
386 #endif
387 struct ip_portfw *pfw;
389 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",
390 skb->dev->name, skb->dev->ifindex, rt->rt_iif, rt->rt_flags,
391 rt->u.dst.dev->name,
392 NIPQUAD(iph->daddr), ntohs(portp[1]));
394 read_lock(&portfw_lock);
395 pfw = ip_portfw_lookup(iph->protocol, portp[1], iph->daddr, NULL, NULL);
396 read_unlock(&portfw_lock);
397 return (pfw!=0);
400 static struct ip_masq * portfw_in_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
403 * If no entry exists in the masquerading table
404 * and the port is involved
405 * in port forwarding, create a new masq entry
408 __u32 raddr;
409 __u16 rport;
410 const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
411 struct ip_masq *ms = NULL;
412 struct ip_portfw *pf;
415 * Lock for writing.
417 write_lock(&portfw_lock);
419 if ((pf=ip_portfw_lookup(iph->protocol,
420 portp[1], iph->daddr,
421 &raddr, &rport))) {
422 ms = ip_masq_new(iph->protocol,
423 iph->daddr, portp[1],
424 raddr, rport,
425 iph->saddr, portp[0],
427 ip_masq_listen(ms);
429 if (!ms || atomic_read(&mmod_self->mmod_nent) <= 1
430 /* || ip_masq_nlocks(&portfw_lock) != 1 */ )
432 * Maybe later...
434 goto out;
437 * Entry created, lock==1.
438 * if pref_cnt == 0, move
439 * entry at _tail_.
440 * This is a simple load balance scheduling
443 if (atomic_dec_and_test(&pf->pref_cnt)) {
445 atomic_set(&pf->pref_cnt, pf->pref);
446 list_del(&pf->list);
447 list_add(&pf->list,
448 portfw_list[portfw_idx(iph->protocol)].prev);
452 out:
453 write_unlock(&portfw_lock);
454 return ms;
457 #define portfw_in_update NULL
458 #define portfw_out_rule NULL
459 #define portfw_out_create NULL
460 #define portfw_out_update NULL
462 static struct ip_masq_mod portfw_mod = {
463 NULL, /* next */
464 NULL, /* next_reg */
465 "portfw", /* name */
466 ATOMIC_INIT(0), /* nent */
467 ATOMIC_INIT(0), /* refcnt */
468 proc_ent,
469 portfw_ctl,
470 NULL, /* masq_mod_init */
471 NULL, /* masq_mod_done */
472 portfw_in_rule,
473 portfw_in_update,
474 portfw_in_create,
475 portfw_out_rule,
476 portfw_out_update,
477 portfw_out_create,
482 __initfunc(int ip_portfw_init(void))
484 INIT_LIST_HEAD(&portfw_list[0]);
485 INIT_LIST_HEAD(&portfw_list[1]);
486 return register_ip_masq_mod ((mmod_self=&portfw_mod));
489 int ip_portfw_done(void)
491 return unregister_ip_masq_mod(&portfw_mod);
494 #ifdef MODULE
495 EXPORT_NO_SYMBOLS;
497 int init_module(void)
499 if (ip_portfw_init() != 0)
500 return -EIO;
501 return 0;
504 void cleanup_module(void)
506 if (ip_portfw_done() != 0)
507 printk(KERN_INFO "ip_portfw_done(): can't remove module");
510 #endif /* MODULE */