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 <asm/uaccess.h> /* for set_fs */
23 #include <net/netfilter/nf_tables.h>
31 nft_compat_set_par(struct xt_action_param
*par
, void *xt
, const void *xt_info
)
34 par
->targinfo
= xt_info
;
38 static void nft_target_eval(const struct nft_expr
*expr
,
39 struct nft_data data
[NFT_REG_MAX
+ 1],
40 const struct nft_pktinfo
*pkt
)
42 void *info
= nft_expr_priv(expr
);
43 struct xt_target
*target
= expr
->ops
->data
;
44 struct sk_buff
*skb
= pkt
->skb
;
47 nft_compat_set_par((struct xt_action_param
*)&pkt
->xt
, target
, info
);
49 ret
= target
->target(skb
, &pkt
->xt
);
56 data
[NFT_REG_VERDICT
].verdict
= NFT_CONTINUE
;
59 data
[NFT_REG_VERDICT
].verdict
= ret
;
65 static const struct nla_policy nft_target_policy
[NFTA_TARGET_MAX
+ 1] = {
66 [NFTA_TARGET_NAME
] = { .type
= NLA_NUL_STRING
},
67 [NFTA_TARGET_REV
] = { .type
= NLA_U32
},
68 [NFTA_TARGET_INFO
] = { .type
= NLA_BINARY
},
72 nft_target_set_tgchk_param(struct xt_tgchk_param
*par
,
73 const struct nft_ctx
*ctx
,
74 struct xt_target
*target
, void *info
,
75 union nft_entry
*entry
, u8 proto
, bool inv
)
78 par
->table
= ctx
->table
->name
;
79 switch (ctx
->afi
->family
) {
81 entry
->e4
.ip
.proto
= proto
;
82 entry
->e4
.ip
.invflags
= inv
? IPT_INV_PROTO
: 0;
85 entry
->e6
.ipv6
.proto
= proto
;
86 entry
->e6
.ipv6
.invflags
= inv
? IP6T_INV_PROTO
: 0;
89 par
->entryinfo
= entry
;
92 if (ctx
->chain
->flags
& NFT_BASE_CHAIN
) {
93 const struct nft_base_chain
*basechain
=
94 nft_base_chain(ctx
->chain
);
95 const struct nf_hook_ops
*ops
= &basechain
->ops
[0];
97 par
->hook_mask
= 1 << ops
->hooknum
;
99 par
->family
= ctx
->afi
->family
;
102 static void target_compat_from_user(struct xt_target
*t
, void *in
, void *out
)
105 if (t
->compat_from_user
) {
108 t
->compat_from_user(out
, in
);
109 pad
= XT_ALIGN(t
->targetsize
) - t
->targetsize
;
111 memset(out
+ t
->targetsize
, 0, pad
);
114 memcpy(out
, in
, XT_ALIGN(t
->targetsize
));
117 static inline int nft_compat_target_offset(struct xt_target
*target
)
120 return xt_compat_target_offset(target
);
126 static const struct nla_policy nft_rule_compat_policy
[NFTA_RULE_COMPAT_MAX
+ 1] = {
127 [NFTA_RULE_COMPAT_PROTO
] = { .type
= NLA_U32
},
128 [NFTA_RULE_COMPAT_FLAGS
] = { .type
= NLA_U32
},
131 static int nft_parse_compat(const struct nlattr
*attr
, u8
*proto
, bool *inv
)
133 struct nlattr
*tb
[NFTA_RULE_COMPAT_MAX
+1];
137 err
= nla_parse_nested(tb
, NFTA_RULE_COMPAT_MAX
, attr
,
138 nft_rule_compat_policy
);
142 if (!tb
[NFTA_RULE_COMPAT_PROTO
] || !tb
[NFTA_RULE_COMPAT_FLAGS
])
145 flags
= ntohl(nla_get_be32(tb
[NFTA_RULE_COMPAT_FLAGS
]));
146 if (flags
& ~NFT_RULE_COMPAT_F_MASK
)
148 if (flags
& NFT_RULE_COMPAT_F_INV
)
151 *proto
= ntohl(nla_get_be32(tb
[NFTA_RULE_COMPAT_PROTO
]));
156 nft_target_init(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
,
157 const struct nlattr
* const tb
[])
159 void *info
= nft_expr_priv(expr
);
160 struct xt_target
*target
= expr
->ops
->data
;
161 struct xt_tgchk_param par
;
162 size_t size
= XT_ALIGN(nla_len(tb
[NFTA_TARGET_INFO
]));
165 union nft_entry e
= {};
168 target_compat_from_user(target
, nla_data(tb
[NFTA_TARGET_INFO
]), info
);
170 if (ctx
->nla
[NFTA_RULE_COMPAT
]) {
171 ret
= nft_parse_compat(ctx
->nla
[NFTA_RULE_COMPAT
], &proto
, &inv
);
176 nft_target_set_tgchk_param(&par
, ctx
, target
, info
, &e
, proto
, inv
);
178 ret
= xt_check_target(&par
, size
, proto
, inv
);
182 /* The standard target cannot be used */
183 if (target
->target
== NULL
) {
190 module_put(target
->me
);
195 nft_target_destroy(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
)
197 struct xt_target
*target
= expr
->ops
->data
;
199 module_put(target
->me
);
203 target_dump_info(struct sk_buff
*skb
, const struct xt_target
*t
, const void *in
)
208 if (t
->compat_to_user
) {
212 out
= kmalloc(XT_ALIGN(t
->targetsize
), GFP_ATOMIC
);
216 /* We want to reuse existing compat_to_user */
219 t
->compat_to_user(out
, in
);
221 ret
= nla_put(skb
, NFTA_TARGET_INFO
, XT_ALIGN(t
->targetsize
), out
);
225 ret
= nla_put(skb
, NFTA_TARGET_INFO
, XT_ALIGN(t
->targetsize
), in
);
230 static int nft_target_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
232 const struct xt_target
*target
= expr
->ops
->data
;
233 void *info
= nft_expr_priv(expr
);
235 if (nla_put_string(skb
, NFTA_TARGET_NAME
, target
->name
) ||
236 nla_put_be32(skb
, NFTA_TARGET_REV
, htonl(target
->revision
)) ||
237 target_dump_info(skb
, target
, info
))
238 goto nla_put_failure
;
246 static int nft_target_validate(const struct nft_ctx
*ctx
,
247 const struct nft_expr
*expr
,
248 const struct nft_data
**data
)
250 struct xt_target
*target
= expr
->ops
->data
;
251 unsigned int hook_mask
= 0;
253 if (ctx
->chain
->flags
& NFT_BASE_CHAIN
) {
254 const struct nft_base_chain
*basechain
=
255 nft_base_chain(ctx
->chain
);
256 const struct nf_hook_ops
*ops
= &basechain
->ops
[0];
258 hook_mask
= 1 << ops
->hooknum
;
259 if (hook_mask
& target
->hooks
)
262 /* This target is being called from an invalid chain */
268 static void nft_match_eval(const struct nft_expr
*expr
,
269 struct nft_data data
[NFT_REG_MAX
+ 1],
270 const struct nft_pktinfo
*pkt
)
272 void *info
= nft_expr_priv(expr
);
273 struct xt_match
*match
= expr
->ops
->data
;
274 struct sk_buff
*skb
= pkt
->skb
;
277 nft_compat_set_par((struct xt_action_param
*)&pkt
->xt
, match
, info
);
279 ret
= match
->match(skb
, (struct xt_action_param
*)&pkt
->xt
);
281 if (pkt
->xt
.hotdrop
) {
282 data
[NFT_REG_VERDICT
].verdict
= NF_DROP
;
288 data
[NFT_REG_VERDICT
].verdict
= NFT_CONTINUE
;
291 data
[NFT_REG_VERDICT
].verdict
= NFT_BREAK
;
296 static const struct nla_policy nft_match_policy
[NFTA_MATCH_MAX
+ 1] = {
297 [NFTA_MATCH_NAME
] = { .type
= NLA_NUL_STRING
},
298 [NFTA_MATCH_REV
] = { .type
= NLA_U32
},
299 [NFTA_MATCH_INFO
] = { .type
= NLA_BINARY
},
302 /* struct xt_mtchk_param and xt_tgchk_param look very similar */
304 nft_match_set_mtchk_param(struct xt_mtchk_param
*par
, const struct nft_ctx
*ctx
,
305 struct xt_match
*match
, void *info
,
306 union nft_entry
*entry
, u8 proto
, bool inv
)
308 par
->net
= &init_net
;
309 par
->table
= ctx
->table
->name
;
310 switch (ctx
->afi
->family
) {
312 entry
->e4
.ip
.proto
= proto
;
313 entry
->e4
.ip
.invflags
= inv
? IPT_INV_PROTO
: 0;
316 entry
->e6
.ipv6
.proto
= proto
;
317 entry
->e6
.ipv6
.invflags
= inv
? IP6T_INV_PROTO
: 0;
320 par
->entryinfo
= entry
;
322 par
->matchinfo
= info
;
323 if (ctx
->chain
->flags
& NFT_BASE_CHAIN
) {
324 const struct nft_base_chain
*basechain
=
325 nft_base_chain(ctx
->chain
);
326 const struct nf_hook_ops
*ops
= &basechain
->ops
[0];
328 par
->hook_mask
= 1 << ops
->hooknum
;
330 par
->family
= ctx
->afi
->family
;
333 static void match_compat_from_user(struct xt_match
*m
, void *in
, void *out
)
336 if (m
->compat_from_user
) {
339 m
->compat_from_user(out
, in
);
340 pad
= XT_ALIGN(m
->matchsize
) - m
->matchsize
;
342 memset(out
+ m
->matchsize
, 0, pad
);
345 memcpy(out
, in
, XT_ALIGN(m
->matchsize
));
349 nft_match_init(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
,
350 const struct nlattr
* const tb
[])
352 void *info
= nft_expr_priv(expr
);
353 struct xt_match
*match
= expr
->ops
->data
;
354 struct xt_mtchk_param par
;
355 size_t size
= XT_ALIGN(nla_len(tb
[NFTA_MATCH_INFO
]));
358 union nft_entry e
= {};
361 match_compat_from_user(match
, nla_data(tb
[NFTA_MATCH_INFO
]), info
);
363 if (ctx
->nla
[NFTA_RULE_COMPAT
]) {
364 ret
= nft_parse_compat(ctx
->nla
[NFTA_RULE_COMPAT
], &proto
, &inv
);
369 nft_match_set_mtchk_param(&par
, ctx
, match
, info
, &e
, proto
, inv
);
371 ret
= xt_check_match(&par
, size
, proto
, inv
);
377 module_put(match
->me
);
382 nft_match_destroy(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
)
384 struct xt_match
*match
= expr
->ops
->data
;
386 module_put(match
->me
);
390 match_dump_info(struct sk_buff
*skb
, const struct xt_match
*m
, const void *in
)
395 if (m
->compat_to_user
) {
399 out
= kmalloc(XT_ALIGN(m
->matchsize
), GFP_ATOMIC
);
403 /* We want to reuse existing compat_to_user */
406 m
->compat_to_user(out
, in
);
408 ret
= nla_put(skb
, NFTA_MATCH_INFO
, XT_ALIGN(m
->matchsize
), out
);
412 ret
= nla_put(skb
, NFTA_MATCH_INFO
, XT_ALIGN(m
->matchsize
), in
);
417 static inline int nft_compat_match_offset(struct xt_match
*match
)
420 return xt_compat_match_offset(match
);
426 static int nft_match_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
428 void *info
= nft_expr_priv(expr
);
429 struct xt_match
*match
= expr
->ops
->data
;
431 if (nla_put_string(skb
, NFTA_MATCH_NAME
, match
->name
) ||
432 nla_put_be32(skb
, NFTA_MATCH_REV
, htonl(match
->revision
)) ||
433 match_dump_info(skb
, match
, info
))
434 goto nla_put_failure
;
442 static int nft_match_validate(const struct nft_ctx
*ctx
,
443 const struct nft_expr
*expr
,
444 const struct nft_data
**data
)
446 struct xt_match
*match
= expr
->ops
->data
;
447 unsigned int hook_mask
= 0;
449 if (ctx
->chain
->flags
& NFT_BASE_CHAIN
) {
450 const struct nft_base_chain
*basechain
=
451 nft_base_chain(ctx
->chain
);
452 const struct nf_hook_ops
*ops
= &basechain
->ops
[0];
454 hook_mask
= 1 << ops
->hooknum
;
455 if (hook_mask
& match
->hooks
)
458 /* This match is being called from an invalid chain */
465 nfnl_compat_fill_info(struct sk_buff
*skb
, u32 portid
, u32 seq
, u32 type
,
466 int event
, u16 family
, const char *name
,
469 struct nlmsghdr
*nlh
;
470 struct nfgenmsg
*nfmsg
;
471 unsigned int flags
= portid
? NLM_F_MULTI
: 0;
473 event
|= NFNL_SUBSYS_NFT_COMPAT
<< 8;
474 nlh
= nlmsg_put(skb
, portid
, seq
, event
, sizeof(*nfmsg
), flags
);
478 nfmsg
= nlmsg_data(nlh
);
479 nfmsg
->nfgen_family
= family
;
480 nfmsg
->version
= NFNETLINK_V0
;
483 if (nla_put_string(skb
, NFTA_COMPAT_NAME
, name
) ||
484 nla_put_be32(skb
, NFTA_COMPAT_REV
, htonl(rev
)) ||
485 nla_put_be32(skb
, NFTA_COMPAT_TYPE
, htonl(target
)))
486 goto nla_put_failure
;
493 nlmsg_cancel(skb
, nlh
);
498 nfnl_compat_get(struct sock
*nfnl
, struct sk_buff
*skb
,
499 const struct nlmsghdr
*nlh
, const struct nlattr
* const tb
[])
502 struct nfgenmsg
*nfmsg
;
506 struct sk_buff
*skb2
;
508 if (tb
[NFTA_COMPAT_NAME
] == NULL
||
509 tb
[NFTA_COMPAT_REV
] == NULL
||
510 tb
[NFTA_COMPAT_TYPE
] == NULL
)
513 name
= nla_data(tb
[NFTA_COMPAT_NAME
]);
514 rev
= ntohl(nla_get_be32(tb
[NFTA_COMPAT_REV
]));
515 target
= ntohl(nla_get_be32(tb
[NFTA_COMPAT_TYPE
]));
517 nfmsg
= nlmsg_data(nlh
);
519 switch(nfmsg
->nfgen_family
) {
527 pr_err("nft_compat: unsupported protocol %d\n",
528 nfmsg
->nfgen_family
);
532 try_then_request_module(xt_find_revision(nfmsg
->nfgen_family
, name
,
539 skb2
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
543 /* include the best revision for this extension in the message */
544 if (nfnl_compat_fill_info(skb2
, NETLINK_CB(skb
).portid
,
546 NFNL_MSG_TYPE(nlh
->nlmsg_type
),
549 name
, ret
, target
) <= 0) {
554 ret
= netlink_unicast(nfnl
, skb2
, NETLINK_CB(skb
).portid
,
559 return ret
== -EAGAIN
? -ENOBUFS
: ret
;
562 static const struct nla_policy nfnl_compat_policy_get
[NFTA_COMPAT_MAX
+1] = {
563 [NFTA_COMPAT_NAME
] = { .type
= NLA_NUL_STRING
,
564 .len
= NFT_COMPAT_NAME_MAX
-1 },
565 [NFTA_COMPAT_REV
] = { .type
= NLA_U32
},
566 [NFTA_COMPAT_TYPE
] = { .type
= NLA_U32
},
569 static const struct nfnl_callback nfnl_nft_compat_cb
[NFNL_MSG_COMPAT_MAX
] = {
570 [NFNL_MSG_COMPAT_GET
] = { .call
= nfnl_compat_get
,
571 .attr_count
= NFTA_COMPAT_MAX
,
572 .policy
= nfnl_compat_policy_get
},
575 static const struct nfnetlink_subsystem nfnl_compat_subsys
= {
576 .name
= "nft-compat",
577 .subsys_id
= NFNL_SUBSYS_NFT_COMPAT
,
578 .cb_count
= NFNL_MSG_COMPAT_MAX
,
579 .cb
= nfnl_nft_compat_cb
,
582 static LIST_HEAD(nft_match_list
);
585 struct list_head head
;
586 struct nft_expr_ops ops
;
589 static struct nft_expr_type nft_match_type
;
591 static const struct nft_expr_ops
*
592 nft_match_select_ops(const struct nft_ctx
*ctx
,
593 const struct nlattr
* const tb
[])
595 struct nft_xt
*nft_match
;
596 struct xt_match
*match
;
600 if (tb
[NFTA_MATCH_NAME
] == NULL
||
601 tb
[NFTA_MATCH_REV
] == NULL
||
602 tb
[NFTA_MATCH_INFO
] == NULL
)
603 return ERR_PTR(-EINVAL
);
605 mt_name
= nla_data(tb
[NFTA_MATCH_NAME
]);
606 rev
= ntohl(nla_get_be32(tb
[NFTA_MATCH_REV
]));
607 family
= ctx
->afi
->family
;
609 /* Re-use the existing match if it's already loaded. */
610 list_for_each_entry(nft_match
, &nft_match_list
, head
) {
611 struct xt_match
*match
= nft_match
->ops
.data
;
613 if (strcmp(match
->name
, mt_name
) == 0 &&
614 match
->revision
== rev
&& match
->family
== family
)
615 return &nft_match
->ops
;
618 match
= xt_request_find_match(family
, mt_name
, rev
);
620 return ERR_PTR(-ENOENT
);
622 /* This is the first time we use this match, allocate operations */
623 nft_match
= kzalloc(sizeof(struct nft_xt
), GFP_KERNEL
);
624 if (nft_match
== NULL
)
625 return ERR_PTR(-ENOMEM
);
627 nft_match
->ops
.type
= &nft_match_type
;
628 nft_match
->ops
.size
= NFT_EXPR_SIZE(XT_ALIGN(match
->matchsize
) +
629 nft_compat_match_offset(match
));
630 nft_match
->ops
.eval
= nft_match_eval
;
631 nft_match
->ops
.init
= nft_match_init
;
632 nft_match
->ops
.destroy
= nft_match_destroy
;
633 nft_match
->ops
.dump
= nft_match_dump
;
634 nft_match
->ops
.validate
= nft_match_validate
;
635 nft_match
->ops
.data
= match
;
637 list_add(&nft_match
->head
, &nft_match_list
);
639 return &nft_match
->ops
;
642 static void nft_match_release(void)
644 struct nft_xt
*nft_match
, *tmp
;
646 list_for_each_entry_safe(nft_match
, tmp
, &nft_match_list
, head
)
650 static struct nft_expr_type nft_match_type __read_mostly
= {
652 .select_ops
= nft_match_select_ops
,
653 .policy
= nft_match_policy
,
654 .maxattr
= NFTA_MATCH_MAX
,
655 .owner
= THIS_MODULE
,
658 static LIST_HEAD(nft_target_list
);
660 static struct nft_expr_type nft_target_type
;
662 static const struct nft_expr_ops
*
663 nft_target_select_ops(const struct nft_ctx
*ctx
,
664 const struct nlattr
* const tb
[])
666 struct nft_xt
*nft_target
;
667 struct xt_target
*target
;
671 if (tb
[NFTA_TARGET_NAME
] == NULL
||
672 tb
[NFTA_TARGET_REV
] == NULL
||
673 tb
[NFTA_TARGET_INFO
] == NULL
)
674 return ERR_PTR(-EINVAL
);
676 tg_name
= nla_data(tb
[NFTA_TARGET_NAME
]);
677 rev
= ntohl(nla_get_be32(tb
[NFTA_TARGET_REV
]));
678 family
= ctx
->afi
->family
;
680 /* Re-use the existing target if it's already loaded. */
681 list_for_each_entry(nft_target
, &nft_match_list
, head
) {
682 struct xt_target
*target
= nft_target
->ops
.data
;
684 if (strcmp(target
->name
, tg_name
) == 0 &&
685 target
->revision
== rev
&& target
->family
== family
)
686 return &nft_target
->ops
;
689 target
= xt_request_find_target(family
, tg_name
, rev
);
691 return ERR_PTR(-ENOENT
);
693 /* This is the first time we use this target, allocate operations */
694 nft_target
= kzalloc(sizeof(struct nft_xt
), GFP_KERNEL
);
695 if (nft_target
== NULL
)
696 return ERR_PTR(-ENOMEM
);
698 nft_target
->ops
.type
= &nft_target_type
;
699 nft_target
->ops
.size
= NFT_EXPR_SIZE(XT_ALIGN(target
->targetsize
) +
700 nft_compat_target_offset(target
));
701 nft_target
->ops
.eval
= nft_target_eval
;
702 nft_target
->ops
.init
= nft_target_init
;
703 nft_target
->ops
.destroy
= nft_target_destroy
;
704 nft_target
->ops
.dump
= nft_target_dump
;
705 nft_target
->ops
.validate
= nft_target_validate
;
706 nft_target
->ops
.data
= target
;
708 list_add(&nft_target
->head
, &nft_target_list
);
710 return &nft_target
->ops
;
713 static void nft_target_release(void)
715 struct nft_xt
*nft_target
, *tmp
;
717 list_for_each_entry_safe(nft_target
, tmp
, &nft_target_list
, head
)
721 static struct nft_expr_type nft_target_type __read_mostly
= {
723 .select_ops
= nft_target_select_ops
,
724 .policy
= nft_target_policy
,
725 .maxattr
= NFTA_TARGET_MAX
,
726 .owner
= THIS_MODULE
,
729 static int __init
nft_compat_module_init(void)
733 ret
= nft_register_expr(&nft_match_type
);
737 ret
= nft_register_expr(&nft_target_type
);
741 ret
= nfnetlink_subsys_register(&nfnl_compat_subsys
);
743 pr_err("nft_compat: cannot register with nfnetlink.\n");
747 pr_info("nf_tables_compat: (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>\n");
752 nft_unregister_expr(&nft_target_type
);
754 nft_unregister_expr(&nft_match_type
);
758 static void __exit
nft_compat_module_exit(void)
760 nfnetlink_subsys_unregister(&nfnl_compat_subsys
);
761 nft_unregister_expr(&nft_target_type
);
762 nft_unregister_expr(&nft_match_type
);
764 nft_target_release();
767 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFT_COMPAT
);
769 module_init(nft_compat_module_init
);
770 module_exit(nft_compat_module_exit
);
772 MODULE_LICENSE("GPL");
773 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
774 MODULE_ALIAS_NFT_EXPR("match");
775 MODULE_ALIAS_NFT_EXPR("target");