X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fnetfilter%2Fip_nat_helper.c;h=1637b96d8c0110c155efd1fe7492570cfdb34650;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=d7ee32f05b6d1db6b2729aa51d4f021abd7281a0;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c index d7ee32f05..1637b96d8 100644 --- a/net/ipv4/netfilter/ip_nat_helper.c +++ b/net/ipv4/netfilter/ip_nat_helper.c @@ -47,8 +47,7 @@ #define DUMP_OFFSET(x) #endif -static LIST_HEAD(helpers); -DECLARE_LOCK(ip_nat_seqofs_lock); +static DECLARE_LOCK(ip_nat_seqofs_lock); /* Setup TCP sequence correction given this change at this sequence */ static inline void @@ -193,9 +192,14 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb, tcph->check = tcp_v4_check(tcph, datalen, iph->saddr, iph->daddr, csum_partial((char *)tcph, datalen, 0)); - adjust_tcp_sequence(ntohl(tcph->seq), - (int)rep_len - (int)match_len, - ct, ctinfo); + if (rep_len != match_len) { + set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); + adjust_tcp_sequence(ntohl(tcph->seq), + (int)rep_len - (int)match_len, + ct, ctinfo); + /* Tell TCP window tracking about seq change */ + ip_conntrack_tcp_update(*pskb, ct, CTINFO2DIR(ctinfo)); + } return 1; } @@ -362,11 +366,6 @@ ip_nat_seq_adjust(struct sk_buff **pskb, this_way = &ct->nat.info.seq[dir]; other_way = &ct->nat.info.seq[!dir]; - /* No adjustments to make? Very common case. */ - if (!this_way->offset_before && !this_way->offset_after - && !other_way->offset_before && !other_way->offset_after) - return 1; - if (!skb_ip_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph))) return 0; @@ -404,75 +403,28 @@ ip_nat_seq_adjust(struct sk_buff **pskb, return 1; } -static inline int -helper_cmp(const struct ip_nat_helper *helper, - const struct ip_conntrack_tuple *tuple) +/* Setup NAT on this expected conntrack so it follows master. */ +/* If we fail to get a free NAT slot, we'll get dropped on confirm */ +void ip_nat_follow_master(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp) { - return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask); -} - -int ip_nat_helper_register(struct ip_nat_helper *me) -{ - int ret = 0; - - WRITE_LOCK(&ip_nat_lock); - if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple)) - ret = -EBUSY; - else - list_prepend(&helpers, me); - WRITE_UNLOCK(&ip_nat_lock); - - return ret; -} - -struct ip_nat_helper * -__ip_nat_find_helper(const struct ip_conntrack_tuple *tuple) -{ - return LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *, tuple); -} - -struct ip_nat_helper * -ip_nat_find_helper(const struct ip_conntrack_tuple *tuple) -{ - struct ip_nat_helper *h; - - READ_LOCK(&ip_nat_lock); - h = __ip_nat_find_helper(tuple); - READ_UNLOCK(&ip_nat_lock); - - return h; -} - -static int -kill_helper(const struct ip_conntrack *i, void *helper) -{ - int ret; - - READ_LOCK(&ip_nat_lock); - ret = (i->nat.info.helper == helper); - READ_UNLOCK(&ip_nat_lock); - - return ret; -} - -void ip_nat_helper_unregister(struct ip_nat_helper *me) -{ - WRITE_LOCK(&ip_nat_lock); - /* Autoloading conntrack helper might have failed */ - if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple)) { - LIST_DELETE(&helpers, me); - } - WRITE_UNLOCK(&ip_nat_lock); - - /* Someone could be still looking at the helper in a bh. */ - synchronize_net(); - - /* Find anything using it, and umm, kill them. We can't turn - them into normal connections: if we've adjusted SYNs, then - they'll ackstorm. So we just drop it. We used to just - bump module count when a connection existed, but that - forces admins to gen fake RSTs or bounce box, either of - which is just a long-winded way of making things - worse. --RR */ - ip_ct_selective_cleanup(kill_helper, me); + struct ip_nat_range range; + + /* This must be a fresh one. */ + BUG_ON(ct->status & IPS_NAT_DONE_MASK); + + /* Change src to where master sends to */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip + = ct->master->tuplehash[!exp->dir].tuple.dst.ip; + /* hook doesn't matter, but it has to do source manip */ + ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); + + /* For DST manip, map port here to where it's expected. */ + range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); + range.min = range.max = exp->saved_proto; + range.min_ip = range.max_ip + = ct->master->tuplehash[!exp->dir].tuple.src.ip; + /* hook doesn't matter, but it has to do destination manip */ + ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); }