Back to home page

OSCL-LXR

 
 

    


0001 /* Kernel module to match connection tracking byte counter.
0002  * GPL (C) 2002 Martin Devera (devik@cdi.cz).
0003  */
0004 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0005 #include <linux/module.h>
0006 #include <linux/bitops.h>
0007 #include <linux/skbuff.h>
0008 #include <linux/math64.h>
0009 #include <linux/netfilter/x_tables.h>
0010 #include <linux/netfilter/xt_connbytes.h>
0011 #include <net/netfilter/nf_conntrack.h>
0012 #include <net/netfilter/nf_conntrack_acct.h>
0013 
0014 MODULE_LICENSE("GPL");
0015 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
0016 MODULE_DESCRIPTION("Xtables: Number of packets/bytes per connection matching");
0017 MODULE_ALIAS("ipt_connbytes");
0018 MODULE_ALIAS("ip6t_connbytes");
0019 
0020 static bool
0021 connbytes_mt(const struct sk_buff *skb, struct xt_action_param *par)
0022 {
0023     const struct xt_connbytes_info *sinfo = par->matchinfo;
0024     const struct nf_conn *ct;
0025     enum ip_conntrack_info ctinfo;
0026     u_int64_t what = 0; /* initialize to make gcc happy */
0027     u_int64_t bytes = 0;
0028     u_int64_t pkts = 0;
0029     const struct nf_conn_acct *acct;
0030     const struct nf_conn_counter *counters;
0031 
0032     ct = nf_ct_get(skb, &ctinfo);
0033     if (!ct)
0034         return false;
0035 
0036     acct = nf_conn_acct_find(ct);
0037     if (!acct)
0038         return false;
0039 
0040     counters = acct->counter;
0041     switch (sinfo->what) {
0042     case XT_CONNBYTES_PKTS:
0043         switch (sinfo->direction) {
0044         case XT_CONNBYTES_DIR_ORIGINAL:
0045             what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
0046             break;
0047         case XT_CONNBYTES_DIR_REPLY:
0048             what = atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
0049             break;
0050         case XT_CONNBYTES_DIR_BOTH:
0051             what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
0052             what += atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
0053             break;
0054         }
0055         break;
0056     case XT_CONNBYTES_BYTES:
0057         switch (sinfo->direction) {
0058         case XT_CONNBYTES_DIR_ORIGINAL:
0059             what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
0060             break;
0061         case XT_CONNBYTES_DIR_REPLY:
0062             what = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
0063             break;
0064         case XT_CONNBYTES_DIR_BOTH:
0065             what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
0066             what += atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
0067             break;
0068         }
0069         break;
0070     case XT_CONNBYTES_AVGPKT:
0071         switch (sinfo->direction) {
0072         case XT_CONNBYTES_DIR_ORIGINAL:
0073             bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
0074             pkts  = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
0075             break;
0076         case XT_CONNBYTES_DIR_REPLY:
0077             bytes = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
0078             pkts  = atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
0079             break;
0080         case XT_CONNBYTES_DIR_BOTH:
0081             bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes) +
0082                 atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
0083             pkts  = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets) +
0084                 atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
0085             break;
0086         }
0087         if (pkts != 0)
0088             what = div64_u64(bytes, pkts);
0089         break;
0090     }
0091 
0092     if (sinfo->count.to >= sinfo->count.from)
0093         return what <= sinfo->count.to && what >= sinfo->count.from;
0094     else /* inverted */
0095         return what < sinfo->count.to || what > sinfo->count.from;
0096 }
0097 
0098 static int connbytes_mt_check(const struct xt_mtchk_param *par)
0099 {
0100     const struct xt_connbytes_info *sinfo = par->matchinfo;
0101     int ret;
0102 
0103     if (sinfo->what != XT_CONNBYTES_PKTS &&
0104         sinfo->what != XT_CONNBYTES_BYTES &&
0105         sinfo->what != XT_CONNBYTES_AVGPKT)
0106         return -EINVAL;
0107 
0108     if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
0109         sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
0110         sinfo->direction != XT_CONNBYTES_DIR_BOTH)
0111         return -EINVAL;
0112 
0113     ret = nf_ct_netns_get(par->net, par->family);
0114     if (ret < 0)
0115         pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
0116                     par->family);
0117 
0118     /*
0119      * This filter cannot function correctly unless connection tracking
0120      * accounting is enabled, so complain in the hope that someone notices.
0121      */
0122     if (!nf_ct_acct_enabled(par->net)) {
0123         pr_warn("Forcing CT accounting to be enabled\n");
0124         nf_ct_set_acct(par->net, true);
0125     }
0126 
0127     return ret;
0128 }
0129 
0130 static void connbytes_mt_destroy(const struct xt_mtdtor_param *par)
0131 {
0132     nf_ct_netns_put(par->net, par->family);
0133 }
0134 
0135 static struct xt_match connbytes_mt_reg __read_mostly = {
0136     .name       = "connbytes",
0137     .revision   = 0,
0138     .family     = NFPROTO_UNSPEC,
0139     .checkentry = connbytes_mt_check,
0140     .match      = connbytes_mt,
0141     .destroy    = connbytes_mt_destroy,
0142     .matchsize  = sizeof(struct xt_connbytes_info),
0143     .me         = THIS_MODULE,
0144 };
0145 
0146 static int __init connbytes_mt_init(void)
0147 {
0148     return xt_register_match(&connbytes_mt_reg);
0149 }
0150 
0151 static void __exit connbytes_mt_exit(void)
0152 {
0153     xt_unregister_match(&connbytes_mt_reg);
0154 }
0155 
0156 module_init(connbytes_mt_init);
0157 module_exit(connbytes_mt_exit);