at v2.6.16-rc5 180 lines 4.5 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 void *matchinfo, 48 int offset, 49 unsigned int protoff, 50 int *hotdrop) 51{ 52 const struct xt_connbytes_info *sinfo = matchinfo; 53 u_int64_t what = 0; /* initialize to make gcc happy */ 54 const struct ip_conntrack_counter *counters; 55 56 if (!(counters = nf_ct_get_counters(skb))) 57 return 0; /* no match */ 58 59 switch (sinfo->what) { 60 case XT_CONNBYTES_PKTS: 61 switch (sinfo->direction) { 62 case XT_CONNBYTES_DIR_ORIGINAL: 63 what = counters[IP_CT_DIR_ORIGINAL].packets; 64 break; 65 case XT_CONNBYTES_DIR_REPLY: 66 what = counters[IP_CT_DIR_REPLY].packets; 67 break; 68 case XT_CONNBYTES_DIR_BOTH: 69 what = counters[IP_CT_DIR_ORIGINAL].packets; 70 what += counters[IP_CT_DIR_REPLY].packets; 71 break; 72 } 73 break; 74 case XT_CONNBYTES_BYTES: 75 switch (sinfo->direction) { 76 case XT_CONNBYTES_DIR_ORIGINAL: 77 what = counters[IP_CT_DIR_ORIGINAL].bytes; 78 break; 79 case XT_CONNBYTES_DIR_REPLY: 80 what = counters[IP_CT_DIR_REPLY].bytes; 81 break; 82 case XT_CONNBYTES_DIR_BOTH: 83 what = counters[IP_CT_DIR_ORIGINAL].bytes; 84 what += counters[IP_CT_DIR_REPLY].bytes; 85 break; 86 } 87 break; 88 case XT_CONNBYTES_AVGPKT: 89 switch (sinfo->direction) { 90 case XT_CONNBYTES_DIR_ORIGINAL: 91 what = div64_64(counters[IP_CT_DIR_ORIGINAL].bytes, 92 counters[IP_CT_DIR_ORIGINAL].packets); 93 break; 94 case XT_CONNBYTES_DIR_REPLY: 95 what = div64_64(counters[IP_CT_DIR_REPLY].bytes, 96 counters[IP_CT_DIR_REPLY].packets); 97 break; 98 case XT_CONNBYTES_DIR_BOTH: 99 { 100 u_int64_t bytes; 101 u_int64_t pkts; 102 bytes = counters[IP_CT_DIR_ORIGINAL].bytes + 103 counters[IP_CT_DIR_REPLY].bytes; 104 pkts = counters[IP_CT_DIR_ORIGINAL].packets+ 105 counters[IP_CT_DIR_REPLY].packets; 106 107 /* FIXME_THEORETICAL: what to do if sum 108 * overflows ? */ 109 110 what = div64_64(bytes, pkts); 111 } 112 break; 113 } 114 break; 115 } 116 117 if (sinfo->count.to) 118 return (what <= sinfo->count.to && what >= sinfo->count.from); 119 else 120 return (what >= sinfo->count.from); 121} 122 123static int check(const char *tablename, 124 const void *ip, 125 void *matchinfo, 126 unsigned int matchsize, 127 unsigned int hook_mask) 128{ 129 const struct xt_connbytes_info *sinfo = matchinfo; 130 131 if (matchsize != XT_ALIGN(sizeof(struct xt_connbytes_info))) 132 return 0; 133 134 if (sinfo->what != XT_CONNBYTES_PKTS && 135 sinfo->what != XT_CONNBYTES_BYTES && 136 sinfo->what != XT_CONNBYTES_AVGPKT) 137 return 0; 138 139 if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL && 140 sinfo->direction != XT_CONNBYTES_DIR_REPLY && 141 sinfo->direction != XT_CONNBYTES_DIR_BOTH) 142 return 0; 143 144 return 1; 145} 146 147static struct xt_match connbytes_match = { 148 .name = "connbytes", 149 .match = &match, 150 .checkentry = &check, 151 .me = THIS_MODULE 152}; 153static struct xt_match connbytes6_match = { 154 .name = "connbytes", 155 .match = &match, 156 .checkentry = &check, 157 .me = THIS_MODULE 158}; 159 160static int __init init(void) 161{ 162 int ret; 163 ret = xt_register_match(AF_INET, &connbytes_match); 164 if (ret) 165 return ret; 166 167 ret = xt_register_match(AF_INET6, &connbytes6_match); 168 if (ret) 169 xt_unregister_match(AF_INET, &connbytes_match); 170 return ret; 171} 172 173static void __exit fini(void) 174{ 175 xt_unregister_match(AF_INET, &connbytes_match); 176 xt_unregister_match(AF_INET6, &connbytes6_match); 177} 178 179module_init(init); 180module_exit(fini);