aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2005-01-04 04:15:13 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-01-04 04:15:13 -0800
commit03b6d0efbf023893cc60fdeb23d8f6e121415a7e (patch)
tree639f73f09aec0d18c14ddf8f0d5a576781ab2a66 /net
parentd2e7f92666baf9da92ceac770ea592e666483dd4 (diff)
downloadhistory-03b6d0efbf023893cc60fdeb23d8f6e121415a7e.tar.gz
[PATCH] ftp nonlinear packet fix
FTP connection tracking assumes it can just dereference tcphdr; not neccessarily true now we don't linearize in ftp conntrack helper or tcp connection tracking. Also found by nfsim. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/netfilter/ip_nat_ftp.c17
1 files changed, 10 insertions, 7 deletions
diff --git a/net/ipv4/netfilter/ip_nat_ftp.c b/net/ipv4/netfilter/ip_nat_ftp.c
index eb2d84aa2a5a45..b488b5e1fca26a 100644
--- a/net/ipv4/netfilter/ip_nat_ftp.c
+++ b/net/ipv4/netfilter/ip_nat_ftp.c
@@ -169,18 +169,16 @@ static int (*mangle[])(struct sk_buff **, u_int32_t, u_int16_t,
static int ftp_data_fixup(const struct ip_ct_ftp_expect *exp_ftp_info,
struct ip_conntrack *ct,
struct sk_buff **pskb,
+ u32 tcp_seq,
enum ip_conntrack_info ctinfo,
struct ip_conntrack_expect *expect)
{
u_int32_t newip;
- struct iphdr *iph = (*pskb)->nh.iph;
- struct tcphdr *tcph = (void *)iph + iph->ihl*4;
u_int16_t port;
struct ip_conntrack_tuple newtuple;
DEBUGP("FTP_NAT: seq %u + %u in %u\n",
- expect->seq, exp_ftp_info->len,
- ntohl(tcph->seq));
+ expect->seq, exp_ftp_info->len, tcp_seq);
/* Change address inside packet to match way we're mapping
this connection. */
@@ -217,7 +215,7 @@ static int ftp_data_fixup(const struct ip_ct_ftp_expect *exp_ftp_info,
return 0;
if (!mangle[exp_ftp_info->ftptype](pskb, newip, port,
- expect->seq - ntohl(tcph->seq),
+ expect->seq - tcp_seq,
exp_ftp_info->len, ct, ctinfo))
return 0;
@@ -232,7 +230,7 @@ static unsigned int help(struct ip_conntrack *ct,
struct sk_buff **pskb)
{
struct iphdr *iph = (*pskb)->nh.iph;
- struct tcphdr *tcph = (void *)iph + iph->ihl*4;
+ struct tcphdr _tcph, *tcph;
unsigned int datalen;
int dir;
struct ip_ct_ftp_expect *exp_ftp_info;
@@ -255,12 +253,17 @@ static unsigned int help(struct ip_conntrack *ct,
return NF_ACCEPT;
}
+ /* We passed tcp tracking, plus ftp helper: this must succeed. */
+ tcph = skb_header_pointer(*pskb, iph->ihl * 4, sizeof(_tcph), &_tcph);
+ BUG_ON(!tcph);
+
datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
/* If it's in the right range... */
if (between(exp->seq + exp_ftp_info->len,
ntohl(tcph->seq),
ntohl(tcph->seq) + datalen)) {
- if (!ftp_data_fixup(exp_ftp_info, ct, pskb, ctinfo, exp))
+ if (!ftp_data_fixup(exp_ftp_info, ct, pskb, ntohl(tcph->seq),
+ ctinfo, exp))
return NF_DROP;
} else {
/* Half a match? This means a partial retransmisison.