linux/net/netfilter/nft_range.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2016 Pablo Neira Ayuso <pablo@netfilter.org>
   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
   9#include <linux/kernel.h>
  10#include <linux/init.h>
  11#include <linux/module.h>
  12#include <linux/netlink.h>
  13#include <linux/netfilter.h>
  14#include <linux/netfilter/nf_tables.h>
  15#include <net/netfilter/nf_tables_core.h>
  16#include <net/netfilter/nf_tables.h>
  17
  18struct nft_range_expr {
  19        struct nft_data         data_from;
  20        struct nft_data         data_to;
  21        enum nft_registers      sreg:8;
  22        u8                      len;
  23        enum nft_range_ops      op:8;
  24};
  25
  26static void nft_range_eval(const struct nft_expr *expr,
  27                         struct nft_regs *regs,
  28                         const struct nft_pktinfo *pkt)
  29{
  30        const struct nft_range_expr *priv = nft_expr_priv(expr);
  31        int d1, d2;
  32
  33        d1 = memcmp(&regs->data[priv->sreg], &priv->data_from, priv->len);
  34        d2 = memcmp(&regs->data[priv->sreg], &priv->data_to, priv->len);
  35        switch (priv->op) {
  36        case NFT_RANGE_EQ:
  37                if (d1 < 0 || d2 > 0)
  38                        regs->verdict.code = NFT_BREAK;
  39                break;
  40        case NFT_RANGE_NEQ:
  41                if (d1 >= 0 && d2 <= 0)
  42                        regs->verdict.code = NFT_BREAK;
  43                break;
  44        }
  45}
  46
  47static const struct nla_policy nft_range_policy[NFTA_RANGE_MAX + 1] = {
  48        [NFTA_RANGE_SREG]               = { .type = NLA_U32 },
  49        [NFTA_RANGE_OP]                 = { .type = NLA_U32 },
  50        [NFTA_RANGE_FROM_DATA]          = { .type = NLA_NESTED },
  51        [NFTA_RANGE_TO_DATA]            = { .type = NLA_NESTED },
  52};
  53
  54static int nft_range_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
  55                        const struct nlattr * const tb[])
  56{
  57        struct nft_range_expr *priv = nft_expr_priv(expr);
  58        struct nft_data_desc desc_from, desc_to;
  59        int err;
  60        u32 op;
  61
  62        if (!tb[NFTA_RANGE_SREG]      ||
  63            !tb[NFTA_RANGE_OP]        ||
  64            !tb[NFTA_RANGE_FROM_DATA] ||
  65            !tb[NFTA_RANGE_TO_DATA])
  66                return -EINVAL;
  67
  68        err = nft_data_init(NULL, &priv->data_from, sizeof(priv->data_from),
  69                            &desc_from, tb[NFTA_RANGE_FROM_DATA]);
  70        if (err < 0)
  71                return err;
  72
  73        err = nft_data_init(NULL, &priv->data_to, sizeof(priv->data_to),
  74                            &desc_to, tb[NFTA_RANGE_TO_DATA]);
  75        if (err < 0)
  76                goto err1;
  77
  78        if (desc_from.len != desc_to.len) {
  79                err = -EINVAL;
  80                goto err2;
  81        }
  82
  83        priv->sreg = nft_parse_register(tb[NFTA_RANGE_SREG]);
  84        err = nft_validate_register_load(priv->sreg, desc_from.len);
  85        if (err < 0)
  86                goto err2;
  87
  88        err = nft_parse_u32_check(tb[NFTA_RANGE_OP], U8_MAX, &op);
  89        if (err < 0)
  90                goto err2;
  91
  92        switch (op) {
  93        case NFT_RANGE_EQ:
  94        case NFT_RANGE_NEQ:
  95                break;
  96        default:
  97                err = -EINVAL;
  98                goto err2;
  99        }
 100
 101        priv->op  = op;
 102        priv->len = desc_from.len;
 103        return 0;
 104err2:
 105        nft_data_uninit(&priv->data_to, desc_to.type);
 106err1:
 107        nft_data_uninit(&priv->data_from, desc_from.type);
 108        return err;
 109}
 110
 111static int nft_range_dump(struct sk_buff *skb, const struct nft_expr *expr)
 112{
 113        const struct nft_range_expr *priv = nft_expr_priv(expr);
 114
 115        if (nft_dump_register(skb, NFTA_RANGE_SREG, priv->sreg))
 116                goto nla_put_failure;
 117        if (nla_put_be32(skb, NFTA_RANGE_OP, htonl(priv->op)))
 118                goto nla_put_failure;
 119
 120        if (nft_data_dump(skb, NFTA_RANGE_FROM_DATA, &priv->data_from,
 121                          NFT_DATA_VALUE, priv->len) < 0 ||
 122            nft_data_dump(skb, NFTA_RANGE_TO_DATA, &priv->data_to,
 123                          NFT_DATA_VALUE, priv->len) < 0)
 124                goto nla_put_failure;
 125        return 0;
 126
 127nla_put_failure:
 128        return -1;
 129}
 130
 131static struct nft_expr_type nft_range_type;
 132static const struct nft_expr_ops nft_range_ops = {
 133        .type           = &nft_range_type,
 134        .size           = NFT_EXPR_SIZE(sizeof(struct nft_range_expr)),
 135        .eval           = nft_range_eval,
 136        .init           = nft_range_init,
 137        .dump           = nft_range_dump,
 138};
 139
 140static struct nft_expr_type nft_range_type __read_mostly = {
 141        .name           = "range",
 142        .ops            = &nft_range_ops,
 143        .policy         = nft_range_policy,
 144        .maxattr        = NFTA_RANGE_MAX,
 145        .owner          = THIS_MODULE,
 146};
 147
 148int __init nft_range_module_init(void)
 149{
 150        return nft_register_expr(&nft_range_type);
 151}
 152
 153void nft_range_module_exit(void)
 154{
 155        nft_unregister_expr(&nft_range_type);
 156}
 157