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_core.h>
0013 #include <net/netfilter/nf_tables.h>
0014
0015 struct nft_range_expr {
0016 struct nft_data data_from;
0017 struct nft_data data_to;
0018 u8 sreg;
0019 u8 len;
0020 enum nft_range_ops op:8;
0021 };
0022
0023 void nft_range_eval(const struct nft_expr *expr,
0024 struct nft_regs *regs, const struct nft_pktinfo *pkt)
0025 {
0026 const struct nft_range_expr *priv = nft_expr_priv(expr);
0027 int d1, d2;
0028
0029 d1 = memcmp(®s->data[priv->sreg], &priv->data_from, priv->len);
0030 d2 = memcmp(®s->data[priv->sreg], &priv->data_to, priv->len);
0031 switch (priv->op) {
0032 case NFT_RANGE_EQ:
0033 if (d1 < 0 || d2 > 0)
0034 regs->verdict.code = NFT_BREAK;
0035 break;
0036 case NFT_RANGE_NEQ:
0037 if (d1 >= 0 && d2 <= 0)
0038 regs->verdict.code = NFT_BREAK;
0039 break;
0040 }
0041 }
0042
0043 static const struct nla_policy nft_range_policy[NFTA_RANGE_MAX + 1] = {
0044 [NFTA_RANGE_SREG] = { .type = NLA_U32 },
0045 [NFTA_RANGE_OP] = { .type = NLA_U32 },
0046 [NFTA_RANGE_FROM_DATA] = { .type = NLA_NESTED },
0047 [NFTA_RANGE_TO_DATA] = { .type = NLA_NESTED },
0048 };
0049
0050 static int nft_range_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
0051 const struct nlattr * const tb[])
0052 {
0053 struct nft_range_expr *priv = nft_expr_priv(expr);
0054 struct nft_data_desc desc_from = {
0055 .type = NFT_DATA_VALUE,
0056 .size = sizeof(priv->data_from),
0057 };
0058 struct nft_data_desc desc_to = {
0059 .type = NFT_DATA_VALUE,
0060 .size = sizeof(priv->data_to),
0061 };
0062 int err;
0063 u32 op;
0064
0065 if (!tb[NFTA_RANGE_SREG] ||
0066 !tb[NFTA_RANGE_OP] ||
0067 !tb[NFTA_RANGE_FROM_DATA] ||
0068 !tb[NFTA_RANGE_TO_DATA])
0069 return -EINVAL;
0070
0071 err = nft_data_init(NULL, &priv->data_from, &desc_from,
0072 tb[NFTA_RANGE_FROM_DATA]);
0073 if (err < 0)
0074 return err;
0075
0076 err = nft_data_init(NULL, &priv->data_to, &desc_to,
0077 tb[NFTA_RANGE_TO_DATA]);
0078 if (err < 0)
0079 goto err1;
0080
0081 if (desc_from.len != desc_to.len) {
0082 err = -EINVAL;
0083 goto err2;
0084 }
0085
0086 err = nft_parse_register_load(tb[NFTA_RANGE_SREG], &priv->sreg,
0087 desc_from.len);
0088 if (err < 0)
0089 goto err2;
0090
0091 err = nft_parse_u32_check(tb[NFTA_RANGE_OP], U8_MAX, &op);
0092 if (err < 0)
0093 goto err2;
0094
0095 switch (op) {
0096 case NFT_RANGE_EQ:
0097 case NFT_RANGE_NEQ:
0098 break;
0099 default:
0100 err = -EINVAL;
0101 goto err2;
0102 }
0103
0104 priv->op = op;
0105 priv->len = desc_from.len;
0106 return 0;
0107 err2:
0108 nft_data_release(&priv->data_to, desc_to.type);
0109 err1:
0110 nft_data_release(&priv->data_from, desc_from.type);
0111 return err;
0112 }
0113
0114 static int nft_range_dump(struct sk_buff *skb, const struct nft_expr *expr)
0115 {
0116 const struct nft_range_expr *priv = nft_expr_priv(expr);
0117
0118 if (nft_dump_register(skb, NFTA_RANGE_SREG, priv->sreg))
0119 goto nla_put_failure;
0120 if (nla_put_be32(skb, NFTA_RANGE_OP, htonl(priv->op)))
0121 goto nla_put_failure;
0122
0123 if (nft_data_dump(skb, NFTA_RANGE_FROM_DATA, &priv->data_from,
0124 NFT_DATA_VALUE, priv->len) < 0 ||
0125 nft_data_dump(skb, NFTA_RANGE_TO_DATA, &priv->data_to,
0126 NFT_DATA_VALUE, priv->len) < 0)
0127 goto nla_put_failure;
0128 return 0;
0129
0130 nla_put_failure:
0131 return -1;
0132 }
0133
0134 static const struct nft_expr_ops nft_range_ops = {
0135 .type = &nft_range_type,
0136 .size = NFT_EXPR_SIZE(sizeof(struct nft_range_expr)),
0137 .eval = nft_range_eval,
0138 .init = nft_range_init,
0139 .dump = nft_range_dump,
0140 .reduce = NFT_REDUCE_READONLY,
0141 };
0142
0143 struct nft_expr_type nft_range_type __read_mostly = {
0144 .name = "range",
0145 .ops = &nft_range_ops,
0146 .policy = nft_range_policy,
0147 .maxattr = NFTA_RANGE_MAX,
0148 .owner = THIS_MODULE,
0149 };