ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / net / ipv4 / netfilter / ipt_NETMAP.c
1 /* NETMAP - static NAT mapping of IP network addresses (1:1).
2  * The mapping can be applied to source (POSTROUTING),
3  * destination (PREROUTING), or both (with separate rules).
4  */
5
6 /* (C) 2000-2001 Svenning Soerensen <svenning@post5.tele.dk>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/config.h>
14 #include <linux/ip.h>
15 #include <linux/module.h>
16 #include <linux/netdevice.h>
17 #include <linux/netfilter.h>
18 #include <linux/netfilter_ipv4.h>
19 #include <linux/netfilter_ipv4/ip_nat_rule.h>
20
21 #define MODULENAME "NETMAP"
22 MODULE_LICENSE("GPL");
23 MODULE_AUTHOR("Svenning Soerensen <svenning@post5.tele.dk>");
24 MODULE_DESCRIPTION("iptables 1:1 NAT mapping of IP networks target");
25
26 #if 0
27 #define DEBUGP printk
28 #else
29 #define DEBUGP(format, args...)
30 #endif
31
32 static int
33 check(const char *tablename,
34       const struct ipt_entry *e,
35       void *targinfo,
36       unsigned int targinfosize,
37       unsigned int hook_mask)
38 {
39         const struct ip_nat_multi_range *mr = targinfo;
40
41         if (strcmp(tablename, "nat") != 0) {
42                 DEBUGP(MODULENAME":check: bad table `%s'.\n", tablename);
43                 return 0;
44         }
45         if (targinfosize != IPT_ALIGN(sizeof(*mr))) {
46                 DEBUGP(MODULENAME":check: size %u.\n", targinfosize);
47                 return 0;
48         }
49         if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING))) {
50                 DEBUGP(MODULENAME":check: bad hooks %x.\n", hook_mask);
51                 return 0;
52         }
53         if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) {
54                 DEBUGP(MODULENAME":check: bad MAP_IPS.\n");
55                 return 0;
56         }
57         if (mr->rangesize != 1) {
58                 DEBUGP(MODULENAME":check: bad rangesize %u.\n", mr->rangesize);
59                 return 0;
60         }
61         return 1;
62 }
63
64 static unsigned int
65 target(struct sk_buff **pskb,
66        const struct net_device *in,
67        const struct net_device *out,
68        unsigned int hooknum,
69        const void *targinfo,
70        void *userinfo)
71 {
72         struct ip_conntrack *ct;
73         enum ip_conntrack_info ctinfo;
74         u_int32_t new_ip, netmask;
75         const struct ip_nat_multi_range *mr = targinfo;
76         struct ip_nat_multi_range newrange;
77
78         IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
79                      || hooknum == NF_IP_POST_ROUTING);
80         ct = ip_conntrack_get(*pskb, &ctinfo);
81
82         netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip);
83
84         if (hooknum == NF_IP_PRE_ROUTING)
85                 new_ip = (*pskb)->nh.iph->daddr & ~netmask;
86         else
87                 new_ip = (*pskb)->nh.iph->saddr & ~netmask;
88         new_ip |= mr->range[0].min_ip & netmask;
89
90         newrange = ((struct ip_nat_multi_range)
91         { 1, { { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS,
92                  new_ip, new_ip,
93                  mr->range[0].min, mr->range[0].max } } });
94
95         /* Hand modified range to generic setup. */
96         return ip_nat_setup_info(ct, &newrange, hooknum);
97 }
98
99 static struct ipt_target target_module = { 
100         .name           = MODULENAME,
101         .target         = target, 
102         .checkentry     = check,
103         .me             = THIS_MODULE 
104 };
105
106 static int __init init(void)
107 {
108         return ipt_register_target(&target_module);
109 }
110
111 static void __exit fini(void)
112 {
113         ipt_unregister_target(&target_module);
114 }
115
116 module_init(init);
117 module_exit(fini);