[NETFILTER]: Introduce NF_INET_ hook values
[safe/jmp/linux-2.6] / net / ipv4 / netfilter / ipt_SAME.c
1 /* Same.  Just like SNAT, only try to make the connections
2  *        between client A and server B always have the same source ip.
3  *
4  * (C) 2000 Paul `Rusty' Russell
5  * (C) 2001 Martin Josefsson
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 #include <linux/types.h>
12 #include <linux/ip.h>
13 #include <linux/timer.h>
14 #include <linux/module.h>
15 #include <linux/netfilter.h>
16 #include <linux/netdevice.h>
17 #include <linux/if.h>
18 #include <linux/inetdevice.h>
19 #include <net/protocol.h>
20 #include <net/checksum.h>
21 #include <linux/netfilter_ipv4.h>
22 #include <linux/netfilter/x_tables.h>
23 #include <net/netfilter/nf_nat_rule.h>
24 #include <linux/netfilter_ipv4/ipt_SAME.h>
25
26 MODULE_LICENSE("GPL");
27 MODULE_AUTHOR("Martin Josefsson <gandalf@wlug.westbo.se>");
28 MODULE_DESCRIPTION("iptables special SNAT module for consistent sourceip");
29
30 static bool
31 same_check(const char *tablename,
32               const void *e,
33               const struct xt_target *target,
34               void *targinfo,
35               unsigned int hook_mask)
36 {
37         unsigned int count, countess, rangeip, index = 0;
38         struct ipt_same_info *mr = targinfo;
39
40         mr->ipnum = 0;
41
42         if (mr->rangesize < 1) {
43                 pr_debug("same_check: need at least one dest range.\n");
44                 return false;
45         }
46         if (mr->rangesize > IPT_SAME_MAX_RANGE) {
47                 pr_debug("same_check: too many ranges specified, maximum "
48                          "is %u ranges\n", IPT_SAME_MAX_RANGE);
49                 return false;
50         }
51         for (count = 0; count < mr->rangesize; count++) {
52                 if (ntohl(mr->range[count].min_ip) >
53                                 ntohl(mr->range[count].max_ip)) {
54                         pr_debug("same_check: min_ip is larger than max_ip in "
55                                  "range `%u.%u.%u.%u-%u.%u.%u.%u'.\n",
56                                  NIPQUAD(mr->range[count].min_ip),
57                                  NIPQUAD(mr->range[count].max_ip));
58                         return false;
59                 }
60                 if (!(mr->range[count].flags & IP_NAT_RANGE_MAP_IPS)) {
61                         pr_debug("same_check: bad MAP_IPS.\n");
62                         return false;
63                 }
64                 rangeip = (ntohl(mr->range[count].max_ip) -
65                                         ntohl(mr->range[count].min_ip) + 1);
66                 mr->ipnum += rangeip;
67
68                 pr_debug("same_check: range %u, ipnum = %u\n", count, rangeip);
69         }
70         pr_debug("same_check: total ipaddresses = %u\n", mr->ipnum);
71
72         mr->iparray = kmalloc((sizeof(u_int32_t) * mr->ipnum), GFP_KERNEL);
73         if (!mr->iparray) {
74                 pr_debug("same_check: Couldn't allocate %Zu bytes "
75                          "for %u ipaddresses!\n",
76                          (sizeof(u_int32_t) * mr->ipnum), mr->ipnum);
77                 return false;
78         }
79         pr_debug("same_check: Allocated %Zu bytes for %u ipaddresses.\n",
80                  (sizeof(u_int32_t) * mr->ipnum), mr->ipnum);
81
82         for (count = 0; count < mr->rangesize; count++) {
83                 for (countess = ntohl(mr->range[count].min_ip);
84                                 countess <= ntohl(mr->range[count].max_ip);
85                                         countess++) {
86                         mr->iparray[index] = countess;
87                         pr_debug("same_check: Added ipaddress `%u.%u.%u.%u' "
88                                  "in index %u.\n", HIPQUAD(countess), index);
89                         index++;
90                 }
91         }
92         return true;
93 }
94
95 static void
96 same_destroy(const struct xt_target *target, void *targinfo)
97 {
98         struct ipt_same_info *mr = targinfo;
99
100         kfree(mr->iparray);
101
102         pr_debug("same_destroy: Deallocated %Zu bytes for %u ipaddresses.\n",
103                  (sizeof(u_int32_t) * mr->ipnum), mr->ipnum);
104 }
105
106 static unsigned int
107 same_target(struct sk_buff *skb,
108                 const struct net_device *in,
109                 const struct net_device *out,
110                 unsigned int hooknum,
111                 const struct xt_target *target,
112                 const void *targinfo)
113 {
114         struct nf_conn *ct;
115         enum ip_conntrack_info ctinfo;
116         u_int32_t tmpip, aindex;
117         __be32 new_ip;
118         const struct ipt_same_info *same = targinfo;
119         struct nf_nat_range newrange;
120         const struct nf_conntrack_tuple *t;
121
122         NF_CT_ASSERT(hooknum == NF_INET_PRE_ROUTING ||
123                         hooknum == NF_INET_POST_ROUTING);
124         ct = nf_ct_get(skb, &ctinfo);
125
126         t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
127
128         /* Base new source on real src ip and optionally dst ip,
129            giving some hope for consistency across reboots.
130            Here we calculate the index in same->iparray which
131            holds the ipaddress we should use */
132
133         tmpip = ntohl(t->src.u3.ip);
134
135         if (!(same->info & IPT_SAME_NODST))
136                 tmpip += ntohl(t->dst.u3.ip);
137         aindex = tmpip % same->ipnum;
138
139         new_ip = htonl(same->iparray[aindex]);
140
141         pr_debug("ipt_SAME: src=%u.%u.%u.%u dst=%u.%u.%u.%u, "
142                  "new src=%u.%u.%u.%u\n",
143                  NIPQUAD(t->src.u3.ip), NIPQUAD(t->dst.u3.ip), NIPQUAD(new_ip));
144
145         /* Transfer from original range. */
146         newrange = ((struct nf_nat_range)
147                 { same->range[0].flags, new_ip, new_ip,
148                   /* FIXME: Use ports from correct range! */
149                   same->range[0].min, same->range[0].max });
150
151         /* Hand modified range to generic setup. */
152         return nf_nat_setup_info(ct, &newrange, hooknum);
153 }
154
155 static struct xt_target same_reg __read_mostly = {
156         .name           = "SAME",
157         .family         = AF_INET,
158         .target         = same_target,
159         .targetsize     = sizeof(struct ipt_same_info),
160         .table          = "nat",
161         .hooks          = (1 << NF_INET_PRE_ROUTING) |
162                           (1 << NF_INET_POST_ROUTING),
163         .checkentry     = same_check,
164         .destroy        = same_destroy,
165         .me             = THIS_MODULE,
166 };
167
168 static int __init ipt_same_init(void)
169 {
170         return xt_register_target(&same_reg);
171 }
172
173 static void __exit ipt_same_fini(void)
174 {
175         xt_unregister_target(&same_reg);
176 }
177
178 module_init(ipt_same_init);
179 module_exit(ipt_same_fini);
180