diff mbox

netfilter 44/62: nf_nat: support mangling a single TCP packet multiple times

Message ID 20100216145617.2796.93888.sendpatchset@x2.localnet
State Accepted, archived
Delegated to: David Miller
Headers show

Commit Message

Patrick McHardy Feb. 16, 2010, 2:56 p.m. UTC
commit 010c0b9f34a4c567b431f8b49a58b7332ed42e47
Author: Patrick McHardy <kaber@trash.net>
Date:   Thu Feb 11 12:27:09 2010 +0100

    netfilter: nf_nat: support mangling a single TCP packet multiple times
    
    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>

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/include/net/netfilter/nf_nat_helper.h b/include/net/netfilter/nf_nat_helper.h
index 4222220..02bb6c2 100644
--- a/include/net/netfilter/nf_nat_helper.h
+++ b/include/net/netfilter/nf_nat_helper.h
@@ -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);
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c
index 7f10a6b..4b6af4b 100644
--- a/net/ipv4/netfilter/nf_nat_helper.c
+++ b/net/ipv4/netfilter/nf_nat_helper.c
@@ -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