linux/net/ipv4/netfilter/ipt_SAME.c
<<
>>
Prefs
   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
  26MODULE_LICENSE("GPL");
  27MODULE_AUTHOR("Martin Josefsson <gandalf@wlug.westbo.se>");
  28MODULE_DESCRIPTION("iptables special SNAT module for consistent sourceip");
  29
  30static bool
  31same_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
  95static void
  96same_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
 106static unsigned int
 107same_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_IP_PRE_ROUTING ||
 123                        hooknum == NF_IP_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
 155static 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_IP_PRE_ROUTING | 1 << NF_IP_POST_ROUTING),
 162        .checkentry     = same_check,
 163        .destroy        = same_destroy,
 164        .me             = THIS_MODULE,
 165};
 166
 167static int __init ipt_same_init(void)
 168{
 169        return xt_register_target(&same_reg);
 170}
 171
 172static void __exit ipt_same_fini(void)
 173{
 174        xt_unregister_target(&same_reg);
 175}
 176
 177module_init(ipt_same_init);
 178module_exit(ipt_same_fini);
 179
 180