at v3.2 155 lines 4.3 kB view raw
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 = counters[IP_CT_DIR_ORIGINAL].packets; 44 break; 45 case XT_CONNBYTES_DIR_REPLY: 46 what = counters[IP_CT_DIR_REPLY].packets; 47 break; 48 case XT_CONNBYTES_DIR_BOTH: 49 what = counters[IP_CT_DIR_ORIGINAL].packets; 50 what += 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 = counters[IP_CT_DIR_ORIGINAL].bytes; 58 break; 59 case XT_CONNBYTES_DIR_REPLY: 60 what = counters[IP_CT_DIR_REPLY].bytes; 61 break; 62 case XT_CONNBYTES_DIR_BOTH: 63 what = counters[IP_CT_DIR_ORIGINAL].bytes; 64 what += 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 = counters[IP_CT_DIR_ORIGINAL].bytes; 72 pkts = counters[IP_CT_DIR_ORIGINAL].packets; 73 break; 74 case XT_CONNBYTES_DIR_REPLY: 75 bytes = counters[IP_CT_DIR_REPLY].bytes; 76 pkts = counters[IP_CT_DIR_REPLY].packets; 77 break; 78 case XT_CONNBYTES_DIR_BOTH: 79 bytes = counters[IP_CT_DIR_ORIGINAL].bytes + 80 counters[IP_CT_DIR_REPLY].bytes; 81 pkts = counters[IP_CT_DIR_ORIGINAL].packets + 82 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);