Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2016 Pablo Neira Ayuso <pablo@netfilter.org>
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(&regs->data[priv->sreg], &priv->data_from, priv->len);
0030     d2 = memcmp(&regs->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 };