--- zzzz-none-000/linux-2.4.17/net/ipv4/netfilter/ip_nat_core.c 2001-12-21 17:42:05.000000000 +0000 +++ sangam-fb-322/linux-2.4.17/net/ipv4/netfilter/ip_nat_core.c 2004-11-24 13:22:08.000000000 +0000 @@ -21,19 +21,26 @@ #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock) #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock) +#include +#include +#include #include #include #include #include +#include #include + #if 0 #define DEBUGP printk #else #define DEBUGP(format, args...) #endif + DECLARE_RWLOCK(ip_nat_lock); +DECLARE_RWLOCK_EXTERN(ip_conntrack_lock); /* Calculated at init based on memory size */ static unsigned int ip_nat_htable_size; @@ -314,6 +321,7 @@ * do_extra_mangle last time. */ *other_ipp = saved_ip; +#ifdef CONFIG_IP_NF_NAT_LOCAL if (hooknum == NF_IP_LOCAL_OUT && *var_ipp != orig_dstip && !do_extra_mangle(*var_ipp, other_ipp)) { @@ -324,6 +332,7 @@ * anyway. */ continue; } +#endif /* Count how many others map onto this. */ score = count_maps(tuple->src.ip, tuple->dst.ip, @@ -367,11 +376,13 @@ else { /* Only do extra mangle when required (breaks socket binding) */ +#ifdef CONFIG_IP_NF_NAT_LOCAL if (tuple->dst.ip != mr->range[0].min_ip && hooknum == NF_IP_LOCAL_OUT && !do_extra_mangle(mr->range[0].min_ip, &tuple->src.ip)) return NULL; +#endif tuple->dst.ip = mr->range[0].min_ip; } } @@ -423,7 +434,7 @@ *tuple = *orig_tuple; while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum)) != NULL) { - DEBUGP("Found best for "); DUMP_TUPLE(tuple); + DEBUGP("Found best for "); DUMP_TUPLE_RAW(tuple); /* 3) The per-protocol part of the manip is made to map into the range to make a unique tuple. */ @@ -494,7 +505,10 @@ static unsigned int opposite_hook[NF_IP_NUMHOOKS] = { [NF_IP_PRE_ROUTING] = NF_IP_POST_ROUTING, [NF_IP_POST_ROUTING] = NF_IP_PRE_ROUTING, - [NF_IP_LOCAL_OUT] = NF_IP_POST_ROUTING +#ifdef CONFIG_IP_NF_NAT_LOCAL + [NF_IP_LOCAL_OUT] = NF_IP_LOCAL_IN, + [NF_IP_LOCAL_IN] = NF_IP_LOCAL_OUT, +#endif }; unsigned int @@ -559,9 +573,9 @@ HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST", conntrack); DEBUGP("Original: "); - DUMP_TUPLE(&orig_tp); + DUMP_TUPLE_RAW(&orig_tp); DEBUGP("New: "); - DUMP_TUPLE(&new_tuple); + DUMP_TUPLE_RAW(&new_tuple); #endif /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT): @@ -621,8 +635,9 @@ } /* If there's a helper, assign it; based on new tuple. */ - info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *, - &reply); + if (!conntrack->master) + info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *, + &reply); /* It's done. */ info->initialized |= (1 << HOOK2MANIP(hooknum)); @@ -717,6 +732,21 @@ #endif } +static inline int exp_for_packet(struct ip_conntrack_expect *exp, + struct sk_buff **pskb) +{ + struct ip_conntrack_protocol *proto; + int ret = 1; + + READ_LOCK(&ip_conntrack_lock); + proto = ip_ct_find_proto((*pskb)->nh.iph->protocol); + if (proto->exp_matches_pkt) + ret = proto->exp_matches_pkt(exp, pskb); + READ_UNLOCK(&ip_conntrack_lock); + + return ret; +} + /* Do packet manipulations according to binding. */ unsigned int do_bindings(struct ip_conntrack *ct, @@ -728,6 +758,7 @@ unsigned int i; struct ip_nat_helper *helper; enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + int is_tcp = (*pskb)->nh.iph->protocol == IPPROTO_TCP; /* Need nat lock to protect against modification, but neither conntrack (referenced) and helper (deleted with @@ -766,11 +797,66 @@ READ_UNLOCK(&ip_nat_lock); if (helper) { + struct ip_conntrack_expect *exp = NULL; + struct list_head *cur_item; + int ret = NF_ACCEPT; + + DEBUGP("do_bindings: helper existing for (%p)\n", ct); + /* Always defragged for helpers */ IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET))); - return helper->help(ct, info, ctinfo, hooknum, pskb); - } else return NF_ACCEPT; + + /* Have to grab read lock before sibling_list traversal */ + READ_LOCK(&ip_conntrack_lock); + list_for_each(cur_item, &ct->sibling_list) { + exp = list_entry(cur_item, struct ip_conntrack_expect, + expected_list); + + /* if this expectation is already established, skip */ + if (exp->sibling) + continue; + + if (exp_for_packet(exp, pskb)) { + /* FIXME: May be true multiple times in the case of UDP!! */ + DEBUGP("calling nat helper (exp=%p) for packet\n", + exp); + ret = helper->help(ct, exp, info, ctinfo, + hooknum, pskb); + if (ret != NF_ACCEPT) { + READ_UNLOCK(&ip_conntrack_lock); + return ret; + } + } + } + /* Helper might want to manip the packet even when there is no expectation */ + if (!exp && helper->flags & IP_NAT_HELPER_F_ALWAYS) { + DEBUGP("calling nat helper for packet without expectation\n"); + ret = helper->help(ct, NULL, info, ctinfo, + hooknum, pskb); + if (ret != NF_ACCEPT) { + READ_UNLOCK(&ip_conntrack_lock); + return ret; + } + } + READ_UNLOCK(&ip_conntrack_lock); + + /* Adjust sequence number only once per packet + * (helper is called at all hooks) */ + if (is_tcp && (hooknum == NF_IP_POST_ROUTING + || hooknum == NF_IP_LOCAL_IN)) { + DEBUGP("ip_nat_core: adjusting sequence number\n"); + /* future: put this in a l4-proto specific function, + * and call this function here. */ + ip_nat_seq_adjust(*pskb, ct, ctinfo); + } + + return ret; + + } else + return NF_ACCEPT; + + /* not reached */ } unsigned int @@ -913,4 +999,5 @@ { ip_ct_selective_cleanup(&clean_nat, NULL); ip_conntrack_destroyed = NULL; + vfree(bysource); }