|
@@ -799,7 +799,7 @@ err:
|
|
}
|
|
}
|
|
|
|
|
|
struct nft_ct_timeout_obj {
|
|
struct nft_ct_timeout_obj {
|
|
- struct nf_conn *tmpl;
|
|
|
|
|
|
+ struct nf_ct_timeout *timeout;
|
|
u8 l4proto;
|
|
u8 l4proto;
|
|
};
|
|
};
|
|
|
|
|
|
@@ -809,26 +809,42 @@ static void nft_ct_timeout_obj_eval(struct nft_object *obj,
|
|
{
|
|
{
|
|
const struct nft_ct_timeout_obj *priv = nft_obj_data(obj);
|
|
const struct nft_ct_timeout_obj *priv = nft_obj_data(obj);
|
|
struct nf_conn *ct = (struct nf_conn *)skb_nfct(pkt->skb);
|
|
struct nf_conn *ct = (struct nf_conn *)skb_nfct(pkt->skb);
|
|
- struct sk_buff *skb = pkt->skb;
|
|
|
|
|
|
+ struct nf_conn_timeout *timeout;
|
|
|
|
+ const unsigned int *values;
|
|
|
|
+
|
|
|
|
+ if (priv->l4proto != pkt->tprot)
|
|
|
|
+ return;
|
|
|
|
|
|
- if (ct ||
|
|
|
|
- priv->l4proto != pkt->tprot)
|
|
|
|
|
|
+ if (!ct || nf_ct_is_template(ct) || nf_ct_is_confirmed(ct))
|
|
return;
|
|
return;
|
|
|
|
|
|
- nf_ct_set(skb, priv->tmpl, IP_CT_NEW);
|
|
|
|
|
|
+ timeout = nf_ct_timeout_find(ct);
|
|
|
|
+ if (!timeout) {
|
|
|
|
+ timeout = nf_ct_timeout_ext_add(ct, priv->timeout, GFP_ATOMIC);
|
|
|
|
+ if (!timeout) {
|
|
|
|
+ regs->verdict.code = NF_DROP;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rcu_assign_pointer(timeout->timeout, priv->timeout);
|
|
|
|
+
|
|
|
|
+ /* adjust the timeout as per 'new' state. ct is unconfirmed,
|
|
|
|
+ * so the current timestamp must not be added.
|
|
|
|
+ */
|
|
|
|
+ values = nf_ct_timeout_data(timeout);
|
|
|
|
+ if (values)
|
|
|
|
+ nf_ct_refresh(ct, pkt->skb, values[0]);
|
|
}
|
|
}
|
|
|
|
|
|
static int nft_ct_timeout_obj_init(const struct nft_ctx *ctx,
|
|
static int nft_ct_timeout_obj_init(const struct nft_ctx *ctx,
|
|
const struct nlattr * const tb[],
|
|
const struct nlattr * const tb[],
|
|
struct nft_object *obj)
|
|
struct nft_object *obj)
|
|
{
|
|
{
|
|
- const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt;
|
|
|
|
struct nft_ct_timeout_obj *priv = nft_obj_data(obj);
|
|
struct nft_ct_timeout_obj *priv = nft_obj_data(obj);
|
|
const struct nf_conntrack_l4proto *l4proto;
|
|
const struct nf_conntrack_l4proto *l4proto;
|
|
- struct nf_conn_timeout *timeout_ext;
|
|
|
|
struct nf_ct_timeout *timeout;
|
|
struct nf_ct_timeout *timeout;
|
|
int l3num = ctx->family;
|
|
int l3num = ctx->family;
|
|
- struct nf_conn *tmpl;
|
|
|
|
__u8 l4num;
|
|
__u8 l4num;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
@@ -863,28 +879,14 @@ static int nft_ct_timeout_obj_init(const struct nft_ctx *ctx,
|
|
|
|
|
|
timeout->l3num = l3num;
|
|
timeout->l3num = l3num;
|
|
timeout->l4proto = l4proto;
|
|
timeout->l4proto = l4proto;
|
|
- tmpl = nf_ct_tmpl_alloc(ctx->net, zone, GFP_ATOMIC);
|
|
|
|
- if (!tmpl) {
|
|
|
|
- ret = -ENOMEM;
|
|
|
|
- goto err_free_timeout;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- timeout_ext = nf_ct_timeout_ext_add(tmpl, timeout, GFP_ATOMIC);
|
|
|
|
- if (!timeout_ext) {
|
|
|
|
- ret = -ENOMEM;
|
|
|
|
- goto err_free_tmpl;
|
|
|
|
- }
|
|
|
|
|
|
|
|
ret = nf_ct_netns_get(ctx->net, ctx->family);
|
|
ret = nf_ct_netns_get(ctx->net, ctx->family);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
- goto err_free_tmpl;
|
|
|
|
-
|
|
|
|
- priv->tmpl = tmpl;
|
|
|
|
|
|
+ goto err_free_timeout;
|
|
|
|
|
|
|
|
+ priv->timeout = timeout;
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
-err_free_tmpl:
|
|
|
|
- nf_ct_tmpl_free(tmpl);
|
|
|
|
err_free_timeout:
|
|
err_free_timeout:
|
|
kfree(timeout);
|
|
kfree(timeout);
|
|
err_proto_put:
|
|
err_proto_put:
|
|
@@ -896,22 +898,19 @@ static void nft_ct_timeout_obj_destroy(const struct nft_ctx *ctx,
|
|
struct nft_object *obj)
|
|
struct nft_object *obj)
|
|
{
|
|
{
|
|
struct nft_ct_timeout_obj *priv = nft_obj_data(obj);
|
|
struct nft_ct_timeout_obj *priv = nft_obj_data(obj);
|
|
- struct nf_conn_timeout *t = nf_ct_timeout_find(priv->tmpl);
|
|
|
|
- struct nf_ct_timeout *timeout;
|
|
|
|
|
|
+ struct nf_ct_timeout *timeout = priv->timeout;
|
|
|
|
|
|
- timeout = rcu_dereference_raw(t->timeout);
|
|
|
|
nf_ct_untimeout(ctx->net, timeout);
|
|
nf_ct_untimeout(ctx->net, timeout);
|
|
nf_ct_l4proto_put(timeout->l4proto);
|
|
nf_ct_l4proto_put(timeout->l4proto);
|
|
nf_ct_netns_put(ctx->net, ctx->family);
|
|
nf_ct_netns_put(ctx->net, ctx->family);
|
|
- nf_ct_tmpl_free(priv->tmpl);
|
|
|
|
|
|
+ kfree(priv->timeout);
|
|
}
|
|
}
|
|
|
|
|
|
static int nft_ct_timeout_obj_dump(struct sk_buff *skb,
|
|
static int nft_ct_timeout_obj_dump(struct sk_buff *skb,
|
|
struct nft_object *obj, bool reset)
|
|
struct nft_object *obj, bool reset)
|
|
{
|
|
{
|
|
const struct nft_ct_timeout_obj *priv = nft_obj_data(obj);
|
|
const struct nft_ct_timeout_obj *priv = nft_obj_data(obj);
|
|
- const struct nf_conn_timeout *t = nf_ct_timeout_find(priv->tmpl);
|
|
|
|
- const struct nf_ct_timeout *timeout = rcu_dereference_raw(t->timeout);
|
|
|
|
|
|
+ const struct nf_ct_timeout *timeout = priv->timeout;
|
|
struct nlattr *nest_params;
|
|
struct nlattr *nest_params;
|
|
int ret;
|
|
int ret;
|
|
|
|
|