at v2.6.25-rc9 160 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#include <linux/module.h> 5#include <linux/bitops.h> 6#include <linux/skbuff.h> 7#include <linux/netfilter/x_tables.h> 8#include <linux/netfilter/xt_connbytes.h> 9#include <net/netfilter/nf_conntrack.h> 10 11#include <asm/div64.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 net_device *in, 21 const struct net_device *out, const struct xt_match *match, 22 const void *matchinfo, int offset, unsigned int protoff, 23 bool *hotdrop) 24{ 25 const struct xt_connbytes_info *sinfo = matchinfo; 26 const struct nf_conn *ct; 27 enum ip_conntrack_info ctinfo; 28 u_int64_t what = 0; /* initialize to make gcc happy */ 29 u_int64_t bytes = 0; 30 u_int64_t pkts = 0; 31 const struct ip_conntrack_counter *counters; 32 33 ct = nf_ct_get(skb, &ctinfo); 34 if (!ct) 35 return false; 36 counters = ct->counters; 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_64(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 96connbytes_mt_check(const char *tablename, const void *ip, 97 const struct xt_match *match, void *matchinfo, 98 unsigned int hook_mask) 99{ 100 const struct xt_connbytes_info *sinfo = matchinfo; 101 102 if (sinfo->what != XT_CONNBYTES_PKTS && 103 sinfo->what != XT_CONNBYTES_BYTES && 104 sinfo->what != XT_CONNBYTES_AVGPKT) 105 return false; 106 107 if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL && 108 sinfo->direction != XT_CONNBYTES_DIR_REPLY && 109 sinfo->direction != XT_CONNBYTES_DIR_BOTH) 110 return false; 111 112 if (nf_ct_l3proto_try_module_get(match->family) < 0) { 113 printk(KERN_WARNING "can't load conntrack support for " 114 "proto=%u\n", match->family); 115 return false; 116 } 117 118 return true; 119} 120 121static void 122connbytes_mt_destroy(const struct xt_match *match, void *matchinfo) 123{ 124 nf_ct_l3proto_module_put(match->family); 125} 126 127static struct xt_match connbytes_mt_reg[] __read_mostly = { 128 { 129 .name = "connbytes", 130 .family = AF_INET, 131 .checkentry = connbytes_mt_check, 132 .match = connbytes_mt, 133 .destroy = connbytes_mt_destroy, 134 .matchsize = sizeof(struct xt_connbytes_info), 135 .me = THIS_MODULE 136 }, 137 { 138 .name = "connbytes", 139 .family = AF_INET6, 140 .checkentry = connbytes_mt_check, 141 .match = connbytes_mt, 142 .destroy = connbytes_mt_destroy, 143 .matchsize = sizeof(struct xt_connbytes_info), 144 .me = THIS_MODULE 145 }, 146}; 147 148static int __init connbytes_mt_init(void) 149{ 150 return xt_register_matches(connbytes_mt_reg, 151 ARRAY_SIZE(connbytes_mt_reg)); 152} 153 154static void __exit connbytes_mt_exit(void) 155{ 156 xt_unregister_matches(connbytes_mt_reg, ARRAY_SIZE(connbytes_mt_reg)); 157} 158 159module_init(connbytes_mt_init); 160module_exit(connbytes_mt_exit);