at v2.6.20-rc5 191 lines 4.9 kB view raw
1/* Kernel module to match connection tracking byte counter. 2 * GPL (C) 2002 Martin Devera (devik@cdi.cz). 3 * 4 * 2004-07-20 Harald Welte <laforge@netfilter.org> 5 * - reimplemented to use per-connection accounting counters 6 * - add functionality to match number of packets 7 * - add functionality to match average packet size 8 * - add support to match directions seperately 9 * 2005-10-16 Harald Welte <laforge@netfilter.org> 10 * - Port to x_tables 11 * 12 */ 13#include <linux/module.h> 14#include <linux/skbuff.h> 15#include <net/netfilter/nf_conntrack_compat.h> 16#include <linux/netfilter/x_tables.h> 17#include <linux/netfilter/xt_connbytes.h> 18 19#include <asm/div64.h> 20#include <asm/bitops.h> 21 22MODULE_LICENSE("GPL"); 23MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); 24MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection"); 25MODULE_ALIAS("ipt_connbytes"); 26 27/* 64bit divisor, dividend and result. dynamic precision */ 28static u_int64_t div64_64(u_int64_t dividend, u_int64_t divisor) 29{ 30 u_int32_t d = divisor; 31 32 if (divisor > 0xffffffffULL) { 33 unsigned int shift = fls(divisor >> 32); 34 35 d = divisor >> shift; 36 dividend >>= shift; 37 } 38 39 do_div(dividend, d); 40 return dividend; 41} 42 43static int 44match(const struct sk_buff *skb, 45 const struct net_device *in, 46 const struct net_device *out, 47 const struct xt_match *match, 48 const void *matchinfo, 49 int offset, 50 unsigned int protoff, 51 int *hotdrop) 52{ 53 const struct xt_connbytes_info *sinfo = matchinfo; 54 u_int64_t what = 0; /* initialize to make gcc happy */ 55 const struct ip_conntrack_counter *counters; 56 57 if (!(counters = nf_ct_get_counters(skb))) 58 return 0; /* no match */ 59 60 switch (sinfo->what) { 61 case XT_CONNBYTES_PKTS: 62 switch (sinfo->direction) { 63 case XT_CONNBYTES_DIR_ORIGINAL: 64 what = counters[IP_CT_DIR_ORIGINAL].packets; 65 break; 66 case XT_CONNBYTES_DIR_REPLY: 67 what = counters[IP_CT_DIR_REPLY].packets; 68 break; 69 case XT_CONNBYTES_DIR_BOTH: 70 what = counters[IP_CT_DIR_ORIGINAL].packets; 71 what += counters[IP_CT_DIR_REPLY].packets; 72 break; 73 } 74 break; 75 case XT_CONNBYTES_BYTES: 76 switch (sinfo->direction) { 77 case XT_CONNBYTES_DIR_ORIGINAL: 78 what = counters[IP_CT_DIR_ORIGINAL].bytes; 79 break; 80 case XT_CONNBYTES_DIR_REPLY: 81 what = counters[IP_CT_DIR_REPLY].bytes; 82 break; 83 case XT_CONNBYTES_DIR_BOTH: 84 what = counters[IP_CT_DIR_ORIGINAL].bytes; 85 what += counters[IP_CT_DIR_REPLY].bytes; 86 break; 87 } 88 break; 89 case XT_CONNBYTES_AVGPKT: 90 switch (sinfo->direction) { 91 case XT_CONNBYTES_DIR_ORIGINAL: 92 what = div64_64(counters[IP_CT_DIR_ORIGINAL].bytes, 93 counters[IP_CT_DIR_ORIGINAL].packets); 94 break; 95 case XT_CONNBYTES_DIR_REPLY: 96 what = div64_64(counters[IP_CT_DIR_REPLY].bytes, 97 counters[IP_CT_DIR_REPLY].packets); 98 break; 99 case XT_CONNBYTES_DIR_BOTH: 100 { 101 u_int64_t bytes; 102 u_int64_t pkts; 103 bytes = counters[IP_CT_DIR_ORIGINAL].bytes + 104 counters[IP_CT_DIR_REPLY].bytes; 105 pkts = counters[IP_CT_DIR_ORIGINAL].packets+ 106 counters[IP_CT_DIR_REPLY].packets; 107 108 /* FIXME_THEORETICAL: what to do if sum 109 * overflows ? */ 110 111 what = div64_64(bytes, pkts); 112 } 113 break; 114 } 115 break; 116 } 117 118 if (sinfo->count.to) 119 return (what <= sinfo->count.to && what >= sinfo->count.from); 120 else 121 return (what >= sinfo->count.from); 122} 123 124static int check(const char *tablename, 125 const void *ip, 126 const struct xt_match *match, 127 void *matchinfo, 128 unsigned int hook_mask) 129{ 130 const struct xt_connbytes_info *sinfo = matchinfo; 131 132 if (sinfo->what != XT_CONNBYTES_PKTS && 133 sinfo->what != XT_CONNBYTES_BYTES && 134 sinfo->what != XT_CONNBYTES_AVGPKT) 135 return 0; 136 137 if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL && 138 sinfo->direction != XT_CONNBYTES_DIR_REPLY && 139 sinfo->direction != XT_CONNBYTES_DIR_BOTH) 140 return 0; 141 142 if (nf_ct_l3proto_try_module_get(match->family) < 0) { 143 printk(KERN_WARNING "can't load conntrack support for " 144 "proto=%d\n", match->family); 145 return 0; 146 } 147 148 return 1; 149} 150 151static void 152destroy(const struct xt_match *match, void *matchinfo) 153{ 154 nf_ct_l3proto_module_put(match->family); 155} 156 157static struct xt_match xt_connbytes_match[] = { 158 { 159 .name = "connbytes", 160 .family = AF_INET, 161 .checkentry = check, 162 .match = match, 163 .destroy = destroy, 164 .matchsize = sizeof(struct xt_connbytes_info), 165 .me = THIS_MODULE 166 }, 167 { 168 .name = "connbytes", 169 .family = AF_INET6, 170 .checkentry = check, 171 .match = match, 172 .destroy = destroy, 173 .matchsize = sizeof(struct xt_connbytes_info), 174 .me = THIS_MODULE 175 }, 176}; 177 178static int __init xt_connbytes_init(void) 179{ 180 return xt_register_matches(xt_connbytes_match, 181 ARRAY_SIZE(xt_connbytes_match)); 182} 183 184static void __exit xt_connbytes_fini(void) 185{ 186 xt_unregister_matches(xt_connbytes_match, 187 ARRAY_SIZE(xt_connbytes_match)); 188} 189 190module_init(xt_connbytes_init); 191module_exit(xt_connbytes_fini);