linux/net/netfilter/xt_connbytes.c
<<
>>
Prefs
   1/* Kernel module to match connection tracking byte counter.
   2 * GPL (C) 2002 Martin Devera (devik@cdi.cz).
   3 */
   4#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   5#include <linux/module.h>
   6#include <linux/bitops.h>
   7#include <linux/skbuff.h>
   8#include <linux/math64.h>
   9#include <linux/netfilter/x_tables.h>
  10#include <linux/netfilter/xt_connbytes.h>
  11#include <net/netfilter/nf_conntrack.h>
  12#include <net/netfilter/nf_conntrack_acct.h>
  13
  14MODULE_LICENSE("GPL");
  15MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
  16MODULE_DESCRIPTION("Xtables: Number of packets/bytes per connection matching");
  17MODULE_ALIAS("ipt_connbytes");
  18MODULE_ALIAS("ip6t_connbytes");
  19
  20static bool
  21connbytes_mt(const struct sk_buff *skb, struct xt_action_param *par)
  22{
  23        const struct xt_connbytes_info *sinfo = par->matchinfo;
  24        const struct nf_conn *ct;
  25        enum ip_conntrack_info ctinfo;
  26        u_int64_t what = 0;     /* initialize to make gcc happy */
  27        u_int64_t bytes = 0;
  28        u_int64_t pkts = 0;
  29        const struct nf_conn_counter *counters;
  30
  31        ct = nf_ct_get(skb, &ctinfo);
  32        if (!ct)
  33                return false;
  34
  35        counters = nf_conn_acct_find(ct);
  36        if (!counters)
  37                return false;
  38
  39        switch (sinfo->what) {
  40        case XT_CONNBYTES_PKTS:
  41                switch (sinfo->direction) {
  42                case XT_CONNBYTES_DIR_ORIGINAL:
  43                        what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
  44                        break;
  45                case XT_CONNBYTES_DIR_REPLY:
  46                        what = atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
  47                        break;
  48                case XT_CONNBYTES_DIR_BOTH:
  49                        what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
  50                        what += atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
  51                        break;
  52                }
  53                break;
  54        case XT_CONNBYTES_BYTES:
  55                switch (sinfo->direction) {
  56                case XT_CONNBYTES_DIR_ORIGINAL:
  57                        what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
  58                        break;
  59                case XT_CONNBYTES_DIR_REPLY:
  60                        what = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
  61                        break;
  62                case XT_CONNBYTES_DIR_BOTH:
  63                        what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
  64                        what += atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
  65                        break;
  66                }
  67                break;
  68        case XT_CONNBYTES_AVGPKT:
  69                switch (sinfo->direction) {
  70                case XT_CONNBYTES_DIR_ORIGINAL:
  71                        bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
  72                        pkts  = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
  73                        break;
  74                case XT_CONNBYTES_DIR_REPLY:
  75                        bytes = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
  76                        pkts  = atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
  77                        break;
  78                case XT_CONNBYTES_DIR_BOTH:
  79                        bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes) +
  80                                atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
  81                        pkts  = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets) +
  82                                atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
  83                        break;
  84                }
  85                if (pkts != 0)
  86                        what = div64_u64(bytes, pkts);
  87                break;
  88        }
  89
  90        if (sinfo->count.to >= sinfo->count.from)
  91                return what <= sinfo->count.to && what >= sinfo->count.from;
  92        else /* inverted */
  93                return what < sinfo->count.to || what > sinfo->count.from;
  94}
  95
  96static int connbytes_mt_check(const struct xt_mtchk_param *par)
  97{
  98        const struct xt_connbytes_info *sinfo = par->matchinfo;
  99        int ret;
 100
 101        if (sinfo->what != XT_CONNBYTES_PKTS &&
 102            sinfo->what != XT_CONNBYTES_BYTES &&
 103            sinfo->what != XT_CONNBYTES_AVGPKT)
 104                return -EINVAL;
 105
 106        if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
 107            sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
 108            sinfo->direction != XT_CONNBYTES_DIR_BOTH)
 109                return -EINVAL;
 110
 111        ret = nf_ct_l3proto_try_module_get(par->family);
 112        if (ret < 0)
 113                pr_info("cannot load conntrack support for proto=%u\n",
 114                        par->family);
 115
 116        /*
 117         * This filter cannot function correctly unless connection tracking
 118         * accounting is enabled, so complain in the hope that someone notices.
 119         */
 120        if (!nf_ct_acct_enabled(par->net)) {
 121                pr_warning("Forcing CT accounting to be enabled\n");
 122                nf_ct_set_acct(par->net, true);
 123        }
 124
 125        return ret;
 126}
 127
 128static void connbytes_mt_destroy(const struct xt_mtdtor_param *par)
 129{
 130        nf_ct_l3proto_module_put(par->family);
 131}
 132
 133static struct xt_match connbytes_mt_reg __read_mostly = {
 134        .name       = "connbytes",
 135        .revision   = 0,
 136        .family     = NFPROTO_UNSPEC,
 137        .checkentry = connbytes_mt_check,
 138        .match      = connbytes_mt,
 139        .destroy    = connbytes_mt_destroy,
 140        .matchsize  = sizeof(struct xt_connbytes_info),
 141        .me         = THIS_MODULE,
 142};
 143
 144static int __init connbytes_mt_init(void)
 145{
 146        return xt_register_match(&connbytes_mt_reg);
 147}
 148
 149static void __exit connbytes_mt_exit(void)
 150{
 151        xt_unregister_match(&connbytes_mt_reg);
 152}
 153
 154module_init(connbytes_mt_init);
 155module_exit(connbytes_mt_exit);
 156