Commit 53bd9728 authored by David S. Miller's avatar David S. Miller
parents bd46cb6c d6d3f08b
...@@ -81,4 +81,17 @@ struct xt_conntrack_mtinfo1 { ...@@ -81,4 +81,17 @@ struct xt_conntrack_mtinfo1 {
__u8 state_mask, status_mask; __u8 state_mask, status_mask;
}; };
struct xt_conntrack_mtinfo2 {
union nf_inet_addr origsrc_addr, origsrc_mask;
union nf_inet_addr origdst_addr, origdst_mask;
union nf_inet_addr replsrc_addr, replsrc_mask;
union nf_inet_addr repldst_addr, repldst_mask;
__u32 expires_min, expires_max;
__u16 l4proto;
__be16 origsrc_port, origdst_port;
__be16 replsrc_port, repldst_port;
__u16 match_flags, invert_flags;
__u16 state_mask, status_mask;
};
#endif /*_XT_CONNTRACK_H*/ #endif /*_XT_CONNTRACK_H*/
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#ifndef _XT_OSF_H #ifndef _XT_OSF_H
#define _XT_OSF_H #define _XT_OSF_H
#include <linux/types.h>
#define MAXGENRELEN 32 #define MAXGENRELEN 32
#define XT_OSF_GENRE (1<<0) #define XT_OSF_GENRE (1<<0)
......
...@@ -258,8 +258,8 @@ static inline bool nf_ct_kill(struct nf_conn *ct) ...@@ -258,8 +258,8 @@ static inline bool nf_ct_kill(struct nf_conn *ct)
/* Update TCP window tracking data when NAT mangles the packet */ /* Update TCP window tracking data when NAT mangles the packet */
extern void nf_conntrack_tcp_update(const struct sk_buff *skb, extern void nf_conntrack_tcp_update(const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
struct nf_conn *ct, struct nf_conn *ct, int dir,
int dir); s16 offset);
/* Fake conntrack entry for untracked connections */ /* Fake conntrack entry for untracked connections */
extern struct nf_conn nf_conntrack_untracked; extern struct nf_conn nf_conntrack_untracked;
......
...@@ -191,7 +191,8 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb, ...@@ -191,7 +191,8 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb,
ct, ctinfo); ct, ctinfo);
/* Tell TCP window tracking about seq change */ /* Tell TCP window tracking about seq change */
nf_conntrack_tcp_update(skb, ip_hdrlen(skb), nf_conntrack_tcp_update(skb, ip_hdrlen(skb),
ct, CTINFO2DIR(ctinfo)); ct, CTINFO2DIR(ctinfo),
(int)rep_len - (int)match_len);
nf_conntrack_event_cache(IPCT_NATSEQADJ, ct); nf_conntrack_event_cache(IPCT_NATSEQADJ, ct);
} }
...@@ -377,6 +378,7 @@ nf_nat_seq_adjust(struct sk_buff *skb, ...@@ -377,6 +378,7 @@ nf_nat_seq_adjust(struct sk_buff *skb,
struct tcphdr *tcph; struct tcphdr *tcph;
int dir; int dir;
__be32 newseq, newack; __be32 newseq, newack;
s16 seqoff, ackoff;
struct nf_conn_nat *nat = nfct_nat(ct); struct nf_conn_nat *nat = nfct_nat(ct);
struct nf_nat_seq *this_way, *other_way; struct nf_nat_seq *this_way, *other_way;
...@@ -390,15 +392,18 @@ nf_nat_seq_adjust(struct sk_buff *skb, ...@@ -390,15 +392,18 @@ nf_nat_seq_adjust(struct sk_buff *skb,
tcph = (void *)skb->data + ip_hdrlen(skb); tcph = (void *)skb->data + ip_hdrlen(skb);
if (after(ntohl(tcph->seq), this_way->correction_pos)) if (after(ntohl(tcph->seq), this_way->correction_pos))
newseq = htonl(ntohl(tcph->seq) + this_way->offset_after); seqoff = this_way->offset_after;
else else
newseq = htonl(ntohl(tcph->seq) + this_way->offset_before); seqoff = this_way->offset_before;
if (after(ntohl(tcph->ack_seq) - other_way->offset_before, if (after(ntohl(tcph->ack_seq) - other_way->offset_before,
other_way->correction_pos)) other_way->correction_pos))
newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after); ackoff = other_way->offset_after;
else else
newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before); ackoff = other_way->offset_before;
newseq = htonl(ntohl(tcph->seq) + seqoff);
newack = htonl(ntohl(tcph->ack_seq) - ackoff);
inet_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, 0); inet_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, 0);
inet_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack, 0); inet_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack, 0);
...@@ -413,7 +418,7 @@ nf_nat_seq_adjust(struct sk_buff *skb, ...@@ -413,7 +418,7 @@ nf_nat_seq_adjust(struct sk_buff *skb,
if (!nf_nat_sack_adjust(skb, tcph, ct, ctinfo)) if (!nf_nat_sack_adjust(skb, tcph, ct, ctinfo))
return 0; return 0;
nf_conntrack_tcp_update(skb, ip_hdrlen(skb), ct, dir); nf_conntrack_tcp_update(skb, ip_hdrlen(skb), ct, dir, seqoff);
return 1; return 1;
} }
......
...@@ -617,8 +617,10 @@ int nf_conntrack_expect_init(struct net *net) ...@@ -617,8 +617,10 @@ int nf_conntrack_expect_init(struct net *net)
void nf_conntrack_expect_fini(struct net *net) void nf_conntrack_expect_fini(struct net *net)
{ {
exp_proc_remove(net); exp_proc_remove(net);
if (net_eq(net, &init_net)) if (net_eq(net, &init_net)) {
rcu_barrier(); /* Wait for call_rcu() before destroy */
kmem_cache_destroy(nf_ct_expect_cachep); kmem_cache_destroy(nf_ct_expect_cachep);
}
nf_ct_free_hashtable(net->ct.expect_hash, net->ct.expect_vmalloc, nf_ct_free_hashtable(net->ct.expect_hash, net->ct.expect_vmalloc,
nf_ct_expect_hsize); nf_ct_expect_hsize);
} }
...@@ -186,6 +186,6 @@ void nf_ct_extend_unregister(struct nf_ct_ext_type *type) ...@@ -186,6 +186,6 @@ void nf_ct_extend_unregister(struct nf_ct_ext_type *type)
rcu_assign_pointer(nf_ct_ext_types[type->id], NULL); rcu_assign_pointer(nf_ct_ext_types[type->id], NULL);
update_alloc_size(type); update_alloc_size(type);
mutex_unlock(&nf_ct_ext_type_mutex); mutex_unlock(&nf_ct_ext_type_mutex);
synchronize_rcu(); rcu_barrier(); /* Wait for completion of call_rcu()'s */
} }
EXPORT_SYMBOL_GPL(nf_ct_extend_unregister); EXPORT_SYMBOL_GPL(nf_ct_extend_unregister);
...@@ -720,8 +720,8 @@ static bool tcp_in_window(const struct nf_conn *ct, ...@@ -720,8 +720,8 @@ static bool tcp_in_window(const struct nf_conn *ct,
/* Caller must linearize skb at tcp header. */ /* Caller must linearize skb at tcp header. */
void nf_conntrack_tcp_update(const struct sk_buff *skb, void nf_conntrack_tcp_update(const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
struct nf_conn *ct, struct nf_conn *ct, int dir,
int dir) s16 offset)
{ {
const struct tcphdr *tcph = (const void *)skb->data + dataoff; const struct tcphdr *tcph = (const void *)skb->data + dataoff;
const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[dir]; const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[dir];
...@@ -734,7 +734,7 @@ void nf_conntrack_tcp_update(const struct sk_buff *skb, ...@@ -734,7 +734,7 @@ void nf_conntrack_tcp_update(const struct sk_buff *skb,
/* /*
* We have to worry for the ack in the reply packet only... * We have to worry for the ack in the reply packet only...
*/ */
if (after(end, ct->proto.tcp.seen[dir].td_end)) if (ct->proto.tcp.seen[dir].td_end + offset == end)
ct->proto.tcp.seen[dir].td_end = end; ct->proto.tcp.seen[dir].td_end = end;
ct->proto.tcp.last_end = end; ct->proto.tcp.last_end = end;
spin_unlock_bh(&ct->lock); spin_unlock_bh(&ct->lock);
......
...@@ -129,7 +129,7 @@ conntrack_addrcmp(const union nf_inet_addr *kaddr, ...@@ -129,7 +129,7 @@ conntrack_addrcmp(const union nf_inet_addr *kaddr,
static inline bool static inline bool
conntrack_mt_origsrc(const struct nf_conn *ct, conntrack_mt_origsrc(const struct nf_conn *ct,
const struct xt_conntrack_mtinfo1 *info, const struct xt_conntrack_mtinfo2 *info,
u_int8_t family) u_int8_t family)
{ {
return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3, return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3,
...@@ -138,7 +138,7 @@ conntrack_mt_origsrc(const struct nf_conn *ct, ...@@ -138,7 +138,7 @@ conntrack_mt_origsrc(const struct nf_conn *ct,
static inline bool static inline bool
conntrack_mt_origdst(const struct nf_conn *ct, conntrack_mt_origdst(const struct nf_conn *ct,
const struct xt_conntrack_mtinfo1 *info, const struct xt_conntrack_mtinfo2 *info,
u_int8_t family) u_int8_t family)
{ {
return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3, return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3,
...@@ -147,7 +147,7 @@ conntrack_mt_origdst(const struct nf_conn *ct, ...@@ -147,7 +147,7 @@ conntrack_mt_origdst(const struct nf_conn *ct,
static inline bool static inline bool
conntrack_mt_replsrc(const struct nf_conn *ct, conntrack_mt_replsrc(const struct nf_conn *ct,
const struct xt_conntrack_mtinfo1 *info, const struct xt_conntrack_mtinfo2 *info,
u_int8_t family) u_int8_t family)
{ {
return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3, return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3,
...@@ -156,7 +156,7 @@ conntrack_mt_replsrc(const struct nf_conn *ct, ...@@ -156,7 +156,7 @@ conntrack_mt_replsrc(const struct nf_conn *ct,
static inline bool static inline bool
conntrack_mt_repldst(const struct nf_conn *ct, conntrack_mt_repldst(const struct nf_conn *ct,
const struct xt_conntrack_mtinfo1 *info, const struct xt_conntrack_mtinfo2 *info,
u_int8_t family) u_int8_t family)
{ {
return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3, return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3,
...@@ -164,7 +164,7 @@ conntrack_mt_repldst(const struct nf_conn *ct, ...@@ -164,7 +164,7 @@ conntrack_mt_repldst(const struct nf_conn *ct,
} }
static inline bool static inline bool
ct_proto_port_check(const struct xt_conntrack_mtinfo1 *info, ct_proto_port_check(const struct xt_conntrack_mtinfo2 *info,
const struct nf_conn *ct) const struct nf_conn *ct)
{ {
const struct nf_conntrack_tuple *tuple; const struct nf_conntrack_tuple *tuple;
...@@ -204,7 +204,7 @@ ct_proto_port_check(const struct xt_conntrack_mtinfo1 *info, ...@@ -204,7 +204,7 @@ ct_proto_port_check(const struct xt_conntrack_mtinfo1 *info,
static bool static bool
conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par) conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par)
{ {
const struct xt_conntrack_mtinfo1 *info = par->matchinfo; const struct xt_conntrack_mtinfo2 *info = par->matchinfo;
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
const struct nf_conn *ct; const struct nf_conn *ct;
unsigned int statebit; unsigned int statebit;
...@@ -278,6 +278,16 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par) ...@@ -278,6 +278,16 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par)
return true; return true;
} }
static bool
conntrack_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par)
{
const struct xt_conntrack_mtinfo2 *const *info = par->matchinfo;
struct xt_match_param newpar = *par;
newpar.matchinfo = *info;
return conntrack_mt(skb, &newpar);
}
static bool conntrack_mt_check(const struct xt_mtchk_param *par) static bool conntrack_mt_check(const struct xt_mtchk_param *par)
{ {
if (nf_ct_l3proto_try_module_get(par->family) < 0) { if (nf_ct_l3proto_try_module_get(par->family) < 0) {
...@@ -288,11 +298,45 @@ static bool conntrack_mt_check(const struct xt_mtchk_param *par) ...@@ -288,11 +298,45 @@ static bool conntrack_mt_check(const struct xt_mtchk_param *par)
return true; return true;
} }
static bool conntrack_mt_check_v1(const struct xt_mtchk_param *par)
{
struct xt_conntrack_mtinfo1 *info = par->matchinfo;
struct xt_conntrack_mtinfo2 *up;
int ret = conntrack_mt_check(par);
if (ret < 0)
return ret;
up = kmalloc(sizeof(*up), GFP_KERNEL);
if (up == NULL) {
nf_ct_l3proto_module_put(par->family);
return -ENOMEM;
}
/*
* The strategy here is to minimize the overhead of v1 matching,
* by prebuilding a v2 struct and putting the pointer into the
* v1 dataspace.
*/
memcpy(up, info, offsetof(typeof(*info), state_mask));
up->state_mask = info->state_mask;
up->status_mask = info->status_mask;
*(void **)info = up;
return true;
}
static void conntrack_mt_destroy(const struct xt_mtdtor_param *par) static void conntrack_mt_destroy(const struct xt_mtdtor_param *par)
{ {
nf_ct_l3proto_module_put(par->family); nf_ct_l3proto_module_put(par->family);
} }
static void conntrack_mt_destroy_v1(const struct xt_mtdtor_param *par)
{
struct xt_conntrack_mtinfo2 **info = par->matchinfo;
kfree(*info);
conntrack_mt_destroy(par);
}
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
struct compat_xt_conntrack_info struct compat_xt_conntrack_info
{ {
...@@ -363,6 +407,16 @@ static struct xt_match conntrack_mt_reg[] __read_mostly = { ...@@ -363,6 +407,16 @@ static struct xt_match conntrack_mt_reg[] __read_mostly = {
.revision = 1, .revision = 1,
.family = NFPROTO_UNSPEC, .family = NFPROTO_UNSPEC,
.matchsize = sizeof(struct xt_conntrack_mtinfo1), .matchsize = sizeof(struct xt_conntrack_mtinfo1),
.match = conntrack_mt_v1,
.checkentry = conntrack_mt_check_v1,
.destroy = conntrack_mt_destroy_v1,
.me = THIS_MODULE,
},
{
.name = "conntrack",
.revision = 2,
.family = NFPROTO_UNSPEC,
.matchsize = sizeof(struct xt_conntrack_mtinfo2),
.match = conntrack_mt, .match = conntrack_mt,
.checkentry = conntrack_mt_check, .checkentry = conntrack_mt_check,
.destroy = conntrack_mt_destroy, .destroy = conntrack_mt_destroy,
......
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