Main Page | Class List | File List | Class Members | File Members

ipt_MASQUERADE.c

Go to the documentation of this file.
00001 /* Masquerade. Simple mapping which alters range to a local IP address 00002 (depending on route). */ 00003 #include <linux/config.h> 00004 #include <linux/types.h> 00005 #include <linux/ip.h> 00006 #include <linux/timer.h> 00007 #include <linux/module.h> 00008 #include <linux/netfilter.h> 00009 #include <net/protocol.h> 00010 #include <net/checksum.h> 00011 #include <linux/netfilter_ipv4.h> 00012 #include <linux/netfilter_ipv4/ip_nat_rule.h> 00013 #include <linux/netfilter_ipv4/ip_tables.h> 00014 00015 #if 0 00016 #define DEBUGP printk 00017 #else 00018 #define DEBUGP(format, args...) 00019 #endif 00020 00021 /* Lock protects masq region inside conntrack */ 00022 static DECLARE_RWLOCK(masq_lock); 00023 00024 /* FIXME: Multiple targets. --RR */ 00025 static int 00026 masquerade_check(const char *tablename, 00027 const struct ipt_entry *e, 00028 void *targinfo, 00029 unsigned int targinfosize, 00030 unsigned int hook_mask) 00031 { 00032 const struct ip_nat_multi_range *mr = targinfo; 00033 00034 if (strcmp(tablename, "nat") != 0) { 00035 DEBUGP("masquerade_check: bad table `%s'.\n", table); 00036 return 0; 00037 } 00038 if (targinfosize != IPT_ALIGN(sizeof(*mr))) { 00039 DEBUGP("masquerade_check: size %u != %u.\n", 00040 targinfosize, sizeof(*mr)); 00041 return 0; 00042 } 00043 if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) { 00044 DEBUGP("masquerade_check: bad hooks %x.\n", hook_mask); 00045 return 0; 00046 } 00047 if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) { 00048 DEBUGP("masquerade_check: bad MAP_IPS.\n"); 00049 return 0; 00050 } 00051 if (mr->rangesize != 1) { 00052 DEBUGP("masquerade_check: bad rangesize %u.\n", mr->rangesize); 00053 return 0; 00054 } 00055 return 1; 00056 } 00057 00058 static unsigned int 00059 masquerade_target(struct sk_buff **pskb, 00060 unsigned int hooknum, 00061 const struct net_device *in, 00062 const struct net_device *out, 00063 const void *targinfo, 00064 void *userinfo) 00065 { 00066 struct ip_conntrack *ct; 00067 enum ip_conntrack_info ctinfo; 00068 const struct ip_nat_multi_range *mr; 00069 struct ip_nat_multi_range newrange; 00070 u_int32_t newsrc; 00071 struct rtable *rt; 00072 struct rt_key key; 00073 00074 IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); 00075 00076 /* FIXME: For the moment, don't do local packets, breaks 00077 testsuite for 2.3.49 --RR */ 00078 if ((*pskb)->sk) 00079 return NF_ACCEPT; 00080 00081 ct = ip_conntrack_get(*pskb, &ctinfo); 00082 IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW 00083 || ctinfo == IP_CT_RELATED)); 00084 00085 mr = targinfo; 00086 00087 key.dst = (*pskb)->nh.iph->daddr; 00088 key.src = 0; /* Unknown: that's what we're trying to establish */ 00089 key.tos = RT_TOS((*pskb)->nh.iph->tos)|RTO_CONN; 00090 key.oif = 0; 00091 #ifdef CONFIG_IP_ROUTE_FWMARK 00092 key.fwmark = (*pskb)->nfmark; 00093 #endif 00094 if (ip_route_output_key(&rt, &key) != 0) { 00095 /* Funky routing can do this. */ 00096 if (net_ratelimit()) 00097 printk("MASQUERADE:" 00098 " No route: Rusty's brain broke!\n"); 00099 return NF_DROP; 00100 } 00101 if (rt->u.dst.dev != out) { 00102 if (net_ratelimit()) 00103 printk("MASQUERADE:" 00104 " Route sent us somewhere else.\n"); 00105 return NF_DROP; 00106 } 00107 00108 newsrc = rt->rt_src; 00109 DEBUGP("newsrc = %u.%u.%u.%u\n", NIPQUAD(newsrc)); 00110 ip_rt_put(rt); 00111 00112 WRITE_LOCK(&masq_lock); 00113 ct->nat.masq_index = out->ifindex; 00114 WRITE_UNLOCK(&masq_lock); 00115 00116 /* Transfer from original range. */ 00117 newrange = ((struct ip_nat_multi_range) 00118 { 1, { { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS, 00119 newsrc, newsrc, 00120 mr->range[0].min, mr->range[0].max } } }); 00121 00122 /* Hand modified range to generic setup. */ 00123 return ip_nat_setup_info(ct, &newrange, hooknum); 00124 } 00125 00126 static inline int 00127 device_cmp(const struct ip_conntrack *i, void *ifindex) 00128 { 00129 int ret; 00130 00131 READ_LOCK(&masq_lock); 00132 ret = (i->nat.masq_index == (int)(long)ifindex); 00133 READ_UNLOCK(&masq_lock); 00134 00135 return ret; 00136 } 00137 00138 static int masq_device_event(struct notifier_block *this, 00139 unsigned long event, 00140 void *ptr) 00141 { 00142 struct net_device *dev = ptr; 00143 00144 if (event == NETDEV_DOWN) { 00145 /* Device was downed. Search entire table for 00146 conntracks which were associated with that device, 00147 and forget them. */ 00148 IP_NF_ASSERT(dev->ifindex != 0); 00149 00150 ip_ct_selective_cleanup(device_cmp, (void *)(long)dev->ifindex); 00151 } 00152 00153 return NOTIFY_DONE; 00154 } 00155 00156 static int masq_inet_event(struct notifier_block *this, 00157 unsigned long event, 00158 void *ptr) 00159 { 00160 struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev; 00161 00162 if (event == NETDEV_DOWN) { 00163 /* IP address was deleted. Search entire table for 00164 conntracks which were associated with that device, 00165 and forget them. */ 00166 IP_NF_ASSERT(dev->ifindex != 0); 00167 00168 ip_ct_selective_cleanup(device_cmp, (void *)(long)dev->ifindex); 00169 } 00170 00171 return NOTIFY_DONE; 00172 } 00173 00174 static struct notifier_block masq_dev_notifier = { 00175 masq_device_event, 00176 NULL, 00177 0 00178 }; 00179 00180 static struct notifier_block masq_inet_notifier = { 00181 masq_inet_event, 00182 NULL, 00183 0 00184 }; 00185 00186 static struct ipt_target masquerade 00187 = { { NULL, NULL }, "MASQUERADE", masquerade_target, masquerade_check, NULL, 00188 THIS_MODULE }; 00189 00190 static int __init init(void) 00191 { 00192 int ret; 00193 00194 ret = ipt_register_target(&masquerade); 00195 00196 if (ret == 0) { 00197 /* Register for device down reports */ 00198 register_netdevice_notifier(&masq_dev_notifier); 00199 /* Register IP address change reports */ 00200 register_inetaddr_notifier(&masq_inet_notifier); 00201 } 00202 00203 return ret; 00204 } 00205 00206 static void __exit fini(void) 00207 { 00208 ipt_unregister_target(&masquerade); 00209 unregister_netdevice_notifier(&masq_dev_notifier); 00210 unregister_inetaddr_notifier(&masq_inet_notifier); 00211 } 00212 00213 module_init(init); 00214 module_exit(fini); 00215 MODULE_LICENSE("GPL");

Generated on Wed Dec 1 21:25:32 2004 for Linux 2.4.23 Networking by doxygen 1.3.8