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

ip_fw_compat_masq.c

Go to the documentation of this file.
00001 /* Masquerading compatibility layer. 00002 00003 Note that there are no restrictions on other programs binding to 00004 ports 61000:65095 (in 2.0 and 2.2 they get EADDRINUSE). Just DONT 00005 DO IT. 00006 */ 00007 #include <linux/skbuff.h> 00008 #include <linux/in.h> 00009 #include <linux/ip.h> 00010 #include <linux/icmp.h> 00011 #include <linux/udp.h> 00012 #include <linux/netfilter_ipv4.h> 00013 #include <linux/netdevice.h> 00014 #include <linux/inetdevice.h> 00015 #include <linux/proc_fs.h> 00016 #include <linux/version.h> 00017 #include <linux/module.h> 00018 #include <net/route.h> 00019 00020 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock) 00021 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock) 00022 00023 #include <linux/netfilter_ipv4/ip_conntrack.h> 00024 #include <linux/netfilter_ipv4/ip_conntrack_core.h> 00025 #include <linux/netfilter_ipv4/ip_nat.h> 00026 #include <linux/netfilter_ipv4/ip_nat_core.h> 00027 #include <linux/netfilter_ipv4/listhelp.h> 00028 00029 #if 0 00030 #define DEBUGP printk 00031 #else 00032 #define DEBUGP(format, args...) 00033 #endif 00034 00035 unsigned int 00036 do_masquerade(struct sk_buff **pskb, const struct net_device *dev) 00037 { 00038 struct iphdr *iph = (*pskb)->nh.iph; 00039 struct ip_nat_info *info; 00040 enum ip_conntrack_info ctinfo; 00041 struct ip_conntrack *ct; 00042 unsigned int ret; 00043 00044 /* Sorry, only ICMP, TCP and UDP. */ 00045 if (iph->protocol != IPPROTO_ICMP 00046 && iph->protocol != IPPROTO_TCP 00047 && iph->protocol != IPPROTO_UDP) 00048 return NF_DROP; 00049 00050 /* Feed it to connection tracking; in fact we're in NF_IP_FORWARD, 00051 but connection tracking doesn't expect that */ 00052 ret = ip_conntrack_in(NF_IP_POST_ROUTING, pskb, dev, NULL, NULL); 00053 if (ret != NF_ACCEPT) { 00054 DEBUGP("ip_conntrack_in returned %u.\n", ret); 00055 return ret; 00056 } 00057 00058 ct = ip_conntrack_get(*pskb, &ctinfo); 00059 00060 if (!ct) { 00061 DEBUGP("ip_conntrack_in set to invalid conntrack.\n"); 00062 return NF_DROP; 00063 } 00064 00065 info = &ct->nat.info; 00066 00067 WRITE_LOCK(&ip_nat_lock); 00068 /* Setup the masquerade, if not already */ 00069 if (!info->initialized) { 00070 u_int32_t newsrc; 00071 struct rtable *rt; 00072 struct ip_nat_multi_range range; 00073 00074 /* Pass 0 instead of saddr, since it's going to be changed 00075 anyway. */ 00076 if (ip_route_output(&rt, iph->daddr, 0, 0, 0) != 0) { 00077 DEBUGP("ipnat_rule_masquerade: Can't reroute.\n"); 00078 return NF_DROP; 00079 } 00080 newsrc = inet_select_addr(rt->u.dst.dev, rt->rt_gateway, 00081 RT_SCOPE_UNIVERSE); 00082 ip_rt_put(rt); 00083 range = ((struct ip_nat_multi_range) 00084 { 1, 00085 {{IP_NAT_RANGE_MAP_IPS|IP_NAT_RANGE_PROTO_SPECIFIED, 00086 newsrc, newsrc, 00087 { htons(61000) }, { htons(65095) } } } }); 00088 00089 ret = ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); 00090 if (ret != NF_ACCEPT) { 00091 WRITE_UNLOCK(&ip_nat_lock); 00092 return ret; 00093 } 00094 00095 place_in_hashes(ct, info); 00096 info->initialized = 1; 00097 } else 00098 DEBUGP("Masquerading already done on this conn.\n"); 00099 WRITE_UNLOCK(&ip_nat_lock); 00100 00101 return do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb); 00102 } 00103 00104 void 00105 check_for_masq_error(struct sk_buff *skb) 00106 { 00107 enum ip_conntrack_info ctinfo; 00108 struct ip_conntrack *ct; 00109 00110 ct = ip_conntrack_get(skb, &ctinfo); 00111 /* Wouldn't be here if not tracked already => masq'ed ICMP 00112 ping or error related to masq'd connection */ 00113 IP_NF_ASSERT(ct); 00114 if (ctinfo == IP_CT_RELATED) { 00115 icmp_reply_translation(skb, ct, NF_IP_PRE_ROUTING, 00116 CTINFO2DIR(ctinfo)); 00117 icmp_reply_translation(skb, ct, NF_IP_POST_ROUTING, 00118 CTINFO2DIR(ctinfo)); 00119 } 00120 } 00121 00122 unsigned int 00123 check_for_demasq(struct sk_buff **pskb) 00124 { 00125 struct ip_conntrack_tuple tuple; 00126 struct iphdr *iph = (*pskb)->nh.iph; 00127 struct ip_conntrack_protocol *protocol; 00128 struct ip_conntrack_tuple_hash *h; 00129 enum ip_conntrack_info ctinfo; 00130 struct ip_conntrack *ct; 00131 int ret; 00132 00133 protocol = ip_ct_find_proto(iph->protocol); 00134 00135 /* We don't feed packets to conntrack system unless we know 00136 they're part of an connection already established by an 00137 explicit masq command. */ 00138 switch (iph->protocol) { 00139 case IPPROTO_ICMP: 00140 /* ICMP errors. */ 00141 ct = icmp_error_track(*pskb, &ctinfo, NF_IP_PRE_ROUTING); 00142 if (ct) { 00143 /* We only do SNAT in the compatibility layer. 00144 So we can manipulate ICMP errors from 00145 server here (== DNAT). Do SNAT icmp manips 00146 in POST_ROUTING handling. */ 00147 if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { 00148 icmp_reply_translation(*pskb, ct, 00149 NF_IP_PRE_ROUTING, 00150 CTINFO2DIR(ctinfo)); 00151 icmp_reply_translation(*pskb, ct, 00152 NF_IP_POST_ROUTING, 00153 CTINFO2DIR(ctinfo)); 00154 } 00155 return NF_ACCEPT; 00156 } 00157 /* Fall thru... */ 00158 case IPPROTO_TCP: 00159 case IPPROTO_UDP: 00160 IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0); 00161 00162 if (!get_tuple(iph, (*pskb)->len, &tuple, protocol)) { 00163 if (net_ratelimit()) 00164 printk("ip_fw_compat_masq: Can't get tuple\n"); 00165 return NF_ACCEPT; 00166 } 00167 break; 00168 00169 default: 00170 /* Not ours... */ 00171 return NF_ACCEPT; 00172 } 00173 h = ip_conntrack_find_get(&tuple, NULL); 00174 00175 /* MUST be found, and MUST be reply. */ 00176 if (h && DIRECTION(h) == 1) { 00177 ret = ip_conntrack_in(NF_IP_PRE_ROUTING, pskb, 00178 NULL, NULL, NULL); 00179 00180 /* Put back the reference gained from find_get */ 00181 nf_conntrack_put(&h->ctrack->infos[0]); 00182 if (ret == NF_ACCEPT) { 00183 struct ip_conntrack *ct; 00184 ct = ip_conntrack_get(*pskb, &ctinfo); 00185 00186 if (ct) { 00187 struct ip_nat_info *info = &ct->nat.info; 00188 00189 do_bindings(ct, ctinfo, info, 00190 NF_IP_PRE_ROUTING, 00191 pskb); 00192 } else 00193 if (net_ratelimit()) 00194 printk("ip_fw_compat_masq: conntrack" 00195 " didn't like\n"); 00196 } 00197 } else { 00198 if (h) 00199 /* Put back the reference gained from find_get */ 00200 nf_conntrack_put(&h->ctrack->infos[0]); 00201 ret = NF_ACCEPT; 00202 } 00203 00204 return ret; 00205 } 00206 00207 int ip_fw_masq_timeouts(void *user, int len) 00208 { 00209 printk("Sorry: masquerading timeouts set 5DAYS/2MINS/60SECS\n"); 00210 return 0; 00211 } 00212 00213 static const char *masq_proto_name(u_int16_t protonum) 00214 { 00215 switch (protonum) { 00216 case IPPROTO_TCP: return "TCP"; 00217 case IPPROTO_UDP: return "UDP"; 00218 case IPPROTO_ICMP: return "ICMP"; 00219 default: return "MORE-CAFFIENE-FOR-RUSTY"; 00220 } 00221 } 00222 00223 static unsigned int 00224 print_masq(char *buffer, const struct ip_conntrack *conntrack) 00225 { 00226 char temp[129]; 00227 00228 /* This is for backwards compatibility, but ick!. 00229 We should never export jiffies to userspace. 00230 */ 00231 sprintf(temp,"%s %08X:%04X %08X:%04X %04X %08X %6d %6d %7lu", 00232 masq_proto_name(conntrack->tuplehash[0].tuple.dst.protonum), 00233 ntohl(conntrack->tuplehash[0].tuple.src.ip), 00234 ntohs(conntrack->tuplehash[0].tuple.src.u.all), 00235 ntohl(conntrack->tuplehash[0].tuple.dst.ip), 00236 ntohs(conntrack->tuplehash[0].tuple.dst.u.all), 00237 ntohs(conntrack->tuplehash[1].tuple.dst.u.all), 00238 /* Sorry, no init_seq, delta or previous_delta (yet). */ 00239 0, 0, 0, 00240 conntrack->timeout.expires - jiffies); 00241 00242 return sprintf(buffer, "%-127s\n", temp); 00243 } 00244 00245 /* Returns true when finished. */ 00246 static int 00247 masq_iterate(const struct ip_conntrack_tuple_hash *hash, 00248 char *buffer, off_t offset, off_t *upto, 00249 unsigned int *len, unsigned int maxlen) 00250 { 00251 unsigned int newlen; 00252 00253 IP_NF_ASSERT(hash->ctrack); 00254 00255 /* Only count originals */ 00256 if (DIRECTION(hash)) 00257 return 0; 00258 00259 if ((*upto)++ < offset) 00260 return 0; 00261 00262 newlen = print_masq(buffer + *len, hash->ctrack); 00263 if (*len + newlen > maxlen) 00264 return 1; 00265 else *len += newlen; 00266 00267 return 0; 00268 } 00269 00270 /* Everything in the hash is masqueraded. */ 00271 static int 00272 masq_procinfo(char *buffer, char **start, off_t offset, int length) 00273 { 00274 unsigned int i; 00275 int len = 0; 00276 off_t upto = 1; 00277 00278 /* Header: first record */ 00279 if (offset == 0) { 00280 char temp[128]; 00281 00282 sprintf(temp, 00283 "Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires (free=0,0,0)"); 00284 len = sprintf(buffer, "%-127s\n", temp); 00285 offset = 1; 00286 } 00287 00288 READ_LOCK(&ip_conntrack_lock); 00289 /* Traverse hash; print originals then reply. */ 00290 for (i = 0; i < ip_conntrack_htable_size; i++) { 00291 if (LIST_FIND(&ip_conntrack_hash[i], masq_iterate, 00292 struct ip_conntrack_tuple_hash *, 00293 buffer, offset, &upto, &len, length)) 00294 break; 00295 } 00296 READ_UNLOCK(&ip_conntrack_lock); 00297 00298 /* `start' hack - see fs/proc/generic.c line ~165 */ 00299 *start = (char *)((unsigned int)upto - offset); 00300 return len; 00301 } 00302 00303 int __init masq_init(void) 00304 { 00305 int ret; 00306 struct proc_dir_entry *proc; 00307 00308 ret = ip_conntrack_init(); 00309 if (ret == 0) { 00310 ret = ip_nat_init(); 00311 if (ret == 0) { 00312 proc = proc_net_create("ip_masquerade", 00313 0, masq_procinfo); 00314 if (proc) 00315 proc->owner = THIS_MODULE; 00316 else { 00317 ip_nat_cleanup(); 00318 ip_conntrack_cleanup(); 00319 ret = -ENOMEM; 00320 } 00321 } else 00322 ip_conntrack_cleanup(); 00323 } 00324 00325 return ret; 00326 } 00327 00328 void masq_cleanup(void) 00329 { 00330 ip_nat_cleanup(); 00331 ip_conntrack_cleanup(); 00332 proc_net_remove("ip_masquerade"); 00333 }

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