netfilter: nf_nat: support mangling a single TCP packet multiple times
authorPatrick McHardy <kaber@trash.net>
Thu, 11 Feb 2010 11:27:09 +0000 (12:27 +0100)
committerPatrick McHardy <kaber@trash.net>
Thu, 11 Feb 2010 11:27:09 +0000 (12:27 +0100)
nf_nat_mangle_tcp_packet() can currently only handle a single mangling
per window because it only maintains two sequence adjustment positions:
the one before the last adjustment and the one after.

This patch makes sequence number adjustment tracking in
nf_nat_mangle_tcp_packet() optional and allows a helper to manually
update the offsets after the packet has been fully handled.

Signed-off-by: Patrick McHardy <kaber@trash.net>
include/net/netfilter/nf_nat_helper.h
net/ipv4/netfilter/nf_nat_helper.c

index 4222220..02bb6c2 100644 (file)
@@ -7,13 +7,27 @@
 struct sk_buff;
 
 /* These return true or false. */
-extern int nf_nat_mangle_tcp_packet(struct sk_buff *skb,
-                                   struct nf_conn *ct,
-                                   enum ip_conntrack_info ctinfo,
-                                   unsigned int match_offset,
-                                   unsigned int match_len,
-                                   const char *rep_buffer,
-                                   unsigned int rep_len);
+extern int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
+                                     struct nf_conn *ct,
+                                     enum ip_conntrack_info ctinfo,
+                                     unsigned int match_offset,
+                                     unsigned int match_len,
+                                     const char *rep_buffer,
+                                     unsigned int rep_len, bool adjust);
+
+static inline int nf_nat_mangle_tcp_packet(struct sk_buff *skb,
+                                          struct nf_conn *ct,
+                                          enum ip_conntrack_info ctinfo,
+                                          unsigned int match_offset,
+                                          unsigned int match_len,
+                                          const char *rep_buffer,
+                                          unsigned int rep_len)
+{
+       return __nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
+                                         match_offset, match_len,
+                                         rep_buffer, rep_len, true);
+}
+
 extern int nf_nat_mangle_udp_packet(struct sk_buff *skb,
                                    struct nf_conn *ct,
                                    enum ip_conntrack_info ctinfo,
@@ -21,6 +35,10 @@ extern int nf_nat_mangle_udp_packet(struct sk_buff *skb,
                                    unsigned int match_len,
                                    const char *rep_buffer,
                                    unsigned int rep_len);
+
+extern void nf_nat_set_seq_adjust(struct nf_conn *ct,
+                                 enum ip_conntrack_info ctinfo,
+                                 __be32 seq, s16 off);
 extern int nf_nat_seq_adjust(struct sk_buff *skb,
                             struct nf_conn *ct,
                             enum ip_conntrack_info ctinfo);
index 7f10a6b..4b6af4b 100644 (file)
@@ -141,6 +141,17 @@ static int enlarge_skb(struct sk_buff *skb, unsigned int extra)
        return 1;
 }
 
+void nf_nat_set_seq_adjust(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
+                          __be32 seq, s16 off)
+{
+       if (!off)
+               return;
+       set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
+       adjust_tcp_sequence(ntohl(seq), off, ct, ctinfo);
+       nf_conntrack_event_cache(IPCT_NATSEQADJ, ct);
+}
+EXPORT_SYMBOL_GPL(nf_nat_set_seq_adjust);
+
 /* Generic function for mangling variable-length address changes inside
  * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
  * command in FTP).
@@ -149,14 +160,13 @@ static int enlarge_skb(struct sk_buff *skb, unsigned int extra)
  * skb enlargement, ...
  *
  * */
-int
-nf_nat_mangle_tcp_packet(struct sk_buff *skb,
-                        struct nf_conn *ct,
-                        enum ip_conntrack_info ctinfo,
-                        unsigned int match_offset,
-                        unsigned int match_len,
-                        const char *rep_buffer,
-                        unsigned int rep_len)
+int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
+                              struct nf_conn *ct,
+                              enum ip_conntrack_info ctinfo,
+                              unsigned int match_offset,
+                              unsigned int match_len,
+                              const char *rep_buffer,
+                              unsigned int rep_len, bool adjust)
 {
        struct rtable *rt = skb_rtable(skb);
        struct iphdr *iph;
@@ -202,16 +212,13 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb,
                inet_proto_csum_replace2(&tcph->check, skb,
                                         htons(oldlen), htons(datalen), 1);
 
-       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);
-               nf_conntrack_event_cache(IPCT_NATSEQADJ, ct);
-       }
+       if (adjust && rep_len != match_len)
+               nf_nat_set_seq_adjust(ct, ctinfo, tcph->seq,
+                                     (int)rep_len - (int)match_len);
+
        return 1;
 }
-EXPORT_SYMBOL(nf_nat_mangle_tcp_packet);
+EXPORT_SYMBOL(__nf_nat_mangle_tcp_packet);
 
 /* Generic function for mangling variable-length address changes inside
  * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX