1/* Redirect. Simple mapping which alters dst to a local IP address. */ 2/* (C) 1999-2001 Paul `Rusty' Russell 3 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 */ 9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10#include <linux/types.h> 11#include <linux/ip.h> 12#include <linux/timer.h> 13#include <linux/module.h> 14#include <linux/netfilter.h> 15#include <linux/netdevice.h> 16#include <linux/if.h> 17#include <linux/inetdevice.h> 18#include <net/protocol.h> 19#include <net/checksum.h> 20#include <linux/netfilter_ipv4.h> 21#include <linux/netfilter/x_tables.h> 22#include <net/netfilter/nf_nat_rule.h> 23 24MODULE_LICENSE("GPL"); 25MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); 26MODULE_DESCRIPTION("Xtables: Connection redirection to localhost"); 27 28static int redirect_tg_check(const struct xt_tgchk_param *par) 29{ 30 const struct nf_nat_multi_range_compat *mr = par->targinfo; 31 32 if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) { 33 pr_debug("bad MAP_IPS.\n"); 34 return -EINVAL; 35 } 36 if (mr->rangesize != 1) { 37 pr_debug("bad rangesize %u.\n", mr->rangesize); 38 return -EINVAL; 39 } 40 return 0; 41} 42 43static unsigned int 44redirect_tg(struct sk_buff *skb, const struct xt_action_param *par) 45{ 46 struct nf_conn *ct; 47 enum ip_conntrack_info ctinfo; 48 __be32 newdst; 49 const struct nf_nat_multi_range_compat *mr = par->targinfo; 50 struct nf_nat_range newrange; 51 52 NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING || 53 par->hooknum == NF_INET_LOCAL_OUT); 54 55 ct = nf_ct_get(skb, &ctinfo); 56 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); 57 58 /* Local packets: make them go to loopback */ 59 if (par->hooknum == NF_INET_LOCAL_OUT) 60 newdst = htonl(0x7F000001); 61 else { 62 struct in_device *indev; 63 struct in_ifaddr *ifa; 64 65 newdst = 0; 66 67 rcu_read_lock(); 68 indev = __in_dev_get_rcu(skb->dev); 69 if (indev && (ifa = indev->ifa_list)) 70 newdst = ifa->ifa_local; 71 rcu_read_unlock(); 72 73 if (!newdst) 74 return NF_DROP; 75 } 76 77 /* Transfer from original range. */ 78 newrange = ((struct nf_nat_range) 79 { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS, 80 newdst, newdst, 81 mr->range[0].min, mr->range[0].max }); 82 83 /* Hand modified range to generic setup. */ 84 return nf_nat_setup_info(ct, &newrange, IP_NAT_MANIP_DST); 85} 86 87static struct xt_target redirect_tg_reg __read_mostly = { 88 .name = "REDIRECT", 89 .family = NFPROTO_IPV4, 90 .target = redirect_tg, 91 .targetsize = sizeof(struct nf_nat_multi_range_compat), 92 .table = "nat", 93 .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT), 94 .checkentry = redirect_tg_check, 95 .me = THIS_MODULE, 96}; 97 98static int __init redirect_tg_init(void) 99{ 100 return xt_register_target(&redirect_tg_reg); 101} 102 103static void __exit redirect_tg_exit(void) 104{ 105 xt_unregister_target(&redirect_tg_reg); 106} 107 108module_init(redirect_tg_init); 109module_exit(redirect_tg_exit); 110