Commit 60b5f8f7 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

netfilter: nf_conntrack: permanently attach timeout policy to conntrack

We need to permanently attach the timeout policy to the conntrack,
otherwise we may apply the custom timeout policy inconsistently.

Without this patch, the following example:

 nfct timeout add test inet icmp timeout 100
 iptables -I PREROUTING -t raw -p icmp -s 1.1.1.1 -j CT --timeout test

Will only apply the custom timeout policy to outgoing packets from
1.1.1.1, but not to reply packets from 2.2.2.2 going to 1.1.1.1.

To fix this issue, this patch modifies the current logic to attach the
timeout policy when the first packet is seen (which is when the
conntrack entry is created). Then, we keep using the attached timeout
policy until the conntrack entry is destroyed.
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent eeb4cb95
...@@ -768,8 +768,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, ...@@ -768,8 +768,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
struct nf_conntrack_l3proto *l3proto, struct nf_conntrack_l3proto *l3proto,
struct nf_conntrack_l4proto *l4proto, struct nf_conntrack_l4proto *l4proto,
struct sk_buff *skb, struct sk_buff *skb,
unsigned int dataoff, u32 hash, unsigned int dataoff, u32 hash)
unsigned int *timeouts)
{ {
struct nf_conn *ct; struct nf_conn *ct;
struct nf_conn_help *help; struct nf_conn_help *help;
...@@ -777,6 +776,8 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, ...@@ -777,6 +776,8 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
struct nf_conntrack_ecache *ecache; struct nf_conntrack_ecache *ecache;
struct nf_conntrack_expect *exp; struct nf_conntrack_expect *exp;
u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE; u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE;
struct nf_conn_timeout *timeout_ext;
unsigned int *timeouts;
if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) { if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) {
pr_debug("Can't invert tuple.\n"); pr_debug("Can't invert tuple.\n");
...@@ -788,12 +789,21 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, ...@@ -788,12 +789,21 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
if (IS_ERR(ct)) if (IS_ERR(ct))
return (struct nf_conntrack_tuple_hash *)ct; return (struct nf_conntrack_tuple_hash *)ct;
timeout_ext = tmpl ? nf_ct_timeout_find(tmpl) : NULL;
if (timeout_ext)
timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext);
else
timeouts = l4proto->get_timeouts(net);
if (!l4proto->new(ct, skb, dataoff, timeouts)) { if (!l4proto->new(ct, skb, dataoff, timeouts)) {
nf_conntrack_free(ct); nf_conntrack_free(ct);
pr_debug("init conntrack: can't track with proto module\n"); pr_debug("init conntrack: can't track with proto module\n");
return NULL; return NULL;
} }
if (timeout_ext)
nf_ct_timeout_ext_add(ct, timeout_ext->timeout, GFP_ATOMIC);
nf_ct_acct_ext_add(ct, GFP_ATOMIC); nf_ct_acct_ext_add(ct, GFP_ATOMIC);
nf_ct_tstamp_ext_add(ct, GFP_ATOMIC); nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
...@@ -854,8 +864,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, ...@@ -854,8 +864,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
struct nf_conntrack_l3proto *l3proto, struct nf_conntrack_l3proto *l3proto,
struct nf_conntrack_l4proto *l4proto, struct nf_conntrack_l4proto *l4proto,
int *set_reply, int *set_reply,
enum ip_conntrack_info *ctinfo, enum ip_conntrack_info *ctinfo)
unsigned int *timeouts)
{ {
struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple tuple;
struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple_hash *h;
...@@ -875,7 +884,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, ...@@ -875,7 +884,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
h = __nf_conntrack_find_get(net, zone, &tuple, hash); h = __nf_conntrack_find_get(net, zone, &tuple, hash);
if (!h) { if (!h) {
h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto, h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto,
skb, dataoff, hash, timeouts); skb, dataoff, hash);
if (!h) if (!h)
return NULL; return NULL;
if (IS_ERR(h)) if (IS_ERR(h))
...@@ -964,19 +973,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, ...@@ -964,19 +973,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
goto out; goto out;
} }
/* Decide what timeout policy we want to apply to this flow. */
if (tmpl) {
timeout_ext = nf_ct_timeout_find(tmpl);
if (timeout_ext)
timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext);
else
timeouts = l4proto->get_timeouts(net);
} else
timeouts = l4proto->get_timeouts(net);
ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum, ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum,
l3proto, l4proto, &set_reply, &ctinfo, l3proto, l4proto, &set_reply, &ctinfo);
timeouts);
if (!ct) { if (!ct) {
/* Not valid part of a connection */ /* Not valid part of a connection */
NF_CT_STAT_INC_ATOMIC(net, invalid); NF_CT_STAT_INC_ATOMIC(net, invalid);
...@@ -993,6 +991,13 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, ...@@ -993,6 +991,13 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
NF_CT_ASSERT(skb->nfct); NF_CT_ASSERT(skb->nfct);
/* Decide what timeout policy we want to apply to this flow. */
timeout_ext = nf_ct_timeout_find(ct);
if (timeout_ext)
timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext);
else
timeouts = l4proto->get_timeouts(net);
ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum, timeouts); ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum, timeouts);
if (ret <= 0) { if (ret <= 0) {
/* Invalid: inverse of the return code tells /* Invalid: inverse of the return code tells
......
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