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 #ifdef CONFIG_NF_CONNTRACK_ZONES
316 static void nft_ct_tmpl_put_pcpu(void)
321 for_each_possible_cpu(cpu
) {
322 ct
= per_cpu(nft_ct_pcpu_template
, cpu
);
326 per_cpu(nft_ct_pcpu_template
, cpu
) = NULL
;
330 static bool nft_ct_tmpl_alloc_pcpu(void)
332 struct nf_conntrack_zone zone
= { .id
= 0 };
336 if (nft_ct_pcpu_template_refcnt
)
339 for_each_possible_cpu(cpu
) {
340 tmp
= nf_ct_tmpl_alloc(&init_net
, &zone
, GFP_KERNEL
);
342 nft_ct_tmpl_put_pcpu();
346 atomic_set(&tmp
->ct_general
.use
, 1);
347 per_cpu(nft_ct_pcpu_template
, cpu
) = tmp
;
354 static int nft_ct_get_init(const struct nft_ctx
*ctx
,
355 const struct nft_expr
*expr
,
356 const struct nlattr
* const tb
[])
358 struct nft_ct
*priv
= nft_expr_priv(expr
);
362 priv
->key
= ntohl(nla_get_be32(tb
[NFTA_CT_KEY
]));
363 priv
->dir
= IP_CT_DIR_MAX
;
365 case NFT_CT_DIRECTION
:
366 if (tb
[NFTA_CT_DIRECTION
] != NULL
)
372 #ifdef CONFIG_NF_CONNTRACK_MARK
375 #ifdef CONFIG_NF_CONNTRACK_SECMARK
378 case NFT_CT_EXPIRATION
:
379 if (tb
[NFTA_CT_DIRECTION
] != NULL
)
383 #ifdef CONFIG_NF_CONNTRACK_LABELS
385 if (tb
[NFTA_CT_DIRECTION
] != NULL
)
387 len
= NF_CT_LABELS_MAX_SIZE
;
391 if (tb
[NFTA_CT_DIRECTION
] != NULL
)
393 len
= NF_CT_HELPER_NAME_LEN
;
396 case NFT_CT_L3PROTOCOL
:
397 case NFT_CT_PROTOCOL
:
398 /* For compatibility, do not report error if NFTA_CT_DIRECTION
399 * attribute is specified.
405 if (tb
[NFTA_CT_DIRECTION
] == NULL
)
408 switch (ctx
->family
) {
410 len
= FIELD_SIZEOF(struct nf_conntrack_tuple
,
415 len
= FIELD_SIZEOF(struct nf_conntrack_tuple
,
419 return -EAFNOSUPPORT
;
422 case NFT_CT_PROTO_SRC
:
423 case NFT_CT_PROTO_DST
:
424 if (tb
[NFTA_CT_DIRECTION
] == NULL
)
426 len
= FIELD_SIZEOF(struct nf_conntrack_tuple
, src
.u
.all
);
433 #ifdef CONFIG_NF_CONNTRACK_ZONES
442 if (tb
[NFTA_CT_DIRECTION
] != NULL
) {
443 priv
->dir
= nla_get_u8(tb
[NFTA_CT_DIRECTION
]);
445 case IP_CT_DIR_ORIGINAL
:
446 case IP_CT_DIR_REPLY
:
453 priv
->dreg
= nft_parse_register(tb
[NFTA_CT_DREG
]);
454 err
= nft_validate_register_store(ctx
, priv
->dreg
, NULL
,
455 NFT_DATA_VALUE
, len
);
459 err
= nf_ct_netns_get(ctx
->net
, ctx
->family
);
463 if (priv
->key
== NFT_CT_BYTES
||
464 priv
->key
== NFT_CT_PKTS
||
465 priv
->key
== NFT_CT_AVGPKT
)
466 nf_ct_set_acct(ctx
->net
, true);
471 static void __nft_ct_set_destroy(const struct nft_ctx
*ctx
, struct nft_ct
*priv
)
474 #ifdef CONFIG_NF_CONNTRACK_LABELS
476 nf_connlabels_put(ctx
->net
);
479 #ifdef CONFIG_NF_CONNTRACK_ZONES
481 if (--nft_ct_pcpu_template_refcnt
== 0)
482 nft_ct_tmpl_put_pcpu();
489 static int nft_ct_set_init(const struct nft_ctx
*ctx
,
490 const struct nft_expr
*expr
,
491 const struct nlattr
* const tb
[])
493 struct nft_ct
*priv
= nft_expr_priv(expr
);
497 priv
->dir
= IP_CT_DIR_MAX
;
498 priv
->key
= ntohl(nla_get_be32(tb
[NFTA_CT_KEY
]));
500 #ifdef CONFIG_NF_CONNTRACK_MARK
502 if (tb
[NFTA_CT_DIRECTION
])
504 len
= FIELD_SIZEOF(struct nf_conn
, mark
);
507 #ifdef CONFIG_NF_CONNTRACK_LABELS
509 if (tb
[NFTA_CT_DIRECTION
])
511 len
= NF_CT_LABELS_MAX_SIZE
;
512 err
= nf_connlabels_get(ctx
->net
, (len
* BITS_PER_BYTE
) - 1);
517 #ifdef CONFIG_NF_CONNTRACK_ZONES
519 if (!nft_ct_tmpl_alloc_pcpu())
521 nft_ct_pcpu_template_refcnt
++;
525 #ifdef CONFIG_NF_CONNTRACK_EVENTS
526 case NFT_CT_EVENTMASK
:
527 if (tb
[NFTA_CT_DIRECTION
])
536 if (tb
[NFTA_CT_DIRECTION
]) {
537 priv
->dir
= nla_get_u8(tb
[NFTA_CT_DIRECTION
]);
539 case IP_CT_DIR_ORIGINAL
:
540 case IP_CT_DIR_REPLY
:
548 priv
->sreg
= nft_parse_register(tb
[NFTA_CT_SREG
]);
549 err
= nft_validate_register_load(priv
->sreg
, len
);
553 err
= nf_ct_netns_get(ctx
->net
, ctx
->family
);
560 __nft_ct_set_destroy(ctx
, priv
);
564 static void nft_ct_get_destroy(const struct nft_ctx
*ctx
,
565 const struct nft_expr
*expr
)
567 nf_ct_netns_put(ctx
->net
, ctx
->family
);
570 static void nft_ct_set_destroy(const struct nft_ctx
*ctx
,
571 const struct nft_expr
*expr
)
573 struct nft_ct
*priv
= nft_expr_priv(expr
);
575 __nft_ct_set_destroy(ctx
, priv
);
576 nf_ct_netns_put(ctx
->net
, ctx
->family
);
579 static int nft_ct_get_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
581 const struct nft_ct
*priv
= nft_expr_priv(expr
);
583 if (nft_dump_register(skb
, NFTA_CT_DREG
, priv
->dreg
))
584 goto nla_put_failure
;
585 if (nla_put_be32(skb
, NFTA_CT_KEY
, htonl(priv
->key
)))
586 goto nla_put_failure
;
591 case NFT_CT_PROTO_SRC
:
592 case NFT_CT_PROTO_DST
:
593 if (nla_put_u8(skb
, NFTA_CT_DIRECTION
, priv
->dir
))
594 goto nla_put_failure
;
600 if (priv
->dir
< IP_CT_DIR_MAX
&&
601 nla_put_u8(skb
, NFTA_CT_DIRECTION
, priv
->dir
))
602 goto nla_put_failure
;
614 static int nft_ct_set_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
616 const struct nft_ct
*priv
= nft_expr_priv(expr
);
618 if (nft_dump_register(skb
, NFTA_CT_SREG
, priv
->sreg
))
619 goto nla_put_failure
;
620 if (nla_put_be32(skb
, NFTA_CT_KEY
, htonl(priv
->key
)))
621 goto nla_put_failure
;
625 if (priv
->dir
< IP_CT_DIR_MAX
&&
626 nla_put_u8(skb
, NFTA_CT_DIRECTION
, priv
->dir
))
627 goto nla_put_failure
;
639 static struct nft_expr_type nft_ct_type
;
640 static const struct nft_expr_ops nft_ct_get_ops
= {
641 .type
= &nft_ct_type
,
642 .size
= NFT_EXPR_SIZE(sizeof(struct nft_ct
)),
643 .eval
= nft_ct_get_eval
,
644 .init
= nft_ct_get_init
,
645 .destroy
= nft_ct_get_destroy
,
646 .dump
= nft_ct_get_dump
,
649 static const struct nft_expr_ops nft_ct_set_ops
= {
650 .type
= &nft_ct_type
,
651 .size
= NFT_EXPR_SIZE(sizeof(struct nft_ct
)),
652 .eval
= nft_ct_set_eval
,
653 .init
= nft_ct_set_init
,
654 .destroy
= nft_ct_set_destroy
,
655 .dump
= nft_ct_set_dump
,
658 #ifdef CONFIG_NF_CONNTRACK_ZONES
659 static const struct nft_expr_ops nft_ct_set_zone_ops
= {
660 .type
= &nft_ct_type
,
661 .size
= NFT_EXPR_SIZE(sizeof(struct nft_ct
)),
662 .eval
= nft_ct_set_zone_eval
,
663 .init
= nft_ct_set_init
,
664 .destroy
= nft_ct_set_destroy
,
665 .dump
= nft_ct_set_dump
,
669 static const struct nft_expr_ops
*
670 nft_ct_select_ops(const struct nft_ctx
*ctx
,
671 const struct nlattr
* const tb
[])
673 if (tb
[NFTA_CT_KEY
] == NULL
)
674 return ERR_PTR(-EINVAL
);
676 if (tb
[NFTA_CT_DREG
] && tb
[NFTA_CT_SREG
])
677 return ERR_PTR(-EINVAL
);
679 if (tb
[NFTA_CT_DREG
])
680 return &nft_ct_get_ops
;
682 if (tb
[NFTA_CT_SREG
]) {
683 #ifdef CONFIG_NF_CONNTRACK_ZONES
684 if (nla_get_be32(tb
[NFTA_CT_KEY
]) == htonl(NFT_CT_ZONE
))
685 return &nft_ct_set_zone_ops
;
687 return &nft_ct_set_ops
;
690 return ERR_PTR(-EINVAL
);
693 static struct nft_expr_type nft_ct_type __read_mostly
= {
695 .select_ops
= nft_ct_select_ops
,
696 .policy
= nft_ct_policy
,
697 .maxattr
= NFTA_CT_MAX
,
698 .owner
= THIS_MODULE
,
701 static void nft_notrack_eval(const struct nft_expr
*expr
,
702 struct nft_regs
*regs
,
703 const struct nft_pktinfo
*pkt
)
705 struct sk_buff
*skb
= pkt
->skb
;
706 enum ip_conntrack_info ctinfo
;
709 ct
= nf_ct_get(pkt
->skb
, &ctinfo
);
710 /* Previously seen (loopback or untracked)? Ignore. */
711 if (ct
|| ctinfo
== IP_CT_UNTRACKED
)
714 nf_ct_set(skb
, ct
, IP_CT_UNTRACKED
);
717 static struct nft_expr_type nft_notrack_type
;
718 static const struct nft_expr_ops nft_notrack_ops
= {
719 .type
= &nft_notrack_type
,
720 .size
= NFT_EXPR_SIZE(0),
721 .eval
= nft_notrack_eval
,
724 static struct nft_expr_type nft_notrack_type __read_mostly
= {
726 .ops
= &nft_notrack_ops
,
727 .owner
= THIS_MODULE
,
730 static int nft_ct_helper_obj_init(const struct nft_ctx
*ctx
,
731 const struct nlattr
* const tb
[],
732 struct nft_object
*obj
)
734 struct nft_ct_helper_obj
*priv
= nft_obj_data(obj
);
735 struct nf_conntrack_helper
*help4
, *help6
;
736 char name
[NF_CT_HELPER_NAME_LEN
];
737 int family
= ctx
->family
;
739 if (!tb
[NFTA_CT_HELPER_NAME
] || !tb
[NFTA_CT_HELPER_L4PROTO
])
742 priv
->l4proto
= nla_get_u8(tb
[NFTA_CT_HELPER_L4PROTO
]);
746 nla_strlcpy(name
, tb
[NFTA_CT_HELPER_NAME
], sizeof(name
));
748 if (tb
[NFTA_CT_HELPER_L3PROTO
])
749 family
= ntohs(nla_get_be16(tb
[NFTA_CT_HELPER_L3PROTO
]));
756 if (ctx
->family
== NFPROTO_IPV6
)
759 help4
= nf_conntrack_helper_try_module_get(name
, family
,
763 if (ctx
->family
== NFPROTO_IPV4
)
766 help6
= nf_conntrack_helper_try_module_get(name
, family
,
769 case NFPROTO_NETDEV
: /* fallthrough */
770 case NFPROTO_BRIDGE
: /* same */
772 help4
= nf_conntrack_helper_try_module_get(name
, NFPROTO_IPV4
,
774 help6
= nf_conntrack_helper_try_module_get(name
, NFPROTO_IPV6
,
778 return -EAFNOSUPPORT
;
781 /* && is intentional; only error if INET found neither ipv4 or ipv6 */
782 if (!help4
&& !help6
)
785 priv
->helper4
= help4
;
786 priv
->helper6
= help6
;
791 static void nft_ct_helper_obj_destroy(struct nft_object
*obj
)
793 struct nft_ct_helper_obj
*priv
= nft_obj_data(obj
);
796 nf_conntrack_helper_put(priv
->helper4
);
798 nf_conntrack_helper_put(priv
->helper6
);
801 static void nft_ct_helper_obj_eval(struct nft_object
*obj
,
802 struct nft_regs
*regs
,
803 const struct nft_pktinfo
*pkt
)
805 const struct nft_ct_helper_obj
*priv
= nft_obj_data(obj
);
806 struct nf_conn
*ct
= (struct nf_conn
*)skb_nfct(pkt
->skb
);
807 struct nf_conntrack_helper
*to_assign
= NULL
;
808 struct nf_conn_help
*help
;
811 nf_ct_is_confirmed(ct
) ||
812 nf_ct_is_template(ct
) ||
813 priv
->l4proto
!= nf_ct_protonum(ct
))
816 switch (nf_ct_l3num(ct
)) {
818 to_assign
= priv
->helper4
;
821 to_assign
= priv
->helper6
;
831 if (test_bit(IPS_HELPER_BIT
, &ct
->status
))
834 help
= nf_ct_helper_ext_add(ct
, to_assign
, GFP_ATOMIC
);
836 rcu_assign_pointer(help
->helper
, to_assign
);
837 set_bit(IPS_HELPER_BIT
, &ct
->status
);
841 static int nft_ct_helper_obj_dump(struct sk_buff
*skb
,
842 struct nft_object
*obj
, bool reset
)
844 const struct nft_ct_helper_obj
*priv
= nft_obj_data(obj
);
845 const struct nf_conntrack_helper
*helper
= priv
->helper4
;
848 if (nla_put_string(skb
, NFTA_CT_HELPER_NAME
, helper
->name
))
851 if (nla_put_u8(skb
, NFTA_CT_HELPER_L4PROTO
, priv
->l4proto
))
854 if (priv
->helper4
&& priv
->helper6
)
855 family
= NFPROTO_INET
;
856 else if (priv
->helper6
)
857 family
= NFPROTO_IPV6
;
859 family
= NFPROTO_IPV4
;
861 if (nla_put_be16(skb
, NFTA_CT_HELPER_L3PROTO
, htons(family
)))
867 static const struct nla_policy nft_ct_helper_policy
[NFTA_CT_HELPER_MAX
+ 1] = {
868 [NFTA_CT_HELPER_NAME
] = { .type
= NLA_STRING
,
869 .len
= NF_CT_HELPER_NAME_LEN
- 1 },
870 [NFTA_CT_HELPER_L3PROTO
] = { .type
= NLA_U16
},
871 [NFTA_CT_HELPER_L4PROTO
] = { .type
= NLA_U8
},
874 static struct nft_object_type nft_ct_helper_obj_type
;
875 static const struct nft_object_ops nft_ct_helper_obj_ops
= {
876 .type
= &nft_ct_helper_obj_type
,
877 .size
= sizeof(struct nft_ct_helper_obj
),
878 .eval
= nft_ct_helper_obj_eval
,
879 .init
= nft_ct_helper_obj_init
,
880 .destroy
= nft_ct_helper_obj_destroy
,
881 .dump
= nft_ct_helper_obj_dump
,
884 static struct nft_object_type nft_ct_helper_obj_type __read_mostly
= {
885 .type
= NFT_OBJECT_CT_HELPER
,
886 .ops
= &nft_ct_helper_obj_ops
,
887 .maxattr
= NFTA_CT_HELPER_MAX
,
888 .policy
= nft_ct_helper_policy
,
889 .owner
= THIS_MODULE
,
892 static int __init
nft_ct_module_init(void)
896 BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE
> NFT_REG_SIZE
);
898 err
= nft_register_expr(&nft_ct_type
);
902 err
= nft_register_expr(&nft_notrack_type
);
906 err
= nft_register_obj(&nft_ct_helper_obj_type
);
913 nft_unregister_expr(&nft_notrack_type
);
915 nft_unregister_expr(&nft_ct_type
);
919 static void __exit
nft_ct_module_exit(void)
921 nft_unregister_obj(&nft_ct_helper_obj_type
);
922 nft_unregister_expr(&nft_notrack_type
);
923 nft_unregister_expr(&nft_ct_type
);
926 module_init(nft_ct_module_init
);
927 module_exit(nft_ct_module_exit
);
929 MODULE_LICENSE("GPL");
930 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
931 MODULE_ALIAS_NFT_EXPR("ct");
932 MODULE_ALIAS_NFT_EXPR("notrack");
933 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_HELPER
);