Commit 010c0b9f authored by Patrick McHardy's avatar Patrick McHardy

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: default avatarPatrick McHardy <kaber@trash.net>
parent f5b321bd
...@@ -7,13 +7,27 @@ ...@@ -7,13 +7,27 @@
struct sk_buff; struct sk_buff;
/* These return true or false. */ /* These return true or false. */
extern int nf_nat_mangle_tcp_packet(struct sk_buff *skb, extern int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
struct nf_conn *ct, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int match_offset, unsigned int match_offset,
unsigned int match_len, unsigned int match_len,
const char *rep_buffer, const char *rep_buffer,
unsigned int rep_len); 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, extern int nf_nat_mangle_udp_packet(struct sk_buff *skb,
struct nf_conn *ct, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
...@@ -21,6 +35,10 @@ extern int nf_nat_mangle_udp_packet(struct sk_buff *skb, ...@@ -21,6 +35,10 @@ extern int nf_nat_mangle_udp_packet(struct sk_buff *skb,
unsigned int match_len, unsigned int match_len,
const char *rep_buffer, const char *rep_buffer,
unsigned int rep_len); 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, extern int nf_nat_seq_adjust(struct sk_buff *skb,
struct nf_conn *ct, struct nf_conn *ct,
enum ip_conntrack_info ctinfo); enum ip_conntrack_info ctinfo);
......
...@@ -141,6 +141,17 @@ static int enlarge_skb(struct sk_buff *skb, unsigned int extra) ...@@ -141,6 +141,17 @@ static int enlarge_skb(struct sk_buff *skb, unsigned int extra)
return 1; 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 /* Generic function for mangling variable-length address changes inside
* NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
* command in FTP). * command in FTP).
...@@ -149,14 +160,13 @@ static int enlarge_skb(struct sk_buff *skb, unsigned int extra) ...@@ -149,14 +160,13 @@ static int enlarge_skb(struct sk_buff *skb, unsigned int extra)
* skb enlargement, ... * skb enlargement, ...
* *
* */ * */
int int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
nf_nat_mangle_tcp_packet(struct sk_buff *skb, struct nf_conn *ct,
struct nf_conn *ct, enum ip_conntrack_info ctinfo,
enum ip_conntrack_info ctinfo, unsigned int match_offset,
unsigned int match_offset, unsigned int match_len,
unsigned int match_len, const char *rep_buffer,
const char *rep_buffer, unsigned int rep_len, bool adjust)
unsigned int rep_len)
{ {
struct rtable *rt = skb_rtable(skb); struct rtable *rt = skb_rtable(skb);
struct iphdr *iph; struct iphdr *iph;
...@@ -202,16 +212,13 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb, ...@@ -202,16 +212,13 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb,
inet_proto_csum_replace2(&tcph->check, skb, inet_proto_csum_replace2(&tcph->check, skb,
htons(oldlen), htons(datalen), 1); htons(oldlen), htons(datalen), 1);
if (rep_len != match_len) { if (adjust && rep_len != match_len)
set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); nf_nat_set_seq_adjust(ct, ctinfo, tcph->seq,
adjust_tcp_sequence(ntohl(tcph->seq), (int)rep_len - (int)match_len);
(int)rep_len - (int)match_len,
ct, ctinfo);
nf_conntrack_event_cache(IPCT_NATSEQADJ, ct);
}
return 1; 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 /* Generic function for mangling variable-length address changes inside
* NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment