2 * net/sched/em_ipt.c IPtables matches Ematch
4 * (c) 2018 Eyal Birger <eyal.birger@gmail.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
12 #include <linux/gfp.h>
13 #include <linux/module.h>
14 #include <linux/types.h>
15 #include <linux/kernel.h>
16 #include <linux/string.h>
17 #include <linux/skbuff.h>
18 #include <linux/tc_ematch/tc_em_ipt.h>
19 #include <linux/netfilter.h>
20 #include <linux/netfilter/x_tables.h>
21 #include <linux/netfilter_ipv4/ip_tables.h>
22 #include <linux/netfilter_ipv6/ip6_tables.h>
23 #include <net/pkt_cls.h>
26 const struct xt_match
*match
;
28 u8 match_data
[0] __aligned(8);
31 struct em_ipt_xt_match
{
33 int (*validate_match_data
)(struct nlattr
**tb
, u8 mrev
);
36 static const struct nla_policy em_ipt_policy
[TCA_EM_IPT_MAX
+ 1] = {
37 [TCA_EM_IPT_MATCH_NAME
] = { .type
= NLA_STRING
,
38 .len
= XT_EXTENSION_MAXNAMELEN
},
39 [TCA_EM_IPT_MATCH_REVISION
] = { .type
= NLA_U8
},
40 [TCA_EM_IPT_HOOK
] = { .type
= NLA_U32
},
41 [TCA_EM_IPT_NFPROTO
] = { .type
= NLA_U8
},
42 [TCA_EM_IPT_MATCH_DATA
] = { .type
= NLA_UNSPEC
},
45 static int check_match(struct net
*net
, struct em_ipt_match
*im
, int mdata_len
)
47 struct xt_mtchk_param mtpar
= {};
54 mtpar
.table
= "filter";
55 mtpar
.hook_mask
= 1 << im
->hook
;
56 mtpar
.family
= im
->match
->family
;
57 mtpar
.match
= im
->match
;
59 mtpar
.matchinfo
= (void *)im
->match_data
;
60 return xt_check_match(&mtpar
, mdata_len
, 0, 0);
63 static int policy_validate_match_data(struct nlattr
**tb
, u8 mrev
)
66 pr_err("only policy match revision 0 supported");
70 if (nla_get_u32(tb
[TCA_EM_IPT_HOOK
]) != NF_INET_PRE_ROUTING
) {
71 pr_err("policy can only be matched on NF_INET_PRE_ROUTING");
78 static const struct em_ipt_xt_match em_ipt_xt_matches
[] = {
80 .match_name
= "policy",
81 .validate_match_data
= policy_validate_match_data
86 static struct xt_match
*get_xt_match(struct nlattr
**tb
)
88 const struct em_ipt_xt_match
*m
;
89 struct nlattr
*mname_attr
;
93 mname_attr
= tb
[TCA_EM_IPT_MATCH_NAME
];
94 for (m
= em_ipt_xt_matches
; m
->match_name
; m
++) {
95 if (!nla_strcmp(mname_attr
, m
->match_name
))
100 pr_err("Unsupported xt match");
101 return ERR_PTR(-EINVAL
);
104 if (tb
[TCA_EM_IPT_MATCH_REVISION
])
105 mrev
= nla_get_u8(tb
[TCA_EM_IPT_MATCH_REVISION
]);
107 ret
= m
->validate_match_data(tb
, mrev
);
111 nfproto
= nla_get_u8(tb
[TCA_EM_IPT_NFPROTO
]);
112 return xt_request_find_match(nfproto
, m
->match_name
, mrev
);
115 static int em_ipt_change(struct net
*net
, void *data
, int data_len
,
116 struct tcf_ematch
*em
)
118 struct nlattr
*tb
[TCA_EM_IPT_MAX
+ 1];
119 struct em_ipt_match
*im
= NULL
;
120 struct xt_match
*match
;
123 ret
= nla_parse(tb
, TCA_EM_IPT_MAX
, data
, data_len
, em_ipt_policy
,
128 if (!tb
[TCA_EM_IPT_HOOK
] || !tb
[TCA_EM_IPT_MATCH_NAME
] ||
129 !tb
[TCA_EM_IPT_MATCH_DATA
] || !tb
[TCA_EM_IPT_NFPROTO
])
132 match
= get_xt_match(tb
);
134 pr_err("unable to load match\n");
135 return PTR_ERR(match
);
138 mdata_len
= XT_ALIGN(nla_len(tb
[TCA_EM_IPT_MATCH_DATA
]));
139 im
= kzalloc(sizeof(*im
) + mdata_len
, GFP_KERNEL
);
146 im
->hook
= nla_get_u32(tb
[TCA_EM_IPT_HOOK
]);
147 nla_memcpy(im
->match_data
, tb
[TCA_EM_IPT_MATCH_DATA
], mdata_len
);
149 ret
= check_match(net
, im
, mdata_len
);
153 em
->datalen
= sizeof(*im
) + mdata_len
;
154 em
->data
= (unsigned long)im
;
159 module_put(match
->me
);
163 static void em_ipt_destroy(struct tcf_ematch
*em
)
165 struct em_ipt_match
*im
= (void *)em
->data
;
170 if (im
->match
->destroy
) {
171 struct xt_mtdtor_param par
= {
174 .matchinfo
= im
->match_data
,
175 .family
= im
->match
->family
177 im
->match
->destroy(&par
);
179 module_put(im
->match
->me
);
183 static int em_ipt_match(struct sk_buff
*skb
, struct tcf_ematch
*em
,
184 struct tcf_pkt_info
*info
)
186 const struct em_ipt_match
*im
= (const void *)em
->data
;
187 struct xt_action_param acpar
= {};
188 struct net_device
*indev
= NULL
;
189 struct nf_hook_state state
;
195 indev
= dev_get_by_index_rcu(em
->net
, skb
->skb_iif
);
197 nf_hook_state_init(&state
, im
->hook
, im
->match
->family
,
198 indev
?: skb
->dev
, skb
->dev
, NULL
, em
->net
, NULL
);
200 acpar
.match
= im
->match
;
201 acpar
.matchinfo
= im
->match_data
;
202 acpar
.state
= &state
;
204 ret
= im
->match
->match(skb
, &acpar
);
210 static int em_ipt_dump(struct sk_buff
*skb
, struct tcf_ematch
*em
)
212 struct em_ipt_match
*im
= (void *)em
->data
;
214 if (nla_put_string(skb
, TCA_EM_IPT_MATCH_NAME
, im
->match
->name
) < 0)
216 if (nla_put_u32(skb
, TCA_EM_IPT_HOOK
, im
->hook
) < 0)
218 if (nla_put_u8(skb
, TCA_EM_IPT_MATCH_REVISION
, im
->match
->revision
) < 0)
220 if (nla_put_u8(skb
, TCA_EM_IPT_NFPROTO
, im
->match
->family
) < 0)
222 if (nla_put(skb
, TCA_EM_IPT_MATCH_DATA
,
223 im
->match
->usersize
?: im
->match
->matchsize
,
230 static struct tcf_ematch_ops em_ipt_ops
= {
232 .change
= em_ipt_change
,
233 .destroy
= em_ipt_destroy
,
234 .match
= em_ipt_match
,
236 .owner
= THIS_MODULE
,
237 .link
= LIST_HEAD_INIT(em_ipt_ops
.link
)
240 static int __init
init_em_ipt(void)
242 return tcf_em_register(&em_ipt_ops
);
245 static void __exit
exit_em_ipt(void)
247 tcf_em_unregister(&em_ipt_ops
);
250 MODULE_LICENSE("GPL");
251 MODULE_AUTHOR("Eyal Birger <eyal.birger@gmail.com>");
252 MODULE_DESCRIPTION("TC extended match for IPtables matches");
254 module_init(init_em_ipt
);
255 module_exit(exit_em_ipt
);
257 MODULE_ALIAS_TCF_EMATCH(TCF_EM_IPT
);