1/* Masquerading compatibility layer. 2 3 Note that there are no restrictions on other programs binding to 4 ports 61000:65095 (in 2.0 and 2.2 they get EADDRINUSE). Just DONT 5 DO IT. 6 */ 7#include <linux/skbuff.h> 8#include <linux/in.h> 9#include <linux/ip.h> 10#include <linux/icmp.h> 11#include <linux/udp.h> 12#include <linux/netfilter_ipv4.h> 13#include <linux/netdevice.h> 14#include <linux/inetdevice.h> 15#include <linux/proc_fs.h> 16#include <linux/version.h> 17#include <linux/module.h> 18#include <net/route.h> 19 20#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock) 21#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock) 22 23#include <linux/netfilter_ipv4/ip_conntrack.h> 24#include <linux/netfilter_ipv4/ip_conntrack_core.h> 25#include <linux/netfilter_ipv4/ip_nat.h> 26#include <linux/netfilter_ipv4/ip_nat_core.h> 27#include <linux/netfilter_ipv4/listhelp.h> 28 29#define DEBUGP(format, args...) 30 31unsigned int 32do_masquerade(struct sk_buff **pskb, const struct net_device *dev) 33{ 34 struct iphdr *iph = (*pskb)->nh.iph; 35 struct ip_nat_info *info; 36 enum ip_conntrack_info ctinfo; 37 struct ip_conntrack *ct; 38 unsigned int ret; 39 40 /* Sorry, only ICMP, TCP and UDP. */ 41 if (iph->protocol != IPPROTO_ICMP 42 && iph->protocol != IPPROTO_TCP 43 && iph->protocol != IPPROTO_UDP) 44 return NF_DROP; 45 46 /* Feed it to connection tracking; in fact we're in NF_IP_FORWARD, 47 but connection tracking doesn't expect that */ 48 ret = ip_conntrack_in(NF_IP_POST_ROUTING, pskb, dev, NULL, NULL); 49 if (ret != NF_ACCEPT) { 50 DEBUGP("ip_conntrack_in returned %u.\n", ret); 51 return ret; 52 } 53 54 ct = ip_conntrack_get(*pskb, &ctinfo); 55 56 if (!ct) { 57 DEBUGP("ip_conntrack_in set to invalid conntrack.\n"); 58 return NF_DROP; 59 } 60 61 info = &ct->nat.info; 62 63 WRITE_LOCK(&ip_nat_lock); 64 /* Setup the masquerade, if not already */ 65 if (!info->initialized) { 66 u_int32_t newsrc; 67 struct rtable *rt; 68 struct ip_nat_multi_range range; 69 70 /* Pass 0 instead of saddr, since it's going to be changed 71 anyway. */ 72 if (ip_route_output(&rt, iph->daddr, 0, 0, 0) != 0) { 73 DEBUGP("ipnat_rule_masquerade: Can't reroute.\n"); 74 return NF_DROP; 75 } 76 newsrc = inet_select_addr(rt->u.dst.dev, rt->rt_gateway, 77 RT_SCOPE_UNIVERSE); 78 ip_rt_put(rt); 79 range = ((struct ip_nat_multi_range) 80 { 1, 81 {{IP_NAT_RANGE_MAP_IPS|IP_NAT_RANGE_PROTO_SPECIFIED, 82 newsrc, newsrc, 83 { htons(61000) }, { htons(65095) } } } }); 84 85 ret = ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); 86 if (ret != NF_ACCEPT) { 87 WRITE_UNLOCK(&ip_nat_lock); 88 return ret; 89 } 90 91 place_in_hashes(ct, info); 92 info->initialized = 1; 93 } else 94 DEBUGP("Masquerading already done on this conn.\n"); 95 WRITE_UNLOCK(&ip_nat_lock); 96 97 return do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb); 98} 99 100void 101check_for_masq_error(struct sk_buff *skb) 102{ 103 enum ip_conntrack_info ctinfo; 104 struct ip_conntrack *ct; 105 106 ct = ip_conntrack_get(skb, &ctinfo); 107 /* Wouldn't be here if not tracked already => masq'ed ICMP 108 ping or error related to masq'd connection */ 109 IP_NF_ASSERT(ct); 110 if (ctinfo == IP_CT_RELATED) { 111 icmp_reply_translation(skb, ct, NF_IP_PRE_ROUTING, 112 CTINFO2DIR(ctinfo)); 113 icmp_reply_translation(skb, ct, NF_IP_POST_ROUTING, 114 CTINFO2DIR(ctinfo)); 115 } 116} 117 118unsigned int 119check_for_demasq(struct sk_buff **pskb) 120{ 121 struct ip_conntrack_tuple tuple; 122 struct iphdr *iph = (*pskb)->nh.iph; 123 struct ip_conntrack_protocol *protocol; 124 struct ip_conntrack_tuple_hash *h; 125 enum ip_conntrack_info ctinfo; 126 struct ip_conntrack *ct; 127 int ret; 128 129 protocol = ip_ct_find_proto(iph->protocol); 130 131 /* We don't feed packets to conntrack system unless we know 132 they're part of an connection already established by an 133 explicit masq command. */ 134 switch (iph->protocol) { 135 case IPPROTO_ICMP: 136 /* ICMP errors. */ 137 ct = icmp_error_track(*pskb, &ctinfo, NF_IP_PRE_ROUTING); 138 if (ct) { 139 /* We only do SNAT in the compatibility layer. 140 So we can manipulate ICMP errors from 141 server here (== DNAT). Do SNAT icmp manips 142 in POST_ROUTING handling. */ 143 if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { 144 icmp_reply_translation(*pskb, ct, 145 NF_IP_PRE_ROUTING, 146 CTINFO2DIR(ctinfo)); 147 icmp_reply_translation(*pskb, ct, 148 NF_IP_POST_ROUTING, 149 CTINFO2DIR(ctinfo)); 150 } 151 return NF_ACCEPT; 152 } 153 /* Fall thru... */ 154 case IPPROTO_TCP: 155 case IPPROTO_UDP: 156 IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0); 157 158 if (!get_tuple(iph, (*pskb)->len, &tuple, protocol)) { 159 if (net_ratelimit()) 160 printk("ip_fw_compat_masq: Can't get tuple\n"); 161 return NF_ACCEPT; 162 } 163 break; 164 165 default: 166 /* Not ours... */ 167 return NF_ACCEPT; 168 } 169 h = ip_conntrack_find_get(&tuple, NULL); 170 171 /* MUST be found, and MUST be reply. */ 172 if (h && DIRECTION(h) == 1) { 173 ret = ip_conntrack_in(NF_IP_PRE_ROUTING, pskb, 174 NULL, NULL, NULL); 175 176 /* Put back the reference gained from find_get */ 177 nf_conntrack_put(&h->ctrack->infos[0]); 178 if (ret == NF_ACCEPT) { 179 struct ip_conntrack *ct; 180 ct = ip_conntrack_get(*pskb, &ctinfo); 181 182 if (ct) { 183 struct ip_nat_info *info = &ct->nat.info; 184 185 do_bindings(ct, ctinfo, info, 186 NF_IP_PRE_ROUTING, 187 pskb); 188 } else 189 if (net_ratelimit()) 190 printk("ip_fw_compat_masq: conntrack" 191 " didn't like\n"); 192 } 193 } else { 194 if (h) 195 /* Put back the reference gained from find_get */ 196 nf_conntrack_put(&h->ctrack->infos[0]); 197 ret = NF_ACCEPT; 198 } 199 200 return ret; 201} 202 203int ip_fw_masq_timeouts(void *user, int len) 204{ 205 printk("Sorry: masquerading timeouts set 5DAYS/2MINS/60SECS\n"); 206 return 0; 207} 208 209static const char *masq_proto_name(u_int16_t protonum) 210{ 211 switch (protonum) { 212 case IPPROTO_TCP: return "TCP"; 213 case IPPROTO_UDP: return "UDP"; 214 case IPPROTO_ICMP: return "ICMP"; 215 default: return "MORE-CAFFIENE-FOR-RUSTY"; 216 } 217} 218 219static unsigned int 220print_masq(char *buffer, const struct ip_conntrack *conntrack) 221{ 222 char temp[129]; 223 224 /* This is for backwards compatibility, but ick!. 225 We should never export jiffies to userspace. 226 */ 227 sprintf(temp,"%s %08X:%04X %08X:%04X %04X %08X %6d %6d %7lu", 228 masq_proto_name(conntrack->tuplehash[0].tuple.dst.protonum), 229 ntohl(conntrack->tuplehash[0].tuple.src.ip), 230 ntohs(conntrack->tuplehash[0].tuple.src.u.all), 231 ntohl(conntrack->tuplehash[0].tuple.dst.ip), 232 ntohs(conntrack->tuplehash[0].tuple.dst.u.all), 233 ntohs(conntrack->tuplehash[1].tuple.dst.u.all), 234 /* Sorry, no init_seq, delta or previous_delta (yet). */ 235 0, 0, 0, 236 conntrack->timeout.expires - jiffies); 237 238 return sprintf(buffer, "%-127s\n", temp); 239} 240 241/* Returns true when finished. */ 242static int 243masq_iterate(const struct ip_conntrack_tuple_hash *hash, 244 char *buffer, off_t offset, off_t *upto, 245 unsigned int *len, unsigned int maxlen) 246{ 247 unsigned int newlen; 248 249 IP_NF_ASSERT(hash->ctrack); 250 251 /* Only count originals */ 252 if (DIRECTION(hash)) 253 return 0; 254 255 if ((*upto)++ < offset) 256 return 0; 257 258 newlen = print_masq(buffer + *len, hash->ctrack); 259 if (*len + newlen > maxlen) 260 return 1; 261 else *len += newlen; 262 263 return 0; 264} 265 266/* Everything in the hash is masqueraded. */ 267static int 268masq_procinfo(char *buffer, char **start, off_t offset, int length) 269{ 270 unsigned int i; 271 int len = 0; 272 off_t upto = 1; 273 274 /* Header: first record */ 275 if (offset == 0) { 276 char temp[128]; 277 278 sprintf(temp, 279 "Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires (free=0,0,0)"); 280 len = sprintf(buffer, "%-127s\n", temp); 281 offset = 1; 282 } 283 284 READ_LOCK(&ip_conntrack_lock); 285 /* Traverse hash; print originals then reply. */ 286 for (i = 0; i < ip_conntrack_htable_size; i++) { 287 if (LIST_FIND(&ip_conntrack_hash[i], masq_iterate, 288 struct ip_conntrack_tuple_hash *, 289 buffer, offset, &upto, &len, length)) 290 break; 291 } 292 READ_UNLOCK(&ip_conntrack_lock); 293 294 /* `start' hack - see fs/proc/generic.c line ~165 */ 295 *start = (char *)((unsigned int)upto - offset); 296 return len; 297} 298 299int __init masq_init(void) 300{ 301 int ret; 302 struct proc_dir_entry *proc; 303 304 ret = ip_conntrack_init(); 305 if (ret == 0) { 306 ret = ip_nat_init(); 307 if (ret == 0) { 308 proc = proc_net_create("ip_masquerade", 309 0, masq_procinfo); 310 if (proc) 311 proc->owner = THIS_MODULE; 312 else { 313 ip_nat_cleanup(); 314 ip_conntrack_cleanup(); 315 ret = -ENOMEM; 316 } 317 } else 318 ip_conntrack_cleanup(); 319 } 320 321 return ret; 322} 323 324void masq_cleanup(void) 325{ 326 ip_nat_cleanup(); 327 ip_conntrack_cleanup(); 328 proc_net_remove("ip_masquerade"); 329} 330