2 * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * This software has been sponsored by Sophos Astaro <http://www.sophos.com>
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/netlink.h>
15 #include <linux/netfilter.h>
16 #include <linux/netfilter/nfnetlink.h>
17 #include <linux/netfilter/nf_tables.h>
18 #include <linux/netfilter/nf_tables_compat.h>
19 #include <linux/netfilter/x_tables.h>
20 #include <linux/netfilter_ipv4/ip_tables.h>
21 #include <linux/netfilter_ipv6/ip6_tables.h>
22 #include <linux/netfilter_bridge/ebtables.h>
23 #include <linux/netfilter_arp/arp_tables.h>
24 #include <net/netfilter/nf_tables.h>
26 static int nft_compat_chain_validate_dependency(const char *tablename
,
27 const struct nft_chain
*chain
)
29 const struct nft_base_chain
*basechain
;
31 if (!tablename
|| !(chain
->flags
& NFT_BASE_CHAIN
))
34 basechain
= nft_base_chain(chain
);
35 if (strcmp(tablename
, "nat") == 0 &&
36 basechain
->type
->type
!= NFT_CHAIN_T_NAT
)
46 struct arpt_entry arp
;
50 nft_compat_set_par(struct xt_action_param
*par
, void *xt
, const void *xt_info
)
53 par
->targinfo
= xt_info
;
57 static void nft_target_eval_xt(const struct nft_expr
*expr
,
58 struct nft_regs
*regs
,
59 const struct nft_pktinfo
*pkt
)
61 void *info
= nft_expr_priv(expr
);
62 struct xt_target
*target
= expr
->ops
->data
;
63 struct sk_buff
*skb
= pkt
->skb
;
66 nft_compat_set_par((struct xt_action_param
*)&pkt
->xt
, target
, info
);
68 ret
= target
->target(skb
, &pkt
->xt
);
75 regs
->verdict
.code
= NFT_CONTINUE
;
78 regs
->verdict
.code
= ret
;
83 static void nft_target_eval_bridge(const struct nft_expr
*expr
,
84 struct nft_regs
*regs
,
85 const struct nft_pktinfo
*pkt
)
87 void *info
= nft_expr_priv(expr
);
88 struct xt_target
*target
= expr
->ops
->data
;
89 struct sk_buff
*skb
= pkt
->skb
;
92 nft_compat_set_par((struct xt_action_param
*)&pkt
->xt
, target
, info
);
94 ret
= target
->target(skb
, &pkt
->xt
);
101 regs
->verdict
.code
= NF_ACCEPT
;
104 regs
->verdict
.code
= NF_DROP
;
107 regs
->verdict
.code
= NFT_CONTINUE
;
110 regs
->verdict
.code
= NFT_RETURN
;
113 regs
->verdict
.code
= ret
;
118 static const struct nla_policy nft_target_policy
[NFTA_TARGET_MAX
+ 1] = {
119 [NFTA_TARGET_NAME
] = { .type
= NLA_NUL_STRING
},
120 [NFTA_TARGET_REV
] = { .type
= NLA_U32
},
121 [NFTA_TARGET_INFO
] = { .type
= NLA_BINARY
},
125 nft_target_set_tgchk_param(struct xt_tgchk_param
*par
,
126 const struct nft_ctx
*ctx
,
127 struct xt_target
*target
, void *info
,
128 union nft_entry
*entry
, u16 proto
, bool inv
)
131 par
->table
= ctx
->table
->name
;
132 switch (ctx
->afi
->family
) {
134 entry
->e4
.ip
.proto
= proto
;
135 entry
->e4
.ip
.invflags
= inv
? IPT_INV_PROTO
: 0;
139 entry
->e6
.ipv6
.flags
|= IP6T_F_PROTO
;
141 entry
->e6
.ipv6
.proto
= proto
;
142 entry
->e6
.ipv6
.invflags
= inv
? IP6T_INV_PROTO
: 0;
145 entry
->ebt
.ethproto
= (__force __be16
)proto
;
146 entry
->ebt
.invflags
= inv
? EBT_IPROTO
: 0;
151 par
->entryinfo
= entry
;
152 par
->target
= target
;
153 par
->targinfo
= info
;
154 if (ctx
->chain
->flags
& NFT_BASE_CHAIN
) {
155 const struct nft_base_chain
*basechain
=
156 nft_base_chain(ctx
->chain
);
157 const struct nf_hook_ops
*ops
= &basechain
->ops
[0];
159 par
->hook_mask
= 1 << ops
->hooknum
;
163 par
->family
= ctx
->afi
->family
;
166 static void target_compat_from_user(struct xt_target
*t
, void *in
, void *out
)
170 memcpy(out
, in
, t
->targetsize
);
171 pad
= XT_ALIGN(t
->targetsize
) - t
->targetsize
;
173 memset(out
+ t
->targetsize
, 0, pad
);
176 static const struct nla_policy nft_rule_compat_policy
[NFTA_RULE_COMPAT_MAX
+ 1] = {
177 [NFTA_RULE_COMPAT_PROTO
] = { .type
= NLA_U32
},
178 [NFTA_RULE_COMPAT_FLAGS
] = { .type
= NLA_U32
},
181 static int nft_parse_compat(const struct nlattr
*attr
, u16
*proto
, bool *inv
)
183 struct nlattr
*tb
[NFTA_RULE_COMPAT_MAX
+1];
187 err
= nla_parse_nested(tb
, NFTA_RULE_COMPAT_MAX
, attr
,
188 nft_rule_compat_policy
);
192 if (!tb
[NFTA_RULE_COMPAT_PROTO
] || !tb
[NFTA_RULE_COMPAT_FLAGS
])
195 flags
= ntohl(nla_get_be32(tb
[NFTA_RULE_COMPAT_FLAGS
]));
196 if (flags
& ~NFT_RULE_COMPAT_F_MASK
)
198 if (flags
& NFT_RULE_COMPAT_F_INV
)
201 *proto
= ntohl(nla_get_be32(tb
[NFTA_RULE_COMPAT_PROTO
]));
206 nft_target_init(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
,
207 const struct nlattr
* const tb
[])
209 void *info
= nft_expr_priv(expr
);
210 struct xt_target
*target
= expr
->ops
->data
;
211 struct xt_tgchk_param par
;
212 size_t size
= XT_ALIGN(nla_len(tb
[NFTA_TARGET_INFO
]));
215 union nft_entry e
= {};
218 ret
= nft_compat_chain_validate_dependency(target
->table
, ctx
->chain
);
222 target_compat_from_user(target
, nla_data(tb
[NFTA_TARGET_INFO
]), info
);
224 if (ctx
->nla
[NFTA_RULE_COMPAT
]) {
225 ret
= nft_parse_compat(ctx
->nla
[NFTA_RULE_COMPAT
], &proto
, &inv
);
230 nft_target_set_tgchk_param(&par
, ctx
, target
, info
, &e
, proto
, inv
);
232 ret
= xt_check_target(&par
, size
, proto
, inv
);
236 /* The standard target cannot be used */
237 if (target
->target
== NULL
) {
244 module_put(target
->me
);
249 nft_target_destroy(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
)
251 struct xt_target
*target
= expr
->ops
->data
;
252 void *info
= nft_expr_priv(expr
);
253 struct xt_tgdtor_param par
;
258 par
.family
= ctx
->afi
->family
;
259 if (par
.target
->destroy
!= NULL
)
260 par
.target
->destroy(&par
);
262 module_put(target
->me
);
265 static int nft_target_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
267 const struct xt_target
*target
= expr
->ops
->data
;
268 void *info
= nft_expr_priv(expr
);
270 if (nla_put_string(skb
, NFTA_TARGET_NAME
, target
->name
) ||
271 nla_put_be32(skb
, NFTA_TARGET_REV
, htonl(target
->revision
)) ||
272 nla_put(skb
, NFTA_TARGET_INFO
, XT_ALIGN(target
->targetsize
), info
))
273 goto nla_put_failure
;
281 static int nft_target_validate(const struct nft_ctx
*ctx
,
282 const struct nft_expr
*expr
,
283 const struct nft_data
**data
)
285 struct xt_target
*target
= expr
->ops
->data
;
286 unsigned int hook_mask
= 0;
289 if (ctx
->chain
->flags
& NFT_BASE_CHAIN
) {
290 const struct nft_base_chain
*basechain
=
291 nft_base_chain(ctx
->chain
);
292 const struct nf_hook_ops
*ops
= &basechain
->ops
[0];
294 hook_mask
= 1 << ops
->hooknum
;
295 if (!(hook_mask
& target
->hooks
))
298 ret
= nft_compat_chain_validate_dependency(target
->table
,
306 static void nft_match_eval(const struct nft_expr
*expr
,
307 struct nft_regs
*regs
,
308 const struct nft_pktinfo
*pkt
)
310 void *info
= nft_expr_priv(expr
);
311 struct xt_match
*match
= expr
->ops
->data
;
312 struct sk_buff
*skb
= pkt
->skb
;
315 nft_compat_set_par((struct xt_action_param
*)&pkt
->xt
, match
, info
);
317 ret
= match
->match(skb
, (struct xt_action_param
*)&pkt
->xt
);
319 if (pkt
->xt
.hotdrop
) {
320 regs
->verdict
.code
= NF_DROP
;
324 switch (ret
? 1 : 0) {
326 regs
->verdict
.code
= NFT_CONTINUE
;
329 regs
->verdict
.code
= NFT_BREAK
;
334 static const struct nla_policy nft_match_policy
[NFTA_MATCH_MAX
+ 1] = {
335 [NFTA_MATCH_NAME
] = { .type
= NLA_NUL_STRING
},
336 [NFTA_MATCH_REV
] = { .type
= NLA_U32
},
337 [NFTA_MATCH_INFO
] = { .type
= NLA_BINARY
},
340 /* struct xt_mtchk_param and xt_tgchk_param look very similar */
342 nft_match_set_mtchk_param(struct xt_mtchk_param
*par
, const struct nft_ctx
*ctx
,
343 struct xt_match
*match
, void *info
,
344 union nft_entry
*entry
, u16 proto
, bool inv
)
347 par
->table
= ctx
->table
->name
;
348 switch (ctx
->afi
->family
) {
350 entry
->e4
.ip
.proto
= proto
;
351 entry
->e4
.ip
.invflags
= inv
? IPT_INV_PROTO
: 0;
355 entry
->e6
.ipv6
.flags
|= IP6T_F_PROTO
;
357 entry
->e6
.ipv6
.proto
= proto
;
358 entry
->e6
.ipv6
.invflags
= inv
? IP6T_INV_PROTO
: 0;
361 entry
->ebt
.ethproto
= (__force __be16
)proto
;
362 entry
->ebt
.invflags
= inv
? EBT_IPROTO
: 0;
367 par
->entryinfo
= entry
;
369 par
->matchinfo
= info
;
370 if (ctx
->chain
->flags
& NFT_BASE_CHAIN
) {
371 const struct nft_base_chain
*basechain
=
372 nft_base_chain(ctx
->chain
);
373 const struct nf_hook_ops
*ops
= &basechain
->ops
[0];
375 par
->hook_mask
= 1 << ops
->hooknum
;
379 par
->family
= ctx
->afi
->family
;
382 static void match_compat_from_user(struct xt_match
*m
, void *in
, void *out
)
386 memcpy(out
, in
, m
->matchsize
);
387 pad
= XT_ALIGN(m
->matchsize
) - m
->matchsize
;
389 memset(out
+ m
->matchsize
, 0, pad
);
393 nft_match_init(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
,
394 const struct nlattr
* const tb
[])
396 void *info
= nft_expr_priv(expr
);
397 struct xt_match
*match
= expr
->ops
->data
;
398 struct xt_mtchk_param par
;
399 size_t size
= XT_ALIGN(nla_len(tb
[NFTA_MATCH_INFO
]));
402 union nft_entry e
= {};
405 ret
= nft_compat_chain_validate_dependency(match
->table
, ctx
->chain
);
409 match_compat_from_user(match
, nla_data(tb
[NFTA_MATCH_INFO
]), info
);
411 if (ctx
->nla
[NFTA_RULE_COMPAT
]) {
412 ret
= nft_parse_compat(ctx
->nla
[NFTA_RULE_COMPAT
], &proto
, &inv
);
417 nft_match_set_mtchk_param(&par
, ctx
, match
, info
, &e
, proto
, inv
);
419 ret
= xt_check_match(&par
, size
, proto
, inv
);
425 module_put(match
->me
);
430 nft_match_destroy(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
)
432 struct xt_match
*match
= expr
->ops
->data
;
433 void *info
= nft_expr_priv(expr
);
434 struct xt_mtdtor_param par
;
438 par
.matchinfo
= info
;
439 par
.family
= ctx
->afi
->family
;
440 if (par
.match
->destroy
!= NULL
)
441 par
.match
->destroy(&par
);
443 module_put(match
->me
);
446 static int nft_match_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
448 void *info
= nft_expr_priv(expr
);
449 struct xt_match
*match
= expr
->ops
->data
;
451 if (nla_put_string(skb
, NFTA_MATCH_NAME
, match
->name
) ||
452 nla_put_be32(skb
, NFTA_MATCH_REV
, htonl(match
->revision
)) ||
453 nla_put(skb
, NFTA_MATCH_INFO
, XT_ALIGN(match
->matchsize
), info
))
454 goto nla_put_failure
;
462 static int nft_match_validate(const struct nft_ctx
*ctx
,
463 const struct nft_expr
*expr
,
464 const struct nft_data
**data
)
466 struct xt_match
*match
= expr
->ops
->data
;
467 unsigned int hook_mask
= 0;
470 if (ctx
->chain
->flags
& NFT_BASE_CHAIN
) {
471 const struct nft_base_chain
*basechain
=
472 nft_base_chain(ctx
->chain
);
473 const struct nf_hook_ops
*ops
= &basechain
->ops
[0];
475 hook_mask
= 1 << ops
->hooknum
;
476 if (!(hook_mask
& match
->hooks
))
479 ret
= nft_compat_chain_validate_dependency(match
->table
,
488 nfnl_compat_fill_info(struct sk_buff
*skb
, u32 portid
, u32 seq
, u32 type
,
489 int event
, u16 family
, const char *name
,
492 struct nlmsghdr
*nlh
;
493 struct nfgenmsg
*nfmsg
;
494 unsigned int flags
= portid
? NLM_F_MULTI
: 0;
496 event
|= NFNL_SUBSYS_NFT_COMPAT
<< 8;
497 nlh
= nlmsg_put(skb
, portid
, seq
, event
, sizeof(*nfmsg
), flags
);
501 nfmsg
= nlmsg_data(nlh
);
502 nfmsg
->nfgen_family
= family
;
503 nfmsg
->version
= NFNETLINK_V0
;
506 if (nla_put_string(skb
, NFTA_COMPAT_NAME
, name
) ||
507 nla_put_be32(skb
, NFTA_COMPAT_REV
, htonl(rev
)) ||
508 nla_put_be32(skb
, NFTA_COMPAT_TYPE
, htonl(target
)))
509 goto nla_put_failure
;
516 nlmsg_cancel(skb
, nlh
);
521 nfnl_compat_get(struct sock
*nfnl
, struct sk_buff
*skb
,
522 const struct nlmsghdr
*nlh
, const struct nlattr
* const tb
[])
525 struct nfgenmsg
*nfmsg
;
529 struct sk_buff
*skb2
;
531 if (tb
[NFTA_COMPAT_NAME
] == NULL
||
532 tb
[NFTA_COMPAT_REV
] == NULL
||
533 tb
[NFTA_COMPAT_TYPE
] == NULL
)
536 name
= nla_data(tb
[NFTA_COMPAT_NAME
]);
537 rev
= ntohl(nla_get_be32(tb
[NFTA_COMPAT_REV
]));
538 target
= ntohl(nla_get_be32(tb
[NFTA_COMPAT_TYPE
]));
540 nfmsg
= nlmsg_data(nlh
);
542 switch(nfmsg
->nfgen_family
) {
556 pr_err("nft_compat: unsupported protocol %d\n",
557 nfmsg
->nfgen_family
);
561 try_then_request_module(xt_find_revision(nfmsg
->nfgen_family
, name
,
568 skb2
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
572 /* include the best revision for this extension in the message */
573 if (nfnl_compat_fill_info(skb2
, NETLINK_CB(skb
).portid
,
575 NFNL_MSG_TYPE(nlh
->nlmsg_type
),
578 name
, ret
, target
) <= 0) {
583 ret
= netlink_unicast(nfnl
, skb2
, NETLINK_CB(skb
).portid
,
588 return ret
== -EAGAIN
? -ENOBUFS
: ret
;
591 static const struct nla_policy nfnl_compat_policy_get
[NFTA_COMPAT_MAX
+1] = {
592 [NFTA_COMPAT_NAME
] = { .type
= NLA_NUL_STRING
,
593 .len
= NFT_COMPAT_NAME_MAX
-1 },
594 [NFTA_COMPAT_REV
] = { .type
= NLA_U32
},
595 [NFTA_COMPAT_TYPE
] = { .type
= NLA_U32
},
598 static const struct nfnl_callback nfnl_nft_compat_cb
[NFNL_MSG_COMPAT_MAX
] = {
599 [NFNL_MSG_COMPAT_GET
] = { .call
= nfnl_compat_get
,
600 .attr_count
= NFTA_COMPAT_MAX
,
601 .policy
= nfnl_compat_policy_get
},
604 static const struct nfnetlink_subsystem nfnl_compat_subsys
= {
605 .name
= "nft-compat",
606 .subsys_id
= NFNL_SUBSYS_NFT_COMPAT
,
607 .cb_count
= NFNL_MSG_COMPAT_MAX
,
608 .cb
= nfnl_nft_compat_cb
,
611 static LIST_HEAD(nft_match_list
);
614 struct list_head head
;
615 struct nft_expr_ops ops
;
618 static struct nft_expr_type nft_match_type
;
620 static const struct nft_expr_ops
*
621 nft_match_select_ops(const struct nft_ctx
*ctx
,
622 const struct nlattr
* const tb
[])
624 struct nft_xt
*nft_match
;
625 struct xt_match
*match
;
629 if (tb
[NFTA_MATCH_NAME
] == NULL
||
630 tb
[NFTA_MATCH_REV
] == NULL
||
631 tb
[NFTA_MATCH_INFO
] == NULL
)
632 return ERR_PTR(-EINVAL
);
634 mt_name
= nla_data(tb
[NFTA_MATCH_NAME
]);
635 rev
= ntohl(nla_get_be32(tb
[NFTA_MATCH_REV
]));
636 family
= ctx
->afi
->family
;
638 /* Re-use the existing match if it's already loaded. */
639 list_for_each_entry(nft_match
, &nft_match_list
, head
) {
640 struct xt_match
*match
= nft_match
->ops
.data
;
642 if (strcmp(match
->name
, mt_name
) == 0 &&
643 match
->revision
== rev
&& match
->family
== family
) {
644 if (!try_module_get(match
->me
))
645 return ERR_PTR(-ENOENT
);
647 return &nft_match
->ops
;
651 match
= xt_request_find_match(family
, mt_name
, rev
);
653 return ERR_PTR(-ENOENT
);
655 /* This is the first time we use this match, allocate operations */
656 nft_match
= kzalloc(sizeof(struct nft_xt
), GFP_KERNEL
);
657 if (nft_match
== NULL
)
658 return ERR_PTR(-ENOMEM
);
660 nft_match
->ops
.type
= &nft_match_type
;
661 nft_match
->ops
.size
= NFT_EXPR_SIZE(XT_ALIGN(match
->matchsize
));
662 nft_match
->ops
.eval
= nft_match_eval
;
663 nft_match
->ops
.init
= nft_match_init
;
664 nft_match
->ops
.destroy
= nft_match_destroy
;
665 nft_match
->ops
.dump
= nft_match_dump
;
666 nft_match
->ops
.validate
= nft_match_validate
;
667 nft_match
->ops
.data
= match
;
669 list_add(&nft_match
->head
, &nft_match_list
);
671 return &nft_match
->ops
;
674 static void nft_match_release(void)
676 struct nft_xt
*nft_match
, *tmp
;
678 list_for_each_entry_safe(nft_match
, tmp
, &nft_match_list
, head
)
682 static struct nft_expr_type nft_match_type __read_mostly
= {
684 .select_ops
= nft_match_select_ops
,
685 .policy
= nft_match_policy
,
686 .maxattr
= NFTA_MATCH_MAX
,
687 .owner
= THIS_MODULE
,
690 static LIST_HEAD(nft_target_list
);
692 static struct nft_expr_type nft_target_type
;
694 static const struct nft_expr_ops
*
695 nft_target_select_ops(const struct nft_ctx
*ctx
,
696 const struct nlattr
* const tb
[])
698 struct nft_xt
*nft_target
;
699 struct xt_target
*target
;
703 if (tb
[NFTA_TARGET_NAME
] == NULL
||
704 tb
[NFTA_TARGET_REV
] == NULL
||
705 tb
[NFTA_TARGET_INFO
] == NULL
)
706 return ERR_PTR(-EINVAL
);
708 tg_name
= nla_data(tb
[NFTA_TARGET_NAME
]);
709 rev
= ntohl(nla_get_be32(tb
[NFTA_TARGET_REV
]));
710 family
= ctx
->afi
->family
;
712 /* Re-use the existing target if it's already loaded. */
713 list_for_each_entry(nft_target
, &nft_target_list
, head
) {
714 struct xt_target
*target
= nft_target
->ops
.data
;
716 if (strcmp(target
->name
, tg_name
) == 0 &&
717 target
->revision
== rev
&& target
->family
== family
) {
718 if (!try_module_get(target
->me
))
719 return ERR_PTR(-ENOENT
);
721 return &nft_target
->ops
;
725 target
= xt_request_find_target(family
, tg_name
, rev
);
727 return ERR_PTR(-ENOENT
);
729 /* This is the first time we use this target, allocate operations */
730 nft_target
= kzalloc(sizeof(struct nft_xt
), GFP_KERNEL
);
731 if (nft_target
== NULL
)
732 return ERR_PTR(-ENOMEM
);
734 nft_target
->ops
.type
= &nft_target_type
;
735 nft_target
->ops
.size
= NFT_EXPR_SIZE(XT_ALIGN(target
->targetsize
));
736 nft_target
->ops
.init
= nft_target_init
;
737 nft_target
->ops
.destroy
= nft_target_destroy
;
738 nft_target
->ops
.dump
= nft_target_dump
;
739 nft_target
->ops
.validate
= nft_target_validate
;
740 nft_target
->ops
.data
= target
;
742 if (family
== NFPROTO_BRIDGE
)
743 nft_target
->ops
.eval
= nft_target_eval_bridge
;
745 nft_target
->ops
.eval
= nft_target_eval_xt
;
747 list_add(&nft_target
->head
, &nft_target_list
);
749 return &nft_target
->ops
;
752 static void nft_target_release(void)
754 struct nft_xt
*nft_target
, *tmp
;
756 list_for_each_entry_safe(nft_target
, tmp
, &nft_target_list
, head
)
760 static struct nft_expr_type nft_target_type __read_mostly
= {
762 .select_ops
= nft_target_select_ops
,
763 .policy
= nft_target_policy
,
764 .maxattr
= NFTA_TARGET_MAX
,
765 .owner
= THIS_MODULE
,
768 static int __init
nft_compat_module_init(void)
772 ret
= nft_register_expr(&nft_match_type
);
776 ret
= nft_register_expr(&nft_target_type
);
780 ret
= nfnetlink_subsys_register(&nfnl_compat_subsys
);
782 pr_err("nft_compat: cannot register with nfnetlink.\n");
786 pr_info("nf_tables_compat: (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>\n");
791 nft_unregister_expr(&nft_target_type
);
793 nft_unregister_expr(&nft_match_type
);
797 static void __exit
nft_compat_module_exit(void)
799 nfnetlink_subsys_unregister(&nfnl_compat_subsys
);
800 nft_unregister_expr(&nft_target_type
);
801 nft_unregister_expr(&nft_match_type
);
803 nft_target_release();
806 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFT_COMPAT
);
808 module_init(nft_compat_module_init
);
809 module_exit(nft_compat_module_exit
);
811 MODULE_LICENSE("GPL");
812 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
813 MODULE_ALIAS_NFT_EXPR("match");
814 MODULE_ALIAS_NFT_EXPR("target");