.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * net/sched/em_ipt.c IPtables matches Ematch |
---|
3 | 4 | * |
---|
4 | 5 | * (c) 2018 Eyal Birger <eyal.birger@gmail.com> |
---|
5 | | - * |
---|
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. |
---|
10 | 6 | */ |
---|
11 | 7 | |
---|
12 | 8 | #include <linux/gfp.h> |
---|
.. | .. |
---|
25 | 21 | struct em_ipt_match { |
---|
26 | 22 | const struct xt_match *match; |
---|
27 | 23 | u32 hook; |
---|
28 | | - u8 match_data[0] __aligned(8); |
---|
| 24 | + u8 nfproto; |
---|
| 25 | + u8 match_data[] __aligned(8); |
---|
29 | 26 | }; |
---|
30 | 27 | |
---|
31 | 28 | struct em_ipt_xt_match { |
---|
.. | .. |
---|
75 | 72 | return 0; |
---|
76 | 73 | } |
---|
77 | 74 | |
---|
| 75 | +static int addrtype_validate_match_data(struct nlattr **tb, u8 mrev) |
---|
| 76 | +{ |
---|
| 77 | + if (mrev != 1) { |
---|
| 78 | + pr_err("only addrtype match revision 1 supported"); |
---|
| 79 | + return -EINVAL; |
---|
| 80 | + } |
---|
| 81 | + |
---|
| 82 | + return 0; |
---|
| 83 | +} |
---|
| 84 | + |
---|
78 | 85 | static const struct em_ipt_xt_match em_ipt_xt_matches[] = { |
---|
79 | 86 | { |
---|
80 | 87 | .match_name = "policy", |
---|
81 | 88 | .validate_match_data = policy_validate_match_data |
---|
| 89 | + }, |
---|
| 90 | + { |
---|
| 91 | + .match_name = "addrtype", |
---|
| 92 | + .validate_match_data = addrtype_validate_match_data |
---|
82 | 93 | }, |
---|
83 | 94 | {} |
---|
84 | 95 | }; |
---|
.. | .. |
---|
119 | 130 | struct em_ipt_match *im = NULL; |
---|
120 | 131 | struct xt_match *match; |
---|
121 | 132 | int mdata_len, ret; |
---|
| 133 | + u8 nfproto; |
---|
122 | 134 | |
---|
123 | | - ret = nla_parse(tb, TCA_EM_IPT_MAX, data, data_len, em_ipt_policy, |
---|
124 | | - NULL); |
---|
| 135 | + ret = nla_parse_deprecated(tb, TCA_EM_IPT_MAX, data, data_len, |
---|
| 136 | + em_ipt_policy, NULL); |
---|
125 | 137 | if (ret < 0) |
---|
126 | 138 | return ret; |
---|
127 | 139 | |
---|
128 | 140 | if (!tb[TCA_EM_IPT_HOOK] || !tb[TCA_EM_IPT_MATCH_NAME] || |
---|
129 | 141 | !tb[TCA_EM_IPT_MATCH_DATA] || !tb[TCA_EM_IPT_NFPROTO]) |
---|
130 | 142 | return -EINVAL; |
---|
| 143 | + |
---|
| 144 | + nfproto = nla_get_u8(tb[TCA_EM_IPT_NFPROTO]); |
---|
| 145 | + switch (nfproto) { |
---|
| 146 | + case NFPROTO_IPV4: |
---|
| 147 | + case NFPROTO_IPV6: |
---|
| 148 | + break; |
---|
| 149 | + default: |
---|
| 150 | + return -EINVAL; |
---|
| 151 | + } |
---|
131 | 152 | |
---|
132 | 153 | match = get_xt_match(tb); |
---|
133 | 154 | if (IS_ERR(match)) { |
---|
.. | .. |
---|
144 | 165 | |
---|
145 | 166 | im->match = match; |
---|
146 | 167 | im->hook = nla_get_u32(tb[TCA_EM_IPT_HOOK]); |
---|
| 168 | + im->nfproto = nfproto; |
---|
147 | 169 | nla_memcpy(im->match_data, tb[TCA_EM_IPT_MATCH_DATA], mdata_len); |
---|
148 | 170 | |
---|
149 | 171 | ret = check_match(net, im, mdata_len); |
---|
.. | .. |
---|
177 | 199 | im->match->destroy(&par); |
---|
178 | 200 | } |
---|
179 | 201 | module_put(im->match->me); |
---|
180 | | - kfree((void *)im); |
---|
| 202 | + kfree(im); |
---|
181 | 203 | } |
---|
182 | 204 | |
---|
183 | 205 | static int em_ipt_match(struct sk_buff *skb, struct tcf_ematch *em, |
---|
.. | .. |
---|
186 | 208 | const struct em_ipt_match *im = (const void *)em->data; |
---|
187 | 209 | struct xt_action_param acpar = {}; |
---|
188 | 210 | struct net_device *indev = NULL; |
---|
| 211 | + u8 nfproto = im->match->family; |
---|
189 | 212 | struct nf_hook_state state; |
---|
190 | 213 | int ret; |
---|
| 214 | + |
---|
| 215 | + switch (skb_protocol(skb, true)) { |
---|
| 216 | + case htons(ETH_P_IP): |
---|
| 217 | + if (!pskb_network_may_pull(skb, sizeof(struct iphdr))) |
---|
| 218 | + return 0; |
---|
| 219 | + if (nfproto == NFPROTO_UNSPEC) |
---|
| 220 | + nfproto = NFPROTO_IPV4; |
---|
| 221 | + break; |
---|
| 222 | + case htons(ETH_P_IPV6): |
---|
| 223 | + if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr))) |
---|
| 224 | + return 0; |
---|
| 225 | + if (nfproto == NFPROTO_UNSPEC) |
---|
| 226 | + nfproto = NFPROTO_IPV6; |
---|
| 227 | + break; |
---|
| 228 | + default: |
---|
| 229 | + return 0; |
---|
| 230 | + } |
---|
191 | 231 | |
---|
192 | 232 | rcu_read_lock(); |
---|
193 | 233 | |
---|
194 | 234 | if (skb->skb_iif) |
---|
195 | 235 | indev = dev_get_by_index_rcu(em->net, skb->skb_iif); |
---|
196 | 236 | |
---|
197 | | - nf_hook_state_init(&state, im->hook, im->match->family, |
---|
| 237 | + nf_hook_state_init(&state, im->hook, nfproto, |
---|
198 | 238 | indev ?: skb->dev, skb->dev, NULL, em->net, NULL); |
---|
199 | 239 | |
---|
200 | 240 | acpar.match = im->match; |
---|
.. | .. |
---|
217 | 257 | return -EMSGSIZE; |
---|
218 | 258 | if (nla_put_u8(skb, TCA_EM_IPT_MATCH_REVISION, im->match->revision) < 0) |
---|
219 | 259 | return -EMSGSIZE; |
---|
220 | | - if (nla_put_u8(skb, TCA_EM_IPT_NFPROTO, im->match->family) < 0) |
---|
| 260 | + if (nla_put_u8(skb, TCA_EM_IPT_NFPROTO, im->nfproto) < 0) |
---|
221 | 261 | return -EMSGSIZE; |
---|
222 | 262 | if (nla_put(skb, TCA_EM_IPT_MATCH_DATA, |
---|
223 | 263 | im->match->usersize ?: im->match->matchsize, |
---|