vserver 1.9.5.x5
[linux-2.6.git] / net / ipv4 / netfilter / ip_nat_helper.c
index d7ee32f..1637b96 100644 (file)
@@ -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);
 }