Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.17-rc7 334 lines 7.9 kB view raw
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 <net/dst.h> 18#include <net/sock.h> 19#include <net/tcp_states.h> /* for TCP_TIME_WAIT */ 20#include <net/netfilter/nf_tables.h> 21#include <net/netfilter/nft_meta.h> 22 23void nft_meta_get_eval(const struct nft_expr *expr, 24 struct nft_data data[NFT_REG_MAX + 1], 25 const struct nft_pktinfo *pkt) 26{ 27 const struct nft_meta *priv = nft_expr_priv(expr); 28 const struct sk_buff *skb = pkt->skb; 29 const struct net_device *in = pkt->in, *out = pkt->out; 30 struct nft_data *dest = &data[priv->dreg]; 31 32 switch (priv->key) { 33 case NFT_META_LEN: 34 dest->data[0] = skb->len; 35 break; 36 case NFT_META_PROTOCOL: 37 *(__be16 *)dest->data = skb->protocol; 38 break; 39 case NFT_META_NFPROTO: 40 dest->data[0] = pkt->ops->pf; 41 break; 42 case NFT_META_L4PROTO: 43 dest->data[0] = pkt->tprot; 44 break; 45 case NFT_META_PRIORITY: 46 dest->data[0] = skb->priority; 47 break; 48 case NFT_META_MARK: 49 dest->data[0] = skb->mark; 50 break; 51 case NFT_META_IIF: 52 if (in == NULL) 53 goto err; 54 dest->data[0] = in->ifindex; 55 break; 56 case NFT_META_OIF: 57 if (out == NULL) 58 goto err; 59 dest->data[0] = out->ifindex; 60 break; 61 case NFT_META_IIFNAME: 62 if (in == NULL) 63 goto err; 64 strncpy((char *)dest->data, in->name, sizeof(dest->data)); 65 break; 66 case NFT_META_OIFNAME: 67 if (out == NULL) 68 goto err; 69 strncpy((char *)dest->data, out->name, sizeof(dest->data)); 70 break; 71 case NFT_META_IIFTYPE: 72 if (in == NULL) 73 goto err; 74 *(u16 *)dest->data = in->type; 75 break; 76 case NFT_META_OIFTYPE: 77 if (out == NULL) 78 goto err; 79 *(u16 *)dest->data = out->type; 80 break; 81 case NFT_META_SKUID: 82 if (skb->sk == NULL || skb->sk->sk_state == TCP_TIME_WAIT) 83 goto err; 84 85 read_lock_bh(&skb->sk->sk_callback_lock); 86 if (skb->sk->sk_socket == NULL || 87 skb->sk->sk_socket->file == NULL) { 88 read_unlock_bh(&skb->sk->sk_callback_lock); 89 goto err; 90 } 91 92 dest->data[0] = 93 from_kuid_munged(&init_user_ns, 94 skb->sk->sk_socket->file->f_cred->fsuid); 95 read_unlock_bh(&skb->sk->sk_callback_lock); 96 break; 97 case NFT_META_SKGID: 98 if (skb->sk == NULL || skb->sk->sk_state == TCP_TIME_WAIT) 99 goto err; 100 101 read_lock_bh(&skb->sk->sk_callback_lock); 102 if (skb->sk->sk_socket == NULL || 103 skb->sk->sk_socket->file == NULL) { 104 read_unlock_bh(&skb->sk->sk_callback_lock); 105 goto err; 106 } 107 dest->data[0] = 108 from_kgid_munged(&init_user_ns, 109 skb->sk->sk_socket->file->f_cred->fsgid); 110 read_unlock_bh(&skb->sk->sk_callback_lock); 111 break; 112#ifdef CONFIG_IP_ROUTE_CLASSID 113 case NFT_META_RTCLASSID: { 114 const struct dst_entry *dst = skb_dst(skb); 115 116 if (dst == NULL) 117 goto err; 118 dest->data[0] = dst->tclassid; 119 break; 120 } 121#endif 122#ifdef CONFIG_NETWORK_SECMARK 123 case NFT_META_SECMARK: 124 dest->data[0] = skb->secmark; 125 break; 126#endif 127 default: 128 WARN_ON(1); 129 goto err; 130 } 131 return; 132 133err: 134 data[NFT_REG_VERDICT].verdict = NFT_BREAK; 135} 136EXPORT_SYMBOL_GPL(nft_meta_get_eval); 137 138void nft_meta_set_eval(const struct nft_expr *expr, 139 struct nft_data data[NFT_REG_MAX + 1], 140 const struct nft_pktinfo *pkt) 141{ 142 const struct nft_meta *meta = nft_expr_priv(expr); 143 struct sk_buff *skb = pkt->skb; 144 u32 value = data[meta->sreg].data[0]; 145 146 switch (meta->key) { 147 case NFT_META_MARK: 148 skb->mark = value; 149 break; 150 case NFT_META_PRIORITY: 151 skb->priority = value; 152 break; 153 case NFT_META_NFTRACE: 154 skb->nf_trace = 1; 155 break; 156 default: 157 WARN_ON(1); 158 } 159} 160EXPORT_SYMBOL_GPL(nft_meta_set_eval); 161 162const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = { 163 [NFTA_META_DREG] = { .type = NLA_U32 }, 164 [NFTA_META_KEY] = { .type = NLA_U32 }, 165 [NFTA_META_SREG] = { .type = NLA_U32 }, 166}; 167EXPORT_SYMBOL_GPL(nft_meta_policy); 168 169int nft_meta_get_init(const struct nft_ctx *ctx, 170 const struct nft_expr *expr, 171 const struct nlattr * const tb[]) 172{ 173 struct nft_meta *priv = nft_expr_priv(expr); 174 int err; 175 176 priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); 177 switch (priv->key) { 178 case NFT_META_LEN: 179 case NFT_META_PROTOCOL: 180 case NFT_META_NFPROTO: 181 case NFT_META_L4PROTO: 182 case NFT_META_PRIORITY: 183 case NFT_META_MARK: 184 case NFT_META_IIF: 185 case NFT_META_OIF: 186 case NFT_META_IIFNAME: 187 case NFT_META_OIFNAME: 188 case NFT_META_IIFTYPE: 189 case NFT_META_OIFTYPE: 190 case NFT_META_SKUID: 191 case NFT_META_SKGID: 192#ifdef CONFIG_IP_ROUTE_CLASSID 193 case NFT_META_RTCLASSID: 194#endif 195#ifdef CONFIG_NETWORK_SECMARK 196 case NFT_META_SECMARK: 197#endif 198 break; 199 default: 200 return -EOPNOTSUPP; 201 } 202 203 priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG])); 204 err = nft_validate_output_register(priv->dreg); 205 if (err < 0) 206 return err; 207 208 err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE); 209 if (err < 0) 210 return err; 211 212 return 0; 213} 214EXPORT_SYMBOL_GPL(nft_meta_get_init); 215 216int nft_meta_set_init(const struct nft_ctx *ctx, 217 const struct nft_expr *expr, 218 const struct nlattr * const tb[]) 219{ 220 struct nft_meta *priv = nft_expr_priv(expr); 221 int err; 222 223 priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); 224 switch (priv->key) { 225 case NFT_META_MARK: 226 case NFT_META_PRIORITY: 227 case NFT_META_NFTRACE: 228 break; 229 default: 230 return -EOPNOTSUPP; 231 } 232 233 priv->sreg = ntohl(nla_get_be32(tb[NFTA_META_SREG])); 234 err = nft_validate_input_register(priv->sreg); 235 if (err < 0) 236 return err; 237 238 return 0; 239} 240EXPORT_SYMBOL_GPL(nft_meta_set_init); 241 242int nft_meta_get_dump(struct sk_buff *skb, 243 const struct nft_expr *expr) 244{ 245 const struct nft_meta *priv = nft_expr_priv(expr); 246 247 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) 248 goto nla_put_failure; 249 if (nla_put_be32(skb, NFTA_META_DREG, htonl(priv->dreg))) 250 goto nla_put_failure; 251 return 0; 252 253nla_put_failure: 254 return -1; 255} 256EXPORT_SYMBOL_GPL(nft_meta_get_dump); 257 258int nft_meta_set_dump(struct sk_buff *skb, 259 const struct nft_expr *expr) 260{ 261 const struct nft_meta *priv = nft_expr_priv(expr); 262 263 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) 264 goto nla_put_failure; 265 if (nla_put_be32(skb, NFTA_META_SREG, htonl(priv->sreg))) 266 goto nla_put_failure; 267 268 return 0; 269 270nla_put_failure: 271 return -1; 272} 273EXPORT_SYMBOL_GPL(nft_meta_set_dump); 274 275static struct nft_expr_type nft_meta_type; 276static const struct nft_expr_ops nft_meta_get_ops = { 277 .type = &nft_meta_type, 278 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), 279 .eval = nft_meta_get_eval, 280 .init = nft_meta_get_init, 281 .dump = nft_meta_get_dump, 282}; 283 284static const struct nft_expr_ops nft_meta_set_ops = { 285 .type = &nft_meta_type, 286 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), 287 .eval = nft_meta_set_eval, 288 .init = nft_meta_set_init, 289 .dump = nft_meta_set_dump, 290}; 291 292static const struct nft_expr_ops * 293nft_meta_select_ops(const struct nft_ctx *ctx, 294 const struct nlattr * const tb[]) 295{ 296 if (tb[NFTA_META_KEY] == NULL) 297 return ERR_PTR(-EINVAL); 298 299 if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG]) 300 return ERR_PTR(-EINVAL); 301 302 if (tb[NFTA_META_DREG]) 303 return &nft_meta_get_ops; 304 305 if (tb[NFTA_META_SREG]) 306 return &nft_meta_set_ops; 307 308 return ERR_PTR(-EINVAL); 309} 310 311static struct nft_expr_type nft_meta_type __read_mostly = { 312 .name = "meta", 313 .select_ops = &nft_meta_select_ops, 314 .policy = nft_meta_policy, 315 .maxattr = NFTA_META_MAX, 316 .owner = THIS_MODULE, 317}; 318 319static int __init nft_meta_module_init(void) 320{ 321 return nft_register_expr(&nft_meta_type); 322} 323 324static void __exit nft_meta_module_exit(void) 325{ 326 nft_unregister_expr(&nft_meta_type); 327} 328 329module_init(nft_meta_module_init); 330module_exit(nft_meta_module_exit); 331 332MODULE_LICENSE("GPL"); 333MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 334MODULE_ALIAS_NFT_EXPR("meta");