2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
3 * Copyright (c) 2016 Pablo Neira Ayuso <pablo@netfilter.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Development of this code funded by Astaro AG (http://www.astaro.com/)
12 #include <linux/kernel.h>
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/netlink.h>
16 #include <linux/netfilter.h>
17 #include <linux/netfilter/nf_tables.h>
18 #include <net/netfilter/nf_tables.h>
19 #include <net/netfilter/nf_conntrack.h>
20 #include <net/netfilter/nf_conntrack_acct.h>
21 #include <net/netfilter/nf_conntrack_tuple.h>
22 #include <net/netfilter/nf_conntrack_helper.h>
23 #include <net/netfilter/nf_conntrack_ecache.h>
24 #include <net/netfilter/nf_conntrack_labels.h>
27 enum nft_ct_keys key
:8;
28 enum ip_conntrack_dir dir
:8;
30 enum nft_registers dreg
:8;
31 enum nft_registers sreg
:8;
35 struct nft_ct_helper_obj
{
36 struct nf_conntrack_helper
*helper4
;
37 struct nf_conntrack_helper
*helper6
;
41 #ifdef CONFIG_NF_CONNTRACK_ZONES
42 static DEFINE_PER_CPU(struct nf_conn
*, nft_ct_pcpu_template
);
43 static unsigned int nft_ct_pcpu_template_refcnt __read_mostly
;
46 static u64
nft_ct_get_eval_counter(const struct nf_conn_counter
*c
,
48 enum ip_conntrack_dir d
)
50 if (d
< IP_CT_DIR_MAX
)
51 return k
== NFT_CT_BYTES
? atomic64_read(&c
[d
].bytes
) :
52 atomic64_read(&c
[d
].packets
);
54 return nft_ct_get_eval_counter(c
, k
, IP_CT_DIR_ORIGINAL
) +
55 nft_ct_get_eval_counter(c
, k
, IP_CT_DIR_REPLY
);
58 static void nft_ct_get_eval(const struct nft_expr
*expr
,
59 struct nft_regs
*regs
,
60 const struct nft_pktinfo
*pkt
)
62 const struct nft_ct
*priv
= nft_expr_priv(expr
);
63 u32
*dest
= ®s
->data
[priv
->dreg
];
64 enum ip_conntrack_info ctinfo
;
65 const struct nf_conn
*ct
;
66 const struct nf_conn_help
*help
;
67 const struct nf_conntrack_tuple
*tuple
;
68 const struct nf_conntrack_helper
*helper
;
71 ct
= nf_ct_get(pkt
->skb
, &ctinfo
);
76 state
= NF_CT_STATE_BIT(ctinfo
);
77 else if (ctinfo
== IP_CT_UNTRACKED
)
78 state
= NF_CT_STATE_UNTRACKED_BIT
;
80 state
= NF_CT_STATE_INVALID_BIT
;
91 case NFT_CT_DIRECTION
:
92 nft_reg_store8(dest
, CTINFO2DIR(ctinfo
));
97 #ifdef CONFIG_NF_CONNTRACK_MARK
102 #ifdef CONFIG_NF_CONNTRACK_SECMARK
107 case NFT_CT_EXPIRATION
:
108 *dest
= jiffies_to_msecs(nf_ct_expires(ct
));
111 if (ct
->master
== NULL
)
113 help
= nfct_help(ct
->master
);
116 helper
= rcu_dereference(help
->helper
);
119 strncpy((char *)dest
, helper
->name
, NF_CT_HELPER_NAME_LEN
);
121 #ifdef CONFIG_NF_CONNTRACK_LABELS
122 case NFT_CT_LABELS
: {
123 struct nf_conn_labels
*labels
= nf_ct_labels_find(ct
);
126 memcpy(dest
, labels
->bits
, NF_CT_LABELS_MAX_SIZE
);
128 memset(dest
, 0, NF_CT_LABELS_MAX_SIZE
);
132 case NFT_CT_BYTES
: /* fallthrough */
134 const struct nf_conn_acct
*acct
= nf_conn_acct_find(ct
);
138 count
= nft_ct_get_eval_counter(acct
->counter
,
139 priv
->key
, priv
->dir
);
140 memcpy(dest
, &count
, sizeof(count
));
143 case NFT_CT_AVGPKT
: {
144 const struct nf_conn_acct
*acct
= nf_conn_acct_find(ct
);
145 u64 avgcnt
= 0, bcnt
= 0, pcnt
= 0;
148 pcnt
= nft_ct_get_eval_counter(acct
->counter
,
149 NFT_CT_PKTS
, priv
->dir
);
150 bcnt
= nft_ct_get_eval_counter(acct
->counter
,
151 NFT_CT_BYTES
, priv
->dir
);
153 avgcnt
= div64_u64(bcnt
, pcnt
);
156 memcpy(dest
, &avgcnt
, sizeof(avgcnt
));
159 case NFT_CT_L3PROTOCOL
:
160 nft_reg_store8(dest
, nf_ct_l3num(ct
));
162 case NFT_CT_PROTOCOL
:
163 nft_reg_store8(dest
, nf_ct_protonum(ct
));
165 #ifdef CONFIG_NF_CONNTRACK_ZONES
167 const struct nf_conntrack_zone
*zone
= nf_ct_zone(ct
);
170 if (priv
->dir
< IP_CT_DIR_MAX
)
171 zoneid
= nf_ct_zone_id(zone
, priv
->dir
);
175 nft_reg_store16(dest
, zoneid
);
183 tuple
= &ct
->tuplehash
[priv
->dir
].tuple
;
186 memcpy(dest
, tuple
->src
.u3
.all
,
187 nf_ct_l3num(ct
) == NFPROTO_IPV4
? 4 : 16);
190 memcpy(dest
, tuple
->dst
.u3
.all
,
191 nf_ct_l3num(ct
) == NFPROTO_IPV4
? 4 : 16);
193 case NFT_CT_PROTO_SRC
:
194 nft_reg_store16(dest
, (__force u16
)tuple
->src
.u
.all
);
196 case NFT_CT_PROTO_DST
:
197 nft_reg_store16(dest
, (__force u16
)tuple
->dst
.u
.all
);
204 regs
->verdict
.code
= NFT_BREAK
;
207 #ifdef CONFIG_NF_CONNTRACK_ZONES
208 static void nft_ct_set_zone_eval(const struct nft_expr
*expr
,
209 struct nft_regs
*regs
,
210 const struct nft_pktinfo
*pkt
)
212 struct nf_conntrack_zone zone
= { .dir
= NF_CT_DEFAULT_ZONE_DIR
};
213 const struct nft_ct
*priv
= nft_expr_priv(expr
);
214 struct sk_buff
*skb
= pkt
->skb
;
215 enum ip_conntrack_info ctinfo
;
216 u16 value
= nft_reg_load16(®s
->data
[priv
->sreg
]);
219 ct
= nf_ct_get(skb
, &ctinfo
);
220 if (ct
) /* already tracked */
226 case IP_CT_DIR_ORIGINAL
:
227 zone
.dir
= NF_CT_ZONE_DIR_ORIG
;
229 case IP_CT_DIR_REPLY
:
230 zone
.dir
= NF_CT_ZONE_DIR_REPL
;
236 ct
= this_cpu_read(nft_ct_pcpu_template
);
238 if (likely(atomic_read(&ct
->ct_general
.use
) == 1)) {
239 nf_ct_zone_add(ct
, &zone
);
241 /* previous skb got queued to userspace */
242 ct
= nf_ct_tmpl_alloc(nft_net(pkt
), &zone
, GFP_ATOMIC
);
244 regs
->verdict
.code
= NF_DROP
;
249 atomic_inc(&ct
->ct_general
.use
);
250 nf_ct_set(skb
, ct
, IP_CT_NEW
);
254 static void nft_ct_set_eval(const struct nft_expr
*expr
,
255 struct nft_regs
*regs
,
256 const struct nft_pktinfo
*pkt
)
258 const struct nft_ct
*priv
= nft_expr_priv(expr
);
259 struct sk_buff
*skb
= pkt
->skb
;
260 #ifdef CONFIG_NF_CONNTRACK_MARK
261 u32 value
= regs
->data
[priv
->sreg
];
263 enum ip_conntrack_info ctinfo
;
266 ct
= nf_ct_get(skb
, &ctinfo
);
267 if (ct
== NULL
|| nf_ct_is_template(ct
))
271 #ifdef CONFIG_NF_CONNTRACK_MARK
273 if (ct
->mark
!= value
) {
275 nf_conntrack_event_cache(IPCT_MARK
, ct
);
279 #ifdef CONFIG_NF_CONNTRACK_LABELS
281 nf_connlabels_replace(ct
,
282 ®s
->data
[priv
->sreg
],
283 ®s
->data
[priv
->sreg
],
284 NF_CT_LABELS_MAX_SIZE
/ sizeof(u32
));
287 #ifdef CONFIG_NF_CONNTRACK_EVENTS
288 case NFT_CT_EVENTMASK
: {
289 struct nf_conntrack_ecache
*e
= nf_ct_ecache_find(ct
);
290 u32 ctmask
= regs
->data
[priv
->sreg
];
293 if (e
->ctmask
!= ctmask
)
298 if (ctmask
&& !nf_ct_is_confirmed(ct
))
299 nf_ct_ecache_ext_add(ct
, ctmask
, 0, GFP_ATOMIC
);
308 static const struct nla_policy nft_ct_policy
[NFTA_CT_MAX
+ 1] = {
309 [NFTA_CT_DREG
] = { .type
= NLA_U32
},
310 [NFTA_CT_KEY
] = { .type
= NLA_U32
},
311 [NFTA_CT_DIRECTION
] = { .type
= NLA_U8
},
312 [NFTA_CT_SREG
] = { .type
= NLA_U32
},
315 static int nft_ct_netns_get(struct net
*net
, uint8_t family
)
319 if (family
== NFPROTO_INET
) {
320 err
= nf_ct_netns_get(net
, NFPROTO_IPV4
);
323 err
= nf_ct_netns_get(net
, NFPROTO_IPV6
);
327 err
= nf_ct_netns_get(net
, family
);
334 nf_ct_netns_put(net
, NFPROTO_IPV4
);
339 static void nft_ct_netns_put(struct net
*net
, uint8_t family
)
341 if (family
== NFPROTO_INET
) {
342 nf_ct_netns_put(net
, NFPROTO_IPV4
);
343 nf_ct_netns_put(net
, NFPROTO_IPV6
);
345 nf_ct_netns_put(net
, family
);
348 #ifdef CONFIG_NF_CONNTRACK_ZONES
349 static void nft_ct_tmpl_put_pcpu(void)
354 for_each_possible_cpu(cpu
) {
355 ct
= per_cpu(nft_ct_pcpu_template
, cpu
);
359 per_cpu(nft_ct_pcpu_template
, cpu
) = NULL
;
363 static bool nft_ct_tmpl_alloc_pcpu(void)
365 struct nf_conntrack_zone zone
= { .id
= 0 };
369 if (nft_ct_pcpu_template_refcnt
)
372 for_each_possible_cpu(cpu
) {
373 tmp
= nf_ct_tmpl_alloc(&init_net
, &zone
, GFP_KERNEL
);
375 nft_ct_tmpl_put_pcpu();
379 atomic_set(&tmp
->ct_general
.use
, 1);
380 per_cpu(nft_ct_pcpu_template
, cpu
) = tmp
;
387 static int nft_ct_get_init(const struct nft_ctx
*ctx
,
388 const struct nft_expr
*expr
,
389 const struct nlattr
* const tb
[])
391 struct nft_ct
*priv
= nft_expr_priv(expr
);
395 priv
->key
= ntohl(nla_get_be32(tb
[NFTA_CT_KEY
]));
396 priv
->dir
= IP_CT_DIR_MAX
;
398 case NFT_CT_DIRECTION
:
399 if (tb
[NFTA_CT_DIRECTION
] != NULL
)
405 #ifdef CONFIG_NF_CONNTRACK_MARK
408 #ifdef CONFIG_NF_CONNTRACK_SECMARK
411 case NFT_CT_EXPIRATION
:
412 if (tb
[NFTA_CT_DIRECTION
] != NULL
)
416 #ifdef CONFIG_NF_CONNTRACK_LABELS
418 if (tb
[NFTA_CT_DIRECTION
] != NULL
)
420 len
= NF_CT_LABELS_MAX_SIZE
;
424 if (tb
[NFTA_CT_DIRECTION
] != NULL
)
426 len
= NF_CT_HELPER_NAME_LEN
;
429 case NFT_CT_L3PROTOCOL
:
430 case NFT_CT_PROTOCOL
:
431 /* For compatibility, do not report error if NFTA_CT_DIRECTION
432 * attribute is specified.
438 if (tb
[NFTA_CT_DIRECTION
] == NULL
)
441 switch (ctx
->afi
->family
) {
443 len
= FIELD_SIZEOF(struct nf_conntrack_tuple
,
448 len
= FIELD_SIZEOF(struct nf_conntrack_tuple
,
452 return -EAFNOSUPPORT
;
455 case NFT_CT_PROTO_SRC
:
456 case NFT_CT_PROTO_DST
:
457 if (tb
[NFTA_CT_DIRECTION
] == NULL
)
459 len
= FIELD_SIZEOF(struct nf_conntrack_tuple
, src
.u
.all
);
466 #ifdef CONFIG_NF_CONNTRACK_ZONES
475 if (tb
[NFTA_CT_DIRECTION
] != NULL
) {
476 priv
->dir
= nla_get_u8(tb
[NFTA_CT_DIRECTION
]);
478 case IP_CT_DIR_ORIGINAL
:
479 case IP_CT_DIR_REPLY
:
486 priv
->dreg
= nft_parse_register(tb
[NFTA_CT_DREG
]);
487 err
= nft_validate_register_store(ctx
, priv
->dreg
, NULL
,
488 NFT_DATA_VALUE
, len
);
492 err
= nft_ct_netns_get(ctx
->net
, ctx
->afi
->family
);
496 if (priv
->key
== NFT_CT_BYTES
||
497 priv
->key
== NFT_CT_PKTS
||
498 priv
->key
== NFT_CT_AVGPKT
)
499 nf_ct_set_acct(ctx
->net
, true);
504 static void __nft_ct_set_destroy(const struct nft_ctx
*ctx
, struct nft_ct
*priv
)
507 #ifdef CONFIG_NF_CONNTRACK_LABELS
509 nf_connlabels_put(ctx
->net
);
512 #ifdef CONFIG_NF_CONNTRACK_ZONES
514 if (--nft_ct_pcpu_template_refcnt
== 0)
515 nft_ct_tmpl_put_pcpu();
522 static int nft_ct_set_init(const struct nft_ctx
*ctx
,
523 const struct nft_expr
*expr
,
524 const struct nlattr
* const tb
[])
526 struct nft_ct
*priv
= nft_expr_priv(expr
);
530 priv
->dir
= IP_CT_DIR_MAX
;
531 priv
->key
= ntohl(nla_get_be32(tb
[NFTA_CT_KEY
]));
533 #ifdef CONFIG_NF_CONNTRACK_MARK
535 if (tb
[NFTA_CT_DIRECTION
])
537 len
= FIELD_SIZEOF(struct nf_conn
, mark
);
540 #ifdef CONFIG_NF_CONNTRACK_LABELS
542 if (tb
[NFTA_CT_DIRECTION
])
544 len
= NF_CT_LABELS_MAX_SIZE
;
545 err
= nf_connlabels_get(ctx
->net
, (len
* BITS_PER_BYTE
) - 1);
550 #ifdef CONFIG_NF_CONNTRACK_ZONES
552 if (!nft_ct_tmpl_alloc_pcpu())
554 nft_ct_pcpu_template_refcnt
++;
558 #ifdef CONFIG_NF_CONNTRACK_EVENTS
559 case NFT_CT_EVENTMASK
:
560 if (tb
[NFTA_CT_DIRECTION
])
569 if (tb
[NFTA_CT_DIRECTION
]) {
570 priv
->dir
= nla_get_u8(tb
[NFTA_CT_DIRECTION
]);
572 case IP_CT_DIR_ORIGINAL
:
573 case IP_CT_DIR_REPLY
:
581 priv
->sreg
= nft_parse_register(tb
[NFTA_CT_SREG
]);
582 err
= nft_validate_register_load(priv
->sreg
, len
);
586 err
= nft_ct_netns_get(ctx
->net
, ctx
->afi
->family
);
593 __nft_ct_set_destroy(ctx
, priv
);
597 static void nft_ct_get_destroy(const struct nft_ctx
*ctx
,
598 const struct nft_expr
*expr
)
600 nf_ct_netns_put(ctx
->net
, ctx
->afi
->family
);
603 static void nft_ct_set_destroy(const struct nft_ctx
*ctx
,
604 const struct nft_expr
*expr
)
606 struct nft_ct
*priv
= nft_expr_priv(expr
);
608 __nft_ct_set_destroy(ctx
, priv
);
609 nft_ct_netns_put(ctx
->net
, ctx
->afi
->family
);
612 static int nft_ct_get_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
614 const struct nft_ct
*priv
= nft_expr_priv(expr
);
616 if (nft_dump_register(skb
, NFTA_CT_DREG
, priv
->dreg
))
617 goto nla_put_failure
;
618 if (nla_put_be32(skb
, NFTA_CT_KEY
, htonl(priv
->key
)))
619 goto nla_put_failure
;
624 case NFT_CT_PROTO_SRC
:
625 case NFT_CT_PROTO_DST
:
626 if (nla_put_u8(skb
, NFTA_CT_DIRECTION
, priv
->dir
))
627 goto nla_put_failure
;
633 if (priv
->dir
< IP_CT_DIR_MAX
&&
634 nla_put_u8(skb
, NFTA_CT_DIRECTION
, priv
->dir
))
635 goto nla_put_failure
;
647 static int nft_ct_set_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
649 const struct nft_ct
*priv
= nft_expr_priv(expr
);
651 if (nft_dump_register(skb
, NFTA_CT_SREG
, priv
->sreg
))
652 goto nla_put_failure
;
653 if (nla_put_be32(skb
, NFTA_CT_KEY
, htonl(priv
->key
)))
654 goto nla_put_failure
;
658 if (priv
->dir
< IP_CT_DIR_MAX
&&
659 nla_put_u8(skb
, NFTA_CT_DIRECTION
, priv
->dir
))
660 goto nla_put_failure
;
672 static struct nft_expr_type nft_ct_type
;
673 static const struct nft_expr_ops nft_ct_get_ops
= {
674 .type
= &nft_ct_type
,
675 .size
= NFT_EXPR_SIZE(sizeof(struct nft_ct
)),
676 .eval
= nft_ct_get_eval
,
677 .init
= nft_ct_get_init
,
678 .destroy
= nft_ct_get_destroy
,
679 .dump
= nft_ct_get_dump
,
682 static const struct nft_expr_ops nft_ct_set_ops
= {
683 .type
= &nft_ct_type
,
684 .size
= NFT_EXPR_SIZE(sizeof(struct nft_ct
)),
685 .eval
= nft_ct_set_eval
,
686 .init
= nft_ct_set_init
,
687 .destroy
= nft_ct_set_destroy
,
688 .dump
= nft_ct_set_dump
,
691 #ifdef CONFIG_NF_CONNTRACK_ZONES
692 static const struct nft_expr_ops nft_ct_set_zone_ops
= {
693 .type
= &nft_ct_type
,
694 .size
= NFT_EXPR_SIZE(sizeof(struct nft_ct
)),
695 .eval
= nft_ct_set_zone_eval
,
696 .init
= nft_ct_set_init
,
697 .destroy
= nft_ct_set_destroy
,
698 .dump
= nft_ct_set_dump
,
702 static const struct nft_expr_ops
*
703 nft_ct_select_ops(const struct nft_ctx
*ctx
,
704 const struct nlattr
* const tb
[])
706 if (tb
[NFTA_CT_KEY
] == NULL
)
707 return ERR_PTR(-EINVAL
);
709 if (tb
[NFTA_CT_DREG
] && tb
[NFTA_CT_SREG
])
710 return ERR_PTR(-EINVAL
);
712 if (tb
[NFTA_CT_DREG
])
713 return &nft_ct_get_ops
;
715 if (tb
[NFTA_CT_SREG
]) {
716 #ifdef CONFIG_NF_CONNTRACK_ZONES
717 if (nla_get_be32(tb
[NFTA_CT_KEY
]) == htonl(NFT_CT_ZONE
))
718 return &nft_ct_set_zone_ops
;
720 return &nft_ct_set_ops
;
723 return ERR_PTR(-EINVAL
);
726 static struct nft_expr_type nft_ct_type __read_mostly
= {
728 .select_ops
= nft_ct_select_ops
,
729 .policy
= nft_ct_policy
,
730 .maxattr
= NFTA_CT_MAX
,
731 .owner
= THIS_MODULE
,
734 static void nft_notrack_eval(const struct nft_expr
*expr
,
735 struct nft_regs
*regs
,
736 const struct nft_pktinfo
*pkt
)
738 struct sk_buff
*skb
= pkt
->skb
;
739 enum ip_conntrack_info ctinfo
;
742 ct
= nf_ct_get(pkt
->skb
, &ctinfo
);
743 /* Previously seen (loopback or untracked)? Ignore. */
744 if (ct
|| ctinfo
== IP_CT_UNTRACKED
)
747 nf_ct_set(skb
, ct
, IP_CT_UNTRACKED
);
750 static struct nft_expr_type nft_notrack_type
;
751 static const struct nft_expr_ops nft_notrack_ops
= {
752 .type
= &nft_notrack_type
,
753 .size
= NFT_EXPR_SIZE(0),
754 .eval
= nft_notrack_eval
,
757 static struct nft_expr_type nft_notrack_type __read_mostly
= {
759 .ops
= &nft_notrack_ops
,
760 .owner
= THIS_MODULE
,
763 static int nft_ct_helper_obj_init(const struct nft_ctx
*ctx
,
764 const struct nlattr
* const tb
[],
765 struct nft_object
*obj
)
767 struct nft_ct_helper_obj
*priv
= nft_obj_data(obj
);
768 struct nf_conntrack_helper
*help4
, *help6
;
769 char name
[NF_CT_HELPER_NAME_LEN
];
770 int family
= ctx
->afi
->family
;
772 if (!tb
[NFTA_CT_HELPER_NAME
] || !tb
[NFTA_CT_HELPER_L4PROTO
])
775 priv
->l4proto
= nla_get_u8(tb
[NFTA_CT_HELPER_L4PROTO
]);
779 nla_strlcpy(name
, tb
[NFTA_CT_HELPER_NAME
], sizeof(name
));
781 if (tb
[NFTA_CT_HELPER_L3PROTO
])
782 family
= ntohs(nla_get_be16(tb
[NFTA_CT_HELPER_L3PROTO
]));
789 if (ctx
->afi
->family
== NFPROTO_IPV6
)
792 help4
= nf_conntrack_helper_try_module_get(name
, family
,
796 if (ctx
->afi
->family
== NFPROTO_IPV4
)
799 help6
= nf_conntrack_helper_try_module_get(name
, family
,
802 case NFPROTO_NETDEV
: /* fallthrough */
803 case NFPROTO_BRIDGE
: /* same */
805 help4
= nf_conntrack_helper_try_module_get(name
, NFPROTO_IPV4
,
807 help6
= nf_conntrack_helper_try_module_get(name
, NFPROTO_IPV6
,
811 return -EAFNOSUPPORT
;
814 /* && is intentional; only error if INET found neither ipv4 or ipv6 */
815 if (!help4
&& !help6
)
818 priv
->helper4
= help4
;
819 priv
->helper6
= help6
;
824 static void nft_ct_helper_obj_destroy(struct nft_object
*obj
)
826 struct nft_ct_helper_obj
*priv
= nft_obj_data(obj
);
829 nf_conntrack_helper_put(priv
->helper4
);
831 nf_conntrack_helper_put(priv
->helper6
);
834 static void nft_ct_helper_obj_eval(struct nft_object
*obj
,
835 struct nft_regs
*regs
,
836 const struct nft_pktinfo
*pkt
)
838 const struct nft_ct_helper_obj
*priv
= nft_obj_data(obj
);
839 struct nf_conn
*ct
= (struct nf_conn
*)skb_nfct(pkt
->skb
);
840 struct nf_conntrack_helper
*to_assign
= NULL
;
841 struct nf_conn_help
*help
;
844 nf_ct_is_confirmed(ct
) ||
845 nf_ct_is_template(ct
) ||
846 priv
->l4proto
!= nf_ct_protonum(ct
))
849 switch (nf_ct_l3num(ct
)) {
851 to_assign
= priv
->helper4
;
854 to_assign
= priv
->helper6
;
864 if (test_bit(IPS_HELPER_BIT
, &ct
->status
))
867 help
= nf_ct_helper_ext_add(ct
, to_assign
, GFP_ATOMIC
);
869 rcu_assign_pointer(help
->helper
, to_assign
);
870 set_bit(IPS_HELPER_BIT
, &ct
->status
);
874 static int nft_ct_helper_obj_dump(struct sk_buff
*skb
,
875 struct nft_object
*obj
, bool reset
)
877 const struct nft_ct_helper_obj
*priv
= nft_obj_data(obj
);
878 const struct nf_conntrack_helper
*helper
= priv
->helper4
;
881 if (nla_put_string(skb
, NFTA_CT_HELPER_NAME
, helper
->name
))
884 if (nla_put_u8(skb
, NFTA_CT_HELPER_L4PROTO
, priv
->l4proto
))
887 if (priv
->helper4
&& priv
->helper6
)
888 family
= NFPROTO_INET
;
889 else if (priv
->helper6
)
890 family
= NFPROTO_IPV6
;
892 family
= NFPROTO_IPV4
;
894 if (nla_put_be16(skb
, NFTA_CT_HELPER_L3PROTO
, htons(family
)))
900 static const struct nla_policy nft_ct_helper_policy
[NFTA_CT_HELPER_MAX
+ 1] = {
901 [NFTA_CT_HELPER_NAME
] = { .type
= NLA_STRING
,
902 .len
= NF_CT_HELPER_NAME_LEN
- 1 },
903 [NFTA_CT_HELPER_L3PROTO
] = { .type
= NLA_U16
},
904 [NFTA_CT_HELPER_L4PROTO
] = { .type
= NLA_U8
},
907 static struct nft_object_type nft_ct_helper_obj_type
;
908 static const struct nft_object_ops nft_ct_helper_obj_ops
= {
909 .type
= &nft_ct_helper_obj_type
,
910 .size
= sizeof(struct nft_ct_helper_obj
),
911 .eval
= nft_ct_helper_obj_eval
,
912 .init
= nft_ct_helper_obj_init
,
913 .destroy
= nft_ct_helper_obj_destroy
,
914 .dump
= nft_ct_helper_obj_dump
,
917 static struct nft_object_type nft_ct_helper_obj_type __read_mostly
= {
918 .type
= NFT_OBJECT_CT_HELPER
,
919 .ops
= &nft_ct_helper_obj_ops
,
920 .maxattr
= NFTA_CT_HELPER_MAX
,
921 .policy
= nft_ct_helper_policy
,
922 .owner
= THIS_MODULE
,
925 static int __init
nft_ct_module_init(void)
929 BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE
> NFT_REG_SIZE
);
931 err
= nft_register_expr(&nft_ct_type
);
935 err
= nft_register_expr(&nft_notrack_type
);
939 err
= nft_register_obj(&nft_ct_helper_obj_type
);
946 nft_unregister_expr(&nft_notrack_type
);
948 nft_unregister_expr(&nft_ct_type
);
952 static void __exit
nft_ct_module_exit(void)
954 nft_unregister_obj(&nft_ct_helper_obj_type
);
955 nft_unregister_expr(&nft_notrack_type
);
956 nft_unregister_expr(&nft_ct_type
);
959 module_init(nft_ct_module_init
);
960 module_exit(nft_ct_module_exit
);
962 MODULE_LICENSE("GPL");
963 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
964 MODULE_ALIAS_NFT_EXPR("ct");
965 MODULE_ALIAS_NFT_EXPR("notrack");
966 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_HELPER
);