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