1/* Redirect. Simple mapping which alters dst to a local IP address. */ 2#include <linux/types.h> 3#include <linux/ip.h> 4#include <linux/timer.h> 5#include <linux/module.h> 6#include <linux/netfilter.h> 7#include <linux/netdevice.h> 8#include <linux/if.h> 9#include <linux/inetdevice.h> 10#include <net/protocol.h> 11#include <net/checksum.h> 12#include <linux/netfilter_ipv4.h> 13#include <linux/netfilter_ipv4/ip_nat_rule.h> 14 15#define DEBUGP(format, args...) 16 17static int 18redirect_check(const char *tablename, 19 const struct ipt_entry *e, 20 void *targinfo, 21 unsigned int targinfosize, 22 unsigned int hook_mask) 23{ 24 const struct ip_nat_multi_range *mr = targinfo; 25 26 if (strcmp(tablename, "nat") != 0) { 27 DEBUGP("redirect_check: bad table `%s'.\n", table); 28 return 0; 29 } 30 if (targinfosize != IPT_ALIGN(sizeof(*mr))) { 31 DEBUGP("redirect_check: size %u.\n", targinfosize); 32 return 0; 33 } 34 if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))) { 35 DEBUGP("redirect_check: bad hooks %x.\n", hook_mask); 36 return 0; 37 } 38 if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) { 39 DEBUGP("redirect_check: bad MAP_IPS.\n"); 40 return 0; 41 } 42 if (mr->rangesize != 1) { 43 DEBUGP("redirect_check: bad rangesize %u.\n", mr->rangesize); 44 return 0; 45 } 46 return 1; 47} 48 49static unsigned int 50redirect_target(struct sk_buff **pskb, 51 unsigned int hooknum, 52 const struct net_device *in, 53 const struct net_device *out, 54 const void *targinfo, 55 void *userinfo) 56{ 57 struct ip_conntrack *ct; 58 enum ip_conntrack_info ctinfo; 59 u_int32_t newdst; 60 const struct ip_nat_multi_range *mr = targinfo; 61 struct ip_nat_multi_range newrange; 62 63 IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING 64 || hooknum == NF_IP_LOCAL_OUT); 65 66 ct = ip_conntrack_get(*pskb, &ctinfo); 67 IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); 68 69 /* Local packets: make them go to loopback */ 70 if (hooknum == NF_IP_LOCAL_OUT) 71 newdst = htonl(0x7F000001); 72 else { 73 struct in_device *indev; 74 75 /* Device might not have an associated in_device. */ 76 indev = (struct in_device *)(*pskb)->dev->ip_ptr; 77 if (indev == NULL) 78 return NF_DROP; 79 80 /* Grab first address on interface. */ 81 newdst = indev->ifa_list->ifa_local; 82 } 83 84 /* Transfer from original range. */ 85 newrange = ((struct ip_nat_multi_range) 86 { 1, { { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS, 87 newdst, newdst, 88 mr->range[0].min, mr->range[0].max } } }); 89 90 /* Hand modified range to generic setup. */ 91 return ip_nat_setup_info(ct, &newrange, hooknum); 92} 93 94static struct ipt_target redirect_reg 95= { { NULL, NULL }, "REDIRECT", redirect_target, redirect_check, NULL, 96 THIS_MODULE }; 97 98static int __init init(void) 99{ 100 return ipt_register_target(&redirect_reg); 101} 102 103static void __exit fini(void) 104{ 105 ipt_unregister_target(&redirect_reg); 106} 107 108module_init(init); 109module_exit(fini); 110MODULE_LICENSE("GPL"); 111