1 /* 2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net> 3 * Copyright (c) 2014 Intel Corporation 4 * Author: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * Development of this code funded by Astaro AG (http://www.astaro.com/) 11 */ 12 13 #include <linux/kernel.h> 14 #include <linux/netlink.h> 15 #include <linux/netfilter.h> 16 #include <linux/netfilter/nf_tables.h> 17 #include <linux/in.h> 18 #include <linux/ip.h> 19 #include <linux/ipv6.h> 20 #include <linux/smp.h> 21 #include <linux/static_key.h> 22 #include <net/dst.h> 23 #include <net/sock.h> 24 #include <net/tcp_states.h> /* for TCP_TIME_WAIT */ 25 #include <net/netfilter/nf_tables.h> 26 #include <net/netfilter/nf_tables_core.h> 27 28 #include <uapi/linux/netfilter_bridge.h> /* NF_BR_PRE_ROUTING */ 29 30 struct nft_meta { 31 enum nft_meta_keys key:8; 32 union { 33 enum nft_registers dreg:8; 34 enum nft_registers sreg:8; 35 }; 36 }; 37 38 static DEFINE_PER_CPU(struct rnd_state, nft_prandom_state); 39 40 #ifdef CONFIG_NF_TABLES_BRIDGE 41 #include "../bridge/br_private.h" 42 #endif 43 44 static void nft_meta_get_eval(const struct nft_expr *expr, 45 struct nft_regs *regs, 46 const struct nft_pktinfo *pkt) 47 { 48 const struct nft_meta *priv = nft_expr_priv(expr); 49 const struct sk_buff *skb = pkt->skb; 50 const struct net_device *in = nft_in(pkt), *out = nft_out(pkt); 51 struct sock *sk; 52 u32 *dest = ®s->data[priv->dreg]; 53 #ifdef CONFIG_NF_TABLES_BRIDGE 54 const struct net_bridge_port *p; 55 #endif 56 57 switch (priv->key) { 58 case NFT_META_LEN: 59 *dest = skb->len; 60 break; 61 case NFT_META_PROTOCOL: 62 nft_reg_store16(dest, (__force u16)skb->protocol); 63 break; 64 case NFT_META_NFPROTO: 65 nft_reg_store8(dest, nft_pf(pkt)); 66 break; 67 case NFT_META_L4PROTO: 68 if (!pkt->tprot_set) 69 goto err; 70 nft_reg_store8(dest, pkt->tprot); 71 break; 72 case NFT_META_PRIORITY: 73 *dest = skb->priority; 74 break; 75 case NFT_META_MARK: 76 *dest = skb->mark; 77 break; 78 case NFT_META_IIF: 79 if (in == NULL) 80 goto err; 81 *dest = in->ifindex; 82 break; 83 case NFT_META_OIF: 84 if (out == NULL) 85 goto err; 86 *dest = out->ifindex; 87 break; 88 case NFT_META_IIFNAME: 89 if (in == NULL) 90 goto err; 91 strncpy((char *)dest, in->name, IFNAMSIZ); 92 break; 93 case NFT_META_OIFNAME: 94 if (out == NULL) 95 goto err; 96 strncpy((char *)dest, out->name, IFNAMSIZ); 97 break; 98 case NFT_META_IIFTYPE: 99 if (in == NULL) 100 goto err; 101 nft_reg_store16(dest, in->type); 102 break; 103 case NFT_META_OIFTYPE: 104 if (out == NULL) 105 goto err; 106 nft_reg_store16(dest, out->type); 107 break; 108 case NFT_META_SKUID: 109 sk = skb_to_full_sk(skb); 110 if (!sk || !sk_fullsock(sk)) 111 goto err; 112 113 read_lock_bh(&sk->sk_callback_lock); 114 if (sk->sk_socket == NULL || 115 sk->sk_socket->file == NULL) { 116 read_unlock_bh(&sk->sk_callback_lock); 117 goto err; 118 } 119 120 *dest = from_kuid_munged(&init_user_ns, 121 sk->sk_socket->file->f_cred->fsuid); 122 read_unlock_bh(&sk->sk_callback_lock); 123 break; 124 case NFT_META_SKGID: 125 sk = skb_to_full_sk(skb); 126 if (!sk || !sk_fullsock(sk)) 127 goto err; 128 129 read_lock_bh(&sk->sk_callback_lock); 130 if (sk->sk_socket == NULL || 131 sk->sk_socket->file == NULL) { 132 read_unlock_bh(&sk->sk_callback_lock); 133 goto err; 134 } 135 *dest = from_kgid_munged(&init_user_ns, 136 sk->sk_socket->file->f_cred->fsgid); 137 read_unlock_bh(&sk->sk_callback_lock); 138 break; 139 #ifdef CONFIG_IP_ROUTE_CLASSID 140 case NFT_META_RTCLASSID: { 141 const struct dst_entry *dst = skb_dst(skb); 142 143 if (dst == NULL) 144 goto err; 145 *dest = dst->tclassid; 146 break; 147 } 148 #endif 149 #ifdef CONFIG_NETWORK_SECMARK 150 case NFT_META_SECMARK: 151 *dest = skb->secmark; 152 break; 153 #endif 154 case NFT_META_PKTTYPE: 155 if (skb->pkt_type != PACKET_LOOPBACK) { 156 nft_reg_store8(dest, skb->pkt_type); 157 break; 158 } 159 160 switch (nft_pf(pkt)) { 161 case NFPROTO_IPV4: 162 if (ipv4_is_multicast(ip_hdr(skb)->daddr)) 163 nft_reg_store8(dest, PACKET_MULTICAST); 164 else 165 nft_reg_store8(dest, PACKET_BROADCAST); 166 break; 167 case NFPROTO_IPV6: 168 nft_reg_store8(dest, PACKET_MULTICAST); 169 break; 170 case NFPROTO_NETDEV: 171 switch (skb->protocol) { 172 case htons(ETH_P_IP): { 173 int noff = skb_network_offset(skb); 174 struct iphdr *iph, _iph; 175 176 iph = skb_header_pointer(skb, noff, 177 sizeof(_iph), &_iph); 178 if (!iph) 179 goto err; 180 181 if (ipv4_is_multicast(iph->daddr)) 182 nft_reg_store8(dest, PACKET_MULTICAST); 183 else 184 nft_reg_store8(dest, PACKET_BROADCAST); 185 186 break; 187 } 188 case htons(ETH_P_IPV6): 189 nft_reg_store8(dest, PACKET_MULTICAST); 190 break; 191 default: 192 WARN_ON_ONCE(1); 193 goto err; 194 } 195 break; 196 default: 197 WARN_ON_ONCE(1); 198 goto err; 199 } 200 break; 201 case NFT_META_CPU: 202 *dest = raw_smp_processor_id(); 203 break; 204 case NFT_META_IIFGROUP: 205 if (in == NULL) 206 goto err; 207 *dest = in->group; 208 break; 209 case NFT_META_OIFGROUP: 210 if (out == NULL) 211 goto err; 212 *dest = out->group; 213 break; 214 #ifdef CONFIG_CGROUP_NET_CLASSID 215 case NFT_META_CGROUP: 216 sk = skb_to_full_sk(skb); 217 if (!sk || !sk_fullsock(sk)) 218 goto err; 219 *dest = sock_cgroup_classid(&sk->sk_cgrp_data); 220 break; 221 #endif 222 case NFT_META_PRANDOM: { 223 struct rnd_state *state = this_cpu_ptr(&nft_prandom_state); 224 *dest = prandom_u32_state(state); 225 break; 226 } 227 #ifdef CONFIG_XFRM 228 case NFT_META_SECPATH: 229 nft_reg_store8(dest, !!skb->sp); 230 break; 231 #endif 232 #ifdef CONFIG_NF_TABLES_BRIDGE 233 case NFT_META_BRI_IIFNAME: 234 if (in == NULL || (p = br_port_get_rcu(in)) == NULL) 235 goto err; 236 strncpy((char *)dest, p->br->dev->name, IFNAMSIZ); 237 return; 238 case NFT_META_BRI_OIFNAME: 239 if (out == NULL || (p = br_port_get_rcu(out)) == NULL) 240 goto err; 241 strncpy((char *)dest, p->br->dev->name, IFNAMSIZ); 242 return; 243 #endif 244 default: 245 WARN_ON(1); 246 goto err; 247 } 248 return; 249 250 err: 251 regs->verdict.code = NFT_BREAK; 252 } 253 254 static void nft_meta_set_eval(const struct nft_expr *expr, 255 struct nft_regs *regs, 256 const struct nft_pktinfo *pkt) 257 { 258 const struct nft_meta *meta = nft_expr_priv(expr); 259 struct sk_buff *skb = pkt->skb; 260 u32 *sreg = ®s->data[meta->sreg]; 261 u32 value = *sreg; 262 u8 value8; 263 264 switch (meta->key) { 265 case NFT_META_MARK: 266 skb->mark = value; 267 break; 268 case NFT_META_PRIORITY: 269 skb->priority = value; 270 break; 271 case NFT_META_PKTTYPE: 272 value8 = nft_reg_load8(sreg); 273 274 if (skb->pkt_type != value8 && 275 skb_pkt_type_ok(value8) && 276 skb_pkt_type_ok(skb->pkt_type)) 277 skb->pkt_type = value8; 278 break; 279 case NFT_META_NFTRACE: 280 value8 = nft_reg_load8(sreg); 281 282 skb->nf_trace = !!value8; 283 break; 284 default: 285 WARN_ON(1); 286 } 287 } 288 289 static const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = { 290 [NFTA_META_DREG] = { .type = NLA_U32 }, 291 [NFTA_META_KEY] = { .type = NLA_U32 }, 292 [NFTA_META_SREG] = { .type = NLA_U32 }, 293 }; 294 295 static int nft_meta_get_init(const struct nft_ctx *ctx, 296 const struct nft_expr *expr, 297 const struct nlattr * const tb[]) 298 { 299 struct nft_meta *priv = nft_expr_priv(expr); 300 unsigned int len; 301 302 priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); 303 switch (priv->key) { 304 case NFT_META_PROTOCOL: 305 case NFT_META_IIFTYPE: 306 case NFT_META_OIFTYPE: 307 len = sizeof(u16); 308 break; 309 case NFT_META_NFPROTO: 310 case NFT_META_L4PROTO: 311 case NFT_META_LEN: 312 case NFT_META_PRIORITY: 313 case NFT_META_MARK: 314 case NFT_META_IIF: 315 case NFT_META_OIF: 316 case NFT_META_SKUID: 317 case NFT_META_SKGID: 318 #ifdef CONFIG_IP_ROUTE_CLASSID 319 case NFT_META_RTCLASSID: 320 #endif 321 #ifdef CONFIG_NETWORK_SECMARK 322 case NFT_META_SECMARK: 323 #endif 324 case NFT_META_PKTTYPE: 325 case NFT_META_CPU: 326 case NFT_META_IIFGROUP: 327 case NFT_META_OIFGROUP: 328 #ifdef CONFIG_CGROUP_NET_CLASSID 329 case NFT_META_CGROUP: 330 #endif 331 len = sizeof(u32); 332 break; 333 case NFT_META_IIFNAME: 334 case NFT_META_OIFNAME: 335 len = IFNAMSIZ; 336 break; 337 case NFT_META_PRANDOM: 338 prandom_init_once(&nft_prandom_state); 339 len = sizeof(u32); 340 break; 341 #ifdef CONFIG_XFRM 342 case NFT_META_SECPATH: 343 len = sizeof(u8); 344 break; 345 #endif 346 #ifdef CONFIG_NF_TABLES_BRIDGE 347 case NFT_META_BRI_IIFNAME: 348 case NFT_META_BRI_OIFNAME: 349 if (ctx->family != NFPROTO_BRIDGE) 350 return -EOPNOTSUPP; 351 len = IFNAMSIZ; 352 break; 353 #endif 354 default: 355 return -EOPNOTSUPP; 356 } 357 358 priv->dreg = nft_parse_register(tb[NFTA_META_DREG]); 359 return nft_validate_register_store(ctx, priv->dreg, NULL, 360 NFT_DATA_VALUE, len); 361 } 362 363 static int nft_meta_get_validate(const struct nft_ctx *ctx, 364 const struct nft_expr *expr, 365 const struct nft_data **data) 366 { 367 #ifdef CONFIG_XFRM 368 const struct nft_meta *priv = nft_expr_priv(expr); 369 unsigned int hooks; 370 371 if (priv->key != NFT_META_SECPATH) 372 return 0; 373 374 switch (ctx->family) { 375 case NFPROTO_NETDEV: 376 hooks = 1 << NF_NETDEV_INGRESS; 377 break; 378 case NFPROTO_IPV4: 379 case NFPROTO_IPV6: 380 case NFPROTO_INET: 381 hooks = (1 << NF_INET_PRE_ROUTING) | 382 (1 << NF_INET_LOCAL_IN) | 383 (1 << NF_INET_FORWARD); 384 break; 385 default: 386 return -EOPNOTSUPP; 387 } 388 389 return nft_chain_validate_hooks(ctx->chain, hooks); 390 #else 391 return 0; 392 #endif 393 } 394 395 static int nft_meta_set_validate(const struct nft_ctx *ctx, 396 const struct nft_expr *expr, 397 const struct nft_data **data) 398 { 399 struct nft_meta *priv = nft_expr_priv(expr); 400 unsigned int hooks; 401 402 if (priv->key != NFT_META_PKTTYPE) 403 return 0; 404 405 switch (ctx->family) { 406 case NFPROTO_BRIDGE: 407 hooks = 1 << NF_BR_PRE_ROUTING; 408 break; 409 case NFPROTO_NETDEV: 410 hooks = 1 << NF_NETDEV_INGRESS; 411 break; 412 case NFPROTO_IPV4: 413 case NFPROTO_IPV6: 414 case NFPROTO_INET: 415 hooks = 1 << NF_INET_PRE_ROUTING; 416 break; 417 default: 418 return -EOPNOTSUPP; 419 } 420 421 return nft_chain_validate_hooks(ctx->chain, hooks); 422 } 423 424 static int nft_meta_set_init(const struct nft_ctx *ctx, 425 const struct nft_expr *expr, 426 const struct nlattr * const tb[]) 427 { 428 struct nft_meta *priv = nft_expr_priv(expr); 429 unsigned int len; 430 int err; 431 432 priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); 433 switch (priv->key) { 434 case NFT_META_MARK: 435 case NFT_META_PRIORITY: 436 len = sizeof(u32); 437 break; 438 case NFT_META_NFTRACE: 439 len = sizeof(u8); 440 break; 441 case NFT_META_PKTTYPE: 442 len = sizeof(u8); 443 break; 444 default: 445 return -EOPNOTSUPP; 446 } 447 448 priv->sreg = nft_parse_register(tb[NFTA_META_SREG]); 449 err = nft_validate_register_load(priv->sreg, len); 450 if (err < 0) 451 return err; 452 453 if (priv->key == NFT_META_NFTRACE) 454 static_branch_inc(&nft_trace_enabled); 455 456 return 0; 457 } 458 459 static int nft_meta_get_dump(struct sk_buff *skb, 460 const struct nft_expr *expr) 461 { 462 const struct nft_meta *priv = nft_expr_priv(expr); 463 464 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) 465 goto nla_put_failure; 466 if (nft_dump_register(skb, NFTA_META_DREG, priv->dreg)) 467 goto nla_put_failure; 468 return 0; 469 470 nla_put_failure: 471 return -1; 472 } 473 474 static int nft_meta_set_dump(struct sk_buff *skb, const struct nft_expr *expr) 475 { 476 const struct nft_meta *priv = nft_expr_priv(expr); 477 478 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) 479 goto nla_put_failure; 480 if (nft_dump_register(skb, NFTA_META_SREG, priv->sreg)) 481 goto nla_put_failure; 482 483 return 0; 484 485 nla_put_failure: 486 return -1; 487 } 488 489 static void nft_meta_set_destroy(const struct nft_ctx *ctx, 490 const struct nft_expr *expr) 491 { 492 const struct nft_meta *priv = nft_expr_priv(expr); 493 494 if (priv->key == NFT_META_NFTRACE) 495 static_branch_dec(&nft_trace_enabled); 496 } 497 498 static const struct nft_expr_ops nft_meta_get_ops = { 499 .type = &nft_meta_type, 500 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), 501 .eval = nft_meta_get_eval, 502 .init = nft_meta_get_init, 503 .dump = nft_meta_get_dump, 504 .validate = nft_meta_get_validate, 505 }; 506 507 static const struct nft_expr_ops nft_meta_set_ops = { 508 .type = &nft_meta_type, 509 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), 510 .eval = nft_meta_set_eval, 511 .init = nft_meta_set_init, 512 .destroy = nft_meta_set_destroy, 513 .dump = nft_meta_set_dump, 514 .validate = nft_meta_set_validate, 515 }; 516 517 static const struct nft_expr_ops * 518 nft_meta_select_ops(const struct nft_ctx *ctx, 519 const struct nlattr * const tb[]) 520 { 521 if (tb[NFTA_META_KEY] == NULL) 522 return ERR_PTR(-EINVAL); 523 524 if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG]) 525 return ERR_PTR(-EINVAL); 526 527 if (tb[NFTA_META_DREG]) 528 return &nft_meta_get_ops; 529 530 if (tb[NFTA_META_SREG]) 531 return &nft_meta_set_ops; 532 533 return ERR_PTR(-EINVAL); 534 } 535 536 struct nft_expr_type nft_meta_type __read_mostly = { 537 .name = "meta", 538 .select_ops = nft_meta_select_ops, 539 .policy = nft_meta_policy, 540 .maxattr = NFTA_META_MAX, 541 .owner = THIS_MODULE, 542 }; 543
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.