Blame view
net/netfilter/nft_compat.c
22 KB
d2912cb15 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
0ca743a55 netfilter: nf_tab... |
2 3 4 |
/* * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org> * |
0ca743a55 netfilter: nf_tab... |
5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
* This software has been sponsored by Sophos Astaro <http://www.sophos.com> */ #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> #include <linux/netlink.h> #include <linux/netfilter.h> #include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nf_tables.h> #include <linux/netfilter/nf_tables_compat.h> #include <linux/netfilter/x_tables.h> #include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv6/ip6_tables.h> |
5191f4d82 netfilter: nft_co... |
19 |
#include <linux/netfilter_bridge/ebtables.h> |
5f1589394 netfilter: nft_co... |
20 |
#include <linux/netfilter_arp/arp_tables.h> |
0ca743a55 netfilter: nf_tab... |
21 |
#include <net/netfilter/nf_tables.h> |
4b512e1c1 netfilter: nft_co... |
22 |
|
732a8049f netfilter: nft_co... |
23 24 25 26 27 28 |
/* Used for matches where *info is larger than X byte */ #define NFT_MATCH_LARGE_THRESH 192 struct nft_xt_match_priv { void *info; }; |
e4844c9c6 netfilter: nft_co... |
29 30 |
static int nft_compat_chain_validate_dependency(const struct nft_ctx *ctx, const char *tablename) |
f3f5ddedd netfilter: nft_co... |
31 |
{ |
e4844c9c6 netfilter: nft_co... |
32 33 |
enum nft_chain_types type = NFT_CHAIN_T_DEFAULT; const struct nft_chain *chain = ctx->chain; |
f3f5ddedd netfilter: nft_co... |
34 |
const struct nft_base_chain *basechain; |
f323d9546 netfilter: nf_tab... |
35 36 |
if (!tablename || !nft_is_base_chain(chain)) |
f3f5ddedd netfilter: nft_co... |
37 |
return 0; |
f3f5ddedd netfilter: nft_co... |
38 |
basechain = nft_base_chain(chain); |
e4844c9c6 netfilter: nft_co... |
39 40 41 42 43 44 |
if (strcmp(tablename, "nat") == 0) { if (ctx->family != NFPROTO_BRIDGE) type = NFT_CHAIN_T_NAT; if (basechain->type->type != type) return -EINVAL; } |
f3f5ddedd netfilter: nft_co... |
45 46 47 |
return 0; } |
0ca743a55 netfilter: nf_tab... |
48 49 50 |
union nft_entry { struct ipt_entry e4; struct ip6t_entry e6; |
5191f4d82 netfilter: nft_co... |
51 |
struct ebt_entry ebt; |
5f1589394 netfilter: nft_co... |
52 |
struct arpt_entry arp; |
0ca743a55 netfilter: nf_tab... |
53 54 55 56 57 58 59 60 61 |
}; static inline void nft_compat_set_par(struct xt_action_param *par, void *xt, const void *xt_info) { par->target = xt; par->targinfo = xt_info; par->hotdrop = false; } |
5191f4d82 netfilter: nft_co... |
62 |
static void nft_target_eval_xt(const struct nft_expr *expr, |
a55e22e92 netfilter: nf_tab... |
63 |
struct nft_regs *regs, |
5191f4d82 netfilter: nft_co... |
64 |
const struct nft_pktinfo *pkt) |
0ca743a55 netfilter: nf_tab... |
65 66 67 68 69 70 71 72 73 74 75 76 |
{ void *info = nft_expr_priv(expr); struct xt_target *target = expr->ops->data; struct sk_buff *skb = pkt->skb; int ret; nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info); ret = target->target(skb, &pkt->xt); if (pkt->xt.hotdrop) ret = NF_DROP; |
5191f4d82 netfilter: nft_co... |
77 |
switch (ret) { |
0ca743a55 netfilter: nf_tab... |
78 |
case XT_CONTINUE: |
a55e22e92 netfilter: nf_tab... |
79 |
regs->verdict.code = NFT_CONTINUE; |
0ca743a55 netfilter: nf_tab... |
80 81 |
break; default: |
a55e22e92 netfilter: nf_tab... |
82 |
regs->verdict.code = ret; |
0ca743a55 netfilter: nf_tab... |
83 84 |
break; } |
5191f4d82 netfilter: nft_co... |
85 86 87 |
} static void nft_target_eval_bridge(const struct nft_expr *expr, |
a55e22e92 netfilter: nf_tab... |
88 |
struct nft_regs *regs, |
5191f4d82 netfilter: nft_co... |
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
const struct nft_pktinfo *pkt) { void *info = nft_expr_priv(expr); struct xt_target *target = expr->ops->data; struct sk_buff *skb = pkt->skb; int ret; nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info); ret = target->target(skb, &pkt->xt); if (pkt->xt.hotdrop) ret = NF_DROP; switch (ret) { case EBT_ACCEPT: |
a55e22e92 netfilter: nf_tab... |
105 |
regs->verdict.code = NF_ACCEPT; |
5191f4d82 netfilter: nft_co... |
106 107 |
break; case EBT_DROP: |
a55e22e92 netfilter: nf_tab... |
108 |
regs->verdict.code = NF_DROP; |
5191f4d82 netfilter: nft_co... |
109 110 |
break; case EBT_CONTINUE: |
a55e22e92 netfilter: nf_tab... |
111 |
regs->verdict.code = NFT_CONTINUE; |
5191f4d82 netfilter: nft_co... |
112 113 |
break; case EBT_RETURN: |
a55e22e92 netfilter: nf_tab... |
114 |
regs->verdict.code = NFT_RETURN; |
5191f4d82 netfilter: nft_co... |
115 116 |
break; default: |
a55e22e92 netfilter: nf_tab... |
117 |
regs->verdict.code = ret; |
5191f4d82 netfilter: nft_co... |
118 119 |
break; } |
0ca743a55 netfilter: nf_tab... |
120 121 122 123 124 125 126 127 128 129 130 131 |
} static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = { [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING }, [NFTA_TARGET_REV] = { .type = NLA_U32 }, [NFTA_TARGET_INFO] = { .type = NLA_BINARY }, }; static void nft_target_set_tgchk_param(struct xt_tgchk_param *par, const struct nft_ctx *ctx, struct xt_target *target, void *info, |
2156d321b netfilter: nft_co... |
132 |
union nft_entry *entry, u16 proto, bool inv) |
0ca743a55 netfilter: nf_tab... |
133 |
{ |
2daf1b4d1 netfilter: nft_co... |
134 |
par->net = ctx->net; |
0ca743a55 netfilter: nf_tab... |
135 |
par->table = ctx->table->name; |
36596dadf netfilter: nf_tab... |
136 |
switch (ctx->family) { |
0ca743a55 netfilter: nf_tab... |
137 138 139 140 141 |
case AF_INET: entry->e4.ip.proto = proto; entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0; break; case AF_INET6: |
749177ccc netfilter: nft_co... |
142 143 |
if (proto) entry->e6.ipv6.flags |= IP6T_F_PROTO; |
0ca743a55 netfilter: nf_tab... |
144 145 146 |
entry->e6.ipv6.proto = proto; entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0; break; |
5191f4d82 netfilter: nft_co... |
147 |
case NFPROTO_BRIDGE: |
2156d321b netfilter: nft_co... |
148 |
entry->ebt.ethproto = (__force __be16)proto; |
5191f4d82 netfilter: nft_co... |
149 150 |
entry->ebt.invflags = inv ? EBT_IPROTO : 0; break; |
5f1589394 netfilter: nft_co... |
151 152 |
case NFPROTO_ARP: break; |
0ca743a55 netfilter: nf_tab... |
153 154 155 156 |
} par->entryinfo = entry; par->target = target; par->targinfo = info; |
f323d9546 netfilter: nf_tab... |
157 |
if (nft_is_base_chain(ctx->chain)) { |
0ca743a55 netfilter: nf_tab... |
158 159 |
const struct nft_base_chain *basechain = nft_base_chain(ctx->chain); |
c974a3a36 netfilter: nf_tab... |
160 |
const struct nf_hook_ops *ops = &basechain->ops; |
0ca743a55 netfilter: nf_tab... |
161 162 |
par->hook_mask = 1 << ops->hooknum; |
493618a92 netfilter: nft_co... |
163 164 |
} else { par->hook_mask = 0; |
0ca743a55 netfilter: nf_tab... |
165 |
} |
36596dadf netfilter: nf_tab... |
166 |
par->family = ctx->family; |
55917a21d netfilter: x_tabl... |
167 |
par->nft_compat = true; |
0ca743a55 netfilter: nf_tab... |
168 169 170 171 |
} static void target_compat_from_user(struct xt_target *t, void *in, void *out) { |
756c1b1a7 netfilter: nft_co... |
172 |
int pad; |
0ca743a55 netfilter: nf_tab... |
173 |
|
756c1b1a7 netfilter: nft_co... |
174 175 176 177 |
memcpy(out, in, t->targetsize); pad = XT_ALIGN(t->targetsize) - t->targetsize; if (pad > 0) memset(out + t->targetsize, 0, pad); |
0ca743a55 netfilter: nf_tab... |
178 179 180 181 182 183 |
} static const struct nla_policy nft_rule_compat_policy[NFTA_RULE_COMPAT_MAX + 1] = { [NFTA_RULE_COMPAT_PROTO] = { .type = NLA_U32 }, [NFTA_RULE_COMPAT_FLAGS] = { .type = NLA_U32 }, }; |
2156d321b netfilter: nft_co... |
184 |
static int nft_parse_compat(const struct nlattr *attr, u16 *proto, bool *inv) |
0ca743a55 netfilter: nf_tab... |
185 186 187 188 |
{ struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1]; u32 flags; int err; |
8cb081746 netlink: make val... |
189 190 |
err = nla_parse_nested_deprecated(tb, NFTA_RULE_COMPAT_MAX, attr, nft_rule_compat_policy, NULL); |
0ca743a55 netfilter: nf_tab... |
191 192 193 194 195 196 197 198 199 200 201 |
if (err < 0) return err; if (!tb[NFTA_RULE_COMPAT_PROTO] || !tb[NFTA_RULE_COMPAT_FLAGS]) return -EINVAL; flags = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_FLAGS])); if (flags & ~NFT_RULE_COMPAT_F_MASK) return -EINVAL; if (flags & NFT_RULE_COMPAT_F_INV) *inv = true; |
8691a9a33 netfilter: nft_co... |
202 203 |
*proto = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_PROTO])); return 0; |
0ca743a55 netfilter: nf_tab... |
204 |
} |
2f941622f netfilter: nft_co... |
205 206 207 208 209 210 211 212 213 214 |
static void nft_compat_wait_for_destructors(void) { /* xtables matches or targets can have side effects, e.g. * creation/destruction of /proc files. * The xt ->destroy functions are run asynchronously from * work queue. If we have pending invocations we thus * need to wait for those to finish. */ nf_tables_trans_destroy_flush_work(); } |
0ca743a55 netfilter: nf_tab... |
215 216 217 218 219 220 221 222 |
static int nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nlattr * const tb[]) { void *info = nft_expr_priv(expr); struct xt_target *target = expr->ops->data; struct xt_tgchk_param par; size_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO])); |
2156d321b netfilter: nft_co... |
223 |
u16 proto = 0; |
0ca743a55 netfilter: nf_tab... |
224 225 226 227 228 |
bool inv = false; union nft_entry e = {}; int ret; target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info); |
8691a9a33 netfilter: nft_co... |
229 230 231 |
if (ctx->nla[NFTA_RULE_COMPAT]) { ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv); if (ret < 0) |
b8e9dc1c7 netfilter: nf_tab... |
232 |
return ret; |
8691a9a33 netfilter: nft_co... |
233 |
} |
0ca743a55 netfilter: nf_tab... |
234 235 |
nft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv); |
2f941622f netfilter: nft_co... |
236 |
nft_compat_wait_for_destructors(); |
ffe8923f1 netfilter: nft_co... |
237 |
|
0ca743a55 netfilter: nf_tab... |
238 239 |
ret = xt_check_target(&par, size, proto, inv); if (ret < 0) |
b8e9dc1c7 netfilter: nf_tab... |
240 |
return ret; |
0ca743a55 netfilter: nf_tab... |
241 242 |
/* The standard target cannot be used */ |
b8e9dc1c7 netfilter: nf_tab... |
243 244 |
if (!target->target) return -EINVAL; |
0ca743a55 netfilter: nf_tab... |
245 246 |
return 0; |
0ca743a55 netfilter: nf_tab... |
247 |
} |
ffe8923f1 netfilter: nft_co... |
248 249 |
static void __nft_mt_tg_destroy(struct module *me, const struct nft_expr *expr) { |
ffe8923f1 netfilter: nft_co... |
250 251 252 |
module_put(me); kfree(expr->ops); } |
0ca743a55 netfilter: nf_tab... |
253 |
static void |
62472bcef netfilter: nf_tab... |
254 |
nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) |
0ca743a55 netfilter: nf_tab... |
255 256 |
{ struct xt_target *target = expr->ops->data; |
3d9b14213 netfilter: nft_co... |
257 |
void *info = nft_expr_priv(expr); |
753c111f6 netfilter: nft_co... |
258 |
struct module *me = target->me; |
3d9b14213 netfilter: nft_co... |
259 260 261 262 263 |
struct xt_tgdtor_param par; par.net = ctx->net; par.target = target; par.targinfo = info; |
36596dadf netfilter: nf_tab... |
264 |
par.family = ctx->family; |
3d9b14213 netfilter: nft_co... |
265 266 |
if (par.target->destroy != NULL) par.target->destroy(&par); |
0ca743a55 netfilter: nf_tab... |
267 |
|
ffe8923f1 netfilter: nft_co... |
268 |
__nft_mt_tg_destroy(me, expr); |
0ca743a55 netfilter: nf_tab... |
269 |
} |
d701d8117 netfilter: nft_co... |
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
static int nft_extension_dump_info(struct sk_buff *skb, int attr, const void *info, unsigned int size, unsigned int user_size) { unsigned int info_size, aligned_size = XT_ALIGN(size); struct nlattr *nla; nla = nla_reserve(skb, attr, aligned_size); if (!nla) return -1; info_size = user_size ? : size; memcpy(nla_data(nla), info, info_size); memset(nla_data(nla) + info_size, 0, aligned_size - info_size); return 0; } |
0ca743a55 netfilter: nf_tab... |
287 288 289 290 291 292 293 |
static int nft_target_dump(struct sk_buff *skb, const struct nft_expr *expr) { const struct xt_target *target = expr->ops->data; void *info = nft_expr_priv(expr); if (nla_put_string(skb, NFTA_TARGET_NAME, target->name) || nla_put_be32(skb, NFTA_TARGET_REV, htonl(target->revision)) || |
d701d8117 netfilter: nft_co... |
294 295 |
nft_extension_dump_info(skb, NFTA_TARGET_INFO, info, target->targetsize, target->usersize)) |
0ca743a55 netfilter: nf_tab... |
296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
goto nla_put_failure; return 0; nla_put_failure: return -1; } static int nft_target_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nft_data **data) { struct xt_target *target = expr->ops->data; unsigned int hook_mask = 0; |
f3f5ddedd netfilter: nft_co... |
310 |
int ret; |
0ca743a55 netfilter: nf_tab... |
311 |
|
f323d9546 netfilter: nf_tab... |
312 |
if (nft_is_base_chain(ctx->chain)) { |
0ca743a55 netfilter: nf_tab... |
313 314 |
const struct nft_base_chain *basechain = nft_base_chain(ctx->chain); |
c974a3a36 netfilter: nf_tab... |
315 |
const struct nf_hook_ops *ops = &basechain->ops; |
0ca743a55 netfilter: nf_tab... |
316 317 |
hook_mask = 1 << ops->hooknum; |
f7fb77fc1 netfilter: nft_co... |
318 |
if (target->hooks && !(hook_mask & target->hooks)) |
f3f5ddedd netfilter: nft_co... |
319 |
return -EINVAL; |
0ca743a55 netfilter: nf_tab... |
320 |
|
e4844c9c6 netfilter: nft_co... |
321 |
ret = nft_compat_chain_validate_dependency(ctx, target->table); |
f3f5ddedd netfilter: nft_co... |
322 323 |
if (ret < 0) return ret; |
0ca743a55 netfilter: nf_tab... |
324 325 326 |
} return 0; } |
8bdf16474 netfilter: nft_co... |
327 328 329 330 |
static void __nft_match_eval(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt, void *info) |
0ca743a55 netfilter: nf_tab... |
331 |
{ |
0ca743a55 netfilter: nf_tab... |
332 333 334 335 336 337 338 339 340 |
struct xt_match *match = expr->ops->data; struct sk_buff *skb = pkt->skb; bool ret; nft_compat_set_par((struct xt_action_param *)&pkt->xt, match, info); ret = match->match(skb, (struct xt_action_param *)&pkt->xt); if (pkt->xt.hotdrop) { |
a55e22e92 netfilter: nf_tab... |
341 |
regs->verdict.code = NF_DROP; |
0ca743a55 netfilter: nf_tab... |
342 343 |
return; } |
c1f866767 netfilter: Fix sw... |
344 345 |
switch (ret ? 1 : 0) { case 1: |
a55e22e92 netfilter: nf_tab... |
346 |
regs->verdict.code = NFT_CONTINUE; |
0ca743a55 netfilter: nf_tab... |
347 |
break; |
c1f866767 netfilter: Fix sw... |
348 |
case 0: |
a55e22e92 netfilter: nf_tab... |
349 |
regs->verdict.code = NFT_BREAK; |
0ca743a55 netfilter: nf_tab... |
350 351 352 |
break; } } |
732a8049f netfilter: nft_co... |
353 354 355 356 357 358 359 360 |
static void nft_match_large_eval(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt) { struct nft_xt_match_priv *priv = nft_expr_priv(expr); __nft_match_eval(expr, regs, pkt, priv->info); } |
8bdf16474 netfilter: nft_co... |
361 362 363 364 365 366 |
static void nft_match_eval(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt) { __nft_match_eval(expr, regs, pkt, nft_expr_priv(expr)); } |
0ca743a55 netfilter: nf_tab... |
367 368 369 370 371 372 373 374 375 376 |
static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = { [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING }, [NFTA_MATCH_REV] = { .type = NLA_U32 }, [NFTA_MATCH_INFO] = { .type = NLA_BINARY }, }; /* struct xt_mtchk_param and xt_tgchk_param look very similar */ static void nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx, struct xt_match *match, void *info, |
2156d321b netfilter: nft_co... |
377 |
union nft_entry *entry, u16 proto, bool inv) |
0ca743a55 netfilter: nf_tab... |
378 |
{ |
2daf1b4d1 netfilter: nft_co... |
379 |
par->net = ctx->net; |
0ca743a55 netfilter: nf_tab... |
380 |
par->table = ctx->table->name; |
36596dadf netfilter: nf_tab... |
381 |
switch (ctx->family) { |
0ca743a55 netfilter: nf_tab... |
382 383 384 385 386 |
case AF_INET: entry->e4.ip.proto = proto; entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0; break; case AF_INET6: |
749177ccc netfilter: nft_co... |
387 388 |
if (proto) entry->e6.ipv6.flags |= IP6T_F_PROTO; |
0ca743a55 netfilter: nf_tab... |
389 390 391 |
entry->e6.ipv6.proto = proto; entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0; break; |
5191f4d82 netfilter: nft_co... |
392 |
case NFPROTO_BRIDGE: |
2156d321b netfilter: nft_co... |
393 |
entry->ebt.ethproto = (__force __be16)proto; |
5191f4d82 netfilter: nft_co... |
394 395 |
entry->ebt.invflags = inv ? EBT_IPROTO : 0; break; |
5f1589394 netfilter: nft_co... |
396 397 |
case NFPROTO_ARP: break; |
0ca743a55 netfilter: nf_tab... |
398 399 400 401 |
} par->entryinfo = entry; par->match = match; par->matchinfo = info; |
f323d9546 netfilter: nf_tab... |
402 |
if (nft_is_base_chain(ctx->chain)) { |
0ca743a55 netfilter: nf_tab... |
403 404 |
const struct nft_base_chain *basechain = nft_base_chain(ctx->chain); |
c974a3a36 netfilter: nf_tab... |
405 |
const struct nf_hook_ops *ops = &basechain->ops; |
0ca743a55 netfilter: nf_tab... |
406 407 |
par->hook_mask = 1 << ops->hooknum; |
493618a92 netfilter: nft_co... |
408 409 |
} else { par->hook_mask = 0; |
0ca743a55 netfilter: nf_tab... |
410 |
} |
36596dadf netfilter: nf_tab... |
411 |
par->family = ctx->family; |
55917a21d netfilter: x_tabl... |
412 |
par->nft_compat = true; |
0ca743a55 netfilter: nf_tab... |
413 414 415 416 |
} static void match_compat_from_user(struct xt_match *m, void *in, void *out) { |
756c1b1a7 netfilter: nft_co... |
417 418 419 420 421 422 |
int pad; memcpy(out, in, m->matchsize); pad = XT_ALIGN(m->matchsize) - m->matchsize; if (pad > 0) memset(out + m->matchsize, 0, pad); |
0ca743a55 netfilter: nf_tab... |
423 424 425 |
} static int |
8bdf16474 netfilter: nft_co... |
426 427 428 |
__nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nlattr * const tb[], void *info) |
0ca743a55 netfilter: nf_tab... |
429 |
{ |
0ca743a55 netfilter: nf_tab... |
430 431 432 |
struct xt_match *match = expr->ops->data; struct xt_mtchk_param par; size_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO])); |
2156d321b netfilter: nft_co... |
433 |
u16 proto = 0; |
0ca743a55 netfilter: nf_tab... |
434 435 436 437 438 |
bool inv = false; union nft_entry e = {}; int ret; match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info); |
8691a9a33 netfilter: nft_co... |
439 440 441 |
if (ctx->nla[NFTA_RULE_COMPAT]) { ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv); if (ret < 0) |
b8e9dc1c7 netfilter: nf_tab... |
442 |
return ret; |
8691a9a33 netfilter: nft_co... |
443 |
} |
0ca743a55 netfilter: nf_tab... |
444 445 |
nft_match_set_mtchk_param(&par, ctx, match, info, &e, proto, inv); |
2f941622f netfilter: nft_co... |
446 |
nft_compat_wait_for_destructors(); |
b8e204006 netfilter: nft_co... |
447 |
return xt_check_match(&par, size, proto, inv); |
0ca743a55 netfilter: nf_tab... |
448 |
} |
8bdf16474 netfilter: nft_co... |
449 450 451 452 453 454 |
static int nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nlattr * const tb[]) { return __nft_match_init(ctx, expr, tb, nft_expr_priv(expr)); } |
732a8049f netfilter: nft_co... |
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
static int nft_match_large_init(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nlattr * const tb[]) { struct nft_xt_match_priv *priv = nft_expr_priv(expr); struct xt_match *m = expr->ops->data; int ret; priv->info = kmalloc(XT_ALIGN(m->matchsize), GFP_KERNEL); if (!priv->info) return -ENOMEM; ret = __nft_match_init(ctx, expr, tb, priv->info); if (ret) kfree(priv->info); return ret; } |
0ca743a55 netfilter: nf_tab... |
472 |
static void |
8bdf16474 netfilter: nft_co... |
473 474 |
__nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr, void *info) |
0ca743a55 netfilter: nf_tab... |
475 476 |
{ struct xt_match *match = expr->ops->data; |
29e388010 netfilter: nf_tab... |
477 |
struct module *me = match->me; |
3d9b14213 netfilter: nft_co... |
478 479 480 481 482 |
struct xt_mtdtor_param par; par.net = ctx->net; par.match = match; par.matchinfo = info; |
36596dadf netfilter: nf_tab... |
483 |
par.family = ctx->family; |
3d9b14213 netfilter: nft_co... |
484 485 |
if (par.match->destroy != NULL) par.match->destroy(&par); |
0ca743a55 netfilter: nf_tab... |
486 |
|
ffe8923f1 netfilter: nft_co... |
487 |
__nft_mt_tg_destroy(me, expr); |
0ca743a55 netfilter: nf_tab... |
488 |
} |
8bdf16474 netfilter: nft_co... |
489 490 491 492 493 |
static void nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) { __nft_match_destroy(ctx, expr, nft_expr_priv(expr)); } |
732a8049f netfilter: nft_co... |
494 495 496 497 498 499 500 501 |
static void nft_match_large_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) { struct nft_xt_match_priv *priv = nft_expr_priv(expr); __nft_match_destroy(ctx, expr, priv->info); kfree(priv->info); } |
8bdf16474 netfilter: nft_co... |
502 503 |
static int __nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr, void *info) |
0ca743a55 netfilter: nf_tab... |
504 |
{ |
0ca743a55 netfilter: nf_tab... |
505 506 507 508 |
struct xt_match *match = expr->ops->data; if (nla_put_string(skb, NFTA_MATCH_NAME, match->name) || nla_put_be32(skb, NFTA_MATCH_REV, htonl(match->revision)) || |
d701d8117 netfilter: nft_co... |
509 510 |
nft_extension_dump_info(skb, NFTA_MATCH_INFO, info, match->matchsize, match->usersize)) |
0ca743a55 netfilter: nf_tab... |
511 512 513 514 515 516 517 |
goto nla_put_failure; return 0; nla_put_failure: return -1; } |
8bdf16474 netfilter: nft_co... |
518 519 520 521 |
static int nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr) { return __nft_match_dump(skb, expr, nft_expr_priv(expr)); } |
732a8049f netfilter: nft_co... |
522 523 524 525 526 527 |
static int nft_match_large_dump(struct sk_buff *skb, const struct nft_expr *e) { struct nft_xt_match_priv *priv = nft_expr_priv(e); return __nft_match_dump(skb, e, priv->info); } |
0ca743a55 netfilter: nf_tab... |
528 529 530 531 532 533 |
static int nft_match_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nft_data **data) { struct xt_match *match = expr->ops->data; unsigned int hook_mask = 0; |
f3f5ddedd netfilter: nft_co... |
534 |
int ret; |
0ca743a55 netfilter: nf_tab... |
535 |
|
f323d9546 netfilter: nf_tab... |
536 |
if (nft_is_base_chain(ctx->chain)) { |
0ca743a55 netfilter: nf_tab... |
537 538 |
const struct nft_base_chain *basechain = nft_base_chain(ctx->chain); |
c974a3a36 netfilter: nf_tab... |
539 |
const struct nf_hook_ops *ops = &basechain->ops; |
0ca743a55 netfilter: nf_tab... |
540 541 |
hook_mask = 1 << ops->hooknum; |
f7fb77fc1 netfilter: nft_co... |
542 |
if (match->hooks && !(hook_mask & match->hooks)) |
f3f5ddedd netfilter: nft_co... |
543 |
return -EINVAL; |
0ca743a55 netfilter: nf_tab... |
544 |
|
e4844c9c6 netfilter: nft_co... |
545 |
ret = nft_compat_chain_validate_dependency(ctx, match->table); |
f3f5ddedd netfilter: nft_co... |
546 547 |
if (ret < 0) return ret; |
0ca743a55 netfilter: nf_tab... |
548 549 550 551 552 553 554 555 556 557 558 559 |
} return 0; } static int nfnl_compat_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, int event, u16 family, const char *name, int rev, int target) { struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; unsigned int flags = portid ? NLM_F_MULTI : 0; |
dedb67c4b netfilter: Add nf... |
560 |
event = nfnl_msg_type(NFNL_SUBSYS_NFT_COMPAT, event); |
0ca743a55 netfilter: nf_tab... |
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 |
nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags); if (nlh == NULL) goto nlmsg_failure; nfmsg = nlmsg_data(nlh); nfmsg->nfgen_family = family; nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; if (nla_put_string(skb, NFTA_COMPAT_NAME, name) || nla_put_be32(skb, NFTA_COMPAT_REV, htonl(rev)) || nla_put_be32(skb, NFTA_COMPAT_TYPE, htonl(target))) goto nla_put_failure; nlmsg_end(skb, nlh); return skb->len; nlmsg_failure: nla_put_failure: nlmsg_cancel(skb, nlh); return -1; } |
eb1fb1479 netfilter: nft_co... |
583 584 585 586 |
static int nfnl_compat_get_rcu(struct net *net, struct sock *nfnl, struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const tb[], struct netlink_ext_ack *extack) |
0ca743a55 netfilter: nf_tab... |
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 |
{ int ret = 0, target; struct nfgenmsg *nfmsg; const char *fmt; const char *name; u32 rev; struct sk_buff *skb2; if (tb[NFTA_COMPAT_NAME] == NULL || tb[NFTA_COMPAT_REV] == NULL || tb[NFTA_COMPAT_TYPE] == NULL) return -EINVAL; name = nla_data(tb[NFTA_COMPAT_NAME]); rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV])); target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE])); nfmsg = nlmsg_data(nlh); switch(nfmsg->nfgen_family) { case AF_INET: fmt = "ipt_%s"; break; case AF_INET6: fmt = "ip6t_%s"; break; |
5191f4d82 netfilter: nft_co... |
613 614 615 |
case NFPROTO_BRIDGE: fmt = "ebt_%s"; break; |
5f1589394 netfilter: nft_co... |
616 617 618 |
case NFPROTO_ARP: fmt = "arpt_%s"; break; |
0ca743a55 netfilter: nf_tab... |
619 620 621 622 623 624 |
default: pr_err("nft_compat: unsupported protocol %d ", nfmsg->nfgen_family); return -EINVAL; } |
eb1fb1479 netfilter: nft_co... |
625 626 627 628 |
if (!try_module_get(THIS_MODULE)) return -EINVAL; rcu_read_unlock(); |
0ca743a55 netfilter: nf_tab... |
629 630 631 |
try_then_request_module(xt_find_revision(nfmsg->nfgen_family, name, rev, target, &ret), fmt, name); |
0ca743a55 netfilter: nf_tab... |
632 |
if (ret < 0) |
eb1fb1479 netfilter: nft_co... |
633 |
goto out_put; |
0ca743a55 netfilter: nf_tab... |
634 635 |
skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
eb1fb1479 netfilter: nft_co... |
636 637 638 639 |
if (skb2 == NULL) { ret = -ENOMEM; goto out_put; } |
0ca743a55 netfilter: nf_tab... |
640 641 642 643 644 645 646 647 648 |
/* include the best revision for this extension in the message */ if (nfnl_compat_fill_info(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq, NFNL_MSG_TYPE(nlh->nlmsg_type), NFNL_MSG_COMPAT_GET, nfmsg->nfgen_family, name, ret, target) <= 0) { kfree_skb(skb2); |
eb1fb1479 netfilter: nft_co... |
649 |
goto out_put; |
0ca743a55 netfilter: nf_tab... |
650 651 652 653 654 655 |
} ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT); if (ret > 0) ret = 0; |
eb1fb1479 netfilter: nft_co... |
656 657 658 |
out_put: rcu_read_lock(); module_put(THIS_MODULE); |
0ca743a55 netfilter: nf_tab... |
659 660 661 662 663 664 665 666 667 668 669 |
return ret == -EAGAIN ? -ENOBUFS : ret; } static const struct nla_policy nfnl_compat_policy_get[NFTA_COMPAT_MAX+1] = { [NFTA_COMPAT_NAME] = { .type = NLA_NUL_STRING, .len = NFT_COMPAT_NAME_MAX-1 }, [NFTA_COMPAT_REV] = { .type = NLA_U32 }, [NFTA_COMPAT_TYPE] = { .type = NLA_U32 }, }; static const struct nfnl_callback nfnl_nft_compat_cb[NFNL_MSG_COMPAT_MAX] = { |
eb1fb1479 netfilter: nft_co... |
670 |
[NFNL_MSG_COMPAT_GET] = { .call_rcu = nfnl_compat_get_rcu, |
0ca743a55 netfilter: nf_tab... |
671 672 673 674 675 676 677 678 679 680 |
.attr_count = NFTA_COMPAT_MAX, .policy = nfnl_compat_policy_get }, }; static const struct nfnetlink_subsystem nfnl_compat_subsys = { .name = "nft-compat", .subsys_id = NFNL_SUBSYS_NFT_COMPAT, .cb_count = NFNL_MSG_COMPAT_MAX, .cb = nfnl_nft_compat_cb, }; |
b8e204006 netfilter: nft_co... |
681 |
static struct nft_expr_type nft_match_type; |
ba378ca9c netfilter: nft_co... |
682 |
|
0ca743a55 netfilter: nf_tab... |
683 684 685 686 |
static const struct nft_expr_ops * nft_match_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[]) { |
b8e204006 netfilter: nft_co... |
687 |
struct nft_expr_ops *ops; |
0ca743a55 netfilter: nf_tab... |
688 |
struct xt_match *match; |
732a8049f netfilter: nft_co... |
689 |
unsigned int matchsize; |
0ca743a55 netfilter: nf_tab... |
690 |
char *mt_name; |
ba378ca9c netfilter: nft_co... |
691 |
u32 rev, family; |
2bf4fade5 netfilter: nft_co... |
692 |
int err; |
0ca743a55 netfilter: nf_tab... |
693 694 695 696 697 698 699 700 |
if (tb[NFTA_MATCH_NAME] == NULL || tb[NFTA_MATCH_REV] == NULL || tb[NFTA_MATCH_INFO] == NULL) return ERR_PTR(-EINVAL); mt_name = nla_data(tb[NFTA_MATCH_NAME]); rev = ntohl(nla_get_be32(tb[NFTA_MATCH_REV])); |
36596dadf netfilter: nf_tab... |
701 |
family = ctx->family; |
0ca743a55 netfilter: nf_tab... |
702 |
|
0ca743a55 netfilter: nf_tab... |
703 704 705 |
match = xt_request_find_match(family, mt_name, rev); if (IS_ERR(match)) return ERR_PTR(-ENOENT); |
2bf4fade5 netfilter: nft_co... |
706 707 708 709 |
if (match->matchsize > nla_len(tb[NFTA_MATCH_INFO])) { err = -EINVAL; goto err; } |
f0716cd6e netfilter: nft_co... |
710 |
|
b8e204006 netfilter: nft_co... |
711 712 |
ops = kzalloc(sizeof(struct nft_expr_ops), GFP_KERNEL); if (!ops) { |
2bf4fade5 netfilter: nft_co... |
713 714 715 |
err = -ENOMEM; goto err; } |
0ca743a55 netfilter: nf_tab... |
716 |
|
b8e204006 netfilter: nft_co... |
717 718 719 720 721 722 723 |
ops->type = &nft_match_type; ops->eval = nft_match_eval; ops->init = nft_match_init; ops->destroy = nft_match_destroy; ops->dump = nft_match_dump; ops->validate = nft_match_validate; ops->data = match; |
0ca743a55 netfilter: nf_tab... |
724 |
|
732a8049f netfilter: nft_co... |
725 726 727 |
matchsize = NFT_EXPR_SIZE(XT_ALIGN(match->matchsize)); if (matchsize > NFT_MATCH_LARGE_THRESH) { matchsize = NFT_EXPR_SIZE(sizeof(struct nft_xt_match_priv)); |
b8e204006 netfilter: nft_co... |
728 729 730 731 |
ops->eval = nft_match_large_eval; ops->init = nft_match_large_init; ops->destroy = nft_match_large_destroy; ops->dump = nft_match_large_dump; |
732a8049f netfilter: nft_co... |
732 |
} |
b8e204006 netfilter: nft_co... |
733 |
ops->size = matchsize; |
732a8049f netfilter: nft_co... |
734 |
|
b8e204006 netfilter: nft_co... |
735 |
return ops; |
2bf4fade5 netfilter: nft_co... |
736 737 738 |
err: module_put(match->me); return ERR_PTR(err); |
0ca743a55 netfilter: nf_tab... |
739 |
} |
b8e204006 netfilter: nft_co... |
740 741 742 743 744 745 746 |
static void nft_match_release_ops(const struct nft_expr_ops *ops) { struct xt_match *match = ops->data; module_put(match->me); kfree(ops); } |
0ca743a55 netfilter: nf_tab... |
747 748 749 |
static struct nft_expr_type nft_match_type __read_mostly = { .name = "match", .select_ops = nft_match_select_ops, |
b8e204006 netfilter: nft_co... |
750 |
.release_ops = nft_match_release_ops, |
0ca743a55 netfilter: nf_tab... |
751 752 753 754 |
.policy = nft_match_policy, .maxattr = NFTA_MATCH_MAX, .owner = THIS_MODULE, }; |
b8e204006 netfilter: nft_co... |
755 |
static struct nft_expr_type nft_target_type; |
ba378ca9c netfilter: nft_co... |
756 |
|
0ca743a55 netfilter: nf_tab... |
757 758 759 760 |
static const struct nft_expr_ops * nft_target_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[]) { |
b8e204006 netfilter: nft_co... |
761 |
struct nft_expr_ops *ops; |
0ca743a55 netfilter: nf_tab... |
762 763 |
struct xt_target *target; char *tg_name; |
ba378ca9c netfilter: nft_co... |
764 |
u32 rev, family; |
2bf4fade5 netfilter: nft_co... |
765 |
int err; |
0ca743a55 netfilter: nf_tab... |
766 767 768 769 770 771 772 773 |
if (tb[NFTA_TARGET_NAME] == NULL || tb[NFTA_TARGET_REV] == NULL || tb[NFTA_TARGET_INFO] == NULL) return ERR_PTR(-EINVAL); tg_name = nla_data(tb[NFTA_TARGET_NAME]); rev = ntohl(nla_get_be32(tb[NFTA_TARGET_REV])); |
36596dadf netfilter: nf_tab... |
774 |
family = ctx->family; |
0ca743a55 netfilter: nf_tab... |
775 |
|
21d5e0781 netfilter: nft_co... |
776 777 778 779 |
if (strcmp(tg_name, XT_ERROR_TARGET) == 0 || strcmp(tg_name, XT_STANDARD_TARGET) == 0 || strcmp(tg_name, "standard") == 0) return ERR_PTR(-EINVAL); |
0ca743a55 netfilter: nf_tab... |
780 781 782 |
target = xt_request_find_target(family, tg_name, rev); if (IS_ERR(target)) return ERR_PTR(-ENOENT); |
21d5e0781 netfilter: nft_co... |
783 784 785 786 |
if (!target->target) { err = -EINVAL; goto err; } |
2bf4fade5 netfilter: nft_co... |
787 788 789 790 |
if (target->targetsize > nla_len(tb[NFTA_TARGET_INFO])) { err = -EINVAL; goto err; } |
f0716cd6e netfilter: nft_co... |
791 |
|
b8e204006 netfilter: nft_co... |
792 793 |
ops = kzalloc(sizeof(struct nft_expr_ops), GFP_KERNEL); if (!ops) { |
2bf4fade5 netfilter: nft_co... |
794 795 796 |
err = -ENOMEM; goto err; } |
0ca743a55 netfilter: nf_tab... |
797 |
|
b8e204006 netfilter: nft_co... |
798 799 800 801 802 803 804 |
ops->type = &nft_target_type; ops->size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize)); ops->init = nft_target_init; ops->destroy = nft_target_destroy; ops->dump = nft_target_dump; ops->validate = nft_target_validate; ops->data = target; |
0ca743a55 netfilter: nf_tab... |
805 |
|
5191f4d82 netfilter: nft_co... |
806 |
if (family == NFPROTO_BRIDGE) |
b8e204006 netfilter: nft_co... |
807 |
ops->eval = nft_target_eval_bridge; |
5191f4d82 netfilter: nft_co... |
808 |
else |
b8e204006 netfilter: nft_co... |
809 |
ops->eval = nft_target_eval_xt; |
0ca743a55 netfilter: nf_tab... |
810 |
|
b8e204006 netfilter: nft_co... |
811 |
return ops; |
2bf4fade5 netfilter: nft_co... |
812 813 814 |
err: module_put(target->me); return ERR_PTR(err); |
0ca743a55 netfilter: nf_tab... |
815 |
} |
b8e204006 netfilter: nft_co... |
816 817 818 819 820 821 822 |
static void nft_target_release_ops(const struct nft_expr_ops *ops) { struct xt_target *target = ops->data; module_put(target->me); kfree(ops); } |
0ca743a55 netfilter: nf_tab... |
823 824 825 |
static struct nft_expr_type nft_target_type __read_mostly = { .name = "target", .select_ops = nft_target_select_ops, |
b8e204006 netfilter: nft_co... |
826 |
.release_ops = nft_target_release_ops, |
0ca743a55 netfilter: nf_tab... |
827 828 829 830 831 832 833 834 835 836 837 |
.policy = nft_target_policy, .maxattr = NFTA_TARGET_MAX, .owner = THIS_MODULE, }; static int __init nft_compat_module_init(void) { int ret; ret = nft_register_expr(&nft_match_type); if (ret < 0) |
b8e204006 netfilter: nft_co... |
838 |
return ret; |
0ca743a55 netfilter: nf_tab... |
839 840 841 842 843 844 845 846 847 848 849 |
ret = nft_register_expr(&nft_target_type); if (ret < 0) goto err_match; ret = nfnetlink_subsys_register(&nfnl_compat_subsys); if (ret < 0) { pr_err("nft_compat: cannot register with nfnetlink. "); goto err_target; } |
0ca743a55 netfilter: nf_tab... |
850 |
return ret; |
0ca743a55 netfilter: nf_tab... |
851 852 853 854 855 856 857 858 859 860 861 862 |
err_target: nft_unregister_expr(&nft_target_type); err_match: nft_unregister_expr(&nft_match_type); return ret; } static void __exit nft_compat_module_exit(void) { nfnetlink_subsys_unregister(&nfnl_compat_subsys); nft_unregister_expr(&nft_target_type); nft_unregister_expr(&nft_match_type); |
0ca743a55 netfilter: nf_tab... |
863 864 865 866 867 868 869 870 871 872 873 |
} MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFT_COMPAT); module_init(nft_compat_module_init); module_exit(nft_compat_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); MODULE_ALIAS_NFT_EXPR("match"); MODULE_ALIAS_NFT_EXPR("target"); |
4cacc3951 netfilter: Add MO... |
874 |
MODULE_DESCRIPTION("x_tables over nftables support"); |