1 /* 2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net> 3 * 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. 7 * 8 * Development of this code funded by Astaro AG (http://www.astaro.com/) 9 */ 10 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/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 #include <net/netfilter/nft_meta.h> 28 29 #include <uapi/linux/netfilter_bridge.h> /* NF_BR_PRE_ROUTING */ 30 31 static DEFINE_PER_CPU(struct rnd_state, nft_prandom_state); 32 33 void nft_meta_get_eval(const struct nft_expr *expr, 34 struct nft_regs *regs, 35 const struct nft_pktinfo *pkt) 36 { 37 const struct nft_meta *priv = nft_expr_priv(expr); 38 const struct sk_buff *skb = pkt->skb; 39 const struct net_device *in = pkt->in, *out = pkt->out; 40 struct sock *sk; 41 u32 *dest = ®s->data[priv->dreg]; 42 43 switch (priv->key) { 44 case NFT_META_LEN: 45 *dest = skb->len; 46 break; 47 case NFT_META_PROTOCOL: 48 *dest = 0; 49 *(__be16 *)dest = skb->protocol; 50 break; 51 case NFT_META_NFPROTO: 52 *dest = pkt->pf; 53 break; 54 case NFT_META_L4PROTO: 55 *dest = pkt->tprot; 56 break; 57 case NFT_META_PRIORITY: 58 *dest = skb->priority; 59 break; 60 case NFT_META_MARK: 61 *dest = skb->mark; 62 break; 63 case NFT_META_IIF: 64 if (in == NULL) 65 goto err; 66 *dest = in->ifindex; 67 break; 68 case NFT_META_OIF: 69 if (out == NULL) 70 goto err; 71 *dest = out->ifindex; 72 break; 73 case NFT_META_IIFNAME: 74 if (in == NULL) 75 goto err; 76 strncpy((char *)dest, in->name, IFNAMSIZ); 77 break; 78 case NFT_META_OIFNAME: 79 if (out == NULL) 80 goto err; 81 strncpy((char *)dest, out->name, IFNAMSIZ); 82 break; 83 case NFT_META_IIFTYPE: 84 if (in == NULL) 85 goto err; 86 *dest = 0; 87 *(u16 *)dest = in->type; 88 break; 89 case NFT_META_OIFTYPE: 90 if (out == NULL) 91 goto err; 92 *dest = 0; 93 *(u16 *)dest = out->type; 94 break; 95 case NFT_META_SKUID: 96 sk = skb_to_full_sk(skb); 97 if (!sk || !sk_fullsock(sk)) 98 goto err; 99 100 read_lock_bh(&sk->sk_callback_lock); 101 if (sk->sk_socket == NULL || 102 sk->sk_socket->file == NULL) { 103 read_unlock_bh(&sk->sk_callback_lock); 104 goto err; 105 } 106 107 *dest = from_kuid_munged(&init_user_ns, 108 sk->sk_socket->file->f_cred->fsuid); 109 read_unlock_bh(&sk->sk_callback_lock); 110 break; 111 case NFT_META_SKGID: 112 sk = skb_to_full_sk(skb); 113 if (!sk || !sk_fullsock(sk)) 114 goto err; 115 116 read_lock_bh(&sk->sk_callback_lock); 117 if (sk->sk_socket == NULL || 118 sk->sk_socket->file == NULL) { 119 read_unlock_bh(&sk->sk_callback_lock); 120 goto err; 121 } 122 *dest = from_kgid_munged(&init_user_ns, 123 sk->sk_socket->file->f_cred->fsgid); 124 read_unlock_bh(&sk->sk_callback_lock); 125 break; 126 #ifdef CONFIG_IP_ROUTE_CLASSID 127 case NFT_META_RTCLASSID: { 128 const struct dst_entry *dst = skb_dst(skb); 129 130 if (dst == NULL) 131 goto err; 132 *dest = dst->tclassid; 133 break; 134 } 135 #endif 136 #ifdef CONFIG_NETWORK_SECMARK 137 case NFT_META_SECMARK: 138 *dest = skb->secmark; 139 break; 140 #endif 141 case NFT_META_PKTTYPE: 142 if (skb->pkt_type != PACKET_LOOPBACK) { 143 *dest = skb->pkt_type; 144 break; 145 } 146 147 switch (pkt->pf) { 148 case NFPROTO_IPV4: 149 if (ipv4_is_multicast(ip_hdr(skb)->daddr)) 150 *dest = PACKET_MULTICAST; 151 else 152 *dest = PACKET_BROADCAST; 153 break; 154 case NFPROTO_IPV6: 155 if (ipv6_hdr(skb)->daddr.s6_addr[0] == 0xFF) 156 *dest = PACKET_MULTICAST; 157 else 158 *dest = PACKET_BROADCAST; 159 break; 160 default: 161 WARN_ON(1); 162 goto err; 163 } 164 break; 165 case NFT_META_CPU: 166 *dest = raw_smp_processor_id(); 167 break; 168 case NFT_META_IIFGROUP: 169 if (in == NULL) 170 goto err; 171 *dest = in->group; 172 break; 173 case NFT_META_OIFGROUP: 174 if (out == NULL) 175 goto err; 176 *dest = out->group; 177 break; 178 #ifdef CONFIG_CGROUP_NET_CLASSID 179 case NFT_META_CGROUP: 180 sk = skb_to_full_sk(skb); 181 if (!sk || !sk_fullsock(sk)) 182 goto err; 183 *dest = sock_cgroup_classid(&sk->sk_cgrp_data); 184 break; 185 #endif 186 case NFT_META_PRANDOM: { 187 struct rnd_state *state = this_cpu_ptr(&nft_prandom_state); 188 *dest = prandom_u32_state(state); 189 break; 190 } 191 default: 192 WARN_ON(1); 193 goto err; 194 } 195 return; 196 197 err: 198 regs->verdict.code = NFT_BREAK; 199 } 200 EXPORT_SYMBOL_GPL(nft_meta_get_eval); 201 202 /* don't change or set _LOOPBACK, _USER, etc. */ 203 static bool pkt_type_ok(u32 p) 204 { 205 return p == PACKET_HOST || p == PACKET_BROADCAST || 206 p == PACKET_MULTICAST || p == PACKET_OTHERHOST; 207 } 208 209 void nft_meta_set_eval(const struct nft_expr *expr, 210 struct nft_regs *regs, 211 const struct nft_pktinfo *pkt) 212 { 213 const struct nft_meta *meta = nft_expr_priv(expr); 214 struct sk_buff *skb = pkt->skb; 215 u32 value = regs->data[meta->sreg]; 216 217 switch (meta->key) { 218 case NFT_META_MARK: 219 skb->mark = value; 220 break; 221 case NFT_META_PRIORITY: 222 skb->priority = value; 223 break; 224 case NFT_META_PKTTYPE: 225 if (skb->pkt_type != value && 226 pkt_type_ok(value) && pkt_type_ok(skb->pkt_type)) 227 skb->pkt_type = value; 228 break; 229 case NFT_META_NFTRACE: 230 skb->nf_trace = 1; 231 break; 232 default: 233 WARN_ON(1); 234 } 235 } 236 EXPORT_SYMBOL_GPL(nft_meta_set_eval); 237 238 const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = { 239 [NFTA_META_DREG] = { .type = NLA_U32 }, 240 [NFTA_META_KEY] = { .type = NLA_U32 }, 241 [NFTA_META_SREG] = { .type = NLA_U32 }, 242 }; 243 EXPORT_SYMBOL_GPL(nft_meta_policy); 244 245 int nft_meta_get_init(const struct nft_ctx *ctx, 246 const struct nft_expr *expr, 247 const struct nlattr * const tb[]) 248 { 249 struct nft_meta *priv = nft_expr_priv(expr); 250 unsigned int len; 251 252 priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); 253 switch (priv->key) { 254 case NFT_META_PROTOCOL: 255 case NFT_META_IIFTYPE: 256 case NFT_META_OIFTYPE: 257 len = sizeof(u16); 258 break; 259 case NFT_META_NFPROTO: 260 case NFT_META_L4PROTO: 261 case NFT_META_LEN: 262 case NFT_META_PRIORITY: 263 case NFT_META_MARK: 264 case NFT_META_IIF: 265 case NFT_META_OIF: 266 case NFT_META_SKUID: 267 case NFT_META_SKGID: 268 #ifdef CONFIG_IP_ROUTE_CLASSID 269 case NFT_META_RTCLASSID: 270 #endif 271 #ifdef CONFIG_NETWORK_SECMARK 272 case NFT_META_SECMARK: 273 #endif 274 case NFT_META_PKTTYPE: 275 case NFT_META_CPU: 276 case NFT_META_IIFGROUP: 277 case NFT_META_OIFGROUP: 278 #ifdef CONFIG_CGROUP_NET_CLASSID 279 case NFT_META_CGROUP: 280 #endif 281 len = sizeof(u32); 282 break; 283 case NFT_META_IIFNAME: 284 case NFT_META_OIFNAME: 285 len = IFNAMSIZ; 286 break; 287 case NFT_META_PRANDOM: 288 prandom_init_once(&nft_prandom_state); 289 len = sizeof(u32); 290 break; 291 default: 292 return -EOPNOTSUPP; 293 } 294 295 priv->dreg = nft_parse_register(tb[NFTA_META_DREG]); 296 return nft_validate_register_store(ctx, priv->dreg, NULL, 297 NFT_DATA_VALUE, len); 298 } 299 EXPORT_SYMBOL_GPL(nft_meta_get_init); 300 301 static int nft_meta_set_init_pkttype(const struct nft_ctx *ctx) 302 { 303 unsigned int hooks; 304 305 switch (ctx->afi->family) { 306 case NFPROTO_BRIDGE: 307 hooks = 1 << NF_BR_PRE_ROUTING; 308 break; 309 case NFPROTO_NETDEV: 310 hooks = 1 << NF_NETDEV_INGRESS; 311 break; 312 default: 313 return -EOPNOTSUPP; 314 } 315 316 return nft_chain_validate_hooks(ctx->chain, hooks); 317 } 318 319 int nft_meta_set_init(const struct nft_ctx *ctx, 320 const struct nft_expr *expr, 321 const struct nlattr * const tb[]) 322 { 323 struct nft_meta *priv = nft_expr_priv(expr); 324 unsigned int len; 325 int err; 326 327 priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); 328 switch (priv->key) { 329 case NFT_META_MARK: 330 case NFT_META_PRIORITY: 331 len = sizeof(u32); 332 break; 333 case NFT_META_NFTRACE: 334 len = sizeof(u8); 335 break; 336 case NFT_META_PKTTYPE: 337 err = nft_meta_set_init_pkttype(ctx); 338 if (err) 339 return err; 340 len = sizeof(u8); 341 break; 342 default: 343 return -EOPNOTSUPP; 344 } 345 346 priv->sreg = nft_parse_register(tb[NFTA_META_SREG]); 347 err = nft_validate_register_load(priv->sreg, len); 348 if (err < 0) 349 return err; 350 351 if (priv->key == NFT_META_NFTRACE) 352 static_branch_inc(&nft_trace_enabled); 353 354 return 0; 355 } 356 EXPORT_SYMBOL_GPL(nft_meta_set_init); 357 358 int nft_meta_get_dump(struct sk_buff *skb, 359 const struct nft_expr *expr) 360 { 361 const struct nft_meta *priv = nft_expr_priv(expr); 362 363 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) 364 goto nla_put_failure; 365 if (nft_dump_register(skb, NFTA_META_DREG, priv->dreg)) 366 goto nla_put_failure; 367 return 0; 368 369 nla_put_failure: 370 return -1; 371 } 372 EXPORT_SYMBOL_GPL(nft_meta_get_dump); 373 374 int nft_meta_set_dump(struct sk_buff *skb, 375 const struct nft_expr *expr) 376 { 377 const struct nft_meta *priv = nft_expr_priv(expr); 378 379 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) 380 goto nla_put_failure; 381 if (nft_dump_register(skb, NFTA_META_SREG, priv->sreg)) 382 goto nla_put_failure; 383 384 return 0; 385 386 nla_put_failure: 387 return -1; 388 } 389 EXPORT_SYMBOL_GPL(nft_meta_set_dump); 390 391 void nft_meta_set_destroy(const struct nft_ctx *ctx, 392 const struct nft_expr *expr) 393 { 394 const struct nft_meta *priv = nft_expr_priv(expr); 395 396 if (priv->key == NFT_META_NFTRACE) 397 static_branch_dec(&nft_trace_enabled); 398 } 399 EXPORT_SYMBOL_GPL(nft_meta_set_destroy); 400 401 static struct nft_expr_type nft_meta_type; 402 static const struct nft_expr_ops nft_meta_get_ops = { 403 .type = &nft_meta_type, 404 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), 405 .eval = nft_meta_get_eval, 406 .init = nft_meta_get_init, 407 .dump = nft_meta_get_dump, 408 }; 409 410 static const struct nft_expr_ops nft_meta_set_ops = { 411 .type = &nft_meta_type, 412 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), 413 .eval = nft_meta_set_eval, 414 .init = nft_meta_set_init, 415 .destroy = nft_meta_set_destroy, 416 .dump = nft_meta_set_dump, 417 }; 418 419 static const struct nft_expr_ops * 420 nft_meta_select_ops(const struct nft_ctx *ctx, 421 const struct nlattr * const tb[]) 422 { 423 if (tb[NFTA_META_KEY] == NULL) 424 return ERR_PTR(-EINVAL); 425 426 if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG]) 427 return ERR_PTR(-EINVAL); 428 429 if (tb[NFTA_META_DREG]) 430 return &nft_meta_get_ops; 431 432 if (tb[NFTA_META_SREG]) 433 return &nft_meta_set_ops; 434 435 return ERR_PTR(-EINVAL); 436 } 437 438 static struct nft_expr_type nft_meta_type __read_mostly = { 439 .name = "meta", 440 .select_ops = &nft_meta_select_ops, 441 .policy = nft_meta_policy, 442 .maxattr = NFTA_META_MAX, 443 .owner = THIS_MODULE, 444 }; 445 446 static int __init nft_meta_module_init(void) 447 { 448 return nft_register_expr(&nft_meta_type); 449 } 450 451 static void __exit nft_meta_module_exit(void) 452 { 453 nft_unregister_expr(&nft_meta_type); 454 } 455 456 module_init(nft_meta_module_init); 457 module_exit(nft_meta_module_exit); 458 459 MODULE_LICENSE("GPL"); 460 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 461 MODULE_ALIAS_NFT_EXPR("meta"); 462