linux-old/net/ipv4/netfilter/ipt_MASQUERADE.c
<<
>>
Prefs
   1/* Masquerade.  Simple mapping which alters range to a local IP address
   2   (depending on route). */
   3#include <linux/config.h>
   4#include <linux/types.h>
   5#include <linux/ip.h>
   6#include <linux/timer.h>
   7#include <linux/module.h>
   8#include <linux/netfilter.h>
   9#include <net/protocol.h>
  10#include <net/checksum.h>
  11#include <linux/netfilter_ipv4.h>
  12#include <linux/netfilter_ipv4/ip_nat_rule.h>
  13#include <linux/netfilter_ipv4/ip_tables.h>
  14
  15#if 0
  16#define DEBUGP printk
  17#else
  18#define DEBUGP(format, args...)
  19#endif
  20
  21/* Lock protects masq region inside conntrack */
  22static DECLARE_RWLOCK(masq_lock);
  23
  24/* FIXME: Multiple targets. --RR */
  25static int
  26masquerade_check(const char *tablename,
  27                 const struct ipt_entry *e,
  28                 void *targinfo,
  29                 unsigned int targinfosize,
  30                 unsigned int hook_mask)
  31{
  32        const struct ip_nat_multi_range *mr = targinfo;
  33
  34        if (strcmp(tablename, "nat") != 0) {
  35                DEBUGP("masquerade_check: bad table `%s'.\n", tablename);
  36                return 0;
  37        }
  38        if (targinfosize != IPT_ALIGN(sizeof(*mr))) {
  39                DEBUGP("masquerade_check: size %u != %u.\n",
  40                       targinfosize, sizeof(*mr));
  41                return 0;
  42        }
  43        if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) {
  44                DEBUGP("masquerade_check: bad hooks %x.\n", hook_mask);
  45                return 0;
  46        }
  47        if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
  48                DEBUGP("masquerade_check: bad MAP_IPS.\n");
  49                return 0;
  50        }
  51        if (mr->rangesize != 1) {
  52                DEBUGP("masquerade_check: bad rangesize %u.\n", mr->rangesize);
  53                return 0;
  54        }
  55        return 1;
  56}
  57
  58static unsigned int
  59masquerade_target(struct sk_buff **pskb,
  60                  unsigned int hooknum,
  61                  const struct net_device *in,
  62                  const struct net_device *out,
  63                  const void *targinfo,
  64                  void *userinfo)
  65{
  66        struct ip_conntrack *ct;
  67        enum ip_conntrack_info ctinfo;
  68        const struct ip_nat_multi_range *mr;
  69        struct ip_nat_multi_range newrange;
  70        u_int32_t newsrc;
  71        struct rtable *rt;
  72        struct rt_key key;
  73
  74        IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
  75
  76        /* FIXME: For the moment, don't do local packets, breaks
  77           testsuite for 2.3.49 --RR */
  78        if ((*pskb)->sk)
  79                return NF_ACCEPT;
  80
  81        ct = ip_conntrack_get(*pskb, &ctinfo);
  82        IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED
  83                            || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
  84
  85        mr = targinfo;
  86
  87        key.dst = (*pskb)->nh.iph->daddr;
  88        key.src = 0; /* Unknown: that's what we're trying to establish */
  89        key.tos = RT_TOS((*pskb)->nh.iph->tos)|RTO_CONN;
  90        key.oif = 0;
  91#ifdef CONFIG_IP_ROUTE_FWMARK
  92        key.fwmark = (*pskb)->nfmark;
  93#endif
  94        if (ip_route_output_key(&rt, &key) != 0) {
  95                /* Funky routing can do this. */
  96                if (net_ratelimit())
  97                        printk("MASQUERADE:"
  98                               " No route: Rusty's brain broke!\n");
  99                return NF_DROP;
 100        }
 101        if (rt->u.dst.dev != out) {
 102                if (net_ratelimit())
 103                        printk("MASQUERADE:"
 104                               " Route sent us somewhere else.\n");
 105                        ip_rt_put(rt);
 106                return NF_DROP;
 107        }
 108
 109        newsrc = rt->rt_src;
 110        DEBUGP("newsrc = %u.%u.%u.%u\n", NIPQUAD(newsrc));
 111        ip_rt_put(rt);
 112
 113        WRITE_LOCK(&masq_lock);
 114        ct->nat.masq_index = out->ifindex;
 115        WRITE_UNLOCK(&masq_lock);
 116
 117        /* Transfer from original range. */
 118        newrange = ((struct ip_nat_multi_range)
 119                { 1, { { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS,
 120                         newsrc, newsrc,
 121                         mr->range[0].min, mr->range[0].max } } });
 122
 123        /* Hand modified range to generic setup. */
 124        return ip_nat_setup_info(ct, &newrange, hooknum);
 125}
 126
 127static inline int
 128device_cmp(struct ip_conntrack *i, void *ifindex)
 129{
 130        int ret;
 131
 132        READ_LOCK(&masq_lock);
 133        ret = (i->nat.masq_index == (int)(long)ifindex);
 134        READ_UNLOCK(&masq_lock);
 135
 136        return ret;
 137}
 138
 139static int masq_device_event(struct notifier_block *this,
 140                             unsigned long event,
 141                             void *ptr)
 142{
 143        struct net_device *dev = ptr;
 144
 145        if (event == NETDEV_DOWN) {
 146                /* Device was downed.  Search entire table for
 147                   conntracks which were associated with that device,
 148                   and forget them. */
 149                IP_NF_ASSERT(dev->ifindex != 0);
 150 
 151                ip_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex);
 152        }
 153
 154        return NOTIFY_DONE;
 155}
 156
 157
 158static int masq_inet_event(struct notifier_block *this,
 159                           unsigned long event,
 160                           void *ptr)
 161{
 162        struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
 163
 164        if (event == NETDEV_DOWN) {
 165                /* IP address was deleted.  Search entire table for
 166                   conntracks which were associated with that device,
 167                   and forget them. */
 168                IP_NF_ASSERT(dev->ifindex != 0);
 169
 170                ip_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex);
 171        }
 172
 173        return NOTIFY_DONE;
 174}
 175
 176static struct notifier_block masq_dev_notifier = {
 177        .notifier_call  = masq_device_event,
 178};
 179
 180static struct notifier_block masq_inet_notifier = {
 181        .notifier_call = masq_inet_event
 182};
 183
 184static struct ipt_target masquerade
 185= { { NULL, NULL }, "MASQUERADE", masquerade_target, masquerade_check, NULL,
 186    THIS_MODULE };
 187
 188static int __init init(void)
 189{
 190        int ret;
 191
 192        ret = ipt_register_target(&masquerade);
 193
 194        if (ret == 0) {
 195                /* Register for device down reports */
 196                register_netdevice_notifier(&masq_dev_notifier);
 197                /* Register IP address change reports */
 198                register_inetaddr_notifier(&masq_inet_notifier);
 199        }
 200
 201        return ret;
 202}
 203
 204static void __exit fini(void)
 205{
 206        ipt_unregister_target(&masquerade);
 207        unregister_netdevice_notifier(&masq_dev_notifier);
 208        unregister_inetaddr_notifier(&masq_inet_notifier);      
 209}
 210
 211module_init(init);
 212module_exit(fini);
 213MODULE_LICENSE("GPL");
 214
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.