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 <net/netfilter/nf_tables.h>
27 } table_to_chaintype
[] = {
28 { "filter", NFT_CHAIN_T_DEFAULT
},
29 { "raw", NFT_CHAIN_T_DEFAULT
},
30 { "security", NFT_CHAIN_T_DEFAULT
},
31 { "mangle", NFT_CHAIN_T_ROUTE
},
32 { "nat", NFT_CHAIN_T_NAT
},
36 static int nft_compat_table_to_chaintype(const char *table
)
40 for (i
= 0; table_to_chaintype
[i
].name
!= NULL
; i
++) {
41 if (strcmp(table_to_chaintype
[i
].name
, table
) == 0)
42 return table_to_chaintype
[i
].type
;
48 static int nft_compat_chain_validate_dependency(const char *tablename
,
49 const struct nft_chain
*chain
)
51 enum nft_chain_type type
;
52 const struct nft_base_chain
*basechain
;
54 if (!tablename
|| !(chain
->flags
& NFT_BASE_CHAIN
))
57 type
= nft_compat_table_to_chaintype(tablename
);
61 basechain
= nft_base_chain(chain
);
62 if (basechain
->type
->type
!= type
)
74 nft_compat_set_par(struct xt_action_param
*par
, void *xt
, const void *xt_info
)
77 par
->targinfo
= xt_info
;
81 static void nft_target_eval(const struct nft_expr
*expr
,
82 struct nft_data data
[NFT_REG_MAX
+ 1],
83 const struct nft_pktinfo
*pkt
)
85 void *info
= nft_expr_priv(expr
);
86 struct xt_target
*target
= expr
->ops
->data
;
87 struct sk_buff
*skb
= pkt
->skb
;
90 nft_compat_set_par((struct xt_action_param
*)&pkt
->xt
, target
, info
);
92 ret
= target
->target(skb
, &pkt
->xt
);
99 data
[NFT_REG_VERDICT
].verdict
= NFT_CONTINUE
;
102 data
[NFT_REG_VERDICT
].verdict
= ret
;
108 static const struct nla_policy nft_target_policy
[NFTA_TARGET_MAX
+ 1] = {
109 [NFTA_TARGET_NAME
] = { .type
= NLA_NUL_STRING
},
110 [NFTA_TARGET_REV
] = { .type
= NLA_U32
},
111 [NFTA_TARGET_INFO
] = { .type
= NLA_BINARY
},
115 nft_target_set_tgchk_param(struct xt_tgchk_param
*par
,
116 const struct nft_ctx
*ctx
,
117 struct xt_target
*target
, void *info
,
118 union nft_entry
*entry
, u8 proto
, bool inv
)
120 par
->net
= &init_net
;
121 par
->table
= ctx
->table
->name
;
122 switch (ctx
->afi
->family
) {
124 entry
->e4
.ip
.proto
= proto
;
125 entry
->e4
.ip
.invflags
= inv
? IPT_INV_PROTO
: 0;
128 entry
->e6
.ipv6
.proto
= proto
;
129 entry
->e6
.ipv6
.invflags
= inv
? IP6T_INV_PROTO
: 0;
132 par
->entryinfo
= entry
;
133 par
->target
= target
;
134 par
->targinfo
= info
;
135 if (ctx
->chain
->flags
& NFT_BASE_CHAIN
) {
136 const struct nft_base_chain
*basechain
=
137 nft_base_chain(ctx
->chain
);
138 const struct nf_hook_ops
*ops
= &basechain
->ops
[0];
140 par
->hook_mask
= 1 << ops
->hooknum
;
144 par
->family
= ctx
->afi
->family
;
147 static void target_compat_from_user(struct xt_target
*t
, void *in
, void *out
)
151 memcpy(out
, in
, t
->targetsize
);
152 pad
= XT_ALIGN(t
->targetsize
) - t
->targetsize
;
154 memset(out
+ t
->targetsize
, 0, pad
);
157 static const struct nla_policy nft_rule_compat_policy
[NFTA_RULE_COMPAT_MAX
+ 1] = {
158 [NFTA_RULE_COMPAT_PROTO
] = { .type
= NLA_U32
},
159 [NFTA_RULE_COMPAT_FLAGS
] = { .type
= NLA_U32
},
162 static int nft_parse_compat(const struct nlattr
*attr
, u8
*proto
, bool *inv
)
164 struct nlattr
*tb
[NFTA_RULE_COMPAT_MAX
+1];
168 err
= nla_parse_nested(tb
, NFTA_RULE_COMPAT_MAX
, attr
,
169 nft_rule_compat_policy
);
173 if (!tb
[NFTA_RULE_COMPAT_PROTO
] || !tb
[NFTA_RULE_COMPAT_FLAGS
])
176 flags
= ntohl(nla_get_be32(tb
[NFTA_RULE_COMPAT_FLAGS
]));
177 if (flags
& ~NFT_RULE_COMPAT_F_MASK
)
179 if (flags
& NFT_RULE_COMPAT_F_INV
)
182 *proto
= ntohl(nla_get_be32(tb
[NFTA_RULE_COMPAT_PROTO
]));
187 nft_target_init(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
,
188 const struct nlattr
* const tb
[])
190 void *info
= nft_expr_priv(expr
);
191 struct xt_target
*target
= expr
->ops
->data
;
192 struct xt_tgchk_param par
;
193 size_t size
= XT_ALIGN(nla_len(tb
[NFTA_TARGET_INFO
]));
196 union nft_entry e
= {};
199 ret
= nft_compat_chain_validate_dependency(target
->table
, ctx
->chain
);
203 target_compat_from_user(target
, nla_data(tb
[NFTA_TARGET_INFO
]), info
);
205 if (ctx
->nla
[NFTA_RULE_COMPAT
]) {
206 ret
= nft_parse_compat(ctx
->nla
[NFTA_RULE_COMPAT
], &proto
, &inv
);
211 nft_target_set_tgchk_param(&par
, ctx
, target
, info
, &e
, proto
, inv
);
213 ret
= xt_check_target(&par
, size
, proto
, inv
);
217 /* The standard target cannot be used */
218 if (target
->target
== NULL
) {
225 module_put(target
->me
);
230 nft_target_destroy(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
)
232 struct xt_target
*target
= expr
->ops
->data
;
233 void *info
= nft_expr_priv(expr
);
234 struct xt_tgdtor_param par
;
239 par
.family
= ctx
->afi
->family
;
240 if (par
.target
->destroy
!= NULL
)
241 par
.target
->destroy(&par
);
243 module_put(target
->me
);
246 static int nft_target_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
248 const struct xt_target
*target
= expr
->ops
->data
;
249 void *info
= nft_expr_priv(expr
);
251 if (nla_put_string(skb
, NFTA_TARGET_NAME
, target
->name
) ||
252 nla_put_be32(skb
, NFTA_TARGET_REV
, htonl(target
->revision
)) ||
253 nla_put(skb
, NFTA_TARGET_INFO
, XT_ALIGN(target
->targetsize
), info
))
254 goto nla_put_failure
;
262 static int nft_target_validate(const struct nft_ctx
*ctx
,
263 const struct nft_expr
*expr
,
264 const struct nft_data
**data
)
266 struct xt_target
*target
= expr
->ops
->data
;
267 unsigned int hook_mask
= 0;
270 if (ctx
->chain
->flags
& NFT_BASE_CHAIN
) {
271 const struct nft_base_chain
*basechain
=
272 nft_base_chain(ctx
->chain
);
273 const struct nf_hook_ops
*ops
= &basechain
->ops
[0];
275 hook_mask
= 1 << ops
->hooknum
;
276 if (!(hook_mask
& target
->hooks
))
279 ret
= nft_compat_chain_validate_dependency(target
->table
,
287 static void nft_match_eval(const struct nft_expr
*expr
,
288 struct nft_data data
[NFT_REG_MAX
+ 1],
289 const struct nft_pktinfo
*pkt
)
291 void *info
= nft_expr_priv(expr
);
292 struct xt_match
*match
= expr
->ops
->data
;
293 struct sk_buff
*skb
= pkt
->skb
;
296 nft_compat_set_par((struct xt_action_param
*)&pkt
->xt
, match
, info
);
298 ret
= match
->match(skb
, (struct xt_action_param
*)&pkt
->xt
);
300 if (pkt
->xt
.hotdrop
) {
301 data
[NFT_REG_VERDICT
].verdict
= NF_DROP
;
307 data
[NFT_REG_VERDICT
].verdict
= NFT_CONTINUE
;
310 data
[NFT_REG_VERDICT
].verdict
= NFT_BREAK
;
315 static const struct nla_policy nft_match_policy
[NFTA_MATCH_MAX
+ 1] = {
316 [NFTA_MATCH_NAME
] = { .type
= NLA_NUL_STRING
},
317 [NFTA_MATCH_REV
] = { .type
= NLA_U32
},
318 [NFTA_MATCH_INFO
] = { .type
= NLA_BINARY
},
321 /* struct xt_mtchk_param and xt_tgchk_param look very similar */
323 nft_match_set_mtchk_param(struct xt_mtchk_param
*par
, const struct nft_ctx
*ctx
,
324 struct xt_match
*match
, void *info
,
325 union nft_entry
*entry
, u8 proto
, bool inv
)
327 par
->net
= &init_net
;
328 par
->table
= ctx
->table
->name
;
329 switch (ctx
->afi
->family
) {
331 entry
->e4
.ip
.proto
= proto
;
332 entry
->e4
.ip
.invflags
= inv
? IPT_INV_PROTO
: 0;
335 entry
->e6
.ipv6
.proto
= proto
;
336 entry
->e6
.ipv6
.invflags
= inv
? IP6T_INV_PROTO
: 0;
339 par
->entryinfo
= entry
;
341 par
->matchinfo
= info
;
342 if (ctx
->chain
->flags
& NFT_BASE_CHAIN
) {
343 const struct nft_base_chain
*basechain
=
344 nft_base_chain(ctx
->chain
);
345 const struct nf_hook_ops
*ops
= &basechain
->ops
[0];
347 par
->hook_mask
= 1 << ops
->hooknum
;
351 par
->family
= ctx
->afi
->family
;
354 static void match_compat_from_user(struct xt_match
*m
, void *in
, void *out
)
358 memcpy(out
, in
, m
->matchsize
);
359 pad
= XT_ALIGN(m
->matchsize
) - m
->matchsize
;
361 memset(out
+ m
->matchsize
, 0, pad
);
365 nft_match_init(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
,
366 const struct nlattr
* const tb
[])
368 void *info
= nft_expr_priv(expr
);
369 struct xt_match
*match
= expr
->ops
->data
;
370 struct xt_mtchk_param par
;
371 size_t size
= XT_ALIGN(nla_len(tb
[NFTA_MATCH_INFO
]));
374 union nft_entry e
= {};
377 ret
= nft_compat_chain_validate_dependency(match
->name
, ctx
->chain
);
381 match_compat_from_user(match
, nla_data(tb
[NFTA_MATCH_INFO
]), info
);
383 if (ctx
->nla
[NFTA_RULE_COMPAT
]) {
384 ret
= nft_parse_compat(ctx
->nla
[NFTA_RULE_COMPAT
], &proto
, &inv
);
389 nft_match_set_mtchk_param(&par
, ctx
, match
, info
, &e
, proto
, inv
);
391 ret
= xt_check_match(&par
, size
, proto
, inv
);
397 module_put(match
->me
);
402 nft_match_destroy(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
)
404 struct xt_match
*match
= expr
->ops
->data
;
405 void *info
= nft_expr_priv(expr
);
406 struct xt_mtdtor_param par
;
410 par
.matchinfo
= info
;
411 par
.family
= ctx
->afi
->family
;
412 if (par
.match
->destroy
!= NULL
)
413 par
.match
->destroy(&par
);
415 module_put(match
->me
);
418 static int nft_match_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
420 void *info
= nft_expr_priv(expr
);
421 struct xt_match
*match
= expr
->ops
->data
;
423 if (nla_put_string(skb
, NFTA_MATCH_NAME
, match
->name
) ||
424 nla_put_be32(skb
, NFTA_MATCH_REV
, htonl(match
->revision
)) ||
425 nla_put(skb
, NFTA_MATCH_INFO
, XT_ALIGN(match
->matchsize
), info
))
426 goto nla_put_failure
;
434 static int nft_match_validate(const struct nft_ctx
*ctx
,
435 const struct nft_expr
*expr
,
436 const struct nft_data
**data
)
438 struct xt_match
*match
= expr
->ops
->data
;
439 unsigned int hook_mask
= 0;
442 if (ctx
->chain
->flags
& NFT_BASE_CHAIN
) {
443 const struct nft_base_chain
*basechain
=
444 nft_base_chain(ctx
->chain
);
445 const struct nf_hook_ops
*ops
= &basechain
->ops
[0];
447 hook_mask
= 1 << ops
->hooknum
;
448 if (!(hook_mask
& match
->hooks
))
451 ret
= nft_compat_chain_validate_dependency(match
->name
,
460 nfnl_compat_fill_info(struct sk_buff
*skb
, u32 portid
, u32 seq
, u32 type
,
461 int event
, u16 family
, const char *name
,
464 struct nlmsghdr
*nlh
;
465 struct nfgenmsg
*nfmsg
;
466 unsigned int flags
= portid
? NLM_F_MULTI
: 0;
468 event
|= NFNL_SUBSYS_NFT_COMPAT
<< 8;
469 nlh
= nlmsg_put(skb
, portid
, seq
, event
, sizeof(*nfmsg
), flags
);
473 nfmsg
= nlmsg_data(nlh
);
474 nfmsg
->nfgen_family
= family
;
475 nfmsg
->version
= NFNETLINK_V0
;
478 if (nla_put_string(skb
, NFTA_COMPAT_NAME
, name
) ||
479 nla_put_be32(skb
, NFTA_COMPAT_REV
, htonl(rev
)) ||
480 nla_put_be32(skb
, NFTA_COMPAT_TYPE
, htonl(target
)))
481 goto nla_put_failure
;
488 nlmsg_cancel(skb
, nlh
);
493 nfnl_compat_get(struct sock
*nfnl
, struct sk_buff
*skb
,
494 const struct nlmsghdr
*nlh
, const struct nlattr
* const tb
[])
497 struct nfgenmsg
*nfmsg
;
501 struct sk_buff
*skb2
;
503 if (tb
[NFTA_COMPAT_NAME
] == NULL
||
504 tb
[NFTA_COMPAT_REV
] == NULL
||
505 tb
[NFTA_COMPAT_TYPE
] == NULL
)
508 name
= nla_data(tb
[NFTA_COMPAT_NAME
]);
509 rev
= ntohl(nla_get_be32(tb
[NFTA_COMPAT_REV
]));
510 target
= ntohl(nla_get_be32(tb
[NFTA_COMPAT_TYPE
]));
512 nfmsg
= nlmsg_data(nlh
);
514 switch(nfmsg
->nfgen_family
) {
522 pr_err("nft_compat: unsupported protocol %d\n",
523 nfmsg
->nfgen_family
);
527 try_then_request_module(xt_find_revision(nfmsg
->nfgen_family
, name
,
534 skb2
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
538 /* include the best revision for this extension in the message */
539 if (nfnl_compat_fill_info(skb2
, NETLINK_CB(skb
).portid
,
541 NFNL_MSG_TYPE(nlh
->nlmsg_type
),
544 name
, ret
, target
) <= 0) {
549 ret
= netlink_unicast(nfnl
, skb2
, NETLINK_CB(skb
).portid
,
554 return ret
== -EAGAIN
? -ENOBUFS
: ret
;
557 static const struct nla_policy nfnl_compat_policy_get
[NFTA_COMPAT_MAX
+1] = {
558 [NFTA_COMPAT_NAME
] = { .type
= NLA_NUL_STRING
,
559 .len
= NFT_COMPAT_NAME_MAX
-1 },
560 [NFTA_COMPAT_REV
] = { .type
= NLA_U32
},
561 [NFTA_COMPAT_TYPE
] = { .type
= NLA_U32
},
564 static const struct nfnl_callback nfnl_nft_compat_cb
[NFNL_MSG_COMPAT_MAX
] = {
565 [NFNL_MSG_COMPAT_GET
] = { .call
= nfnl_compat_get
,
566 .attr_count
= NFTA_COMPAT_MAX
,
567 .policy
= nfnl_compat_policy_get
},
570 static const struct nfnetlink_subsystem nfnl_compat_subsys
= {
571 .name
= "nft-compat",
572 .subsys_id
= NFNL_SUBSYS_NFT_COMPAT
,
573 .cb_count
= NFNL_MSG_COMPAT_MAX
,
574 .cb
= nfnl_nft_compat_cb
,
577 static LIST_HEAD(nft_match_list
);
580 struct list_head head
;
581 struct nft_expr_ops ops
;
584 static struct nft_expr_type nft_match_type
;
586 static const struct nft_expr_ops
*
587 nft_match_select_ops(const struct nft_ctx
*ctx
,
588 const struct nlattr
* const tb
[])
590 struct nft_xt
*nft_match
;
591 struct xt_match
*match
;
595 if (tb
[NFTA_MATCH_NAME
] == NULL
||
596 tb
[NFTA_MATCH_REV
] == NULL
||
597 tb
[NFTA_MATCH_INFO
] == NULL
)
598 return ERR_PTR(-EINVAL
);
600 mt_name
= nla_data(tb
[NFTA_MATCH_NAME
]);
601 rev
= ntohl(nla_get_be32(tb
[NFTA_MATCH_REV
]));
602 family
= ctx
->afi
->family
;
604 /* Re-use the existing match if it's already loaded. */
605 list_for_each_entry(nft_match
, &nft_match_list
, head
) {
606 struct xt_match
*match
= nft_match
->ops
.data
;
608 if (strcmp(match
->name
, mt_name
) == 0 &&
609 match
->revision
== rev
&& match
->family
== family
)
610 return &nft_match
->ops
;
613 match
= xt_request_find_match(family
, mt_name
, rev
);
615 return ERR_PTR(-ENOENT
);
617 /* This is the first time we use this match, allocate operations */
618 nft_match
= kzalloc(sizeof(struct nft_xt
), GFP_KERNEL
);
619 if (nft_match
== NULL
)
620 return ERR_PTR(-ENOMEM
);
622 nft_match
->ops
.type
= &nft_match_type
;
623 nft_match
->ops
.size
= NFT_EXPR_SIZE(XT_ALIGN(match
->matchsize
));
624 nft_match
->ops
.eval
= nft_match_eval
;
625 nft_match
->ops
.init
= nft_match_init
;
626 nft_match
->ops
.destroy
= nft_match_destroy
;
627 nft_match
->ops
.dump
= nft_match_dump
;
628 nft_match
->ops
.validate
= nft_match_validate
;
629 nft_match
->ops
.data
= match
;
631 list_add(&nft_match
->head
, &nft_match_list
);
633 return &nft_match
->ops
;
636 static void nft_match_release(void)
638 struct nft_xt
*nft_match
, *tmp
;
640 list_for_each_entry_safe(nft_match
, tmp
, &nft_match_list
, head
)
644 static struct nft_expr_type nft_match_type __read_mostly
= {
646 .select_ops
= nft_match_select_ops
,
647 .policy
= nft_match_policy
,
648 .maxattr
= NFTA_MATCH_MAX
,
649 .owner
= THIS_MODULE
,
652 static LIST_HEAD(nft_target_list
);
654 static struct nft_expr_type nft_target_type
;
656 static const struct nft_expr_ops
*
657 nft_target_select_ops(const struct nft_ctx
*ctx
,
658 const struct nlattr
* const tb
[])
660 struct nft_xt
*nft_target
;
661 struct xt_target
*target
;
665 if (tb
[NFTA_TARGET_NAME
] == NULL
||
666 tb
[NFTA_TARGET_REV
] == NULL
||
667 tb
[NFTA_TARGET_INFO
] == NULL
)
668 return ERR_PTR(-EINVAL
);
670 tg_name
= nla_data(tb
[NFTA_TARGET_NAME
]);
671 rev
= ntohl(nla_get_be32(tb
[NFTA_TARGET_REV
]));
672 family
= ctx
->afi
->family
;
674 /* Re-use the existing target if it's already loaded. */
675 list_for_each_entry(nft_target
, &nft_target_list
, head
) {
676 struct xt_target
*target
= nft_target
->ops
.data
;
678 if (strcmp(target
->name
, tg_name
) == 0 &&
679 target
->revision
== rev
&& target
->family
== family
)
680 return &nft_target
->ops
;
683 target
= xt_request_find_target(family
, tg_name
, rev
);
685 return ERR_PTR(-ENOENT
);
687 /* This is the first time we use this target, allocate operations */
688 nft_target
= kzalloc(sizeof(struct nft_xt
), GFP_KERNEL
);
689 if (nft_target
== NULL
)
690 return ERR_PTR(-ENOMEM
);
692 nft_target
->ops
.type
= &nft_target_type
;
693 nft_target
->ops
.size
= NFT_EXPR_SIZE(XT_ALIGN(target
->targetsize
));
694 nft_target
->ops
.eval
= nft_target_eval
;
695 nft_target
->ops
.init
= nft_target_init
;
696 nft_target
->ops
.destroy
= nft_target_destroy
;
697 nft_target
->ops
.dump
= nft_target_dump
;
698 nft_target
->ops
.validate
= nft_target_validate
;
699 nft_target
->ops
.data
= target
;
701 list_add(&nft_target
->head
, &nft_target_list
);
703 return &nft_target
->ops
;
706 static void nft_target_release(void)
708 struct nft_xt
*nft_target
, *tmp
;
710 list_for_each_entry_safe(nft_target
, tmp
, &nft_target_list
, head
)
714 static struct nft_expr_type nft_target_type __read_mostly
= {
716 .select_ops
= nft_target_select_ops
,
717 .policy
= nft_target_policy
,
718 .maxattr
= NFTA_TARGET_MAX
,
719 .owner
= THIS_MODULE
,
722 static int __init
nft_compat_module_init(void)
726 ret
= nft_register_expr(&nft_match_type
);
730 ret
= nft_register_expr(&nft_target_type
);
734 ret
= nfnetlink_subsys_register(&nfnl_compat_subsys
);
736 pr_err("nft_compat: cannot register with nfnetlink.\n");
740 pr_info("nf_tables_compat: (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>\n");
745 nft_unregister_expr(&nft_target_type
);
747 nft_unregister_expr(&nft_match_type
);
751 static void __exit
nft_compat_module_exit(void)
753 nfnetlink_subsys_unregister(&nfnl_compat_subsys
);
754 nft_unregister_expr(&nft_target_type
);
755 nft_unregister_expr(&nft_match_type
);
757 nft_target_release();
760 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFT_COMPAT
);
762 module_init(nft_compat_module_init
);
763 module_exit(nft_compat_module_exit
);
765 MODULE_LICENSE("GPL");
766 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
767 MODULE_ALIAS_NFT_EXPR("match");
768 MODULE_ALIAS_NFT_EXPR("target");