0001
0002
0003
0004
0005
0006 #include <linux/kernel.h>
0007 #include <linux/init.h>
0008 #include <linux/module.h>
0009 #include <linux/netlink.h>
0010 #include <linux/netfilter.h>
0011 #include <linux/netfilter/nf_tables.h>
0012 #include <net/netfilter/nf_tables.h>
0013 #include <net/netfilter/nf_tables_core.h>
0014 #include <linux/jhash.h>
0015
0016 struct nft_jhash {
0017 u8 sreg;
0018 u8 dreg;
0019 u8 len;
0020 bool autogen_seed:1;
0021 u32 modulus;
0022 u32 seed;
0023 u32 offset;
0024 };
0025
0026 static void nft_jhash_eval(const struct nft_expr *expr,
0027 struct nft_regs *regs,
0028 const struct nft_pktinfo *pkt)
0029 {
0030 struct nft_jhash *priv = nft_expr_priv(expr);
0031 const void *data = ®s->data[priv->sreg];
0032 u32 h;
0033
0034 h = reciprocal_scale(jhash(data, priv->len, priv->seed),
0035 priv->modulus);
0036
0037 regs->data[priv->dreg] = h + priv->offset;
0038 }
0039
0040 struct nft_symhash {
0041 u8 dreg;
0042 u32 modulus;
0043 u32 offset;
0044 };
0045
0046 static void nft_symhash_eval(const struct nft_expr *expr,
0047 struct nft_regs *regs,
0048 const struct nft_pktinfo *pkt)
0049 {
0050 struct nft_symhash *priv = nft_expr_priv(expr);
0051 struct sk_buff *skb = pkt->skb;
0052 u32 h;
0053
0054 h = reciprocal_scale(__skb_get_hash_symmetric(skb), priv->modulus);
0055
0056 regs->data[priv->dreg] = h + priv->offset;
0057 }
0058
0059 static const struct nla_policy nft_hash_policy[NFTA_HASH_MAX + 1] = {
0060 [NFTA_HASH_SREG] = { .type = NLA_U32 },
0061 [NFTA_HASH_DREG] = { .type = NLA_U32 },
0062 [NFTA_HASH_LEN] = { .type = NLA_U32 },
0063 [NFTA_HASH_MODULUS] = { .type = NLA_U32 },
0064 [NFTA_HASH_SEED] = { .type = NLA_U32 },
0065 [NFTA_HASH_OFFSET] = { .type = NLA_U32 },
0066 [NFTA_HASH_TYPE] = { .type = NLA_U32 },
0067 };
0068
0069 static int nft_jhash_init(const struct nft_ctx *ctx,
0070 const struct nft_expr *expr,
0071 const struct nlattr * const tb[])
0072 {
0073 struct nft_jhash *priv = nft_expr_priv(expr);
0074 u32 len;
0075 int err;
0076
0077 if (!tb[NFTA_HASH_SREG] ||
0078 !tb[NFTA_HASH_DREG] ||
0079 !tb[NFTA_HASH_LEN] ||
0080 !tb[NFTA_HASH_MODULUS])
0081 return -EINVAL;
0082
0083 if (tb[NFTA_HASH_OFFSET])
0084 priv->offset = ntohl(nla_get_be32(tb[NFTA_HASH_OFFSET]));
0085
0086 err = nft_parse_u32_check(tb[NFTA_HASH_LEN], U8_MAX, &len);
0087 if (err < 0)
0088 return err;
0089 if (len == 0)
0090 return -ERANGE;
0091
0092 priv->len = len;
0093
0094 err = nft_parse_register_load(tb[NFTA_HASH_SREG], &priv->sreg, len);
0095 if (err < 0)
0096 return err;
0097
0098 priv->modulus = ntohl(nla_get_be32(tb[NFTA_HASH_MODULUS]));
0099 if (priv->modulus < 1)
0100 return -ERANGE;
0101
0102 if (priv->offset + priv->modulus - 1 < priv->offset)
0103 return -EOVERFLOW;
0104
0105 if (tb[NFTA_HASH_SEED]) {
0106 priv->seed = ntohl(nla_get_be32(tb[NFTA_HASH_SEED]));
0107 } else {
0108 priv->autogen_seed = true;
0109 get_random_bytes(&priv->seed, sizeof(priv->seed));
0110 }
0111
0112 return nft_parse_register_store(ctx, tb[NFTA_HASH_DREG], &priv->dreg,
0113 NULL, NFT_DATA_VALUE, sizeof(u32));
0114 }
0115
0116 static int nft_symhash_init(const struct nft_ctx *ctx,
0117 const struct nft_expr *expr,
0118 const struct nlattr * const tb[])
0119 {
0120 struct nft_symhash *priv = nft_expr_priv(expr);
0121
0122 if (!tb[NFTA_HASH_DREG] ||
0123 !tb[NFTA_HASH_MODULUS])
0124 return -EINVAL;
0125
0126 if (tb[NFTA_HASH_OFFSET])
0127 priv->offset = ntohl(nla_get_be32(tb[NFTA_HASH_OFFSET]));
0128
0129 priv->modulus = ntohl(nla_get_be32(tb[NFTA_HASH_MODULUS]));
0130 if (priv->modulus < 1)
0131 return -ERANGE;
0132
0133 if (priv->offset + priv->modulus - 1 < priv->offset)
0134 return -EOVERFLOW;
0135
0136 return nft_parse_register_store(ctx, tb[NFTA_HASH_DREG],
0137 &priv->dreg, NULL, NFT_DATA_VALUE,
0138 sizeof(u32));
0139 }
0140
0141 static int nft_jhash_dump(struct sk_buff *skb,
0142 const struct nft_expr *expr)
0143 {
0144 const struct nft_jhash *priv = nft_expr_priv(expr);
0145
0146 if (nft_dump_register(skb, NFTA_HASH_SREG, priv->sreg))
0147 goto nla_put_failure;
0148 if (nft_dump_register(skb, NFTA_HASH_DREG, priv->dreg))
0149 goto nla_put_failure;
0150 if (nla_put_be32(skb, NFTA_HASH_LEN, htonl(priv->len)))
0151 goto nla_put_failure;
0152 if (nla_put_be32(skb, NFTA_HASH_MODULUS, htonl(priv->modulus)))
0153 goto nla_put_failure;
0154 if (!priv->autogen_seed &&
0155 nla_put_be32(skb, NFTA_HASH_SEED, htonl(priv->seed)))
0156 goto nla_put_failure;
0157 if (priv->offset != 0)
0158 if (nla_put_be32(skb, NFTA_HASH_OFFSET, htonl(priv->offset)))
0159 goto nla_put_failure;
0160 if (nla_put_be32(skb, NFTA_HASH_TYPE, htonl(NFT_HASH_JENKINS)))
0161 goto nla_put_failure;
0162 return 0;
0163
0164 nla_put_failure:
0165 return -1;
0166 }
0167
0168 static bool nft_jhash_reduce(struct nft_regs_track *track,
0169 const struct nft_expr *expr)
0170 {
0171 const struct nft_jhash *priv = nft_expr_priv(expr);
0172
0173 nft_reg_track_cancel(track, priv->dreg, sizeof(u32));
0174
0175 return false;
0176 }
0177
0178 static int nft_symhash_dump(struct sk_buff *skb,
0179 const struct nft_expr *expr)
0180 {
0181 const struct nft_symhash *priv = nft_expr_priv(expr);
0182
0183 if (nft_dump_register(skb, NFTA_HASH_DREG, priv->dreg))
0184 goto nla_put_failure;
0185 if (nla_put_be32(skb, NFTA_HASH_MODULUS, htonl(priv->modulus)))
0186 goto nla_put_failure;
0187 if (priv->offset != 0)
0188 if (nla_put_be32(skb, NFTA_HASH_OFFSET, htonl(priv->offset)))
0189 goto nla_put_failure;
0190 if (nla_put_be32(skb, NFTA_HASH_TYPE, htonl(NFT_HASH_SYM)))
0191 goto nla_put_failure;
0192 return 0;
0193
0194 nla_put_failure:
0195 return -1;
0196 }
0197
0198 static bool nft_symhash_reduce(struct nft_regs_track *track,
0199 const struct nft_expr *expr)
0200 {
0201 struct nft_symhash *priv = nft_expr_priv(expr);
0202 struct nft_symhash *symhash;
0203
0204 if (!nft_reg_track_cmp(track, expr, priv->dreg)) {
0205 nft_reg_track_update(track, expr, priv->dreg, sizeof(u32));
0206 return false;
0207 }
0208
0209 symhash = nft_expr_priv(track->regs[priv->dreg].selector);
0210 if (priv->offset != symhash->offset ||
0211 priv->modulus != symhash->modulus) {
0212 nft_reg_track_update(track, expr, priv->dreg, sizeof(u32));
0213 return false;
0214 }
0215
0216 if (!track->regs[priv->dreg].bitwise)
0217 return true;
0218
0219 return false;
0220 }
0221
0222 static struct nft_expr_type nft_hash_type;
0223 static const struct nft_expr_ops nft_jhash_ops = {
0224 .type = &nft_hash_type,
0225 .size = NFT_EXPR_SIZE(sizeof(struct nft_jhash)),
0226 .eval = nft_jhash_eval,
0227 .init = nft_jhash_init,
0228 .dump = nft_jhash_dump,
0229 .reduce = nft_jhash_reduce,
0230 };
0231
0232 static const struct nft_expr_ops nft_symhash_ops = {
0233 .type = &nft_hash_type,
0234 .size = NFT_EXPR_SIZE(sizeof(struct nft_symhash)),
0235 .eval = nft_symhash_eval,
0236 .init = nft_symhash_init,
0237 .dump = nft_symhash_dump,
0238 .reduce = nft_symhash_reduce,
0239 };
0240
0241 static const struct nft_expr_ops *
0242 nft_hash_select_ops(const struct nft_ctx *ctx,
0243 const struct nlattr * const tb[])
0244 {
0245 u32 type;
0246
0247 if (!tb[NFTA_HASH_TYPE])
0248 return &nft_jhash_ops;
0249
0250 type = ntohl(nla_get_be32(tb[NFTA_HASH_TYPE]));
0251 switch (type) {
0252 case NFT_HASH_SYM:
0253 return &nft_symhash_ops;
0254 case NFT_HASH_JENKINS:
0255 return &nft_jhash_ops;
0256 default:
0257 break;
0258 }
0259 return ERR_PTR(-EOPNOTSUPP);
0260 }
0261
0262 static struct nft_expr_type nft_hash_type __read_mostly = {
0263 .name = "hash",
0264 .select_ops = nft_hash_select_ops,
0265 .policy = nft_hash_policy,
0266 .maxattr = NFTA_HASH_MAX,
0267 .owner = THIS_MODULE,
0268 };
0269
0270 static int __init nft_hash_module_init(void)
0271 {
0272 return nft_register_expr(&nft_hash_type);
0273 }
0274
0275 static void __exit nft_hash_module_exit(void)
0276 {
0277 nft_unregister_expr(&nft_hash_type);
0278 }
0279
0280 module_init(nft_hash_module_init);
0281 module_exit(nft_hash_module_exit);
0282
0283 MODULE_LICENSE("GPL");
0284 MODULE_AUTHOR("Laura Garcia <nevola@gmail.com>");
0285 MODULE_ALIAS_NFT_EXPR("hash");
0286 MODULE_DESCRIPTION("Netfilter nftables hash module");